我們不再積極開發此應用程式的功能。 PR 將被接受用於錯誤修復、翻譯和內容更新。活躍的功能開發正在進行 https://github.com/zooniverse/front-end-monorepo/
為了避免安裝 Node.js 或任何其他依賴項,您可以使用 Docker 和 Docker Compose 來執行所有內容。
docker-compose build
將建置本機 Docker 映像並執行npm ci
。每當您更改package.json
中的依賴項時執行此命令。
docker-compose up
啟動一個偵聽連接埠 3735 的開發 Web 伺服器。
docker-compose down
停止開發伺服器。
docker-compose run --rm shell
啟動一個運行 shell 的容器,例如。用於運行測試。
確保您有 Node 8 和npm
5 或更高版本。建議您使用nvm管理 Node 安裝。
npm ci
安裝依賴項。
npm start
在本地建置並運行該網站。
npm ci --legacy-peer-deps
來繞過此問題。請參閱問題 6155 以了解更多詳細資訊。
根/
被重定向到 www.zooniverse.org,因為該前端應用程式不再用於主頁。將瀏覽器指向子路徑以查看本地運行的應用程式。
開啟您選擇的網頁瀏覽器並前往https://localhost:3735/lab
如果您想透過 Panoptes API登入並查看經過驗證的頁面,則需要設定並使用https://local.zooniverse.org:3735/lab
而不是使用 localhost:3735。否則,您將遇到 CORS 錯誤。 (您需要將主機名稱新增至您的主機檔案中,指向本機。說明位於我們的 Stackoverflow 上。)
故障排除:網頁瀏覽器封鎖本地網站
問題:當嘗試查看localhost:3735或local.zooniverse.org:3735 時,我的網頁瀏覽器會阻止我並顯示警告畫面。
錯誤範例:Chrome 104 上的「您的連線不是私有的/NET::ERR_CERT_AUTHORITY_INVALID」; Firefox 103 上的「警告:未來存在潛在安全風險」; Safari 15.4 上「此連線不是私人的」。
原因:本機 Web 伺服器正在執行 HTTPS,並且使用自簽名憑證。現代網頁瀏覽器認為這些憑證非常不可信,並且可能是中間人攻擊的指標。
解決方案:
thisisunsafe
) 可暫時繞過警告;或者可以使用以下環境變數配置該應用程式:
NODE_ENV
- 設定程式碼的環境,並確定是否對捆綁程式碼應用任何生產最佳化,以及套用哪一組預設值,例如 API 主機 url、Talk 主機 url 等。PANOPTES_API_APPLICATION
- 設定向 Panoptes API 發出驗證請求時要使用的應用程式 ID。預設為NODE_ENV
設定的值。PANOPTES_API_HOST
- 設定 Panoptes API 實例的 URL。預設為NODE_ENV
設定的值。STAT_HOST
- 設定統計 API 實例的 URL。預設為NODE_ENV
設定的值。SUGAR_HOST
- 設定 Sugar API 實例的 URL。預設為NODE_ENV
設定的值。TALK_HOST
- 設定 Talk API 實例的 URL。預設為NODE_ENV
設定的值。 package.json
scripts
區塊中的命令設定的;為了覆蓋它們,您需要修改package.json
。NODE_ENV
環境變數設定的預設值,請參閱 panoptes-javascript-client 中的config.js
。來自 Zooniverse 組織內部的新 GitHub PR 將由 Jenkins 上演,作為 CI 流程的一部分。 CI 完成後,您的變更應在 https://pr-{PR-Number}.pfe-preview.zooniverse.org 上暫存。詹金斯有時會在完成構建之前超時。如果 PR 建置失敗,請使用 Jenkins 的連結(來自您的 PR)登入並嘗試重新啟動建置。
若要使用生產資料進行測試,您可以將env=production
新增至開發 URL,例如localhost:3735/projects?env=production
。請注意,它會在每次頁面刷新時被刪除。
所有好東西都在./app中。從./app/main.cjsx開始
我們根據 AirBnB 風格指南的修改版本來檢查 JavaScript 程式碼。請使用此儲存庫根目錄下的 .eslintrc 文件,透過 eslint 檢查您的變更。如果您有任何疑問,請隨時在 GitHub 上詢問我們。
編輯時,請盡力遵循專案已使用的樣式和架構約定。程式碼庫很大,風格在開發過程中不斷演變。請參閱 Zooniverse/front-end-monorepo 以了解我們組織組件的約定。
嘗試使用npm ci
更新您的依賴項。並且閱讀警告,它們應該告訴您是否使用了錯誤版本的 Node 或 npm 或是否缺少任何依賴項。如果您使用docker-compose
建置和測試站點,則 Node 版本不應遇到任何問題,但docker-compose build
將使用新的npm ci
建置新映像。
如果您編寫一個新元件,請編寫一個測試。每個元件都應該有自己的.spec.js
檔案。測試運行器是 Mocha,Enzyme 可用於測試 React 元件。編譯包含帶有模板字串的 ES6 導入語句的 CoffeeScript 檔案時,Mocha 會拋出錯誤( Illegal import declaration
)。將這些導入轉換為require
語句。您可以使用npm test
來執行測試。
部署由 Github Action 處理。
開啟拉取請求時,會觸發 Github 操作以部署到分支暫存位置。 Blob 儲存位置取決於拉取請求編號,例如https://pr-5926.pfe-preview.zooniverse.org
。
推送到 master 時,會觸發 Github Action 來部署到https://master.pfe-preview.zooniverse.org
上找到的 master staging。
生產部署由production-release
標籤指向的提交更新觸發。該標籤應透過聊天操作進行更新,然後執行 Github Action,建立檔案並將其上傳到我們的雲端供應商(網址為https://www.zooniverse.org
。如果您對儲存庫具有適當的權限,則可以根據需要在操作標籤中暫時執行生產部署,但僅在緊急情況下執行此操作。
所有與分類器相關的事情。
與集合相關的組件。
其他通用、可重複使用的元件。
應用程式層級的佈局內容放在這裡。如果它影響主網站頁首、主站頁腳或主站內容的佈局,那麼這就是它所在的位置。
跨組件重複使用的單一函數和資料。
這是應用程式的大部分內容所在。理想情況下,每個路由都指向一個頁面元件,該元件負責獲取資料並處理使用者可以對該資料執行的任何操作。此頁面元件使用該資料透過啞組件呈現 UI,並根據需要向下傳遞操作。
最初的目的是容納實際上不會在任何地方重複使用的隔離組件。這些可能更接近它們實際使用的地方。
主題視圖(TODOC:這與演講/收藏有什麼關係?)
與談話相關的組件。
此處的檔案將在建置期間複製到輸出目錄。
每個任務組件類別應該有幾個靜態組件:
Summary
:顯示任務註釋的分類後摘要。
Editor
:用於在專案建構器中編輯工作流程任務的元件。
如果任務需要在任務區域之外渲染,還有一些可用的分類介面的其餘部分的鉤子。
BeforeSubject
:任務期間出現在主題圖像之前的 HTML 內容。
InsideSubject
:任務期間顯示在主題影像上的 SVG 內容。
AfterSubject
HTML 內容在任務期間出現在主題圖像之後。
這些掛鉤可以以Persist
為前綴,這將使它們與任務一起出現,並且即使在使用者繼續執行下一個任務後也仍然存在。
Persist{Before,After}Task
運作方式相同,但針對的是任務區域。任務區域不需要非持久掛鉤。
每個元件還需要一些靜態方法:
getDefaultTask
:傳回當使用者將任務新增至專案建構器中的工作流程時用作預設值的任務描述。
getTaskText
:給定一個任務,這將傳回該任務的基本文字描述(例如問題任務中的問題、繪圖任務中的指令等)
getDefaultAnnotation
:分類器開始任務時產生的註釋
isAnnotationComplete
:給定一個任務和一個註釋,這決定了分類器是否允許使用者繼續執行下一個任務。
testAnnotationQuality
:給定使用者的註釋和相同任務的已知良好「黃金標準」註釋,這將傳回 0(完全錯誤)和 1(完全正確)之間的數字,指示使用者註釋與標準的接近程度。
確保在更新的任務變更時呼叫this.props.onChange
。
從MarkInitializer
元件呼叫的一些靜態方法,用於在使用者第一次建立標記操作期間控制標記的值:
defaultValues
:只是標記的一些預設值。
initStart
:對於每次 mousedown/touchstart,直到isComplete
回傳 true,傳回標記的值。
initMove
:對於每個 mousemove/touchmove,傳回標記的新值。
initRelease
:對於每個 mouseup/touchend,傳回標記的新值。
isComplete
:標記是否完整?在初始化器放棄控制之前,某些標記需要多次互動。
initValid
:如果標記無效(例如寬度或高度為零的矩形),它將自動銷毀。
幾個輔助元件是DrawingToolRoot
,它處理選取/停用狀態並呈現子任務彈出窗口,以及DeleteButton
和DragHandle
,它們為繪圖工具呈現一致的控制項。還有一個deleteIfOutOfBounds
函數,應該在任何整個標記拖曳後呼叫。
React 要求數組中的每個元件都有一個同級唯一的key
。當渲染沒有 ID 的事物陣列(註解、答案)時,請提供隨機_key
屬性(如果不存在)。確保以下劃線前綴的屬性不會保留。這對於JSONAPIClient.Model
類別來說是自動的。
< ul >
{ for item in things
item . _key ?= Math . random ()
< li key = { item . _key }>{ item . label }</ li >}
</ ul >
有一些好的不幸的是(事後看來)元件可以幫助處理非同步值。他們採用一個函數@props.children
,它看起來有點馬虎,但工作得相當不錯。大多數請求的資料都在本地緩存,因此通常是安全的,但如果您注意到連續多次發出相同的請求,那麼這些是開始尋找冗餘調用的好地方。下面是專案變更時重新渲染的範例,這會導致檢查專案擁有者。
< ChangeListener target = { @props . project }>{ =>
< PromiseRenderer promise = { @props . project . get ( ' owners ' )}>{([owner]) =>
if owner is @props . user
< p > This project is yours.</ p >
else
< p > This project belongs to { owner . display_name }.</ p >
}</ PromiseRenderer >
}</ ChangeListener >
不要使用ChangeListener
或PromiseRenderer
來寫新程式碼。
如果合理,請將ChangeListener
和PromiseRenderer
實例替換為您正在處理的程式碼中的元件狀態。它更冗長,但更具可讀性,而且它將使我們更接近將來在伺服器上渲染。
將組件功能所需的任何 CSS 包含在組件中,否則將其保存在單獨的文件中,每個組件一個。對於給定的元件,為該元件選擇一個唯一的頂層類別名,並在其下方嵌套子類別。在common.styl中保留通用的基本樣式和變數。手寫筆格式:有冒號,沒有分號,沒有大括號。 @extends
向上擴展,然後是屬性(按字母順序),然後是後代選擇器。盡可能使用display: flex
和flex-wrap: wrap
來明確媒體查詢。
我們的 CSS 已經變得非常龐大,因此我們正在嘗試使用 BEM 進行組織。
// <special-button.styl>
.special-button
background : red
color : white
.special-button__icon
width : 1 em ;
// <special-container.styl>
.special-container
margin : 1 em 1 vw
.special-container__button
border : 1 px solid
我們正在從 CoffeeScript 遷移到 ES6。這可以透過在 ES6 中編寫新元件或重寫現有元件來逐步完成。應該要提一些問題:
ES6 中不存在存在運算符。要麼明確地與null
比較,要麼使用!!thing
如果它只需要為真)。
原生 ES6 類別是首選,因為React.createClass()
已被棄用,但是,如果現有元件依賴 mixin,則考慮使用createReactClass()
。
Mixins 已被棄用,並且不受本機類支持,因此不要在新組件中使用它們。
使用反引號將 ES6 元件匯入 CoffeeScript 元件:
`import NewComponent from './new-component'`
ESLint 設定檔設定在儲存庫的根目錄中,供您與文字編輯器一起使用來檢查 ES6 並使用 Airbnb 的 React 風格指南。
編寫本機類別與使用createReactClass()
指南
請參閱panoptes-client庫:https://www.npmjs.com/package/panoptes-client。
註釋值的格式取決於用於產生它的任務。
single:所選答案的索引。
multiple:所選答案的索引數組(依照選取的順序)。
繪圖:一組繪圖工具標記(其說明如下)。
調查:一系列作為對象的標識。每個識別一個choice
(識別的動物的 ID)和answers
,一個物件。 answers
中的每個鍵都是問題的 ID。如果該問題允許多個答案,則該值將是答案 ID 的數組,否則只是答案 ID。
裁剪:包含裁剪區域的x
、 y
、 width
和height
的物件。
文字:一個字串。
組合:註釋的子數組。
dropdown:物件數組,其中字串value
指對應問題的答案,布林option
表示答案位於選項列表中。
所有座標均相對於圖像的左上角。
所有標記都有一個tool
,它是用來製作標記的工具的索引(例如workflow.tasks.T0.tools[0]
)。
所有標記都包含一個frame
,它是標記所在的主題幀(例如subject.locations[0]
)的索引。
如果為工具定義了details
任務,則其標記將具有子分類的details
數組(每個子分類都有一個value
,遵循上面的描述)。
圖紙標註值如下:
點: x
和y
座標。
line:起點 ( x1
, y1
) 和終點 ( x2
, y2
) 座標。
多邊形:物件數組,每個物件包含頂點的x
和y
座標。如果使用者未明確關閉該標記,則auto_closed
為true
。
矩形:矩形左上角的x
、 y
座標及其width
和height
。
圓:圓心的x
和y
座標及其半徑r
。
ellipse:橢圓中心的x
和y
座標、半徑rx
和ry
以及rx
相對於 x 軸的angle
(以度為單位)(從 3:00 開始逆時針)。
貝塞爾曲線:與多邊形相同,但每個奇數索引點都是二次貝塞爾曲線控制點的座標。
列:最左邊的x
像素和列選擇的width
。
感謝BrowserStack支援開源並讓我們在多個平台上測試這個專案。