Kami tidak lagi aktif mengembangkan fitur untuk aplikasi ini. PR akan diterima untuk perbaikan bug, terjemahan, dan pembaruan konten. Pengembangan fitur aktif sedang dilakukan di https://github.com/zooniverse/front-end-monorepo/
Untuk menghindari keharusan menginstal Node.js atau dependensi lainnya, Anda dapat menjalankan semuanya dengan Docker dan Docker Compose.
docker-compose build
akan membuat image Docker lokal dan menjalankan npm ci
. Jalankan ini setiap kali Anda mengubah dependensi di package.json
.
docker-compose up
memulai server web pengembangan yang mendengarkan pada port 3735.
docker-compose down
menghentikan server pengembangan.
docker-compose run --rm shell
memulai wadah yang menjalankan shell misalnya. untuk menjalankan tes.
Pastikan Anda memiliki Node 8 dan npm
5 atau lebih tinggi. Anda disarankan untuk mengelola instalasi Node Anda dengan nvm .
npm ci
menginstal dependensi.
npm start
membangun dan menjalankan situs secara lokal.
npm ci --legacy-peer-deps
. Silakan lihat edisi 6155 untuk lebih jelasnya.
Root /
dialihkan ke www.zooniverse.org karena aplikasi frontend ini tidak lagi digunakan untuk beranda. Arahkan browser Anda ke subjalur untuk melihat aplikasi ini berjalan secara lokal.
Buka browser web pilihan Anda dan buka https://localhost:3735/lab
Jika Anda ingin masuk melalui API Panoptes dan melihat halaman yang diautentikasi, Anda harus menyiapkan dan menggunakan https://local.zooniverse.org:3735/lab
daripada menggunakan localhost:3735. Jika tidak, Anda akan mengalami kesalahan CORS. (Anda perlu menambahkan nama host ke file host Anda, menunjuk ke lokal. Petunjuk ada di Stackoverflow kami.)
Pemecahan masalah: browser web memblokir situs web lokal
Masalahnya: ketika mencoba melihat localhost:3735 atau local.zooniverse.org:3735, browser web saya menghentikan saya dan menampilkan layar peringatan.
Contoh kesalahan: "Sambungan Anda tidak bersifat pribadi / NET::ERR_CERT_AUTHORITY_INVALID" di Chrome 104; "Peringatan: Potensi Risiko Keamanan di Depan" di Firefox 103; "Koneksi ini tidak bersifat pribadi" di Safari 15.4.
Penyebabnya: server web lokal menjalankan HTTPS dan menggunakan sertifikat yang ditandatangani sendiri. Peramban web modern menganggap sertifikat ini sangat tidak dapat dipercaya, dan kemungkinan merupakan indikator serangan man-in-the-middle.
Solusinya:
thisisunsafe
) di mana saja pada jendela untuk mengabaikan peringatan sementara; atauAplikasi dapat dikonfigurasi menggunakan variabel lingkungan berikut:
NODE_ENV
- menyetel lingkungan kode, dan menentukan apakah akan menerapkan pengoptimalan produksi apa pun pada kode yang dibundel, dan rangkaian default mana yang akan diterapkan misalnya url host API, url host Talk, dll.PANOPTES_API_APPLICATION
- menyetel ID aplikasi yang akan digunakan saat membuat permintaan autentikasi ke Panoptes API. Defaultnya ditetapkan oleh NODE_ENV
.PANOPTES_API_HOST
- menyetel URL instance API Panoptes. Defaultnya ditetapkan oleh NODE_ENV
.STAT_HOST
- menetapkan URL instance Stats API. Defaultnya ditetapkan oleh NODE_ENV
.SUGAR_HOST
- menyetel URL instance Sugar API. Defaultnya ditetapkan oleh NODE_ENV
.TALK_HOST
- menyetel URL instance Talk API. Defaultnya ditetapkan oleh NODE_ENV
. scripts
package.json
; untuk menggantinya, Anda perlu memodifikasi package.json
.NODE_ENV
, lihat config.js
di panoptes-javascript-client.PR GitHub baru dari dalam organisasi Zooniverse akan dipentaskan oleh Jenkins sebagai bagian dari proses CI. Setelah CI selesai, perubahan Anda akan dilakukan di https://pr-{PR-Number}.pfe-preview.zooniverse.org. Jenkins terkadang kehabisan waktu sebelum menyelesaikan pembangunan. Jika pembangunan PR gagal, gunakan tautan ke Jenkins (dari PR Anda) untuk masuk dan coba memulai ulang pembangunan.
Untuk pengujian dengan data produksi, Anda dapat menambahkan env=production
ke url pengembangan Anda, misalnya localhost:3735/projects?env=production
. Perhatikan bahwa itu dihapus pada setiap penyegaran halaman.
Semua hal bagus ada di ./app . Mulai di ./app/main.cjsx
Kami mengaitkan kode JavaScript kami dengan versi panduan gaya AirBnB yang dimodifikasi. Harap lint perubahan Anda dengan eslint, menggunakan file .eslintrc di root repo ini. Jika Anda memiliki pertanyaan, jangan ragu untuk bertanya kepada kami di GitHub.
Saat mengedit, lakukan yang terbaik untuk mengikuti gaya dan konvensi arsitektur yang sudah digunakan oleh proyek. Basis kodenya besar, dan gayanya telah berevolusi seiring perkembangannya. Lihat zooniverse/front-end-monorepo untuk mendapatkan gambaran tentang konvensi kami dalam mengatur komponen.
Coba npm ci
untuk menyegarkan dependensi Anda. Dan baca peringatannya, mereka akan memberi tahu Anda jika Anda menggunakan versi Node atau npm yang salah atau jika Anda kehilangan dependensi apa pun. Jika Anda menggunakan docker-compose
untuk membangun dan menguji situs, Anda tidak akan mengalami masalah apa pun dengan versi Node, tetapi docker-compose build
akan membuat image baru dengan npm ci
yang baru.
Jika Anda menulis komponen baru, tulis tes. Setiap komponen harus memiliki file .spec.js
sendiri. Test runnernya adalah Mocha dan Enzyme tersedia untuk menguji komponen React. Mocha memunculkan kesalahan ( Illegal import declaration
) saat mengkompilasi file skrip kopi yang berisi pernyataan impor ES6 dengan string templat. Ubah impor ini menjadi pernyataan require
. Anda dapat menjalankan tes dengan npm test
.
Penerapan ditangani oleh Github Action.
Saat membuka permintaan tarik, Tindakan Github dipicu untuk diterapkan ke lokasi pementasan cabang. Lokasi penyimpanan blob bergantung pada nomor permintaan penarikan, misalnya https://pr-5926.pfe-preview.zooniverse.org
.
Saat push to master, Tindakan Github dipicu untuk diterapkan ke staging master yang ditemukan di https://master.pfe-preview.zooniverse.org
.
Penerapan produksi dipicu oleh pembaruan yang menjadi tujuan penerapan tag production-release
. Tag ini harus diperbarui melalui operasi obrolan dan kemudian Tindakan Github akan berjalan yang membangun dan mengunggah file ke penyedia cloud kami yang terdapat di https://www.zooniverse.org
. Penerapan produksi dapat dijalankan secara ad hoc di tab tindakan sesuai kebutuhan jika Anda memiliki izin yang sesuai pada repositori, tetapi lakukan ini hanya dalam keadaan darurat.
Semua hal yang berhubungan dengan pengklasifikasi.
Komponen terkait koleksi.
Komponen umum lainnya yang dapat digunakan kembali.
Hal-hal tata letak tingkat aplikasi ada di sini. Jika memengaruhi header situs utama, footer situs utama, atau tata letak konten situs utama, di sinilah tempatnya.
Fungsi dan data individual yang digunakan kembali di seluruh komponen.
Di sinilah sebagian besar aplikasi berada. Idealnya, setiap rute menunjuk ke komponen halaman yang bertanggung jawab mengambil data dan menangani tindakan apa pun yang dapat dilakukan pengguna pada data tersebut. Komponen halaman tersebut menggunakan data tersebut untuk merender UI dengan komponen bodoh, meneruskan tindakan seperlunya.
Awalnya dimaksudkan untuk menampung komponen terisolasi yang sebenarnya tidak akan digunakan kembali di mana pun. Ini mungkin lebih dekat dengan tempat penggunaannya sebenarnya.
Tampilan subjek (TODOC: Apa kaitannya dengan Pembicaraan/koleksi?)
Komponen yang berhubungan dengan pembicaraan.
File di sini akan disalin ke direktori keluaran selama pembuatan.
Setiap kelas komponen tugas harus memiliki beberapa komponen statis:
Summary
: Menampilkan ringkasan pasca-klasifikasi dari anotasi tugas.
Editor
: Komponen yang digunakan untuk mengedit tugas alur kerja di pembuat proyek.
Ada juga beberapa kaitan ke antarmuka klasifikasi lainnya yang tersedia, jika tugas perlu dirender di luar area tugas.
BeforeSubject
: Konten HTML yang muncul sebelum gambar subjek selama tugas.
InsideSubject
: Konten SVG yang muncul di atas gambar subjek selama tugas.
Konten HTML AfterSubject
muncul setelah gambar subjek selama tugas.
Kait ini dapat diawali dengan Persist
, yang akan menyebabkan kait tersebut muncul bersama tugas dan tetap ada bahkan setelah pengguna berpindah ke tugas berikutnya.
Persist{Before,After}Task
bekerja dengan cara yang sama, tetapi untuk area tugas. Kait non-persisten tidak diperlukan untuk area tugas.
Setiap komponen juga memerlukan beberapa metode statis:
getDefaultTask
: Mengembalikan deskripsi tugas untuk digunakan sebagai default ketika pengguna menambahkan tugas ke alur kerja di pembuat proyek.
getTaskText
: Diberikan sebuah tugas, ini mengembalikan deskripsi teks dasar dari tugas tersebut (misalnya pertanyaan dalam tugas pertanyaan, instruksi dalam tugas menggambar, dll.)
getDefaultAnnotation
: Anotasi yang akan dihasilkan saat pengklasifikasi memulai tugas
isAnnotationComplete
: Diberikan tugas dan anotasi, ini menentukan apakah pengklasifikasi akan mengizinkan pengguna untuk melanjutkan ke tugas berikutnya atau tidak.
testAnnotationQuality
: Mengingat anotasi pengguna dan anotasi "standar emas" yang dikenal baik untuk tugas yang sama, ini mengembalikan angka antara 0 (benar-benar salah) dan 1 (benar sekali) yang menunjukkan seberapa dekat anotasi pengguna dengan standar.
Pastikan Anda memanggil this.props.onChange
dengan tugas yang diperbarui ketika ada perubahan.
Beberapa metode statis, dipanggil dari komponen MarkInitializer
, yang mengontrol nilai tanda selama tindakan pertama pengguna membuat tanda:
defaultValues
: Hanya beberapa default untuk tanda tersebut.
initStart
: Untuk setiap mousedown/touchstart hingga isComplete
mengembalikan nilai true, kembalikan nilai tandanya.
initMove
: Untuk setiap gerakan mouse/sentuh, kembalikan nilai baru untuk tandanya.
initRelease
: Untuk setiap mouseup/touchend, kembalikan nilai baru untuk tandanya.
isComplete
: Apakah tandanya sudah selesai? Beberapa tanda memerlukan beberapa interaksi sebelum penginisialisasi menyerahkan kendali.
initValid
: Jika suatu tanda tidak valid (misalnya persegi panjang dengan lebar dan tinggi nol), tanda tersebut akan dimusnahkan secara otomatis.
Beberapa komponen pembantu adalah DrawingToolRoot
yang menangani status yang dipilih/dinonaktifkan dan menampilkan popup subtugas, serta DeleteButton
dan DragHandle
, yang memberikan kontrol yang konsisten untuk alat menggambar. Ada juga fungsi deleteIfOutOfBounds
yang harus dipanggil setelah seluruh tanda ditarik.
React mengharuskan setiap komponen dalam array memiliki key
unik saudaranya. Saat merender array yang tidak memiliki ID (anotasi, jawaban), berikan properti _key
acak jika tidak ada. Pastikan properti dengan awalan garis bawah tidak dipertahankan. Itu otomatis dengan kelas JSONAPIClient.Model
.
< ul >
{ for item in things
item . _key ?= Math . random ()
< li key = { item . _key }>{ item . label }</ li >}
</ ul >
ada beberapa Bagus komponen yang disayangkan (jika dipikir-pikir) untuk membantu dengan nilai async. Mereka mengambil fungsi sebagai @props.children
, yang terlihat agak berlebihan tetapi berfungsi dengan baik. Sebagian besar data yang diminta di-cache secara lokal, jadi ini biasanya aman, namun jika Anda melihat permintaan yang sama dibuat beberapa kali berturut-turut, ini adalah tempat yang baik untuk mulai mencari panggilan yang berlebihan. Berikut ini contoh rendering ulang ketika suatu proyek berubah, yang mengakibatkan pengecekan pemilik proyek.
< 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 >
Jangan menulis kode baru menggunakan ChangeListener
atau PromiseRenderer
.
Jika masuk akal, ganti instance ChangeListener
dan PromiseRenderer
dengan status komponen dalam kode yang Anda kerjakan. Ini lebih bertele-tele, tapi lebih mudah dibaca, dan akan membuat kita lebih dekat untuk melakukan rendering di server di masa depan.
Sertakan CSS apa pun yang diperlukan untuk fungsionalitas komponen sejajar dengan komponen, jika tidak, simpanlah dalam file terpisah, satu per komponen. Untuk komponen tertentu, pilih nama kelas tingkat atas yang unik untuk komponen tersebut dan susun kelas turunan di bawahnya. Pertahankan gaya dan variabel dasar yang umum di common.styl . Pemformatan stylus: Ya titik dua, tanpa titik koma, tanpa kurung kurawal. @extends
di bagian atas, lalu properti (menurut abjad), lalu pemilih turunan. Lebih suka penggunaan display: flex
dan flex-wrap: wrap
daripada kueri media eksplisit jika memungkinkan.
CSS kami menjadi sangat besar, jadi kami mencoba BEM untuk organisasi.
// <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
Kami bermigrasi dari coffeescript ke ES6. Hal ini dapat dilakukan secara bertahap dengan menulis komponen baru atau menulis ulang komponen yang sudah ada di ES6. Beberapa hal yang perlu disebutkan:
Operator eksistensial tidak ada di ES6. Bandingkan secara eksplisit dengan null
atau gunakan !!thing
jika itu memang benar.
Kelas ES6 asli lebih disukai karena React.createClass()
tidak digunakan lagi. Namun, jika komponen yang ada mengandalkan mixin, maka pertimbangkan untuk menggunakan createReactClass()
.
Mixin sudah tidak digunakan lagi dan tidak didukung dengan kelas asli, jadi jangan menggunakannya di komponen baru.
Gunakan backticks untuk mengimpor komponen ES6 ke dalam komponen coffeescript:
`import NewComponent from './new-component'`
File konfigurasi ESLint disiapkan di root repositori untuk Anda gunakan dengan editor teks Anda untuk lint ES6 dan menggunakan panduan gaya React Airbnb.
Panduan tentang menulis kelas asli versus menggunakan createReactClass()
Lihat perpustakaan panoptes-client : https://www.npmjs.com/package/panoptes-client.
Format nilai anotasi bergantung pada tugas yang digunakan untuk menghasilkannya.
single : Indeks jawaban yang dipilih.
multiple: Serangkaian indeks jawaban yang dipilih (sesuai urutan pilihannya).
gambar: Serangkaian tanda alat gambar (deskripsinya ikuti di bawah).
survei: Serangkaian identifikasi sebagai objek. Setiap identifikasi merupakan choice
(ID hewan yang diidentifikasi) dan answers
, suatu objek. Setiap kunci answers
adalah ID pertanyaan. Jika pertanyaan tersebut memungkinkan beberapa jawaban, nilainya akan berupa array ID jawaban, jika tidak, hanya satu ID jawaban.
crop: Objek yang berisi x
, y
, width
, dan height
wilayah yang dipangkas.
teks: Sebuah string.
kombo: Sub-array anotasi.
dropdown: Array objek yang value
stringnya mengacu pada jawaban pertanyaan terkait dan option
boolean menunjukkan bahwa jawabannya ada dalam daftar opsi.
Semua koordinat relatif terhadap kiri atas gambar.
Semua tanda memiliki tool
, yang merupakan indeks dari alat tersebut (misalnya workflow.tasks.T0.tools[0]
) yang digunakan untuk membuat tanda.
Semua tanda mengandung frame
, yang merupakan indeks dari frame subjek (misalnya subject.locations[0]
) tempat tanda tersebut dibuat.
Jika tugas details
ditentukan untuk suatu alat, tandanya akan memiliki susunan subklasifikasi details
(masing-masing dengan value
, mengikuti uraian di atas).
Nilai anotasi gambar adalah sebagai berikut:
titik: Koordinat x
dan y
.
garis: Koordinat awal ( x1
, y1
) dan akhir ( x2
, y2
).
poligon: Array objek, masing-masing berisi koordinat x
dan y
dari sebuah titik. Jika tanda tidak ditutup secara eksplisit oleh pengguna, auto_closed
adalah true
.
persegi panjang: Koordinat x
, y
dari titik kiri atas persegi panjang beserta width
dan height
.
lingkaran: Koordinat x
dan y
dari pusat lingkaran dan jari-jarinya r
.
elips: Koordinat x
dan y
dari pusat elips, jari-jarinya rx
dan ry
, dan angle
rx
terhadap sumbu x dalam derajat (berlawanan arah jarum jam mulai pukul 3:00).
bezier: Sama seperti poligon, tetapi setiap titik berindeks ganjil adalah koordinat titik kendali kurva bezier kuadrat.
kolom: x
piksel paling kiri dan width
pilihan kolom.
Terima kasih kepada BrowserStack yang mendukung open source dan mengizinkan kami menguji proyek ini di berbagai platform.