우리는 더 이상 이 앱의 기능을 적극적으로 개발하지 않습니다. 버그 수정, 번역, 콘텐츠 업데이트에 대한 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에서 수신 대기하는 개발 웹 서버를 시작합니다.
docker-compose down
개발 서버를 중지합니다.
docker-compose run --rm shell
쉘을 실행하는 컨테이너를 시작합니다. 테스트를 실행하기 위해.
Node 8 및 npm
5 이상이 있는지 확인하세요. nvm 을 사용하여 노드 설치를 관리하는 것이 좋습니다.
npm ci
종속성을 설치합니다.
npm start
사이트를 로컬로 빌드하고 실행합니다.
npm ci --legacy-peer-deps
실행하여 이 문제를 우회할 수 있습니다. 자세한 내용은 문제 6155를 참조하세요.
이 프런트엔드 앱은 더 이상 홈페이지에 사용되지 않으므로 루트 /
www.zooniverse.org로 리디렉션됩니다. 이 앱이 로컬에서 실행되는 것을 보려면 브라우저에서 하위 경로를 지정하세요.
원하는 웹 브라우저를 열고 https://localhost:3735/lab
로 이동합니다.
Panoptes API를 통해 로그인 하고 인증된 페이지를 보려면 localhost:3735를 사용하는 대신 https://local.zooniverse.org:3735/lab
설정하고 사용해야 합니다. 그렇지 않으면 CORS 오류가 발생합니다. (로컬을 가리키는 호스트 이름을 호스트 파일에 추가해야 합니다. 지침은 Stackoverflow에 있습니다.)
문제 해결: 웹 브라우저가 로컬 웹사이트를 차단합니다.
문제: localhost:3735 또는 local.zooniverse.org:3735 를 보려고 할 때 웹 브라우저가 나를 멈추고 경고 화면을 표시합니다.
오류 예: Chrome 104에서 "연결이 비공개가 아닙니다/NET::ERR_CERT_AUTHORITY_INVALID"; Firefox 103의 "경고: 잠재적인 보안 위험"; Safari 15.4에서 "이 연결은 비공개가 아닙니다."
원인: 로컬 웹 서버가 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은 CI 프로세스의 일부로 Jenkins에 의해 준비됩니다. CI가 완료되면 변경 사항이 https://pr-{PR-Number}.pfe-preview.zooniverse.org에 준비되어야 합니다. Jenkins는 빌드를 완료하기 전에 시간이 초과되는 경우가 있습니다. PR 빌드가 실패하면 PR의 Jenkins 링크를 사용하여 로그인하고 빌드를 다시 시작해 보세요.
프로덕션 데이터로 테스트하려면 개발 URL에 env=production
추가할 수 있습니다(예: 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 가져오기 문이 포함된 커피 스크립트 파일을 컴파일할 때 Mocha에서 오류( Illegal import declaration
)가 발생합니다. 이러한 가져오기를 require
문으로 변환하세요. npm test
사용하여 테스트를 실행할 수 있습니다.
배포는 Github Action에 의해 처리됩니다.
끌어오기 요청을 열면 Github 작업이 트리거되어 분기 준비 위치에 배포됩니다. Blob 저장소 위치는 끌어오기 요청 번호에 따라 다릅니다(예: https://pr-5926.pfe-preview.zooniverse.org
).
마스터로 푸시하면 https://master.pfe-preview.zooniverse.org
에 있는 마스터 스테이징에 배포하기 위해 Github 작업이 트리거됩니다.
프로덕션 배포는 production-release
태그가 가리키는 커밋 업데이트에 의해 트리거됩니다. 이 태그는 채팅 작업을 통해 업데이트되어야 하며, Github 작업이 실행되어 파일을 빌드하고 https://www.zooniverse.org
에 있는 클라우드 제공업체에 업로드합니다. 리포지토리에 대한 적절한 권한이 있는 경우 필요에 따라 작업 탭에서 프로덕션 배포를 임시로 실행할 수 있지만 이는 긴급 상황에서만 수행하십시오.
분류기와 관련된 모든 것.
컬렉션 관련 구성요소.
기타 일반, 재사용 가능한 구성 요소.
앱 수준 레이아웃 항목이 여기에 표시됩니다. 기본 사이트 헤더, 기본 사이트 바닥글 또는 기본 사이트 콘텐츠의 레이아웃에 영향을 미치는 경우 여기에 위치합니다.
구성 요소 전체에서 재사용되는 개별 기능 및 데이터입니다.
이곳은 앱의 대부분이 존재하는 곳입니다. 이상적으로 각 경로는 데이터를 가져오고 사용자가 해당 데이터에 대해 수행할 수 있는 모든 작업을 처리하는 페이지 구성 요소를 가리킵니다. 해당 페이지 구성 요소는 해당 데이터를 사용하여 단순 구성 요소로 UI를 렌더링하고 필요에 따라 작업을 전달합니다.
원래는 실제로 어디에서나 재사용되지 않는 분리된 구성 요소를 보관하기 위한 것이었습니다. 이것들은 아마도 실제로 사용되는 곳에 더 가깝습니다.
주제 보기(TODOC: Talk/컬렉션과 어떤 관련이 있나요?)
Talk 관련 구성 요소입니다.
여기에 있는 파일은 빌드 중에 출력 디렉터리에 복사됩니다.
각 작업 구성 요소 클래스에는 몇 가지 정적 구성 요소가 있어야 합니다.
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
: isComplete
true를 반환할 때까지 모든 mousedown/touchstart에 대해 마크 값을 반환합니다.
initMove
: 모든 마우스 이동/터치 이동에 대해 마크에 대한 새 값을 반환합니다.
initRelease
: 모든 mouseup/touchend에 대해 마크에 대한 새 값을 반환합니다.
isComplete
: 마크가 완료되었나요? 일부 표시에는 이니셜라이저가 제어를 포기하기 전에 여러 상호 작용이 필요합니다.
initValid
: 마크가 유효하지 않은 경우(예: 너비나 높이가 0인 직사각형) 자동으로 삭제됩니다.
몇 가지 도우미 구성 요소는 선택/비활성화 상태를 처리하고 하위 작업 팝업을 렌더링하는 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
사용하세요.
React.createClass()
더 이상 사용되지 않으므로 기본 ES6 클래스가 선호됩니다. 그러나 기존 구성 요소가 믹스인에 의존하는 경우 createReactClass()
사용을 고려하세요.
믹스인은 더 이상 사용되지 않으며 기본 클래스에서 지원되지 않으므로 새 구성 요소에서는 사용하지 마세요.
백틱을 사용하여 ES6 구성 요소를 Coffeescript 구성 요소로 가져옵니다.
`import NewComponent from './new-component'`
ES6를 린트하고 Airbnb의 React 스타일 가이드를 사용하기 위해 텍스트 편집기와 함께 사용할 수 있도록 저장소 루트에 ESLint 구성 파일이 설정되어 있습니다.
네이티브 클래스 작성과 createReactClass()
사용에 대한 가이드
panoptes-client 라이브러리(https://www.npmjs.com/package/panoptes-client)를 참조하세요.
주석 값의 형식은 주석을 생성하는 데 사용된 작업에 따라 다릅니다.
단일: 선택한 답변의 인덱스입니다.
multiple: 선택한 답변의 인덱스 배열(선택한 순서대로)입니다.
Drawing: 그리기 도구 표시의 배열입니다(아래에 설명되어 있음).
설문 조사: 개체로서의 식별 배열입니다. 각 식별은 choice
(식별된 동물의 ID)과 answers
, 개체입니다. answers
의 각 키는 질문의 ID입니다. 해당 질문이 여러 답변을 허용하는 경우 값은 답변 ID의 배열이 되고, 그렇지 않으면 단일 답변 ID만 됩니다.
자르기: 잘린 영역의 x
, y
, width
및 height
포함하는 객체입니다.
텍스트: 문자열입니다.
콤보: 주석의 하위 배열입니다.
드롭다운: 문자열 value
해당 질문에 대한 답변을 참조하고 부울 option
답변이 옵션 목록에 있음을 나타내는 개체 배열입니다.
모든 좌표는 이미지의 왼쪽 상단을 기준으로 합니다.
모든 마크에는 마크를 만드는 데 사용된 tool
(예: workflow.tasks.T0.tools[0]
)의 인덱스인 도구가 있습니다.
모든 마크에는 마크가 만들어진 주제 프레임(예: subject.locations[0]
)의 인덱스인 frame
이 포함되어 있습니다.
도구에 대해 details
작업이 정의된 경우 해당 표시에는 하위 분류의 details
배열이 포함됩니다(위 설명에 따라 각각 value
있음).
도면 주석 값은 다음과 같습니다.
point: x
및 y
좌표입니다.
line: 시작( x1
, y1
) 및 끝( x2
, y2
) 좌표입니다.
다각형: 각각 정점의 x
및 y
좌표를 포함하는 객체 배열입니다. 사용자가 마크를 명시적으로 닫지 않은 경우 auto_closed
는 true
입니다.
직사각형: 직사각형의 왼쪽 상단 지점의 x
, y
좌표와 width
및 height
입니다.
원: 원 중심의 x
및 y
좌표와 반지름 r
입니다.
ellipse: 타원 중심의 x
및 y
좌표, 반경 rx
및 ry
, x 축을 기준으로 한 rx
angle
(도 단위)(3:00부터 시계 반대 방향).
베지어: 다각형과 동일하지만 홀수 인덱스의 모든 점은 2차 베지어 곡선의 제어점 좌표입니다.
열: 가장 왼쪽 x
픽셀 및 열 선택 width
.
오픈 소스를 지원하고 여러 플랫폼에서 이 프로젝트를 테스트할 수 있게 해준 BrowserStack에게 감사드립니다.