Мы больше не занимаемся активной разработкой функций этого приложения. 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 или выше. Рекомендуется управлять установками Node с помощью nvm .
npm ci
устанавливает зависимости.
npm start
собирает и запускает сайт локально.
npm ci --legacy-peer-deps
. Дополнительные сведения см. в выпуске 6155.
Корневой каталог /
перенаправляется на www.zooniverse.org, поскольку это внешнее приложение больше не используется для домашней страницы. Укажите в браузере дополнительный путь, чтобы просмотреть это приложение, работающее локально.
Откройте выбранный вами веб-браузер и перейдите по адресу https://localhost:3735/lab
Если вы хотите войти в систему через API Panoptes и просматривать аутентифицированные страницы, вам необходимо настроить и использовать https://local.zooniverse.org:3735/lab
вместо использования localhost:3735. В противном случае вы столкнетесь с ошибками CORS. (Вам необходимо добавить имя хоста в файл хостов, указав на локальный. Инструкции находятся в нашем Stackoverflow.)
Устранение неполадок: веб-браузер блокирует локальный веб-сайт.
Проблема: при попытке просмотра localhost:3735 или local.zooniverse.org:3735 мой веб-браузер останавливает меня и показывает экран с предупреждением.
Примеры ошибок: «Ваше соединение не является частным / NET::ERR_CERT_AUTHORITY_INVALID» в Chrome 104; «Предупреждение: впереди потенциальная угроза безопасности» в Firefox 103; «Это соединение не является частным» в Safari 15.4.
Причина: на локальном веб-сервере работает HTTPS и используется самозаверяющий сертификат. Современные веб-браузеры считают эти сертификаты очень ненадежными и могут служить индикатором атаки «человек посередине».
Решение(а):
thisisunsafe
) в любом месте окна, чтобы временно обойти предупреждение; илиПриложение можно настроить с использованием следующих переменных среды:
NODE_ENV
— устанавливает среду кода и определяет, следует ли применять какие-либо производственные оптимизации к связанному коду, а также какой набор значений по умолчанию применять, например, для URL-адреса хоста API, URL-адреса хоста Talk и т. д.PANOPTES_API_APPLICATION
— устанавливает идентификатор приложения, который будет использоваться при отправке запросов аутентификации к API Panoptes. По умолчанию установлено значение NODE_ENV
.PANOPTES_API_HOST
— устанавливает URL-адрес экземпляра Panoptes API. По умолчанию установлено значение NODE_ENV
.STAT_HOST
— устанавливает URL-адрес экземпляра Stats API. По умолчанию установлено значение NODE_ENV
.SUGAR_HOST
— устанавливает URL-адрес экземпляра Sugar API. По умолчанию установлено значение NODE_ENV
.TALK_HOST
— устанавливает URL-адрес экземпляра Talk API. По умолчанию установлено значение NODE_ENV
. scripts
package.json
; чтобы их переопределить, вам необходимо изменить package.json
.NODE_ENV
, см. config.js
в panoptes-javascript-client.Новые PR-сообщения GitHub от организации Zooniverse будут организованы Дженкинсом в рамках процесса 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.
Мы сравниваем наш код JavaScript с модифицированной версией руководства по стилю AirBnB. Пожалуйста, проверьте свои изменения с помощью eslint, используя файл .eslintrc в корне этого репозитория. Если у вас есть какие-либо вопросы, не стесняйтесь задавать их нам на GitHub.
При редактировании старайтесь следовать правилам стиля и архитектуры, уже использованным в проекте. Кодовая база велика, и стили менялись в ходе ее разработки. Взгляните на Zooniverse/front-end-monorepo, чтобы получить представление о наших соглашениях по организации компонентов.
Попробуйте npm ci
чтобы обновить ваши зависимости. И прочитайте предупреждения, они должны сообщить вам, используете ли вы неправильную версию Node или npm или у вас отсутствуют какие-либо зависимости. Если вы используете docker-compose
для сборки и тестирования сайта, у вас не должно возникнуть никаких проблем с версией Node, но docker-compose build
создаст новый образ со свежим npm ci
.
Если вы пишете новый компонент, напишите тест. Каждый компонент должен иметь собственный файл .spec.js
. Средство запуска тестов — Mocha, а для тестирования компонентов React доступен Enzyme. Mocha выдает ошибку ( Illegal import declaration
) при компиляции файлов Coffeescript, содержащих операторы импорта ES6 со строками шаблона. Преобразуйте этот импорт в операторы require
. Вы можете запустить тесты с помощью npm test
.
Развертывание осуществляется Github Action.
При открытии запросов на включение запускается действие Github для развертывания в промежуточном месте ветки. Местоположение хранилища больших двоичных объектов зависит от номера запроса на извлечение, например https://pr-5926.pfe-preview.zooniverse.org
.
При нажатии на мастер запускается действие Github для развертывания на главной промежуточной стадии, расположенной по адресу https://master.pfe-preview.zooniverse.org
.
Производственное развертывание инициируется обновлением, на фиксацию которого указывает тег production-release
. Этот тег следует обновить через чат, а затем запустится действие Github, которое создаст и загрузит файлы нашему облачному провайдеру, расположенному по адресу https://www.zooniverse.org
. Рабочее развертывание можно запускать по мере необходимости на вкладке действий, если у вас есть соответствующие разрешения на доступ к репозиторию, но делайте это только в экстренных случаях.
Все, что связано с классификаторами.
Компоненты, связанные с коллекциями.
Различные универсальные, многоразовые компоненты.
Здесь находятся макеты уровня приложения. Если он влияет на заголовок основного сайта, нижний колонтитул основного сайта или макет основного содержимого сайта, он находится здесь.
Отдельные функции и данные, которые повторно используются в компонентах.
Здесь находится большая часть приложения. В идеале каждый маршрут указывает на компонент страницы, отвечающий за получение данных и обработку любых действий, которые пользователь может выполнить с этими данными. Этот компонент страницы использует эти данные для рендеринга пользовательского интерфейса с помощью простых компонентов, передавая действия по мере необходимости.
Первоначально предназначался для хранения изолированных компонентов, которые фактически нигде не использовались повторно. Они, вероятно, принадлежат ближе к тому месту, где они на самом деле используются.
Просмотры предметов (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
: для каждого нажатия кнопки мыши/нажатия до тех пор, пока isComplete
не вернет true, возвращает значения для метки.
initMove
: для каждого перемещения мыши/прикосновения возвращайте новые значения метки.
initRelease
: при каждом нажатии мыши или касании возвращать новые значения метки.
isComplete
: Отметка завершена? Некоторые метки требуют нескольких взаимодействий, прежде чем инициализатор передаст управление.
initValid
: Если метка недействительна (например, прямоугольник с нулевой шириной или высотой), она будет автоматически уничтожена.
Пара вспомогательных компонентов — это DrawingToolRoot
, который обрабатывает выбранные/отключенные состояния и отображает всплывающие окна подзадач, а также DeleteButton
и DragHandle
, которые отображают согласованные элементы управления для инструментов рисования. Существует также функция deleteIfOutOfBounds
, которую следует вызывать после любого перетаскивания целой метки.
React требует, чтобы каждый компонент в массиве имел уникальный key
. При рендеринге массивов вещей, у которых нет идентификаторов (аннотаций, ответов), укажите случайное свойство _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 стал действительно огромным, поэтому мы пробуем БЭМ для организации.
// <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()
устарел, однако, если существующий компонент использует примеси, рассмотрите возможность использования createReactClass()
.
Миксины устарели и не поддерживаются нативными классами, поэтому не используйте их в новых компонентах.
Используйте обратные кавычки для импорта компонентов ES6 в компоненты Coffeescript:
`import NewComponent from './new-component'`
Файл конфигурации ESLint устанавливается в корне репозитория, чтобы вы могли использовать его с текстовым редактором для проверки ES6 и использования руководства по стилю Airbnb React.
Руководство по написанию собственных классов в сравнении с использованием createReactClass()
См. библиотеку panoptes-client : https://www.npmjs.com/package/panoptes-client.
Формат значения аннотации зависит от задачи, использованной для ее создания.
одиночный: индекс выбранного ответа.
Multiple: Массив индексов выбранных ответов (в том порядке, в котором они были выбраны).
рисунок: Массив меток инструмента рисования (описания которых приведены ниже).
опрос: Массив идентификаций как объектов. Каждая идентификация choice
(идентификатор идентифицированного животного) и answers
, объект. Каждый ключ в answers
является идентификатором вопроса. Если этот вопрос допускает несколько ответов, значением будет массив идентификаторов ответов, в противном случае — только один идентификатор ответа.
обрезка: объект, содержащий x
, y
, width
и height
обрезанной области.
текст: строка.
комбо: подмассив аннотаций.
раскрывающийся список: массив объектов, где строковое value
относится к ответу на соответствующий вопрос, а логический option
указывает, что ответ был в списке параметров.
Все координаты указаны относительно верхнего левого угла изображения.
У всех отметок есть tool
, который является индексом инструмента (например, workflow.tasks.T0.tools[0]
), использованного для создания отметки.
Все метки содержат frame
, который является индексом предметного фрейма (например, subject.locations[0]
), в котором была сделана метка.
Если для инструмента определены details
задачи, его отметки будут иметь массив подклассов details
(каждый со value
, как описано выше).
Значение аннотации чертежа следующее:
точка: координаты x
и y
.
линия: координаты начала ( x1
, y1
) и конца ( x2
, y2
).
многоугольник: Массив объектов, каждый из которых содержит координаты x
и y
вершины. Если отметка не была закрыта пользователем явно, auto_closed
имеет значение true
.
прямоугольник: координаты x
, y
верхней левой точки прямоугольника, а также его width
и height
.
круг: координаты x
и y
центра круга и его радиуса r
.
эллипс: координаты x
и y
центра эллипса, его радиусы rx
и ry
и angle
rx
относительно оси x в градусах (против часовой стрелки, начиная с 3:00).
Безье: То же, что и многоугольник, но каждая точка с нечетным индексом является координатой контрольной точки квадратичной кривой Безье.
столбец: крайний левый пиксель x
и width
выделенного столбца.
Спасибо BrowserStack за поддержку открытого исходного кода и возможность протестировать этот проект на нескольких платформах.