diff --git a/.github/workflows/cache-modifier.yml b/.github/workflows/cache-modifier.yml new file mode 100644 index 0000000000..0c32c846c4 --- /dev/null +++ b/.github/workflows/cache-modifier.yml @@ -0,0 +1,29 @@ +name: Cache Modifier + +on: + workflow_call: + inputs: + skip-cache: + description: "Skip Cache" + required: true + default: "false" + type: string + outputs: + cache-modifier: + description: "Cache Modifier" + value: ${{ jobs.prepare-cache.outputs.cache-modifier }} + +jobs: + prepare-cache: + runs-on: ubuntu-latest + outputs: + cache-modifier: ${{ steps.set-cache-modifier.outputs.cache-modifier }} + steps: + - name: Set cache modifier + id: set-cache-modifier + run: | + if [[ "${{ inputs.skip-cache }}" == "true" ]] || [[ "$GITHUB_EVENT_NAME" == "schedule" ]]; then + echo "cache-modifier=$(date +%s)" >> $GITHUB_OUTPUT + else + echo "cache-modifier=" >> $GITHUB_OUTPUT + fi diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 53fcae1e4e..6284354a18 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -3,12 +3,35 @@ on: workflow_call: inputs: environment: + description: The Github environment to load secrets from type: string required: true + netlify-context: + description: The Netlify context use when building + type: string + required: true + netlify-alias: + description: The Netlify alias to deploy to (empty deploys to production) + type: string + required: true + sha: + description: The commit SHA to deploy + type: string + required: true + runner-label: + description: The label of the runner to use + type: string + cache-modifier: + description: A modifier for the cache key used to bypass existing cache + type: string + required: false + default: "" + jobs: netlify-deploy: environment: ${{ inputs.environment }} - runs-on: ubuntu-latest + runs-on: + labels: ${{ inputs.runner-label || 'ubuntu-latest' }} defaults: run: shell: bash @@ -19,35 +42,33 @@ jobs: - name: Checkout uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ inputs.sha }} - name: Read node modules from cache id: cache-nodemodules - uses: actions/cache/restore@v3 + uses: actions/cache/restore@v4 env: cache-name: cache-install-folder with: path: | site/gatsby-site/node_modules - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}-${{ inputs.cache-modifier }} - name: Set up Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 - name: Install dependencies if: steps.cache-nodemodules.outputs.cache-hit != 'true' run: npm ci - - name: Use new netlify.toml - run: | - rm -f netlify.toml - mv github-netlify.toml netlify.toml + - name: Use deploy specific netlify.toml + run: mv deploy-netlify.toml netlify.toml - name: Install Netlify CLI run: npm install netlify-cli -g - name: Build using Netlify - run: netlify build --context deploy-preview --offline + run: netlify build --context ${{ inputs.netlify-context }} --offline env: NETLIFY_SITE_ID: ${{ vars.NETLIFY_SITE_ID }} NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} @@ -65,6 +86,7 @@ jobs: MONGODB_CONNECTION_STRING: ${{ secrets.MONGODB_CONNECTION_STRING }} MONGODB_REPLICA_SET: ${{ secrets.MONGODB_REPLICA_SET }} MONGODB_TRANSLATIONS_CONNECTION_STRING: ${{ secrets.MONGODB_TRANSLATIONS_CONNECTION_STRING }} + TRANSLATE_SUBMISSION_DATE_START: ${{ vars.TRANSLATE_SUBMISSION_DATE_START }} MONGODB_MIGRATIONS_CONNECTION_STRING: ${{ secrets.MONGODB_MIGRATIONS_CONNECTION_STRING }} GATSBY_REALM_APP_GRAPHQL_URL: ${{ secrets.GATSBY_REALM_APP_GRAPHQL_URL }} GATSBY_PRISMIC_REPO_NAME: ${{ vars.GATSBY_PRISMIC_REPO_NAME }} @@ -78,13 +100,20 @@ jobs: CLOUDFLARE_R2_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }} CLOUDFLARE_R2_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_SECRET_ACCESS_KEY }} REALM_GRAPHQL_API_KEY: ${{ secrets.REALM_GRAPHQL_API_KEY }} + GATSBY_COMMIT_SHA: ${{ inputs.sha }} - name: Upload to netlify id: deploy-netlify working-directory: site/gatsby-site run: | set -e - OUTPUT=$(bash -c "netlify deploy --json --alias=pr-${{ github.event.pull_request.number }}" | tr '\n' ' ') + # If no alias is specified, deploy to production + if [[ -z "${{ inputs.netlify-alias }}" ]]; then + OUTPUT=$(bash -c "netlify deploy --json --prod" | tr '\n' ' ') + # Otherwise, deploy to the specified alias + else + OUTPUT=$(bash -c "netlify deploy --json --alias=${{ inputs.netlify-alias }}" | tr '\n' ' ') + fi set +e NETLIFY_OUTPUT=$(echo "$OUTPUT") echo "deploy_log=$NETLIFY_OUTPUT" >> $GITHUB_OUTPUT @@ -93,16 +122,28 @@ jobs: NETLIFY_SITE_ID: ${{ vars.NETLIFY_SITE_ID }} - name: Comment on PR - uses: actions/github-script@v5 + uses: actions/github-script@v7 with: github-token: ${{secrets.GITHUB_TOKEN}} script: | const deployOutput = `${{ steps.deploy-netlify.outputs.deploy_log }}`; const deployData = JSON.parse(deployOutput); const comment = `🚀 Deployed to Netlify!\n\n✅ Build Log: \n${deployData.logs}\n\n🔗 Preview URL: ${deployData.deploy_url}`; - github.rest.issues.createComment({ - issue_number: context.issue.number, + + const { data: pullRequests } = await github.rest.repos.listPullRequestsAssociatedWithCommit({ owner: context.repo.owner, repo: context.repo.repo, - body: comment + commit_sha: '${{ inputs.sha }}' }); + + for (const pr of pullRequests) { + if (pr.state === 'open') { + github.rest.issues.createComment({ + issue_number: pr.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: comment + }); + break; // Assuming you want to comment only on the first open PR + } + } diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 5820fdcf5d..357759f273 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -5,6 +5,7 @@ on: branches: - staging types: [opened, synchronize, reopened] + jobs: permissions-check: runs-on: ubuntu-latest @@ -31,7 +32,9 @@ jobs: needs: permissions-check secrets: inherit with: + sha: ${{ github.event.pull_request.head.sha }} environment: staging + netlify-context: deploy-preview call-test: if: ${{ !failure() }} @@ -39,6 +42,7 @@ jobs: needs: call-test-build secrets: inherit with: + sha: ${{ github.event.pull_request.head.sha }} environment: staging call-deploy: @@ -49,4 +53,7 @@ jobs: permissions: pull-requests: write with: + sha: ${{ github.event.pull_request.head.sha }} environment: staging + netlify-context: deploy-preview + netlify-alias: pr-${{ github.event.pull_request.number }} diff --git a/.github/workflows/production.yml b/.github/workflows/production.yml new file mode 100644 index 0000000000..c471747bcc --- /dev/null +++ b/.github/workflows/production.yml @@ -0,0 +1,71 @@ +name: Deploy Production Branch + +on: + push: + branches: + - master + schedule: + - cron: "0 6,18 * * *" + workflow_dispatch: + inputs: + skip-cache: + description: "Skip Cache" + required: true + default: true + type: boolean + force-deploy: + description: "Deploy even if tests fail" + required: true + default: false + type: boolean +jobs: + + cache-modifier: + uses: ./.github/workflows/cache-modifier.yml + with: + skip-cache: ${{ github.event.inputs.skip-cache }} + + call-atlas: + uses: ./.github/workflows/realm.yml + secrets: inherit + needs: cache-modifier + with: + sha: ${{ github.sha }} + environment: production + runner-label: ${{ vars.PRODUCTION_RUNNER_LABEL }} + + call-test-build: + uses: ./.github/workflows/test-build.yml + secrets: inherit + needs: [cache-modifier, call-atlas] + with: + sha: ${{ github.sha }} + environment: production + netlify-context: production + runner-label: ${{ vars.PRODUCTION_RUNNER_LABEL }} + cache-modifier: ${{ needs.cache-modifier.outputs.cache-modifier }} + + call-test: + uses: ./.github/workflows/test.yml + needs: [cache-modifier, call-test-build] + secrets: inherit + with: + sha: ${{ github.sha }} + environment: production + runner-label: ${{ vars.PRODUCTION_RUNNER_LABEL }} + cache-modifier: ${{ needs.cache-modifier.outputs.cache-modifier }} + + call-deploy: + if: inputs.force-deploy == true || success() + uses: ./.github/workflows/deploy.yml + needs: [cache-modifier, call-test] + secrets: inherit + permissions: + pull-requests: write + with: + environment: production + sha: ${{ github.sha }} + netlify-context: production + netlify-alias: + runner-label: ${{ vars.PRODUCTION_RUNNER_LABEL }} + cache-modifier: ${{ needs.cache-modifier.outputs.cache-modifier }} diff --git a/.github/workflows/realm-empty-env.yml b/.github/workflows/realm-empty-env.yml index f439f72d9b..9150fee5a0 100644 --- a/.github/workflows/realm-empty-env.yml +++ b/.github/workflows/realm-empty-env.yml @@ -17,7 +17,7 @@ jobs: npm install -g mongodb-realm-cli - name: Login run: | - realm-cli login --api-key="${{ secrets.REALM_API_PUBLIC_KEY }}" --private-api-key="${{ secrets.REALM_API_PRIVATE_KEY }}" --realm-url https://realm.mongodb.com --atlas-url https://cloud.mongodb.com + realm-cli login --api-key="${{ secrets.REALM_API_PUBLIC_KEY }}" --private-api-key="${{ secrets.REALM_API_PRIVATE_KEY }}" --realm-url https://services.cloud.mongodb.com --atlas-url https://cloud.mongodb.com - name: Push run: | cd site/realm diff --git a/.github/workflows/realm-production.yml b/.github/workflows/realm-production.yml deleted file mode 100644 index f6ca061ce4..0000000000 --- a/.github/workflows/realm-production.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Realm Deploy Production - -on: - push: - branches: - - master - -jobs: - push_production: - runs-on: ubuntu-latest - environment: production - steps: - - uses: actions/checkout@v2 - - name: "Install the Realm CLI" - run: | - npm install -g mongodb-realm-cli - - name: Login - run: | - realm-cli login --api-key="${{ secrets.REALM_API_PUBLIC_KEY }}" --private-api-key="${{ secrets.REALM_API_PRIVATE_KEY }}" --realm-url https://realm.mongodb.com --atlas-url https://cloud.mongodb.com - - name: Push - run: | - cd site/realm - realm-cli push --remote="${{ secrets.GATSBY_REALM_APP_ID }}" -y diff --git a/.github/workflows/realm-staging.yml b/.github/workflows/realm-staging.yml deleted file mode 100644 index 1a9c8298a3..0000000000 --- a/.github/workflows/realm-staging.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Realm Deploy Staging - -on: - push: - branches: - - staging - -jobs: - push: - runs-on: ubuntu-latest - environment: staging - steps: - - uses: actions/checkout@v2 - - name: "Install the Realm CLI" - run: | - npm install -g mongodb-realm-cli - - name: Login - run: | - realm-cli login --api-key="${{ secrets.REALM_API_PUBLIC_KEY }}" --private-api-key="${{ secrets.REALM_API_PRIVATE_KEY }}" --realm-url https://realm.mongodb.com --atlas-url https://cloud.mongodb.com - - name: Push - run: | - cd site/realm - realm-cli push --remote="${{ secrets.GATSBY_REALM_APP_ID }}" -y - diff --git a/.github/workflows/realm.yml b/.github/workflows/realm.yml new file mode 100644 index 0000000000..040e3e8407 --- /dev/null +++ b/.github/workflows/realm.yml @@ -0,0 +1,40 @@ +name: Realm Deploy + +on: + workflow_call: + inputs: + environment: + description: The Github environment to load secrets from + type: string + required: true + sha: + description: The commit SHA to deploy + type: string + required: true + runner-label: + description: The label of the runner to use + type: string + +jobs: + push: + runs-on: + labels: ${{ inputs.runner-label || 'ubuntu-latest' }} + environment: ${{ inputs.environment }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ inputs.sha }} + + - name: "Install the Realm (Atlas) CLI" + run: | + npm install -g mongodb-realm-cli + + - name: Login + run: | + realm-cli login --api-key="${{ secrets.REALM_API_PUBLIC_KEY }}" --private-api-key="${{ secrets.REALM_API_PRIVATE_KEY }}" --realm-url https://services.cloud.mongodb.com --atlas-url https://cloud.mongodb.com + + - name: Push + run: | + cd site/realm + realm-cli push --remote="${{ vars.GATSBY_REALM_APP_ID }}" -y diff --git a/.github/workflows/run_build.yml b/.github/workflows/run_build.yml deleted file mode 100644 index d6d0898ed0..0000000000 --- a/.github/workflows/run_build.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: 'Netlify Deploy to Production' - -on: - schedule: - - cron: "0 6,18 * * *" - -jobs: - deploy: - name: 'Deploy' - runs-on: ubuntu-latest - - steps: - - name: Curl request - run: curl -X POST -d {} ${{ secrets.NETLIFYBUILDURL }} diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml new file mode 100644 index 0000000000..fdc31f6b8a --- /dev/null +++ b/.github/workflows/staging.yml @@ -0,0 +1,69 @@ +name: Deploy Staging Branch + +on: + push: + branches: + - staging + workflow_dispatch: + inputs: + skip-cache: + description: "Skip Cache" + required: true + default: true + type: boolean + force-deploy: + description: "Deploy even if tests fail" + required: true + default: false + type: boolean + +jobs: + cache-modifier: + uses: ./.github/workflows/cache-modifier.yml + with: + skip-cache: ${{ github.event.inputs.skip-cache }} + + call-atlas: + uses: ./.github/workflows/realm.yml + secrets: inherit + needs: cache-modifier + with: + sha: ${{ github.sha }} + environment: staging + runner-label: ${{ vars.STAGING_RUNNER_LABEL }} + + call-test-build: + uses: ./.github/workflows/test-build.yml + secrets: inherit + needs: [cache-modifier, call-atlas] + with: + sha: ${{ github.sha }} + environment: staging + netlify-context: production + runner-label: ${{ vars.STAGING_RUNNER_LABEL }} + cache-modifier: ${{ needs.cache-modifier.outputs.cache-modifier }} + + call-test: + uses: ./.github/workflows/test.yml + needs: [cache-modifier, call-test-build] + secrets: inherit + with: + sha: ${{ github.sha }} + environment: staging + runner-label: ${{ vars.STAGING_RUNNER_LABEL }} + cache-modifier: ${{ needs.cache-modifier.outputs.cache-modifier }} + + call-deploy: + if: inputs.force-deploy == true || success() + uses: ./.github/workflows/deploy.yml + needs: [cache-modifier, call-test] + secrets: inherit + permissions: + pull-requests: write + with: + environment: staging + sha: ${{ github.sha }} + netlify-context: production + netlify-alias: + runner-label: ${{ vars.STAGING_RUNNER_LABEL }} + cache-modifier: ${{ needs.cache-modifier.outputs.cache-modifier }} diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index ce4c83a620..a1ea584841 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -3,30 +3,48 @@ on: workflow_call: inputs: environment: + description: The Github environment to load secrets from type: string required: true + sha: + description: The SHA of the commit to build + type: string + required: true + netlify-context: + description: The Netlify context use when building + type: string + required: true + runner-label: + description: The label of the runner to use + type: string + cache-modifier: + description: A modifier for the cache key used to bypass existing cache + type: string + required: false + default: "" jobs: test: name: Build site for testing environment: ${{ inputs.environment }} - runs-on: ubuntu-latest + runs-on: + labels: ${{ inputs.runner-label || 'ubuntu-latest' }} steps: - name: Checkout uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ inputs.sha }} - name: Read node modules from cache id: cache-nodemodules - uses: actions/cache/restore@v3 + uses: actions/cache/restore@v4 env: cache-name: cache-install-folder with: path: | site/gatsby-site/node_modules ~/.cache/Cypress - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}-${{ inputs.cache-modifier}} - name: Install NPM dependencies if: steps.cache-nodemodules.outputs.cache-hit != 'true' @@ -36,17 +54,15 @@ jobs: runTests: false install-command: npm ci - - name: Use tests specific netlify.toml - run: | - rm -f netlify.toml - mv tests-netlify.toml netlify.toml + - name: Use tests specific netlify.toml + run: mv tests-netlify.toml netlify.toml working-directory: site/gatsby-site - + - name: Install Netlify CLI run: npm install netlify-cli -g - name: Build using Netlify - run: netlify build --context deploy-preview --offline + run: netlify build --context ${{ inputs.netlify-context }} --offline working-directory: site/gatsby-site env: INSTRUMENT: true @@ -67,6 +83,7 @@ jobs: MONGODB_REPLICA_SET: ${{ secrets.MONGODB_REPLICA_SET }} MONGODB_TRANSLATIONS_CONNECTION_STRING: ${{ secrets.MONGODB_TRANSLATIONS_CONNECTION_STRING }} MONGODB_MIGRATIONS_CONNECTION_STRING: ${{ secrets.MONGODB_MIGRATIONS_CONNECTION_STRING }} + TRANSLATE_SUBMISSION_DATE_START: ${{ vars.TRANSLATE_SUBMISSION_DATE_START }} GATSBY_REALM_APP_GRAPHQL_URL: ${{ secrets.GATSBY_REALM_APP_GRAPHQL_URL }} GATSBY_PRISMIC_REPO_NAME: ${{ vars.GATSBY_PRISMIC_REPO_NAME }} PRISMIC_ACCESS_TOKEN: ${{ secrets.PRISMIC_ACCESS_TOKEN }} @@ -79,13 +96,14 @@ jobs: CLOUDFLARE_R2_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }} CLOUDFLARE_R2_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_SECRET_ACCESS_KEY }} REALM_GRAPHQL_API_KEY: ${{ secrets.REALM_GRAPHQL_API_KEY }} + GATSBY_COMMIT_SHA: ${{ inputs.sha }} - name: Cache build - uses: actions/cache/save@v3 + uses: actions/cache/save@v4 env: cache-name: cache-build-folder with: path: | site/gatsby-site/public site/gatsby-site/.cache/functions - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ github.event.pull_request.head.sha }} + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ inputs.sha }}-${{ inputs.cache-modifier }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2010da2399..e612285e7a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,14 +3,28 @@ on: workflow_call: inputs: environment: + description: The Github environment to load secrets from type: string required: true + sha: + description: The commit SHA to run the tests against + type: string + required: true + runner-label: + description: The label of the runner to use + type: string + cache-modifier: + description: A modifier for the cache key used to bypass existing cache + type: string + required: false + default: "" jobs: test: name: Run Cypress tests environment: ${{ inputs.environment }} - runs-on: ubuntu-latest + runs-on: + labels: ${{ inputs.runner-label || 'ubuntu-latest' }} defaults: run: shell: bash @@ -26,23 +40,23 @@ jobs: containers: [1, 2, 3, 4] # stop the job if it runs over 20 minutes # to prevent a hanging process from using all your CI minutes - timeout-minutes: 40 + timeout-minutes: 80 steps: - name: Checkout uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ inputs.sha }} - name: Read node modules from cache id: cache-nodemodules - uses: actions/cache/restore@v3 + uses: actions/cache/restore@v4 env: cache-name: cache-install-folder with: path: | site/gatsby-site/node_modules ~/.cache/Cypress - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}-${{ inputs.cache-modifier }} - name: Install NPM dependencies if: steps.cache-nodemodules.outputs.cache-hit != 'true' @@ -53,14 +67,14 @@ jobs: install-command: npm ci - name: Restore build cache - uses: actions/cache/restore@v3 + uses: actions/cache/restore@v4 env: cache-name: cache-build-folder with: path: | site/gatsby-site/public site/gatsby-site/.cache/functions - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ github.event.pull_request.head.sha }} + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ inputs.sha }}-${{ inputs.cache-modifier }} - name: Extract branch name shell: bash @@ -97,6 +111,7 @@ jobs: MONGODB_CONNECTION_STRING: ${{ secrets.MONGODB_CONNECTION_STRING }} MONGODB_REPLICA_SET: ${{ secrets.MONGODB_REPLICA_SET }} MONGODB_TRANSLATIONS_CONNECTION_STRING: ${{ secrets.MONGODB_TRANSLATIONS_CONNECTION_STRING }} + TRANSLATE_SUBMISSION_DATE_START: ${{ vars.TRANSLATE_SUBMISSION_DATE_START }} MONGODB_MIGRATIONS_CONNECTION_STRING: ${{ secrets.MONGODB_MIGRATIONS_CONNECTION_STRING }} GATSBY_REALM_APP_GRAPHQL_URL: ${{ secrets.GATSBY_REALM_APP_GRAPHQL_URL }} GATSBY_ROLLBAR_TOKEN: ${{ secrets.GATSBY_ROLLBAR_TOKEN }} @@ -111,6 +126,6 @@ jobs: REALM_GRAPHQL_API_KEY: ${{ secrets.REALM_GRAPHQL_API_KEY }} - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} \ No newline at end of file + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.gitignore b/.gitignore index a0f951d474..204746165b 100644 --- a/.gitignore +++ b/.gitignore @@ -77,4 +77,6 @@ package-lock.json !themes/gatsby-starter-theme/package-lock.json !themes/gatsby-starter-theme-workspace/package-lock.json -.nyc_output \ No newline at end of file +.nyc_output + +site/gatsby-site/src/api/lookupIndex.json \ No newline at end of file diff --git a/README.md b/README.md index 8de84e38e8..40bebe717e 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,21 @@

+

Artificial Intelligence Incident Database

-[![Netlify Status](https://api.netlify.com/api/v1/badges/9eb0dda2-916c-46f9-a0bd-9ddab3879c6e/deploy-status)](https://app.netlify.com/sites/aiid/deploys) -[![Slack Link](https://img.shields.io/badge/Join%20the%20RAIC%20Slack!-purple?logo=slack)](https://forms.gle/v7UHJvEkYSJQ7jHj7) + +

+ +   + +   + +   + +

Information about the goals and organization of the AI Incident Database can be found on the [production website](https://incidentdatabase.ai/). This page concentrates on onboarding for the following types of contributions to the database, @@ -321,6 +330,12 @@ The dry run is disabled through an environment variable as follows: TRANSLATE_DRY_RUN=false ``` +In addition to the Dry Run mode, you can also limit the number of reports to translate by setting the following environment variable. This variable sets the date from which the reports will be translated (using the `date_submitted` report field): + +``` +TRANSLATE_SUBMISSION_DATE_START=2024-01-01 +``` + ### Geocoding If the feature you are working on depends on Google's Geocoding API, please add the following environment variable with the appropriate value to your .env file. @@ -398,7 +413,7 @@ As soon as a user is signed in, the system assigns a `subscriber` role by defaul |-------------------------------|----------------------------------------------------------------------------------------------------------------------------------------| | `subscriber` | This is the default role assigned to all users. It allows the user to subscribe to new incidents, specific incidents, entities, and anything else that is subscribeable. | | `submitter` | This role allows the user to submit new incidents under their user account. | -| `incident_editor` | This role allows the user to:
- Edit and clone incidents
- See the live incident data. The live data is the data that is currently stored in the database. Keep in mind that incident pages are generated on each build, so if a user edits an incident, the change will be only visible if the live data options is activated until the next build finishes.
- Add, edit, approve and delete incident variants
- View and submit incident candidates
- Restore previous versions of incidents and reports. | +| `incident_editor` | This role allows the user to:
- Edit and clone incidents
- See the live incident data. The live data is the data that is currently stored in the database. Keep in mind that incident pages are generated on each build, so if a user edits an incident, the change will be only visible if the live data options is activated until the next build finishes.
- Add, edit, approve and delete incident variants
- View and submit incident candidates
- Restore previous versions of incidents and reports.
- Approve and reject new submissions. Which involves converting a submission into an incident or report (create incident or report and linked notifications), or deleting the submission | | `taxonomy_editor` | This role allows the user to edit all taxonomies. | | `taxonomy_editor_{taxonomy_name}` | This role allows the user to edit a specific taxonomy. ie: `taxonomy_editor_csetv1` role allows the user to edit the `CSETv1` taxonomy. | | `admin` | This role has full access to the site, including the ability to edit users' roles. | @@ -466,6 +481,54 @@ CLOUDFLARE_R2_SECRET_ACCESS_KEY=[The Cloudflare R2 secret access key] CLOUDFLARE_R2_BUCKET_NAME=[The Cloudflare R2 bucket name (e.g.: 'aiid-public')] GATSBY_CLOUDFLARE_R2_PUBLIC_BUCKET_URL=[The Cloudflare R2 public bucket URL (e.g.: https://pub-daddb16dc28841779b83690f75eb5c58.r2.dev)] ``` + +### New Netlify Setup + +This guide walks you through the steps to set up a Netlify site for your project by importing an existing project from GitHub. + +### Prerequisites + +- Ensure you have a GitHub account and your project is already pushed to a repository. +- Make sure you have a Netlify account. If not, sign up at [Netlify](https://www.netlify.com/). + +### Steps to Set Up + +#### 1. Add New Site + +- Go to your Netlify dashboard. +- Click on **Add New Site**. + +#### 2. Import Existing Project + +- Choose **Import Existing Project**. + +#### 3. Deploy with GitHub + +- Select **Deploy with GitHub** to connect your GitHub account. + +#### 4. Select Repository + +- Choose the repository where your project is located. + +#### 5. Configure Deployment + +- Under **Branch to Deploy**, select `master`. This setting doesn't matter for now. +- Leave all other settings as default. +- Click on **Deploy Site**. + +#### 6. Site Configuration + +##### Build and Deploy + +- Navigate to **Site Configuration** > **Build & Deploy**. +- Under **Build Settings** > **Build Status**, find **Stopped Builds**. +- Click **Save**. + +##### Site Details + +- Go to **Site Configuration** > **Site Details**. +- Copy the `NETLIFY_SITE_ID`. This will be useful when setting up the GitHub environment. + ### Github Actions Two workflows take care of deploying the Realm app to both `production` and `staging` environments, defined in `realm-production.yml` and `realm-staging.yml`. Each workflow looks for environment variables defined in a GitHub Environment named `production` and `staging`. @@ -475,9 +538,71 @@ GATSBY_REALM_APP_ID= REALM_API_PRIVATE_KEY= REALM_API_PUBLIC_KEY= ``` - To get your Public and Private API Key, follow these [instructions](https://www.mongodb.com/docs/atlas/configure-api-access/#std-label-create-org-api-key). +### Deployment Workflows on GitHub Actions + +We have integrated our testing and deployment processes with GitHub Actions. There are three primary workflows for deployment: Deploy Previews, Staging, and Production. The goal of these workflows is to continuously test and integrate changes in pull requests across environments. + +#### 1) Deploy Previews Workflow + +- **File:** [/.github/workflows/preview.yml](/.github/workflows/preview.yml) +- **Trigger:** This workflow is activated for pushes to pull requests that target the `staging` branch. +- **Process:** Executes both the integration tests and deploys the application to Netlify. +- **Post-Deployment:** Upon a successful deployment, the workflow automatically posts a comment on the pull request. This comment includes a link to the Netlify preview of the changes and a link to the Netlify deploy log. +- **Environment:** This workflow uses the `staging` GitHub environment. + +#### 2) Staging Workflow (WIP) + +- **Trigger:** Runs only on pushes to the `staging` branch. +- **Process:** Executes both the integration tests and deploys to Netlify. +- **Deployment Criteria:** If the tests fail, no deployment will be carried out. +- **Environment:** This workflow uses the `staging` GitHub environment. + +#### 3) Production Workflow (WIP) + +- **Trigger:** Runs only on pushes to the `master` branch. +- **Process:** Executes both the integration tests and deploys to Netlify. +- **Deployment Criteria:** If the tests fail, no deployment will be carried out. +- **Environment:** This workflow uses the `production` GitHub environment. + +### GitHub Environment Configuration + +All three workflows share a common set of environment variables, which need to be defined for each environment. (Currently, we have only two environments: `staging` and `production`.) These variables are categorized into secrets and standard variables, and are accessed via GitHub actions as such. + +#### Secrets + +- `ALGOLIA_ADMIN_KEY` +- `CLOUDFLARE_R2_ACCESS_KEY_ID` +- `CLOUDFLARE_R2_ACCOUNT_ID` +- `CLOUDFLARE_R2_BUCKET_NAME` +- `CLOUDFLARE_R2_SECRET_ACCESS_KEY` +- `CYPRESS_RECORD_KEY` +- `E2E_ADMIN_PASSWORD` +- `E2E_ADMIN_USERNAME` +- `GOOGLE_TRANSLATE_API_KEY` +- `MONGODB_CONNECTION_STRING` +- `MONGODB_MIGRATIONS_CONNECTION_STRING` +- `MONGODB_REPLICA_SET` +- `MONGODB_TRANSLATIONS_CONNECTION_STRING` +- `NETLIFY_AUTH_TOKEN` +- `PRISMIC_ACCESS_TOKEN` +- `REALM_API_PRIVATE_KEY` +- `REALM_GRAPHQL_API_KEY` +- `REALM_API_PUBLIC_KEY` +- `GATSBY_ROLLBAR_TOKEN` + +#### Variables + +- `CYPRESS_PROJECT_ID` +- `GATSBY_ALGOLIA_APP_ID` +- `GATSBY_ALGOLIA_SEARCH_KEY` +- `GATSBY_AVAILABLE_LANGUAGES` +- `GATSBY_CLOUDFLARE_R2_PUBLIC_BUCKET_URL` +- `GATSBY_PRISMIC_REPO_NAME` +- `GATSBY_REALM_APP_ID` +- `NETLIFY_SITE_ID` + ### Testing For integration testing, we use Cypress. You can run the desktop app continuously as part of your development environment or run it on demand in headless mode. @@ -755,7 +880,7 @@ appId = [Atlas Service App ID, eg: "62cc98647e6a26c53d5b4b53"] To get your Public and Private API Key, follow these [instructions](https://www.mongodb.com/docs/atlas/configure-api-access/#std-label-create-org-api-key). To get the group ID and the app ID, the easiest way is to navigate to your Atlas Service App dashboard and copy from the URL. -The URL format is https://realm.mongodb.com/groups/[groupId]/apps/[appId]/dashboard +The URL format is https://services.cloud.mongodb.com/groups/[groupId]/apps/[appId]/dashboard Email notifications to New Incidents (subscription type **New Incident**), Incident updates (subscription type **Incident**) and Submission Promoted (subscription type **Submission Promoted**) are sent when the next build finishes. This is because we have to wait until the new Incident page is generated and accessible. When a new Incident is created or updates, a pending notification item is saved into the `notifications` DB collection with `processed=false` field. diff --git a/site/gatsby-site/blog/deepfakes-child-safety/index.es.mdx b/site/gatsby-site/blog/deepfakes-child-safety/index.es.mdx index 9ed57828b0..6527b949f6 100644 --- a/site/gatsby-site/blog/deepfakes-child-safety/index.es.mdx +++ b/site/gatsby-site/blog/deepfakes-child-safety/index.es.mdx @@ -1,7 +1,7 @@ --- title: 'Deepfakes y seguridad infantil: encuesta y análisis de incidentes y respuestas de 2023' metaTitle: 'Deepfakes y seguridad infantil: encuesta y análisis de incidentes y respuestas de 2023' -metaDescription: "" +metaDescription: "Preocupaciones crecientes y desafíos legales en relación a la creación y distribución de materiales de abuso sexual infantil generados por IA en 2023." date: '2024-01-09' image: './images/image_doj.jpg' author: 'Daniel Atherton' @@ -11,9 +11,9 @@ aiTranslated: true **AVISO LEGAL:** Esta publicación no es un consejo o comentario legal y no debe interpretarse como tal. -En 2023 se produjo un aumento de los materiales de abuso sexual infantil (CSAM) generados por IA, junto con procesamientos de los infractores, una variedad de intentos legislativos para combatir los deepfakes de IA dirigidos a menores y la [orden ejecutiva sobre inteligencia artificial de la administración Biden](https://www.whitehouse.gov/briefing-room/presidential-actions/2023/10/30/executive-order-on-the-safe-secure-and-trustworthy-development-and-use-of-artificial-intelligence/). +En 2023 se produjo un aumento de los materiales de abuso sexual infantil (MASI) generados por IA, junto con procesamientos de los infractores, una variedad de intentos legislativos para combatir los deepfakes de IA dirigidos a menores y la [orden ejecutiva sobre inteligencia artificial de la administración Biden](https://www.whitehouse.gov/briefing-room/presidential-actions/2023/10/30/executive-order-on-the-safe-secure-and-trustworthy-development-and-use-of-artificial-intelligence/). -Los deepfakes se pueden clasificar en términos generales en dos categorías principales, cada una con su propio subconjunto relacionado con CSAM. La primera categoría incluye deepfakes de individuos reales, donde el daño predominante asociado con CSAM surge de la generación de pornografía deepfake con niños reales. La segunda categoría abarca los deepfakes en los que los sujetos son completamente virtuales pero convincentemente realistas. En esta categoría, las preocupaciones sobre CSAM están relacionadas principalmente con la creación de medios audiovisuales sintéticos inapropiados que representan niños virtuales. En conjunto, estas dos categorías taxonómicas demuestran las diversas formas preocupantes en que se puede emplear la tecnología deepfake, especialmente en la generación y proliferación de CSAM. +Los deepfakes se pueden clasificar en términos generales en dos categorías principales, cada una con su propio subconjunto relacionado con MASI. La primera categoría incluye deepfakes de individuos reales, donde el daño predominante asociado con MASI surge de la generación de pornografía deepfake con niños reales. La segunda categoría abarca los deepfakes en los que los sujetos son completamente virtuales pero convincentemente realistas. En esta categoría, las preocupaciones sobre MASI están relacionadas principalmente con la creación de medios audiovisuales sintéticos inapropiados que representan niños virtuales. En conjunto, estas dos categorías taxonómicas demuestran las diversas formas preocupantes en que se puede emplear la tecnología deepfake, especialmente en la generación y proliferación de MASI. Este artículo proporciona una instantánea de parte del trabajo de la base de datos de incidentes de IA en el seguimiento de estos incidentes emergentes, junto con un estudio de algunas de las respuestas legislativas incipientes. @@ -37,9 +37,9 @@ Recientemente, [un incidente](https://incidentdatabase.ai/cite/576/) salió a la *The Wall Street Journal* también [informado recientemente](https://www.wsj.com/tech/facebook-and-instagram-steer-predators-to-children-new-mexico-attorney-general-alleges-in-demand-b76a5b04?mod=Searchresults_pos1&page=1) sobre el Fiscal General de Nuevo México que presentó una demanda contra Meta, alegando que los algoritmos de Facebook e Instagram dirigieron a los depredadores y al contenido pornográfico a cuentas de prueba de temas menores. La investigación involucró imágenes de niños ficticios generadas por IA, lo que resultó en que las cuentas recibieran mensajes explícitos y proposiciones sexuales. La demanda afirma que las plataformas de Meta se han convertido en un mercado para depredadores y critica su falta de protección a los usuarios menores de edad, citando varios casos penales de explotación a través de estas plataformas. En este caso, fueron los investigadores quienes generaron las imágenes de los menores ficticios, adaptando las nuevas tecnologías a antiguas técnicas en este ámbito específico de la aplicación de la ley. -Un [estudio reciente](https://stacks.stanford.edu/file/druid:kh752sm9123/ml_training_data_csam_report-2023-12-21.pdf) realizado por David Thiel del Stanford Internet Observatory detalla la presencia de CSAM en los datos de entrenamiento de Modelos generativos de aprendizaje automático, centrándose en el conjunto de datos LAION-5B utilizado para modelos como Difusión estable. A través de varios métodos, incluidos los clasificadores PhotoDNA y ML, Thiel identificó numerosos casos nuevos y conocidos de CSAM en el conjunto de datos. Los hallazgos son oportunos ya que muestran la necesidad de prácticas de capacitación de modelos y curación de datos más rigurosas para evitar la perpetuación de contenido dañino, en línea con las preocupaciones planteadas por los incidentes en las plataformas de redes sociales y enfatizando la importancia de un mayor desarrollo responsable de la IA en este sentido. frente. +Un [estudio reciente](https://stacks.stanford.edu/file/druid:kh752sm9123/ml_training_data_csam_report-2023-12-21.pdf) realizado por David Thiel del Stanford Internet Observatory detalla la presencia de MASI en los datos de entrenamiento de Modelos generativos de aprendizaje automático, centrándose en el conjunto de datos LAION-5B utilizado para modelos como Difusión estable. A través de varios métodos, incluidos los clasificadores PhotoDNA y ML, Thiel identificó numerosos casos nuevos y conocidos de MASI en el conjunto de datos. Los hallazgos son oportunos ya que muestran la necesidad de prácticas de capacitación de modelos y curación de datos más rigurosas para evitar la perpetuación de contenido dañino, en línea con las preocupaciones planteadas por los incidentes en las plataformas de redes sociales y enfatizando la importancia de un mayor desarrollo responsable de la IA en este sentido. frente. -Actualmente, los esfuerzos legales para abordar los deepfakes de CSAM han sido reactivos y poco sistemáticos. Sin embargo, la orden ejecutiva del presidente Biden sobre la IA tiene como objetivo establecer normas estrictas para prevenir el uso indebido de la IA, centrándose en la seguridad nacional y la seguridad individual, lo que implica autenticar el contenido digital y etiquetar los medios sintéticos, especialmente para proteger a los niños de los daños provocados por la IA. Los desarrolladores deben compartir los resultados de las pruebas de seguridad de la IA antes de su uso público, centrándose en problemas como la creación de CSAM. La orden dirige el desarrollo de estándares para la autenticación de contenido y la detección de IA, y aborda el CSAM generado por IA y las imágenes sexualizadas no consensuales. Antes de la orden ejecutiva, [U.S. Los fiscales generales instaron al Congreso](https://www.scag.gov/media/pvehppkm/54-state-ags-urge-study-of-ai-and-harmful-impacts-on-children.pdf) a investigar el papel de la IA. en la explotación infantil, enfatizando la necesidad de una legislación integral sobre privacidad de datos. +Actualmente, los esfuerzos legales para abordar los deepfakes de MASI han sido reactivos y poco sistemáticos. Sin embargo, la orden ejecutiva del presidente Biden sobre la IA tiene como objetivo establecer normas estrictas para prevenir el uso indebido de la IA, centrándose en la seguridad nacional y la seguridad individual, lo que implica autenticar el contenido digital y etiquetar los medios sintéticos, especialmente para proteger a los niños de los daños provocados por la IA. Los desarrolladores deben compartir los resultados de las pruebas de seguridad de la IA antes de su uso público, centrándose en problemas como la creación de MASI. La orden dirige el desarrollo de estándares para la autenticación de contenido y la detección de IA, y aborda el MASI generado por IA y las imágenes sexualizadas no consensuales. Antes de la orden ejecutiva, [U.S. Los fiscales generales instaron al Congreso](https://www.scag.gov/media/pvehppkm/54-state-ags-urge-study-of-ai-and-harmful-impacts-on-children.pdf) a investigar el papel de la IA. en la explotación infantil, enfatizando la necesidad de una legislación integral sobre privacidad de datos. Hasta el momento, [no existe ningún proyecto de ley federal general](https://www.nbcnews.com/news/us-news/little-recourse-teens-girls-victimized-ai-deepfake-nudes-rcna126399), pero se han realizado esfuerzos. (por ejemplo, [Ley de Responsabilidad H.R.3230 DEEP FAKES](https://www.congress.gov/bill/116th-congress/house-bill/3230)). A continuación se muestran cuatro ejemplos de legislación a nivel estatal: @@ -51,4 +51,4 @@ Hasta el momento, [no existe ningún proyecto de ley federal general](https://ww * [Virginia, Código 18.2-386.2](https://law.lis.virginia.gov/vacode/title18.2/chapter8/section18.2-386.2/): convierte en un delito menor de Clase 1 compartir o vender desnudos maliciosamente o imágenes sexualmente explícitas de alguien sin su consentimiento, especialmente si se hacen para acosar, coaccionar o intimidar. Esto incluye imágenes que han sido alteradas digitalmente para representar a una persona. Los proveedores de servicios de Internet no se hacen responsables del contenido compartido por otros. Se pueden emprender acciones legales donde se produjo el hecho ilícito o donde se manipuló la imagen. También pueden aplicarse otros cargos legales. -En la base de datos de incidentes de IA (AIID), hemos estado catalogando e investigando con preocupación estos incidentes recientes de CSAM. Como toda tecnología, la IA generativa plantea riesgos y oportunidades, y los riesgos para los niños en este caso son graves. Si desea unirse a nosotros en nuestra misión de documentar incidentes de IA con el objetivo de aprender de los errores del pasado para mitigar riesgos futuros, puede conectarse con nosotros a través de nuestra página de [contacto](https://incidentdatabase.ai/contact/) . Agradecemos los envíos que informen sobre todos y cada uno de los incidentes de IA utilizando nuestra página [envío](https://incidentdatabase.ai/apps/submit/); sin embargo, tenga en cuenta que, si bien rastreamos y analizamos activamente las tendencias e incidentes de CSAM, el AIID no es el destino directo para informar sobre CSAM real. Dirija la denuncia de CSAM al Departamento de Justicia [Sección de Obscenidad y Explotación Infantil](https://www.justice.gov/criminal/criminal-ceos/report-violations). \ No newline at end of file +En la base de datos de incidentes de IA (AIID), hemos estado catalogando e investigando con preocupación estos incidentes recientes de MASI. Como toda tecnología, la IA generativa plantea riesgos y oportunidades, y los riesgos para los niños en este caso son graves. Si desea unirse a nosotros en nuestra misión de documentar incidentes de IA con el objetivo de aprender de los errores del pasado para mitigar riesgos futuros, puede conectarse con nosotros a través de nuestra página de [contacto](https://incidentdatabase.ai/contact/) . Agradecemos los envíos que informen sobre todos y cada uno de los incidentes de IA utilizando nuestra página [envío](https://incidentdatabase.ai/apps/submit/); sin embargo, tenga en cuenta que, si bien rastreamos y analizamos activamente las tendencias e incidentes de MASI, el AIID no es el destino directo para informar sobre MASI real. Dirija la denuncia de MASI al Departamento de Justicia [Sección de Obscenidad y Explotación Infantil](https://www.justice.gov/criminal/criminal-ceos/report-violations). \ No newline at end of file diff --git a/site/gatsby-site/blog/deepfakes-child-safety/index.fr.mdx b/site/gatsby-site/blog/deepfakes-child-safety/index.fr.mdx index 702ee8317f..fbd542a4ff 100644 --- a/site/gatsby-site/blog/deepfakes-child-safety/index.fr.mdx +++ b/site/gatsby-site/blog/deepfakes-child-safety/index.fr.mdx @@ -1,7 +1,7 @@ --- title: 'Deepfakes et sécurité des enfants : une enquête et une analyse des incidents et des réponses de 2023' metaTitle: 'Deepfakes et sécurité des enfants : une enquête et une analyse des incidents et des réponses de 2023' -metaDescription: "" +metaDescription: "Préoccupations croissantes et défis juridiques concernant la création et la distribution de matériaux d'abus sexuels sur enfants générés par IA en 2023." date: '2024-01-09' image: './images/image_doj.jpg' author: 'Daniel Atherton' diff --git a/site/gatsby-site/blog/deepfakes-child-safety/index.mdx b/site/gatsby-site/blog/deepfakes-child-safety/index.mdx index e8cad11d2b..3226d2f4f5 100644 --- a/site/gatsby-site/blog/deepfakes-child-safety/index.mdx +++ b/site/gatsby-site/blog/deepfakes-child-safety/index.mdx @@ -1,7 +1,7 @@ --- title: 'Deepfakes and Child Safety: A Survey and Analysis of 2023 Incidents and Responses' metaTitle: 'Deepfakes and Child Safety: A Survey and Analysis of 2023 Incidents and Responses' -metaDescription: "" +metaDescription: "Rising concerns and legal challenges regarding the creation and distribution of AI-generated child sexual abuse materials in 2023." date: '2024-01-09' image: './images/image_doj.jpg' author: 'Daniel Atherton' @@ -10,7 +10,7 @@ slug: '/blog/deepfakes-and-child-safety' **DISCLAIMER:** This post is not legal advice or commentary and should not be construed as such. -2023 saw an increase in AI-generated child sex abuse materials (CSAM), along with prosecutions of offenders, a variety of legislative attempts to combat AI deepfakes targeting minors, and the Biden administration's [executive order on artificial intelligence](https://www.whitehouse.gov/briefing-room/presidential-actions/2023/10/30/executive-order-on-the-safe-secure-and-trustworthy-development-and-use-of-artificial-intelligence/). +2023 saw an increase in AI-generated child sexual abuse materials (CSAM), along with prosecutions of offenders, a variety of legislative attempts to combat AI deepfakes targeting minors, and the Biden administration's [executive order on artificial intelligence](https://www.whitehouse.gov/briefing-room/presidential-actions/2023/10/30/executive-order-on-the-safe-secure-and-trustworthy-development-and-use-of-artificial-intelligence/). Deepfakes can be broadly classified into two main categories, each with its own subset related to CSAM. The first category includes deepfakes of actual individuals, where the predominant harm associated with CSAM arises from the generation of deepfake pornography featuring real children. The second category encompasses deepfakes where the subjects are entirely virtual yet convincingly realistic. In this category, CSAM concerns are primarily linked to the creation of inappropriate synthetic audiovisual media depicting virtual children. Collectively, these two taxonomic categories demonstrate the various troubling ways deepfake technology can be employed, especially in the generation and proliferation of CSAM. diff --git a/site/gatsby-site/content/about/index.ja.mdx b/site/gatsby-site/content/about/index.ja.mdx new file mode 100644 index 0000000000..f64e457c47 --- /dev/null +++ b/site/gatsby-site/content/about/index.ja.mdx @@ -0,0 +1,173 @@ +--- +title: "約" +metaTitle: "データベースの開発者とその目的に関する詳細" +metaDescription: "AIIDを開発している人々と組織は誰であり、なぜそれを開発しているのか?" +slug: "/about" +aiTranslated: true +--- + +import Leaderboards from '../../src/components/landing/Leaderboards'; +import Sponsors from '../../src/components/landing/Sponsors'; + +## なぜ「AIインシデント」? + +現在、インテリジェントシステムは実世界に展開される際に予期しない危険な障害に対して脆弱です。これは、それ以前の運輸部門(例えば、[FAA](https://www.faa.gov/data_research/accident_incident/)や[FARS](https://www.nhtsa.gov/research-data/fatality-analysis-reporting-system-fars))、そして最近では[コンピューターシステム](https://cve.mitre.org/cve/)のように、現実世界での経験に基づいた問題のリポジトリが必要とされています。これにより、将来の研究者や開発者が繰り返し起こる悪い結果を緩和または回避することができます。 + +## インシデントとは何ですか? + +最初の1000以上のインシデント報告は意図的に幅広いものでした。現在の例には次のものがあります。 + +- *自律型車両*が[歩行者を ation](/cite/4)しました。 +- *トレーディングアルゴリズム*が "[フラッシュクラッシュ](/cite/28)" を引き起こし、数十億ドルが関係者間で移動しました。 +- *顔認識システム*が[無実の人を逮捕](/cite/74)しました。 + +あなたは、[これまでに収集されたインシデントを探索](/apps/discover)し、[完全なリスト](/summaries/incidents)を表示し、さらにインシデントレポートを[提出](/apps/submit)するよう招待されています。研究者は、[AIインシデントの作業定義](/research/1-criteria)を確認してください。 + +## 現在のおよび将来のユーザー + +このデータベースは常に進化し続けるデータ製品であり、アプリケーションの集合です。 + +- **現在のユーザー**には、システムアーキテクト、産業製品開発者、広報マネージャー、[研究者](/research)、および公共政策研究者が含まれます。これらのユーザーは、最近展開されたインテリジェントシステムが実世界で予想外の結果を生み出した方法を[Discover](/apps/discover)アプリケーションを使用して積極的に発見するよう招待されています。これにより、彼らは開発中に類似した失敗を回避することができます。 +- **将来の利用**は、[オープンソース](https://github.com/responsible-ai-collaborative/aiid)コミュニティからのコード貢献により[進化します](/research/2-roadmap)。これには、追加のデータベース[サマリー](/about_apps/)や[タクソノミー](/research/2-roadmap)が含まれます。 + +## インシデントを報告するタイミング + +イベントがインシデントと見なされるかどうかが不明な場合は、[提出して](/apps/submit)ください!このプロジェクトは、広範なコミュニティによって提出された候補インシデントの探索を通じて、「AIインシデント」という[共有定義](/research/1-criteria)に収束することを目指しています。 + +## 取締役会 + +インシデントデータベースは、コード、研究、およびより広範な影響を提供する人々や組織によって協力的に管理されています。プロジェクトのガバナンスに参加したい場合は、[お問い合わせ](/contact)して、AIインシデントデータベースへの貢献内容をお知らせください。 + +**投票メンバー** + +- **[Patrick Hall](https://business.gwu.edu/johnston-patrick-hall):** Patrickは最近、AIとデータ分析に特化したワシントンDCに拠点を置く法律事務所であるbnh.aiの主任科学者でした。Patrickはジョージワシントン大学ビジネススクールの助教授でもあります。bnh.aiを共同設立する前、Patrickは機械学習ソフトウェア企業であるH2O.aiで責任あるAIの取り組みを率いており、その成果は世界で最初の説明可能で公正な機械学習の商用ソリューションの1つにつながりました。Patrickは説明可能かつ責任ある機械学習に関する人気のある電子書籍の主要著者の1人です。Patrickはイリノイ大学で計算化学を学び、ノースカロライナ州立大学の高度な解析研究所を卒業しました。 +**貢献内容:** PatrickはAIインシデントデータベースへのインシデントレポートの[主要な](https://incidentdatabase.ai/summaries/leaderboard)投稿者であり、取締役会の戦略的リーダーシップを提供しています。 + +- **[Heather Frase](https://cset.georgetown.edu/staff/heather-frase/):** Heather Frase博士はジョージタウン大学の[セキュリティと新興技術センター](https://cset.georgetown.edu/)(CSET)のシニアフェローであり、AIアセスメントに取り組んでいます。また、MetaのOpen Loopプロジェクトの無給アドバイザーとして、国立標準技術研究所のAIリスク管理フレームワークの実装に関する専門知識を提供しています。CSETに加入する前、Heatherは8年間、情報、防衛、および連邦契約にデータ分析、計算モデリング、機械学習(ML)、人工知能(AI)のサポートを提供しました。さらに、Heatherは14年間、Institute for Defense Analyses(IDA)で過ごし、Director、Operational Test and Evaluation(DOT&E)を支援しました。IDAでは、彼女は科学、技術、統計の専門知識を活用して、主要な国防システムの運用テストのためのデータメトリックスおよび収集計画を開発し、テストデータを分析し、運用効率と適合性の評価を行う分析研究チームを率いました。彼女はカリフォルニア工科大学で材料科学の博士号、マイアミ大学オックスフォード校で物理学の学士号、言語のディプロマを取得しています。 +**貢献内容:** Heatherは[CSETタクソノミー](https://incidentdatabase.ai/taxonomy/cset)の監督のほか、AIインシデントの研究を行っています。 + +- **[Kristian J. Hammond](https://www.mccormick.northwestern.edu/research-faculty/directory/profiles/hammond-kristian.html):** Kris Hammondはノースウェスタン大学のBill and Cathy Osborn Computer Science教授であり、Salesforceに買収された人工知能企業Narrative Scienceの共同創業者です。また、彼はノースウェスタン大学のCS + Xイニシアチブの学部リーダーであり、法律、医学、教育、ビジネスなどの分野をどのように変革するかを探求しています。彼はノースウェスタン大学のMaster of Science in Artificial Intelligence(MSAI)の学部長でもあります。最近、Dr. HammondはUnderwriter’s Laboratoriesによって資金提供された研究拠点であるCenter for Advancing Safety in Machine Intelligence(CASMI)を設立しました。CASMIは、AIシステムの設計と評価を人間の生活と安全に与える影響の観点から実行することを目的としています。 +**貢献内容:** Krisは、インシデントのケーススタディに焦点を当てた共同プロジェクトを開発しています。 + +**名誉取締役会** + +名誉取締役会メンバーは、責任あるAIコラボレーションに対する彼らの奉仕において特に優れています。彼らは組織内でのガバナンスの役職を持ちません。 + +- **[Sean McGregor](https://seanbmcgregor.com/):** Sean McGregorはAIインシデントデータベースプロジェクトの創設者であり、最近、[Digital Safety Research Institute](https://ul.org/research/digital-safety)の創設ディレクターとして加わりました。Responsible AI Collaborativeを始める前に、SeanはニューラルアクセラレータスタートアップSyntiantの機械学習アーキテクトの職を辞め、インテリジェントシステムの保証に全力を注ぐことができました。Dr. McGregorの業績には、エネルギー効率的推論のためのニューラルアクセラレータ、スピーチとヘリオフィジックスのための深層学習、および山火事の抑制政策のための強化学習が含まれます。有給の仕事の外で、Seanは「AI for Good」に関するトピックで主要な学術AI会議でワークショップシリーズを主催し、AIインシデント記録をAIテストプログラムに結び付けることで、AIの利点を安全に実現しようとしています。 + +- **[Helen Toner](https://cset.georgetown.edu/staff/helen-toner/):** Helen Tonerはジョージタウン大学のセキュリティと新興技術センター(CSET)の戦略ディレクターです。彼女は以前、Open Philanthropyのシニアリサーチアナリストとして働いており、AIポリシーと戦略についての政策立案者と助成機関にアドバイスしていました。Open Philanthropyでの勤務とCSETへの参加の間、Helenはオックスフォード大学AIガバナンスセンターの研究フェローとして北京に住んでいました。Helenは、AIと機械学習が中国とアメリカ合衆国の国家安全保障に与える影響に関して、Foreign Affairsなどの出版物に寄稿し、米中経済安全保障調査委員会に証言しています。彼女はOpenAIの取締役会のメンバーでもあります。Helenは、ジョージタウン大学でセキュリティスタディーズの修士号、マイアミ大学で化学工学の学士号、言語のディプロマを取得しています。 + +## 共同者 + +**責任あるAIコラボレーシブ:** AIインシデントデータベースの背後にある組織に奉仕する人々。 + +- [Scott Allen Cambo](https://www.scottallencambo.com/) +- [Janet Boutilier Schwartz](https://www.linkedin.com/in/janet-boutilier-schwartz/) + +**デジタルセーフティリサーチインスティテュート(DSRI):** AIIDプログラムに大きな支援を提供する[DSRI](https://ul.org/research/digital-safety)と関連する人々。 + +- [Kevin Paeth](https://www.linkedin.com/in/kevinpaeth/) はDSRIのリードです。 +- [César Varela](https://github.com/cesarvarela) はフルスタックエンジニアです。 +- [Luna McNulty](https://lmcnulty.me/) はUXエンジニアです。 +- [Pablo Costa](https://www.linkedin.com/in/pablo-costa/) はフルスタックエンジニアです。 +- [Clara Youdale Pinelli](https://www.linkedin.com/in/clarayoudale/) はフロントエンドエンジニアです。 +- [Sean McGregor](https://seanbmcgregor.com/) はDSRIのディレクターです。 + +**インシデントエディタ:** インシデントの提出を解決し、それらを維持する人々。 + +- [Daniel Atherton](https://www.linkedin.com/in/daniel-atherton-167819251/) +- [Sean McGregor](https://seanbmcgregor.com/) +- [Khoa Lam](https://www.linkedin.com/in/khoalklam/) +- [Kate Perkins](https://www.linkedin.com/in/kateeperkins/) +- [Janet Boutilier Schwartz](https://www.linkedin.com/in/janet-boutilier-schwartz/) + +さらに、[Zachary Arnold](https://cset.georgetown.edu/staff/zachary-arnold/) は[インシデント基準](/research/1-criteria)に重要な貢献をしました。 + +**タクソノミーエディタ:** データベースに[タクソノミー](https://incidentdatabase.ai/taxonomies)を提供した組織または個人。 + +- [セキュリティと新興技術センター](https://cset.georgetown.edu/)(CSET) +- [Nikiforos Pittaras](https://npit.github.io/)(GMF) + +**パートナーシップAIスタッフ:** +[Jingying Yang](https://www.linkedin.com/in/jingyingyang/) と [Dr. Christine Custis](https://www.su.edu/symposium/business-symposium-speakers/christine-custis/) はAIIDの初期段階で大きな貢献をしました。 + +**オープンソース貢献者:** AIインシデントデータベースに複数のプルリクエスト、グラフィック、サイトのコピー、またはバグレポートを提供した人々。 + +- [Neama Dadkhahnikoo](https://www.linkedin.com/in/neama/):NeamaはResponsible AI Collaborativeのボランティアエグゼクティブディレクターおよびボードオブザーバーを務めました。 +- [Kit Harris](https://www.linkedin.com/in/kitharris/):Kitは理事会のオブザーバーとして務め、助成金アドバイザーとして戦略的アドバイスを提供しました。 +- [Alex Muscă](https://github.com/alexmcode) +- [Chloe Kam](http://kamchy.com) AIIDロゴを開発しました +- [JT McHorse](https://github.com/jt-mchorse) +- Seth Reid + +**インシデント投稿者:** データベースに多数のインシデントを貢献した人々。 + +- [Roman Lutz(Max Planck Institute for Intelligent Systems、以前はMicrosoft)](/apps/discover?display=details&lang=en&page=1&submitters=Roman%20Lutz) +- [Patrick Hall(Burt and Hall LLP)](/apps/discover?display=details&lang=en&page=1&submitters=Patrick%20Hall%20%28BNH.ai%29) +- [Catherine Olsson(Google)](/apps/discover?display=details&lang=en&page=1&submitters=Catherine%20Olsson) +- [Chris Nicholson(Skymind)](/apps/discover?display=details&lang=en&page=1&submitters=Chris%20Nicholson) +- [Jeffrey Bigham(CMU)](/apps/discover?display=details&lang=en&page=1&submitters=Jeffrey%20Bigham) +- [Lara Martin(Flourish)](/apps/discover?display=details&lang=en&page=1&submitters=Lara%20Martin) +- [Matt Mahmoudi(ITU)](/apps/discover?display=details&lang=en&page=1&submitters=Matt%20Mahmoudi) +- [Freyja Daly(ITU)](/apps/discover?display=details&lang=en&page=1&submitters=Freyja%20Daly) +- [Jonas Öberg(GNU)](/apps/discover?display=details&lang=en&page=1&submitters=Jonas%20%C3%96berg) +- [Sai Pathuri(ETH)](/apps/discover?display=details&lang=en&page=1&submitters=Sai%20Pathuri) +- [Raúl Ortiz(UC Berkeley)](/apps/discover?display=details&lang=en&page=1&submitters=Ra%C3%BAl%20Ortiz) +- [Thomas Zeinzinger(Robolab)](/apps/discover?display=details&lang=en&page=1&submitters=Thomas%20Zeinzinger) +- [Jian Chang(DeepMind)](/apps/discover?display=details&lang=en&page=1&submitters=Jian%20Chang) +- [Marina Riabiz(ITU)](/apps/discover?display=details&lang=en&page=1&submitters=Marina%20Riabiz) +- [Nicholas Luciano(ITU)](/apps/discover?display=details&lang=en&page=1&submitters=Nicholas%20Luciano) + +**貢献的な団体:** データベースへの[インシデントの投稿](/apps/submit)、[パートナーシップ](/partners)、および[タクソノミーの作成](/research/2-roadmap)を通じてAIIDに大きな支援を提供した組織。 + +- [セキュリティと新興技術センター(CSET)](https://cset.georgetown.edu/) +- [Meta AI(前Facebook)](https://ai.facebook.com/) +- [Underwriter’s Laboratories](https://ul.org/) +- [Institute for Defense Analyses(IDA)](https://www.ida.org/) +- [イリノイ大学](https://illinois.edu/) +- [Google](https://www.google.com/) +- [Max Planck Institute for Intelligent Systems](https://www.is.mpg.de/) +- [DeepMind](https://deepmind.com/) +- [ITU](https://www.itu.int/) + +**貢献的なデザイナーと開発者:** ウェブサイト、ツール、およびインシデントのデザイン、開発、テストを支援した人々。 + +- [Faisal Nawaz](https://www.linkedin.com/in/faisnawaz/) +- [Sina Pourmahdian](https://www.linkedin.com/in/sina-pourmahdian-09a1a47/) +- [Gregor Cima](https://www.linkedin.com/in/gregor-cima/) +- [Brian Lewis](https://www.linkedin.com/in/lewisbrian/) + +**その他の貢献者:** AIインシデントデータベースに寄与したが、他のグループに属さない人々。 + +- [David Danks(CMU)](/apps/discover?display=details&lang=en&page=1&submitters=David%20Danks) +- [Tom Dietterich(Oregon State)](/apps/discover?display=details&lang=en&page=1&submitters=Tom%20Dietterich) +- [Alexandre Lacoste(Element AI)](/apps/discover?display=details&lang=en&page=1&submitters=Alexandre%20Lacoste) +- [Catherine Olsson(Google)](/apps/discover?display=details&lang=en&page=1&submitters=Catherine%20Olsson) +- [Patrick Hall(Burt and Hall LLP)](/apps/discover?display=details&lang=en&page=1&submitters=Patrick%20Hall%20%28BNH.ai%29) +- [Kris Hammond(ノースウェスタン大学)](/apps/discover?display=details&lang=en&page=1&submitters=Kris%20Hammond) +- [Oscar Reimer(ITU)](/apps/discover?display=details&lang=en&page=1&submitters=Oscar%20Reimer) +- [Ian Roth](/apps/discover?display=details&lang=en&page=1&submitters=Ian%20Roth) +- [Hadi Sharifi](/apps/discover?display=details&lang=en&page=1&submitters=Hadi%20Sharifi) +- [Daniel Walker](/apps/discover?display=details&lang=en&page=1&submitters=Daniel%20Walker) + +**その他の貢献者:** AIIDに貢献したが、他のグループに属さない人々。 + +- [Jillian Anderson](/apps/discover?display=details&lang=en&page=1&submitters=Jillian%20Anderson) +- [Joe Chasinga](/apps/discover?display=details&lang=en&page=1&submitters=Joe%20Chasinga) +- [Brice Dondoua](/apps/discover?display=details&lang=en&page=1&submitters=Brice%20Dondoua) +- [Taylor Edmiston](/apps/discover?display=details&lang=en&page=1&submitters=Taylor%20Edmiston) +- [Sam Greydanus](/apps/discover?display=details&lang=en&page=1&submitters=Sam%20Greydanus) +- [Kyle Hanrahan](/apps/discover?display=details&lang=en&page=1&submitters=Kyle%20Hanrahan) +- [Kimi Kobayashi](/apps/discover?display=details&lang=en&page=1&submitters=Kimi%20Kobayashi) +- [Jonathon Meza](/apps/discover?display=details&lang=en&page=1&submitters=Jonathon%20Meza) +- [Dane Myers](/apps/discover?display=details&lang=en&page=1&submitters=Dane%20Myers) +- [Aaron Patterson](/apps/discover?display=details&lang=en&page=1&submitters=Aaron%20Patterson) +- [Ryan Regier](/apps/discover?display=details&lang=en&page=1&submitters=Ryan%20Regier) +- [Harrison Ruess](/apps/discover?display=details&lang=en&page=1&submitters=Harrison%20Ruess) +- [Brandon Terrell](/apps/discover?display=details&lang=en&page=1&submitters=Brandon%20Terrell) +- [Tanner Upthegrove](/apps/discover?display=details&lang=en&page=1&submitters=Tanner%20Upthegrove) +- [Randy Wang](/apps/discover?display=details&lang=en&page=1&submitters=Randy%20Wang) +- [Connor Warren](/apps/discover?display=details&lang=en&page=1&submitters=Connor%20Warren) +- [Thomas Welsh](/apps/discover?display=details&lang=en&page=1&submitters=Thomas%20Welsh) +- [Corey White](/apps/discover?display=details&lang=en&page=1&submitters=Corey%20White) +- [Isaac Winkler](/apps/discover?display=details&lang=en&page=1&submitters=Isaac%20Winkler) diff --git a/site/gatsby-site/content/research/1-criteria/index.es.mdx b/site/gatsby-site/content/research/1-criteria/index.es.mdx index 2f16acebc0..56fa69095f 100644 --- a/site/gatsby-site/content/research/1-criteria/index.es.mdx +++ b/site/gatsby-site/content/research/1-criteria/index.es.mdx @@ -6,8 +6,6 @@ slug: "/research/1-criteria" aiTranslated: true --- -## Definición de un "incidente de IA" - La industria de los viajes aéreos comerciales debe gran parte de su creciente seguridad al análisis y archivo sistemáticos de accidentes e incidentes pasados dentro de una base de datos compartida. En aviación, un accidente es un caso en el que se produce un daño sustancial o la pérdida de vidas. Los incidentes son casos en los que el riesgo de accidente aumenta sustancialmente. Por ejemplo, cuando un pequeño incendio se extingue rápidamente en una cabina, es un "incidente", pero si el fuego quema a los miembros de la tripulación en el curso de la extinción, es un "accidente". La [base de datos de aviación de la FAA](https://www.faa.gov/data_research/accident_incident/) indexa datos de registro de vuelo e investigaciones posteriores de expertos en exámenes integrales de factores tecnológicos y humanos. En parte debido a este autoexamen continuo, viajar en avión es una de las formas más seguras de viajar. Décadas de mejoras iterativas en los sistemas de seguridad y la capacitación han reducido las muertes [81 veces](https://theblogbyjavier.com/2020/01/02/aviation-safety-evolution-2019-update/) desde 1970 cuando se normalizó para millas de pasajeros. Donde la industria de la aviación tiene definiciones claras, los informáticos y los filósofos han debatido durante mucho tiempo las definiciones fundamentales de la inteligencia artificial. En ausencia de líneas claras que diferencien los algoritmos, la inteligencia y los daños que pueden causar directa o indirectamente, esta base de datos adopta un criterio adaptativo para ingerir "incidentes" donde los informes se aceptan o rechazan sobre la base de un [conjunto de reglas cada vez mayor](/es/editors-guide). diff --git a/site/gatsby-site/content/research/1-criteria/index.fr.mdx b/site/gatsby-site/content/research/1-criteria/index.fr.mdx index efb6b48967..472f179bb1 100644 --- a/site/gatsby-site/content/research/1-criteria/index.fr.mdx +++ b/site/gatsby-site/content/research/1-criteria/index.fr.mdx @@ -6,8 +6,6 @@ slug: "/research/1-criteria" aiTranslated: true --- -# Définir un "Incident IA" - L'industrie du transport aérien commercial doit une grande partie de sa sécurité croissante à l'analyse et à l'archivage systématiques des accidents et incidents passés dans une base de données partagée. Dans l'aviation, un accident est un cas où des dommages importants ou des pertes de vie se produisent. Les incidents sont des cas où le risque d'accident augmente considérablement. Par exemple, lorsqu'un petit incendie est rapidement éteint dans un poste de pilotage, il s'agit d'un "incident", mais si le feu brûle des membres d'équipage en cours d'extinction, il s'agit d'un "accident". La [base de données de l'aviation de la FAA](https://www.faa.gov/data_research/accident_incident/) indexe les données des journaux de vol et les enquêtes d'experts ultérieures dans des examens complets des facteurs technologiques et humains. En partie à cause de cet examen de soi continu, le transport aérien est l'un des modes de transport les plus sûrs. Des décennies d'améliorations itératives des systèmes de sécurité et de la formation ont réduit le nombre de décès [81 fois](https://theblogbyjavier.com/2020/01/02/aviation-safety-evolution-2019-update/) depuis 1970 lorsqu'il est normalisé pour les milles passagers. Là où l'industrie aéronautique a des définitions claires, les informaticiens et les philosophes débattent depuis longtemps des définitions fondamentales de l'intelligence artificielle. En l'absence de lignes claires différenciant les algorithmes, l'intelligence et les dommages qu'ils peuvent causer directement ou indirectement, cette base de données adopte un critère adaptatif pour ingérer les "incidents" où les rapports sont acceptés ou rejetés sur la base d'un [ensemble de règles croissant](/fr/editors-guide). diff --git a/site/gatsby-site/content/research/1-criteria/index.ja.mdx b/site/gatsby-site/content/research/1-criteria/index.ja.mdx new file mode 100644 index 0000000000..fa762e1026 --- /dev/null +++ b/site/gatsby-site/content/research/1-criteria/index.ja.mdx @@ -0,0 +1,11 @@ +--- +title: "「AIインシデント」の定義" +metaTitle: "「AIインシデント」の定義" +metaDescription: "AIインシデントデータベースにインシデントレポートが受け入れられるかどうかの理由は何か?" +slug: "/research/1-criteria" +aiTranslated: true +--- + +商業航空旅行業界は、過去の事故やインシデントを体系的に分析し、共有データベースにアーカイブすることで安全性を向上させています。航空では、事故は実質的な損傷や生命の喪失が発生するケースです。インシデントは事故のリスクが実質的に増加するケースです。たとえば、コックピットで小さな火災が素早く消火されると「インシデント」ですが、その消火の過程で火災が乗員に被害を与える場合は「事故」となります。FAA(航空宇宙局)の[航空データベース](https://www.faa.gov/data_research/accident_incident/)は、飛行記録データとその後の専門家による調査を索引化し、技術的および人間の要因の包括的な調査につなげています。この継続的な自己検証の一環として、航空旅行は最も安全な旅行手段の一つです。安全システムとトレーニングの繰り返しの改善により、1970年以来の乗客マイルに対する死亡者数は[81倍減少](https://theblogbyjavier.com/2020/01/02/aviation-safety-evolution-2019-update/)しています。 + +航空産業が明確な定義を持っているのに対し、コンピュータサイエンティストと哲学者は長らく人工知能の基本的な定義について議論してきました。明確な線引きがない中で、アルゴリズム、知能、およびそれらが直接または間接的に引き起こす可能性のある害について、このデータベースは「インシデント」を取り込むための適応的な基準を採用しており、報告が[編集者ガイド](/editors-guide)で定義された規則セットに基づいて受け入れられるか拒否されるかが判断されます。 diff --git a/site/gatsby-site/content/research/2-roadmap/index.ja.mdx b/site/gatsby-site/content/research/2-roadmap/index.ja.mdx new file mode 100644 index 0000000000..ae904a125a --- /dev/null +++ b/site/gatsby-site/content/research/2-roadmap/index.ja.mdx @@ -0,0 +1,33 @@ +--- +title: "データベースのロードマップ" +metaTitle: "ロードマップと将来の開発" +metaDescription: "AIIDの発展に伴う変更についての予測" +slug: "/research/2-roadmap" +aiTranslated: true +--- + +## 開発中 + +**インシデントレポートの翻訳:** 現在、インシデントデータベースは英語圏向けに収集および提供されていますが、知的システムは言語、文化、場所を横断して展開されています。このプロジェクトは、すべての機械翻訳可能な言語のサポートに向けて進行中であり、インシデントレポートをどの言語からでも取得し、70億人以上の潜在ユーザーに提供できるようにしています。 + +**ベストプラクティスリソース:** AIインシデントデータベースの動機の1つは、インシデントがデプロイ前にプロダクトやエンジニアリングチームと共有できるようにすることです。現在、データベースは問題(つまり、インシデント)のみを表示していますが、問題を防止または緩和するためのリソースを選択的に表示できるように進化しています。 + +**ポストモーテムレポート:** ホステッドサービスでは、サービスの停止後に「ポストモーテム」を公開することが一般的です。ここで、企業は何が起こったか、誰が影響を受けたか、どれくらいの期間影響を受けたか、そして将来的にそのような停止を防ぐために企業が行う取り組みについて説明します。AIインシデントデータベースは、AIインシデントのポストモーテムに特にサポートを提供することを検討しています。 + +**インシデントモニタリング:** より多くの知的システムが実世界で展開されるにつれて、インシデントの監視、収集、分類がますます難しくなります。AIインシデントデータベースが最新の知的システムに対応し続けるためには、AIインシデントを監視し、簡単に取り込むためのスクレイパーが必要です。現在、学生チームがこのプロジェクトのための基本的なAPIを開発しています。 + +## 可能性のある将来のプロジェクト + +**技術的な障害のタクソノミー:** AIIDには、経験した被害とそれに関連する技術的要素をリンクする厳密な技術的なタクソノミーが欠けています。システムがどのように構築されるかに関する知識を持つ機械学習エンジニアのチームがこのギャップを埋めることを望んでいます。 + +**インシデントデータの収集:** 多くのインシデントタイプは、企業によって分析され、内部で再発を避けるために使用されるインシデントデータを生成します。研究アソシエイトには、インシデントデータの自発的な開示を促進し、そのデータをインシデントレコードと関連付ける役割があります。将来的には、この種の開示が特定の管轄区域では義務付けられる可能性があり、AIIDはそのサポートが必要です。 + +**あなたのプロジェクト:** AIインシデントデータベースは、責任あるAIコラボレーション(RAIC)によって管理されています。これはAIインシデントデータベースの影響テーゼに合致するプロジェクトに協力するためのオープンな招待と考えてください。 + +## 提供された成果 + +**初期のインシデント収集:** 初期データセットは2019年に[Roman Yampolskiy](http://cecs.louisville.edu/ry/)、[Catherine Olsson](https://www.linkedin.com/in/catherineolsson/)、および[Sam Yoon](https://www.linkedin.com/in/samyoonnz/)からのインシデントリストを結合して収集されました。これらのインシデントは合計1,000以上のインシデントレポートに関連しています。 + +**インシデントディスカバリーアプリケーション:** 初期データセット収集の後、[Sean McGregor](https://seanbmcgregor.com/)が[Discover](/apps/discover)アプリケーションを開発し、初期のインシデントレポート収集で組み立てられた1,000以上のレポートの索引付けとクリーニングをサポートしました。 + +**タクソノミー:** すべての市場セグメントおよび政府の機能に対して知的システムが開発されています。データ製品の[研究品質](/research)を向上させるには、インシデントをインシデントのタイプ、規模、関与した技術、影響を受けた当事者に応じて正規化および分類するシステムが必要です。これらおよび他の分類は、多利害関係者システムで議論の的となります。すべての分類について完全な合意が必要ではなく、研究データベースの研究有用性を向上させるために、中央の分類機関なしにタクソノミーを適用することが可能です。各「[分類のスコープ](/research/4-taxonomies)」は、タクソノミーを開発し、インシデント全体にタクソノミーを適用する責任を持つエディタによって管理されます。詳細については[お問い合わせください](/contact)。 diff --git a/site/gatsby-site/content/research/3-history/index.ja.mdx b/site/gatsby-site/content/research/3-history/index.ja.mdx new file mode 100644 index 0000000000..1e1951072b --- /dev/null +++ b/site/gatsby-site/content/research/3-history/index.ja.mdx @@ -0,0 +1,17 @@ +--- +title: "初期収集方法論" +metaTitle: "初期収集方法論" +metaDescription: "AIインシデントデータベースの初期のインシデントレポートがどのように収集されたか?" +slug: "/research/3-history" +aiTranslated: true +--- + +アメリカの航空産業は法律により、インシデントや事故を連邦航空局に報告することが義務付けられています。知的システムに対する強制的な報告義務は存在しないため、AIIDは一般的または研究のプレスに取り上げられるほど有名になったインシデントに基づいて構築されています。その結果、データベースは人々によって知られているすべてのインシデントではなく、「公共のインシデント」を代表するものと考えるべきです。 + +現在のデータベースは、研究アシスタントのサム・ユンによって以下の方法で集められた初期のインシデントレポートによって支配されています。 + +- [YampolskiとOlssonによって集められた初期のリンク](/research/2-roadmap)。 +- リンクはGoogle検索の一連の結果で関連する情報を見つけるためのキーワードを示していました。 +- Google検索結果のトップ3ページに潜在的に関連するリンクは開かれ、ソースによって説明されているイベントについての質の高い情報があるかどうかが確認されました。関連する場合、それらはデータセットに追加されました。 +- 検索プロセス中に識別された他の関連するように見えるインシデントもデータセットに含まれました。 +- 特定の種類の結果は含まれませんでした。それらは仮説的であるか、学術的であるか、および/または実際の害を引き起こさないためです。 diff --git a/site/gatsby-site/content/research/4-related-work/index.ja.mdx b/site/gatsby-site/content/research/4-related-work/index.ja.mdx new file mode 100644 index 0000000000..de95ca7b48 --- /dev/null +++ b/site/gatsby-site/content/research/4-related-work/index.ja.mdx @@ -0,0 +1,90 @@ +--- +title: "関連する研究" +metaTitle: "関連する研究" +metaDescription: "関連する研究" +slug: "/research/4-related-work" +aiTranslated: true +--- + +公式なAIインシデント研究は比較的新しいものですが、何人かの人々がインシデントと見なされる可能性のある事例を収集しています。これには、 + +* [素晴らしい機械学習の解釈性: AIインシデントトラッカー](https://github.com/jphall663/awesome-machine-learning-interpretability/blob/master/README.md#ai-incident-tracker) +* [Charlie PownallのAIおよびアルゴリズムインシデントと論争](https://charliepownall.com/ai-algorithimic-incident-controversy-database/) +* [有益なおよび有害なAIのマップ](https://map.ai-global.org/) + +ここに追加できるインシデントリソースがあれば、[お問い合わせ](/contact)してください。 + +以下の出版物は[Google Scholarによってデータベース自体を参照している](https://scholar.google.com/scholar?oi=bibs&hl=en&cites=3482645389524246185)とされていますが、個々のインシデントだけでなく、お手数ですが、お問い合わせいただければ幸いです。[お問い合わせ](/contact) + +## 責任あるAI協力的研究 + +広範な安全性と公平性の共同体に奉仕する必要がある場合、Collabは研究を制作およびスポンサーします。これまでの作業には以下が含まれます。 + +* AIインシデントデータベースの公開発表時にリリースされたオリジナルな研究出版物。この作業へのすべての引用はこのページに追加されます。 +[McGregor, Sean. "Preventing repeated real-world AI failures by cataloging incidents: The AI incident database." AAAI Conference on Artificial Intelligenceの論文集. Vol. 35. No. 17. 2021.](https://ojs.aaai.org/index.php/AAAI/article/download/17817/17624) +* [2022 NeurIPS Workshop on Human-Centered AI](https://nips.cc/virtual/2022/workshop/50008)で提示されたインシデントの定義と基準の主要な更新。 +[McGregor, Sean, Kevin Paeth, and Khoa Lam. "Indexing AI Risks with Incidents, Issues, and Variants." arXiv preprint arXiv:2211.10384 (2022).](https://arxiv.org/pdf/2211.10384) +* オープンソースのインシデントレポートを分析する際のインシデントの原因の不確実性を減少させるアプローチ。[SafeAI](https://safeai.webs.upv.es/)で発表。 +[Pittaras, Nikiforos, and Sean McGregor. "A taxonomic system for failure cause analysis of open source AI incidents." arXiv preprint arXiv:2211.07280 (2022).](https://arxiv.org/pdf/2211.07280) + +## 2023年(2月24日まで) + +* [McGregor, Sean, and Jesse Hostetler. "データ中心のガバナンス." arXiv プリプリント arXiv:2302.07872 (2023).](https://arxiv.org/pdf/2302.07872) +* [NIST. リスクマネジメントプレイブック. 2023](https://pages.nist.gov/AIRMF/) + +## 2022年 + +* [Macrae, Carl. "自律型および知能型システムの失敗からの学び:事故、安全性、および社会技術的なリスクの分析." リスク分析 42.9 (2022): 1999-2025.](https://onlinelibrary.wiley.com/doi/pdfdirect/10.1111/risa.13850) +* [Felländer, Anna, et al. "倫理的AIのためのデータ駆動型リスク評価手法の達成." Digital Society 1.2 (2022): 13.](https://link.springer.com/article/10.1007/s44206-022-00016-0) +* [Apruzzese, Giovanni, et al. ""実際の攻撃者は勾配を計算しない":敵対的なML研究と実践のギャップを埋める." arXiv プリプリント arXiv:2212.14315 (2022).](https://arxiv.org/pdf/2212.14315) +* [Petersen, Eike, et al. "医学のための責任あるおよび規制適合機械学習:課題と解決策の調査." IEEE Access 10 (2022): 58375-58418.](https://ieeexplore.ieee.org/iel7/6287639/9668973/09783196.pdf) +* [Schuett, Jonas. "AIからのリスクに対する三つの防御ライン." arXiv プリプリント arXiv:2212.08364 (2022).](https://arxiv.org/pdf/2212.08364) +* [Schiff, Daniel S. "色付きのメガネで政策ウィンドウを見る:米国のAI政策の議題設定." レビュー・オブ・ポリシー・リサーチ.](https://onlinelibrary.wiley.com/doi/abs/10.1111/ropr.12535) +* [Neretin, Oleksii, and Vyacheslav Kharchenko. "Big Dataツールを使用したAIシステムの脆弱性収集と分析のプロセスを記述するモデル." 2022年第12回信頼性システム、サービス、および技術国際会議(DESSERT). IEEE、2022.](https://ieeexplore.ieee.org/abstract/document/10018811/) +* [Durso, Francis, et al. "人工知能学習システムにおける障害の分析(FAILS)." 2022 IEEE 29th Annual Software Technology Conference (STC). IEEE、2022.](https://ieeexplore.ieee.org/abstract/document/9951011/) +* [Kassab, Mohamad, Joanna DeFranco, and Phillip Laplante. "AIインフューズドシステムのバグの調査:分析と提案された分類." 2022 IEEE International Symposium on Software Reliability Engineering Workshops (ISSREW). IEEE、2022.](https://ieeexplore.ieee.org/abstract/document/9985178/) +* [Braga, Juliao, et al. "アルゴリズムとデータのガバナンスに関する論文の開発プロジェクト." (2022).](https://osf.io/xcpsd/download) +* [Secchi, Carlo, and Alessandro Gili. "持続可能なインフラのためのデジタル化:前途." 持続可能なインフラのためのデジタル化(2022):1-326.](https://www.torrossa.com/it/resources/an/5394879) +* [Groza, Adrian, et al. "Elaborarea cadrului strategic nat, ional în domeniul inteligent, ei artificiale."](https://www.adr.gov.ro/wp-content/uploads/2022/03/Analiza-reglementarilor-pentru-domeniul-inteligentei-artificiale.pdf) +* [Braga, Juliao, et al. "アルゴリズムとデータガバナンスに関する論文の開発プロジェクト." (2022).](https://osf.io/sr7kt/download)([元のポルトガル語](https://osf.io/xcpsd/download)). +* [NIST. リスクマネジメントプレイブック. 2022](https://pages.nist.gov/AIRMF/) +* [Shneiderman, Ben. Human-Centered AI. Oxford University Press, 2022.](https://www.amazon.com/Human-Centered-AI-Ben-Shneiderman/dp/0192845292) +* [Schwartz, Reva, et al. "人工知能における偏見の特定および管理のための標準に向けて." (2022).](https://tsapps.nist.gov/publication/get_pdf.cfm?pub_id=934464) +* [McGrath, Quintin et al. "プロ倫理的AIソリューションを設計するためのエンタープライズリスク管理フレームワーク." University of South Florida. (2022)](https://www.usf.edu/business/documents/desrist/paper_65.pdf). +* [Nor, Ahmad Kamal Mohd, et al. "説明可能なベイジアンディープラーニングを使用した異常検知と故障予測:実世界のガスタービンの異常の方法論と事例研究." (2022).](https://www.mdpi.com/2227-7390/10/4/554/pdf) +* [Xie, Xuan, Kristian Kersting, and Daniel Neider. "ディープニューラルネットワークの神経記号的検証." arXiv プリプリント arXiv:2203.00938 (2022).](https://arxiv.org/pdf/2203.00938) +* [Hundt, Andrew, et al. "ロボットが悪意あるステレオタイプを実行する." 2022 ACM Conference on Fairness, Accountability, and Transparency. 2022.](https://dl.acm.org/doi/fullHtml/10.1145/3531146.3533138) +* [Tidjon, Lionel Nganyewou, and Foutse Khomh. "機械学習ベースのシステムにおける脅威評価." arXiv プリプリント arXiv:2207.00091 (2022).](https://arxiv.org/pdf/2207.00091) +* [Naja, Iman, et al. "ナレッジグラフを使用したAIの説明責任情報の実用的な収集、統合、および監査の解除." IEEE Access 10 (2022): 74383-74411.](https://ieeexplore.ieee.org/iel7/6287639/9668973/09815594.pdf) +* [Cinà, Antonio Emanuele, et al. "ワイルドパターンリローデッド:機械学習セキュリティに対するトレーニングデータの汚染の調査." arXiv プリプリント arXiv:2205.01992 (2022).](https://arxiv.org/pdf/2205.01992) +* [Schröder, Tim, and Michael Schulz. "機械学習モデルの監視:課題と方法のカテゴリ化." データサイエンスとマネジメント(2022).](https://www.sciencedirect.com/science/article/pii/S2666764922000303) +* [Corea, Francesco, et al. "AIに対する原則ベースのアプローチ:欧州連合およびイタリアの事例." AI & SOCIETY (2022): 1-15.](https://link.springer.com/article/10.1007/s00146-022-01453-8) +* [Carmichael, Zachariah, and Walter J. Scheirer. "アンフーリング摂動ベースの事後説明." arXiv プリプリント arXiv:2205.14772 (2022).](https://arxiv.org/pdf/2205.14772) +* [Wei, Mengyi, and Zhixuan Zhou. "現実世界のAI倫理問題:AIインシデントデータベースからのエビデンス." arXiv プリプリント arXiv:2206.07635 (2022).](https://arxiv.org/pdf/2206.07635) +* [Petersen, Eike, et al. "医学のための責任あるおよび規制適合機械学習:課題と解決策の調査." IEEE Access (2022).](https://ieeexplore.ieee.org/iel7/6287639/9668973/09783196.pdf) +* [Karunagaran, Surya, Ana Lucic, and Christine Custis. "XAI Toolsheet: XAIツールのためのドキュメンテーションフレームワークに向けて."](https://a-lucic.github.io/talks/xai_pai_toolsheets.pdf) +* [Paudel, Shreyasha, and Aatiz Ghimire. "ネパールにおけるAI倫理調査."](https://www.naamii.org.np/wp-content/uploads/2021/11/AI-Ethics-Survey-Report.pdf) +* [Ferguson, Ryan. "ニューラルネットワークを使用したリスクプロセスの変革."](https://www.firm.fm/wp-content/uploads/2022/05/Papers-Round-Table-AI-April-2022.pdf) +* [Fujitsu Corporation. "AI倫理影響評価ケースブック," 2022](https://www.fujitsu.com/global/documents/about/research/technology/aiethics/fujitsu-AIethics-case_en.pdf) +* [Shneiderman, Ben and Du, Mengnan. "Human-Centered AI: Tools" 2022](https://hcai.site/tools/) +* [Salih, Salih. "機械学習の解釈可能性を理解する." Medium. 2022](https://towardsdatascience.com/understanding-machine-learning-interpretability-168fd7562a1a) +* [Garner, Carrie. "変革的で信頼性のあるAIシステムを作成するには、コミュニティの協力が必要です." Software Engineering Institute. 2022](https://insights.sei.cmu.edu/blog/creating-transformative-and-trustworthy-ai-systems-requires-a-community-effort/) +* [Weissinger, Laurin, AI, Complexity, and Regulation (February 14, 2022). The Oxford Handbook of AI Governance](https://academic.oup.com/edited-volume/41989) + +## 2021 + +* [Arnold, Z., Toner, H., CSET Policy. "AI Accidents: An Emerging Threat." (2021).](https://cset.georgetown.edu/wp-content/uploads/CSET-AI-Accidents-An-Emerging-Threat.pdf) +* [Aliman, Nadisha-Marie, Leon Kester, and Roman Yampolskiy. "トランスディシプリナリーAIオブザーバトリー—回顧的分析と将来志向の対照." Philosophies 6.1 (2021): 6.](https://www.mdpi.com/2409-9287/6/1/6/pdf) +* [Falco, Gregory, and Leilani H. Gilpin. "自律システムの検証および検証(V&V)のためのストレステストフレームワーク." 2021 IEEE International Conference on Autonomous Systems (ICAS). IEEE, 2021.](https://www.researchgate.net/profile/Gregory-Falco/publication/352930787_A_Stress_Testing_Framework_For_Autonomous_System_Verification_And_Validation_VV/links/60e911fcb8c0d5588ce64ec5/A-Stress-Testing-Framework-For-Autonomous-System-Verification-And-Validation-V-V.pdf) +* [Petersen, Eike, et al. "医学のための責任あるおよび規制適合機械学習:技術的課題と解決策の調査." arXiv プリプリント arXiv:2107.09546 (2021).](https://arxiv.org/pdf/2107.09546) +* [John-Mathews, Jean-Marie. AI倫理の実践、課題、および制約. Diss. Université Paris-Saclay, 2021.](https://tel.archives-ouvertes.fr/tel-03527232/document) +* [Macrae, Carl. "自律および知的システムの失敗からの学び:事故、安全性、および社会技術的リスクの源." Safety and Sociotechnical Sources of Risk (June 4, 2021) (2021).](https://nottingham-repository.worktribe.com/OutputFile/7164920) +* [Hong, Matthew K., et al. "自然言語の失敗に備えたAIプレイブック." Proceedings of the 2021 CHI Conference on Human Factors in Computing Systems. 2021.](https://www.adamfourney.com/papers/hong_chi2021.pdf) +* [Ruohonen, Jukka. "ヨーロッパ連合における製品安全規制のレビュー." arXiv プリプリント arXiv:2102.03679 (2021).](https://arxiv.org/pdf/2102.03679) +* [Kalin, Josh, David Noever, および Matthew Ciolino. "マシンラーニングモデルへの敵対的リスクを評価するための修正されたドレイク方程式." arXiv プリプリント arXiv:2103.02718 (2021).](https://arxiv.org/pdf/2103.02718) +* [Aliman, Nadisha Marie, および Leon Kester. "科学的および経験的な敵対的AI攻撃に対するエピステミックな防御." CEUR Workshop Proceedings. Vol. 2916. CEUR WS, 2021.](https://dspace.library.uu.nl/bitstream/handle/1874/413353/paper_1.pdf?sequence=1) +* [John-Mathews, Jean-Marie. L’Éthique de l’Intelligence Artificielle en Pratique. Enjeux et Limites. Diss. université Paris-Saclay, 2021.](https://www.theses.fr/2021UPASI015.pdf) +* [Smith, Catherine. "知的自由の自動化:人工知能、偏見、および情報の風景." IFLA Journal (2021): 03400352211057145](https://journals.sagepub.com/doi/abs/10.1177/03400352211057145) + + +もしここに追加すべき学術的な研究があれば、[お問い合わせ](/contact) からご連絡ください。 diff --git a/site/gatsby-site/content/research/5-response/index.ja.mdx b/site/gatsby-site/content/research/5-response/index.ja.mdx new file mode 100644 index 0000000000..fbe4e21ede --- /dev/null +++ b/site/gatsby-site/content/research/5-response/index.ja.mdx @@ -0,0 +1,67 @@ +--- +title: "「AIインシデントレスポンス」の定義" +metaTitle: "「AIインシデントレスポンス」の定義" +metaDescription: "AIインシデントレスポンスとは何か?" +slug: "/research/5-response" +aiTranslated: true +--- + +**AIインシデントレスポンス** は、AIインシデントデータベース(AIID)の**[インシデント](/research/1-criteria)**に対する**公的な対応**を指し、該当のインシデントにおいて、AIまたはAIシステムの開発または導入に**責任を負っているとされるエンティティ**(企業、組織、個人)からのものです。 + +AIインシデントレスポンスには通常、以下の点に関する合理的な情報が含まれます: + +1. 何が起こったか +2. インシデントが発生した理由 +3. エンティティが行ったまたは今後行うであろう対応に関する +
    +
  1. インシデントの是正
  2. +
  3. 将来のインシデントの再発防止
  4. +
+ +## インシデントレスポンスの提出 + +AIインシデントデータベースは、AIインシデントに関する情報、構造、および視点を提供するために設計されています。エンティティが1つまたは複数のインシデントのエンティティとしてリストされている場合、あなたの視点を提供するために一緒に作業したいと考えています。[データベースに直接レスポンスを提出](/apps/submit?tags=response)するか、[お問い合わせ](/contact)してレスポンスの提出について相談してください。 + +## AIインシデントレスポンスの目的 + +AIIDに対するレスポンスを公開することは、責任を負っているとされるエンティティが、インシデントの議論において声を持つ機会であり、将来の被害を予防し、AIの倫理的で責任ある実践を促進するためのものです。 + +レスポンスは以下の目的で活用されます: + +- AIインシデントに関する透明性を一般に提供し、根本的な原因、エンティティが行ったまたは行う被害の是正および/または将来の被害の予防に関する情報を提供すること +- 積極性とリーダーシップを示すこと +- AIシステムの基盤となる技術的な知識に基づくエンティティ固有の視点と関連する分析を強調すること + +完全で詳細なインシデントレスポンスは、同時に社会と企業の利益に貢献する機会です。何が「完全で詳細」であるかを説明するために、既にインシデントデータベースにあるいくつかのインシデントレスポンスの例と、それらがどこで改善できるかを紹介します。 + +## インシデントレスポンスの例 + +### レポート1:[Knightscopeがフィールドインシデントレポートを発行](/cite/51#r1765) + +インシデントの説明:2016年7月7日、Knightscope K5自律型セキュリティロボットがカリフォルニア州パロアルトのスタンフォードショッピングセンターで巡回中に、16か月の男児と衝突しました。 + +[Knightscope, Inc.](/entities/knightscope)によるインシデントレスポンス抜粋: + +> 「K5 Autonomous Data Machinesは25,000マイル以上走行し、通常は約1マイル毎時で走行し、報告されたインシデントはありませんでした。社会メディアでは、毎日大人、子供、大型および小型のペットとの数千のエンカウンターが報告されており、これらは報告されたインシデントなしに行われています。各K5には、レーザーレンジングデバイス、ソナーセンサー、頑丈なソフトウェアスタックを含む約30のセンサーが搭載されており、マシンが周囲の環境を1インチ未満から300フィート以上先まで感知する能力を提供しています。」 + +**このレポートがAIインシデントレスポンスである理由:** このレポートは、インシデントがなぜ起こったのか、関与したAIに関する詳細、関係者との公の謝罪およびインシデントの是正方法についてのエンティティの視点を提供しています。 + +**レスポンスから欠落しているもの:** エンティティは将来のインシデントの防止に関する詳細を提供していませんでした。 + +### レポート2:[ジョージア、ベトナム、および米国からの調整された不正行為の削除](/cite/324#r2002) + +インシデントの説明:The BLと関連付けられた大規模なページ、グループ、GAN生成の顔写真を持つ偽アカウントのネットワークが、米国のメディアアウトレットであるThe BLの政治的なナラティブをプラットフォームとInstagramで推進するために、Facebookのモデレーションシステムをバイパスしたとされています。 + +[Facebook](/entities/facebook)によるインシデントレスポンス抜粋: + +*Facebookは攻撃を実施していないが、彼らのユーザーをこれらの攻撃から保護する責任を持つソーシャルメディアプラットフォームとしての関与が、彼らのレスポンスをインシデントレスポンスとして資格付けます。* + +> 私たちはこのタイプの活動を検出および停止するために常に取り組んでいます。私たちのサービスが人々を操作に使用されないようにしたいからです。私たちは、これらのページ、グループ、およびアカウントを彼らの行動に基づいて取り下げています。これらのケースでは、この活動の背後にいる人々がお互いと協力し、フェイクアカウントを使用して自分自身を誤魔化すため、それが私たちの行動の根拠でした。 +> +> 今日、私たちはジョージアから発信した国内志向のネットワークの一環として、Facebookアカウント39個、ページ344個、グループ13個、Instagramアカウント22個を取り下げました。 +> +> また、ベトナムと米国発信で、主に米国および一部がベトナム、スペイン語、中国語を話す観客に焦点を当てた610のアカウント、89のFacebookページ、156のグループ、72のInstagramアカウントを取り下げました。 + +**このレポートがAIインシデントレスポンスである理由:** このレポートは、The BLがFacebookサービスを使用して人々を操作した方法についての明確な説明と、インシデントおよび直ちに行われた封じ込めおよび是正プロセスに関する詳細なアカウントを提供しています。 + +**レスポンスから欠落しているもの:** エンティティは将来のインシデントや再発の被害に関する詳細を含めていませんでした。 diff --git a/site/gatsby-site/content/terms-of-use/index.ja.mdx b/site/gatsby-site/content/terms-of-use/index.ja.mdx new file mode 100644 index 0000000000..90a39610f1 --- /dev/null +++ b/site/gatsby-site/content/terms-of-use/index.ja.mdx @@ -0,0 +1,108 @@ +--- +title: '利用規約' +metaTitle: '利用規約' +metaDescription: '人工知能データベースの利用規約' +slug: '/terms-of-use' +aiTranslated: true +--- + +人工知能インシデントデータベースウェブサイト、サービス、および{`/`}またはAPI(以下、「サイト」)のご利用ありがとうございます!私たちは、「過去を覚えていない者は、それを繰り返すことになる」というサンタヤーナの格言にデータで答えるため、貢献者と関係者のコミュニティを構築しています。これらの利用規約(以下、「規約」)は、サイトを使用する際のあなたの権利と責任、および私たちのあなたに対する約束を説明しています。注意深くお読みいただき、質問がある場合はお問い合わせください。これらの規約には、強制的な仲裁条項が含まれています。これらの規約に同意しない場合は、サイトを使用しないでください。 + +サイトおよび関連するドキュメンテーション、データ、およびデータベースにアクセスするか、または使用することで、ここに記載された規約と参照によって組み込まれたすべての規約、ポリシー、およびガイドライン、および特定のコンテンツや製品、サービス、または機能に関連して提示される追加の規約および制限に法的に拘束され、これに従うことに同意したものと見なされます(以下、「規約」と統一して「規約」と呼びます)。これらの規約はResponsible AI Collaborative(以下、「RAIC」、「私たち」、「私たち」、および{`/`}または「私たちの」)との間で締結されます。RAICはこれらの規約を変更するか、いつでもサイトの利用を一時停止または終了できることを理解しています。変更がある場合は、サイトの利用規約への変更に関する通知をウェブサイトに掲載します。新しい規約が発効した後も引き続きサイトを使用することは、新しい規約に従うものとされるため、新しい規約に同意しない場合は、サイトの使用を停止する必要があります。 + +## 利用条件 + +あなたは、サイトにコンテンツを提出できます。これには、違法、わいせつ、ポルノグラフィ、脅迫的、中傷的、知的財産権の侵害、またはソフトウェアウイルスや商業的な勧誘を含まない限り、データベースへの提出と関連するテキスト、エディタのノート、およびその他の対応するデータが含まれます。RAICは、そのようなコンテンツを監視、レビュー、削除、または編集する権利(ただし義務はありません)を留保します。RAICはまた、この利用規約に違反する個人によるサイトのさらなる利用の防止を求めるために行動を起こす権利を留保します。RAICは、あなたまたは第三者に事前の通知なしでこれらの措置を講じる可能性があります。RAICは、ユーザーがサイトに提出したコンテンツの適合性や真実性に関するいかなる表明または保証も行いません。 + +サイトまたはRAICにコンテンツを提出する場合、そのコンテンツについて非独占的、無償、永続的、取り消し不能、および完全なサブライセンス可能な権利を、世界中のどんなメディアで使用、複製、変更、適応、公開、翻訳、派生的な作品の作成、配布、および表示する権利をRAICおよび関連会社に付与します。提出するコンテンツのすべての権利を所有または他に制御していること、提供されるコンテンツが正確であること、提供されたコンテンツの使用がこのポリシーに違反していないこと、および提供したコンテンツから生じるすべての請求に対して、合理的な弁護士費用を含むRAICまたはその関連会社を保護するとともにこれに補償することを表明および保証します。RAICは、提供されたコンテンツによって提出されたものまたは第三者によって提出されたものに対していかなる責任も負わず、またいかなる義務も負いません。また、提供したコンテンツが米国で合法であり、サイトの一般的な観客に適していることを表明および保証します。著作権のある素材、ソフトウェア、グラフィックス、テキスト、写真、音声、ビデオ、および音楽の録音を含むがこれに限定されない著作物は、著作権者の明示的な許可なしにサイトに配置することはできません。 + +提出されるコンテンツに関して、サイトの訪問者が生成したコンテンツについてRAICは責任を負いません。RAICは、訪問者が生成したコンテンツに含まれるいかなる意見も支持していません。 + +すべてのスパムおよび広告は禁止されています。ボットやスパイダーなどの「ハイボリューム」なサイトへのアクセス手段も禁止されています。 + +RAICは、利用規約の違反から生じる問題について一切責任を負いません。 + +法的な理由から、13歳未満の者はサイトの使用またはアクセスを禁止されています。 + +サイトを通じて提供されたオリジナルなコンテンツおよび情報(以下、「オリジナルマテリアル」)は、RAIC(またはそれをライセンス供与した者)の所有物であり、アメリカ合衆国および外国の法律で指定された著作権、特許、および{`/`}または他の知的財産権によって保護されています。オリジナルマテリアルに見られるサードパーティの素材の一部は、著作権法のセクション107で規定されているフェアユース教義に基づいて使用されています。RAICはそのようなサードパーティの素材に関して権利を付与せず、また保証も行いません。ユーザーが提出したコンテンツと情報には別途ライセンス契約が適用されます。 + +これらの規約と条件への同意に対する考慮として、RAICは個人的で非独占的で譲渡不能で取り消し可能なサイトへのアクセスおよび使用のライセンスを提供します。RAICがサイトまたはサードパーティのページを通じて掲載したすべてのコンテンツは、明示的にマークされていない限りCC BY-SA 2.0ライセンス(CC BY ND)が適用されます。適用可能なライセンスと{`/`}またはマテリアルの免責事項の条件を確認し、マテリアルを使用する前に、適切な帰属を提供し、そのようなマテリアルを使用するために必要な許可とライセンスを取得することがあなたの責任です。マテリアルをコピー、複製、再送信、配布、公開、商業的に利用したり、その他の方法でマテリアルを変更または派生作品を作成することは、私たちの明示的な許可なしにはできません。 + +RAICの明示的な許可なしには、サイトのいかなる側面も販売または商業的に利用することはできません。 + +私たちはいつでも、理由の有無にかかわらず、通知有無にかかわらず、即時に効力を持って、サイトからの任意の人の禁止またはブロックを行う権利を有します。私たちは、唯一の裁量で、これらの利用規約またはRAICの方針のいずれかに違反していると合理的に判断されるコンテンツを拒否または削除する権利(しかし義務はありません)を有します。いつでもサイトの使用を停止できます。 + +RAICは、通知または通知なしで、サイト(またはその一部)の変更、一時停止、または永久終了の権利を留保します。RAICは、サイトの変更、一時停止、または終了に関して、あなたまたは第三者に対して一切の責任を負わないことに同意します。 + +### サードパーティのコンテンツ + +サイトコンテンツはさまざまな形式があり、いかなるサードパーティのコンテンツもRAICが所有しているもの、事実に基づくもの、RAICがモデレートしたもの、RAICが承認または審査したもの、またはRAICが支持または推奨したものと解釈されるべきではありません。サイトにはRAICが所有または制御していないサードパーティのウェブサイトやコンテンツへのリンクが含まれている可能性があります。RAICはサードパーティのウェブサイトのコンテンツ、プライバシーポリシー、または慣行を制御できず、また一切の責任を負いません。さらに、RAICはサードパーティのウェブサイトのコンテンツを検閲または編集することはできません。サイトの利用により、明示的にRAICをいかなる責任からも免れさせます。したがって、サードパーティのコンテンツやウェブサイトにリンクする際には、その他のウェブサイトの利用規約やプライバシーポリシーを注意深く読むようお勧めします。 + +## 著作権ポリシー + +RAICは他者の知的財産権を尊重し、ユーザーにも同様の行動を求めています。あなたが自分の作品が著作権侵害を構成すると考えるか、または他の知的財産権が他に侵害されたと考える場合は、以下の手順に従ってRAICに侵害の主張を通知する必要があります。 + +デジタルミレニアム著作権法(「DMCA」)は、可能性のある著作権侵害の通知に含まれるべき内容に関するいくつかの重要な問題を扱っています。 + +### DMCAテイクダウン通知: + +RAICは、DMCA(デジタルミレニアム著作権法)に準拠して、主張される著作権侵害の通知に対応する方針を採っています。特に、あなたが著作権者またはその代理人であり、どの素材があなたの著作権に侵害していると信じる場合は、デジタルミレニアム著作権法(「DMCA」)に基づいて通知を提出することができます。これには、以下の情報をRAICの著作権エージェントに書面で提供する必要があります(詳細については17 U.S.C 512(c)(3)を参照してください): + +- 主張される侵害の所有者を代表して行動する権限を持つ者の物理的または電子的署名; +- 侵害されたと主張される著作権作品の識別、または1つのオンラインサイトで複数の著作権作品が1つの通知でカバーされている場合は、そのサイトでそのような作品の代表的なリスト; +- 侵害されたと主張される素材の識別または侵害されるべき活動の対象であり、RAICがその素材を見つけるのに十分な情報; +- RAICがあなたに連絡するための合理的な手段、住所、電話番号、および利用可能な場合は電子メール; +- 使用が著作権者、その代理人、または法律によって認可されていないと信じる者の良心的な信念が述べられた声明; +- 通知に含まれる情報が正確であり、虚偽の宣誓のもとで、あなたが主張された侵害の所有者を代表して行動する権限があること。 + +米国著作権局は、[](https://www.copyright.gov/title17/92chap1.html#107)で基本情報を提供しており、ここで公正使用などの例外や防衛が適用されるかどうかを判断するのに役立つでしょう。 + +RAICの指定著作権エージェントは次のとおりです: +Responsible AI Collaborative, Inc. +636 Acanto St, Apt 102 +Los Angeles, CA 90049 +Attn: Designated Copyright Agent +{``} + +あなたがこのセクションのテイクダウン通知の要件をすべて満たさない場合、あなたのDMCA通知は無効になる可能性があることを認識しています。ここで予想されるテイクダウン通知の適切なサービスとDMCAに準拠して。なお、オンラインコンテンツが侵害されていると知りながら虚偽の申し立てを行った場合、民事罰の対象となる可能性があります。これらの罰金には、RAIC、著作権所有者、または著作権所有者のライセンシーがあなたの虚偽の陳述に依存して被った金銭的損害、裁判費用、および弁護士の手数料が含まれる可能性があります。 + +### カウンターノーティフィケーション: 素材の復元. + +RAICはすぐに侵害コンテンツを削除します。あなたが著作権侵害の主張に基づいて素材が取り下げられたという通知を受け取った場合、対象の素材をサイトに復元しようとするために、あなたは対抗通知を提供することができます。この通知は、17 USCセクション512(g)(3)に基づいて、次の要素を実質的に含んでいなければなりません: + +- あなたの物理的または電子的な署名; +- あなたの名前、住所、および電話番号; +- 素材およびそれが削除される前の場所の識別; +- 誤りまたは誤認識によって素材が削除されたという虚偽の宣誓の声明; +- あなたが住んでいる地区の連邦裁判所の管轄権に同意するもの(米国にいる場合)またはあなたのサービスプロバイダが位置している地区の連邦裁判所の管轄権に同意するもの(米国にいない場合); +- テイクダウン通知を提出した当事者からの訴訟送達を受け入れるあなたの同意。 + +**RAICは、これらの利用規約の繰り返し違反者と判断された場合、あなたのサイトへのアクセスを終了します。RAICはまた、素材が適切であり、これらの利用規約に遵守しているかどうかを判断する権利を留保しています。RAICは、これらの利用規約に違反する素材を随時、事前通知なしで、独自の裁量で削除するか、あなたのアクセスを終了するかもしれません。** + +## 弁償; 保証の否認; 責任の制限 + +あなたは、弊社のサイトの使用に関連して、合意またはサイトと関連して使用されたサードパーティサービスのプロバイダとの合意の違反を含む、いかなる損失、責任、請求、損害、費用、請求および経費、弁護士費用を含むすべての損失からRAIC、その請負業者、およびそのライセンサー、およびそれらの取締役、役員、従業員、および代理人を弁護し、無害に保つことに同意します。 + +サイトはいかなる保証もいたしません。素材は「そのまま」提供され、それ以上の保証はありません。RAICは、当社のサイトがエラーフリーであるか、またはそのアクセスが連続的または中断されないことを保証しません。あなたは、当社のサイトからダウンロードしたり、その他の方法でコンテンツやサービスを入手したりする際に、独自の裁量とリスクで行うことを理解しています。また、当社がリンクしているいかなるサイトのプラクティスについても責任を負いません。 + +いかなる場合でも、RAIC、または弊社の提携先またはライセンサーは、利用規約に基づくこれらの条件に関連して、利益の喪失、信用、使用、データの損失、その他の損失に対する直接、間接、付随的、特別、結果的または模範的な損害、およびその他の損失について一切の責任を負いません(当社がそのような損害の可能性について通知されていた場合でも)。いかなる場合でも、これらの条件に基づく弊社の総責任は$100に制限されます。 + +## 管轄 + +適用法律が異なる場合を除き、本契約および当社サイトのアクセスまたは使用に関する一切は、カリフォルニア州の法律に準拠し、その法律の適用除外を除きます。本契約および当社サイトのアクセスまたは使用に関する紛争(以下、「紛争」)が仲裁の対象外でない場合の適切な管轄地は、カリフォルニア州ロサンゼルス郡にある州および連邦裁判所です。 + +## 紛争解決 + +これらの利用規約またはそれらの違反、終了、施行、解釈、または有効性に関連する紛争、請求、または論争が発生した場合(以下総称して「紛争」)、各当事者の最高代表は、その他の紛争については米国カリフォルニア中央地区連邦地方裁判所で解決されることになります)善意で交渉に入り、円満に解決するために努力します。各当事者が善意で交渉に入る最初の要請後、または当事者が書面で同意する他の期間内に紛争を解決できない場合、いずれかの当事者はJAMS包括的仲裁規則および手続きの下で拘束力のある仲裁を開始することができます。当事者は、JAMSの仲裁人の料金と経費を平等に分担します。仲裁は、当事者の相互の合意によって選ばれた単独の仲裁人によって行われるか、それに失敗した場合はJAMSの当時の規則に従って行われます。仲裁人によって下された賞の判決は、適任な司法機関において執行することができます。仲裁人は特定の実行または他の公正かつ法的な救済措置、仮の措置を含む、授与する権限を有します。各当事者は、紛争解決プロセスに起因する自身の経費に対して責任を負います。仲裁手続きはすべてカリフォルニア州ロサンゼルスで行われます。 + +## プライバシーポリシー + +RAICでは、ユーザーのプライバシーを尊重しています。詳細については、[プライバシーポリシー](/privacy-policy)をご覧ください。サイトの使用により、そこで記述されている通りに個人データの収集および使用に同意したものと見なされます。 + +プライバシーに関する質問や未解決の問題がある場合は、[お問い合わせ](/contact)してください。 + +## 全文合意 + +これらの利用規約は、ここに関連する当事者間の完全な合意書です。これらの利用規約のいかなる部分が違法、無効、または執行不可能であるとされても、その部分は切り離され、残りの規定の有効性および執行可能性に影響を与えません。RAICがこれらの利用規約のいずれかを厳格に執行しない場合でも、それはRAICが存在するいかなる権利または救済の放棄と見なされません。RAICの書面による同意なしに、利用規約の一部または全部に関する権利または義務を譲渡、移転、または処理してはなりません。 + +有効日:2022年7月7日 diff --git a/site/gatsby-site/cypress/e2e/incidentVariants.cy.js b/site/gatsby-site/cypress/e2e/incidentVariants.cy.js index c02e029fba..1f867e3e6c 100644 --- a/site/gatsby-site/cypress/e2e/incidentVariants.cy.js +++ b/site/gatsby-site/cypress/e2e/incidentVariants.cy.js @@ -66,12 +66,12 @@ describe('Variants pages', () => { cy.disableSmoothScroll(); }); - it('Should display Variant list', async () => { + it('Should display Variant list', () => { cy.visit(url); cy.contains('h1', 'Variants').should('exist').scrollIntoView(); - getVariants(async (variants) => { + getVariants((variants) => { cy.get('[data-cy=variant-card]').should('have.length', variants.length); for (let index = 0; index < variants.length; index++) { @@ -79,7 +79,7 @@ describe('Variants pages', () => { cy.get('[data-cy=variant-card]') .eq(index) - .within(async () => { + .within(() => { cy.get('[data-cy=variant-status-badge]').contains( getVariantStatusText(getVariantStatus(variant)) ); diff --git a/site/gatsby-site/cypress/e2e/integration/api/lookupbyurl.cy.js b/site/gatsby-site/cypress/e2e/integration/api/lookupbyurl.cy.js new file mode 100644 index 0000000000..55a90a6cf5 --- /dev/null +++ b/site/gatsby-site/cypress/e2e/integration/api/lookupbyurl.cy.js @@ -0,0 +1,119 @@ +import normalizeRequest from '../../../../src/utils/normalizeRequest'; +import { conditionalIt } from '../../../support/utils'; + +describe('/api/lookupbyurl endpoint', () => { + conditionalIt( + !Cypress.env('isEmptyEnvironment'), + 'Should fetch matching incidents and reports', + () => { + const url1 = + 'https://www.today.com/parents/moms-warn-disturbing-video-found-youtube-kids-please-be-careful-t101552?random=querystring'; + + const url2 = + 'https://www.nj.com/mercer/2018/12/80-workers-at-amazon-warehouse-in-nj-treated-after-being-sickened-by-bear-repellant.html#incart_river_index'; + + const url3 = 'https://noresults.com/none'; + + const query = [url1, url2, url3].map((url) => `urls[]=${encodeURIComponent(url)}`).join('&'); + + const url = `/api/lookupbyurl?${query}`; + + cy.log(`GET ${url}`); + + cy.request(url).then((response) => { + expect(response.body).to.deep.eq({ + results: [ + { + url: 'https://www.today.com/parents/moms-warn-disturbing-video-found-youtube-kids-please-be-careful-t101552?random=querystring', + reports: [ + { + report_number: 3, + title: 'Disturbing YouTube Kids video shows Mickey Mouse with gun', + url: 'https://www.today.com/parents/moms-warn-disturbing-video-found-youtube-kids-please-be-careful-t101552', + }, + ], + incidents: [ + { + incident_id: 1, + title: 'Google’s YouTube Kids App Presents Inappropriate Content', + url: 'https://incidentdatabase.ai/cite/1', + }, + ], + }, + { + url: 'https://www.nj.com/mercer/2018/12/80-workers-at-amazon-warehouse-in-nj-treated-after-being-sickened-by-bear-repellant.html#incart_river_index', + reports: [ + { + report_number: 141, + title: + '1 critical, 54 Amazon workers treated after bear repellent discharge in N.J. warehouse', + url: 'https://www.nj.com/mercer/2018/12/80-workers-at-amazon-warehouse-in-nj-treated-after-being-sickened-by-bear-repellant.html#incart_river_index', + }, + ], + incidents: [ + { + incident_id: 2, + title: 'Warehouse robot ruptures can of bear spray and injures workers', + url: 'https://incidentdatabase.ai/cite/2', + }, + ], + }, + { + url: 'https://noresults.com/none', + reports: [], + incidents: [], + }, + ], + }); + }); + } + ); + + conditionalIt(!Cypress.env('isEmptyEnvironment'), 'Should throw 400', () => { + const url1 = 'badurl'; + + const query = [url1].map((url) => `urls[]=${encodeURIComponent(url)}`).join('&'); + + const url = `/api/lookupbyurl?${query}`; + + cy.log(`GET ${url}`); + + cy.request({ url, failOnStatusCode: false }).then((response) => { + expect(response.body).to.deep.eq({ + status: 400, + errors: [ + { + path: 'urls.0', + errorCode: 'format.openapi.requestValidation', + message: 'must match format "url"', + location: 'query', + }, + ], + }); + }); + }); + + it('Should normalize request when on Netlify', () => { + const req = { query: { urls: 'https://url1.com, https://url2.com' } }; + + normalizeRequest(req); + + expect(req.query.urls).to.deep.eq(['https://url1.com', 'https://url2.com']); + }); + + it('Should normalize request when running on node with only one param', () => { + const req = { query: { urls: 'https://url1.com' } }; + + normalizeRequest(req); + + expect(req.query.urls).to.deep.eq(['https://url1.com']); + }); + + it('Should leave request unchanged', () => { + const req = { query: { urls: ['https://url1.com'] } }; + + normalizeRequest(req); + + expect(req.query.urls).to.deep.eq(['https://url1.com']); + }); +}); diff --git a/site/gatsby-site/cypress/e2e/integration/apps/checklistsForm.cy.js b/site/gatsby-site/cypress/e2e/integration/apps/checklistsForm.cy.js index 2fecc18356..96555ad6f9 100644 --- a/site/gatsby-site/cypress/e2e/integration/apps/checklistsForm.cy.js +++ b/site/gatsby-site/cypress/e2e/integration/apps/checklistsForm.cy.js @@ -121,6 +121,24 @@ describe('Checklists App Form', () => { }); }); + maybeIt('Should trigger GraphQL upsert query on adding tag', () => { + withLogin(({ user }) => { + interceptFindChecklist({ ...defaultChecklist, owner_id: user.userId }); + interceptUpsertChecklist({}); + + cy.visit(url); + + cy.get('#tags_goals_input').type('Code Generation'); + cy.get('#tags_goals').contains('Code Generation').click(); + + cy.wait(['@upsertChecklist']).then((xhr) => { + expect(xhr.request.body.variables.checklist).to.deep.nested.include({ + tags_goals: ['GMF:Known AI Goal:Code Generation'], + }); + }); + }); + }); + maybeIt('Should trigger GraphQL update on removing tag', () => { withLogin(({ user }) => { interceptFindChecklist({ diff --git a/site/gatsby-site/cypress/e2e/integration/apps/submitted.cy.js b/site/gatsby-site/cypress/e2e/integration/apps/submitted.cy.js index 3c3c619002..6a12f1172c 100644 --- a/site/gatsby-site/cypress/e2e/integration/apps/submitted.cy.js +++ b/site/gatsby-site/cypress/e2e/integration/apps/submitted.cy.js @@ -21,6 +21,10 @@ describe('Submitted reports', () => { userId first_name last_name + roles + adminData { + email + } } } `, @@ -95,6 +99,10 @@ describe('Submitted reports', () => { maybeIt('Promotes a submission to a new report and links it to a new incident', () => { cy.login(Cypress.env('e2eUsername'), Cypress.env('e2ePassword')); + if (user.adminData.email == Cypress.env('e2eUsername')) { + expect(user.roles.some((role) => ['admin', 'incident_editor'].includes(role))).to.be.true; + } + const submission = submittedReports.data.submissions.find( (r) => r._id === '5f9c3ebfd4896d392493f03c' ); @@ -206,6 +214,10 @@ describe('Submitted reports', () => { maybeIt('Promotes a submission to a new report and links it to an existing incident', () => { cy.login(Cypress.env('e2eUsername'), Cypress.env('e2ePassword')); + if (user.adminData.email == Cypress.env('e2eUsername')) { + expect(user.roles.some((role) => ['admin', 'incident_editor'].includes(role))).to.be.true; + } + const submission = submittedReports.data.submissions.find( (r) => r.incident_ids.length == 1 && r.incident_ids.includes(10) ); @@ -311,6 +323,10 @@ describe('Submitted reports', () => { maybeIt('Promotes a submission to a new report and links it to multiple incidents', () => { cy.login(Cypress.env('e2eUsername'), Cypress.env('e2ePassword')); + if (user.adminData.email == Cypress.env('e2eUsername')) { + expect(user.roles.some((role) => ['admin', 'incident_editor'].includes(role))).to.be.true; + } + const submission = submittedReports.data.submissions.find( (r) => r._id == '444461606b4bb5e39601234' ); @@ -448,6 +464,10 @@ describe('Submitted reports', () => { maybeIt('Promotes a submission to a new issue', () => { cy.login(Cypress.env('e2eUsername'), Cypress.env('e2ePassword')); + if (user.adminData.email == Cypress.env('e2eUsername')) { + expect(user.roles.some((role) => ['admin', 'incident_editor'].includes(role))).to.be.true; + } + const submission = submittedReports.data.submissions.find( (r) => r._id === '62d561606b4bb5e39605555' ); @@ -531,6 +551,10 @@ describe('Submitted reports', () => { maybeIt('Rejects a submission', () => { cy.login(Cypress.env('e2eUsername'), Cypress.env('e2ePassword')); + if (user.adminData.email == Cypress.env('e2eUsername')) { + expect(user.roles.some((role) => ['admin', 'incident_editor'].includes(role))).to.be.true; + } + const submission = submittedReports.data.submissions.find( (r) => r.incident_ids.length == 1 && r.incident_ids.includes(10) ); @@ -599,6 +623,10 @@ describe('Submitted reports', () => { maybeIt('Edits a submission - update just a text', () => { cy.login(Cypress.env('e2eUsername'), Cypress.env('e2ePassword')); + if (user.adminData.email == Cypress.env('e2eUsername')) { + expect(user.roles.some((role) => ['admin', 'incident_editor'].includes(role))).to.be.true; + } + cy.conditionalIntercept( '**/graphql', (req) => req.body.operationName == 'FindSubmissions', @@ -733,6 +761,10 @@ describe('Submitted reports', () => { maybeIt('Edits a submission - uses fetch info', () => { cy.login(Cypress.env('e2eUsername'), Cypress.env('e2ePassword')); + if (user.adminData.email == Cypress.env('e2eUsername')) { + expect(user.roles.some((role) => ['admin', 'incident_editor'].includes(role))).to.be.true; + } + cy.conditionalIntercept( '**/graphql', (req) => req.body.operationName == 'FindSubmissions', @@ -808,6 +840,10 @@ describe('Submitted reports', () => { () => { cy.login(Cypress.env('e2eUsername'), Cypress.env('e2ePassword')); + if (user.adminData.email == Cypress.env('e2eUsername')) { + expect(user.roles.some((role) => ['admin', 'incident_editor'].includes(role))).to.be.true; + } + const submission = submittedReports.data.submissions.find( (r) => r._id === '62d561606b4bb5e396034444' ); @@ -872,91 +908,102 @@ describe('Submitted reports', () => { cy.get('[data-cy="promote-button"]').click(); - cy.contains('[data-cy="toast"]', 'Description is required.').should('exist'); + cy.contains('[data-cy="toast"]', 'Description is required').should('exist'); cy.wait('@promotionInvoked', { timeout: 2000 }); } ); - it.only('Does not allow promotion of submission to Issue if schema is invalid (missing Title).', () => { - cy.login(Cypress.env('e2eUsername'), Cypress.env('e2ePassword')); - - const submission = submittedReports.data.submissions.find( - (r) => r._id === '123461606b4bb5e39601234' - ); + maybeIt( + 'Does not allow promotion of submission to Issue if schema is invalid (missing Title).', + () => { + cy.login(Cypress.env('e2eUsername'), Cypress.env('e2ePassword')); - cy.conditionalIntercept( - '**/graphql', - (req) => req.body.operationName == 'FindSubmissions', - 'FindSubmissions', - { - data: { - submissions: [submission], - }, + if (user.adminData.email == Cypress.env('e2eUsername')) { + expect(user.roles.some((role) => ['admin', 'incident_editor'].includes(role))).to.be.true; } - ); - cy.conditionalIntercept( - '**/graphql', - (req) => req.body.operationName == 'FindSubmission', - 'FindSubmission', - { - data: { - submission: submission, - }, - } - ); + const submission = submittedReports.data.submissions.find( + (r) => r._id === '123461606b4bb5e39601234' + ); - cy.conditionalIntercept( - '**/graphql', - (req) => req.body.operationName == 'AllQuickAdd', - 'AllQuickAdd', - { - data: { - quickadds: [quickAdds], - }, - } - ); + cy.conditionalIntercept( + '**/graphql', + (req) => req.body.operationName == 'FindSubmissions', + 'FindSubmissions', + { + data: { + submissions: [submission], + }, + } + ); - cy.visit(url); + cy.conditionalIntercept( + '**/graphql', + (req) => req.body.operationName == 'FindSubmission', + 'FindSubmission', + { + data: { + submission: submission, + }, + } + ); - cy.waitForStableDOM(); + cy.conditionalIntercept( + '**/graphql', + (req) => req.body.operationName == 'AllQuickAdd', + 'AllQuickAdd', + { + data: { + quickadds: [quickAdds], + }, + } + ); - cy.wait('@FindSubmissions'); + cy.visit(url); - cy.visit(url + `?editSubmission=${submission._id}`); + cy.waitForStableDOM(); - cy.wait('@AllQuickAdd'); + cy.wait('@FindSubmissions'); - cy.on('fail', (err) => { - expect(err.message).to.include( - '`cy.wait()` timed out waiting `2000ms` for the 1st request to the route: `promotionInvoked`. No request ever occurred.' - ); - }); + cy.visit(url + `?editSubmission=${submission._id}`); - cy.conditionalIntercept( - '**/graphql', - (req) => req.body.operationName === 'PromoteSubmission', - 'promotionInvoked', - {} - ); + cy.wait('@AllQuickAdd'); - cy.get('select[data-cy="promote-select"]').as('dropdown'); + cy.on('fail', (err) => { + expect(err.message).to.include( + '`cy.wait()` timed out waiting `2000ms` for the 1st request to the route: `promotionInvoked`. No request ever occurred.' + ); + }); - cy.get('@dropdown').select('Issue'); + cy.conditionalIntercept( + '**/graphql', + (req) => req.body.operationName === 'PromoteSubmission', + 'promotionInvoked', + {} + ); - cy.get('[data-cy="promote-button"]').click(); + cy.get('select[data-cy="promote-select"]').as('dropdown'); - cy.contains('[data-cy="toast"]', 'Title is required').should('exist'); + cy.get('@dropdown').select('Issue'); - cy.wait('@promotionInvoked', { timeout: 2000 }); - }); + cy.get('[data-cy="promote-button"]').click(); + + cy.contains('[data-cy="toast"]', 'Title is required').should('exist'); + + cy.wait('@promotionInvoked', { timeout: 2000 }); + } + ); maybeIt( 'Does not allow promotion of submission to Report if schema is invalid (missing Date).', () => { cy.login(Cypress.env('e2eUsername'), Cypress.env('e2ePassword')); + if (user.adminData.email == Cypress.env('e2eUsername')) { + expect(user.roles.some((role) => ['admin', 'incident_editor'].includes(role))).to.be.true; + } + const submission = submittedReports.data.submissions.find( (r) => r._id === '333561606b4bb5e39601234' ); @@ -1027,6 +1074,10 @@ describe('Submitted reports', () => { // With new submission list, we allow to save changes always cy.login(Cypress.env('e2eUsername'), Cypress.env('e2ePassword')); + if (user.adminData.email == Cypress.env('e2eUsername')) { + expect(user.roles.some((role) => ['admin', 'incident_editor'].includes(role))).to.be.true; + } + const submission = submittedReports.data.submissions.find( (r) => r._id === '62d561606b4bb5e39601234' ); @@ -1102,6 +1153,10 @@ describe('Submitted reports', () => { maybeIt('Should display submission image on edit page', () => { cy.login(Cypress.env('e2eUsername'), Cypress.env('e2ePassword')); + if (user.adminData.email == Cypress.env('e2eUsername')) { + expect(user.roles.some((role) => ['admin', 'incident_editor'].includes(role))).to.be.true; + } + const submission = submittedReports.data.submissions.find( (s) => s.cloudinary_id && s.cloudinary_id != 'reports/' && s.cloudinary_id != '' ); @@ -1173,6 +1228,10 @@ describe('Submitted reports', () => { maybeIt('Should display fallback image on edit modal if submission doesnt have an image', () => { cy.login(Cypress.env('e2eUsername'), Cypress.env('e2ePassword')); + if (user.adminData.email == Cypress.env('e2eUsername')) { + expect(user.roles.some((role) => ['admin', 'incident_editor'].includes(role))).to.be.true; + } + const submission = submittedReports.data.submissions.find((s) => s.cloudinary_id === null); cy.conditionalIntercept( @@ -1222,6 +1281,10 @@ describe('Submitted reports', () => { maybeIt('Should display an error message if Date Published is not in the past', () => { cy.login(Cypress.env('e2eUsername'), Cypress.env('e2ePassword')); + if (user.adminData.email == Cypress.env('e2eUsername')) { + expect(user.roles.some((role) => ['admin', 'incident_editor'].includes(role))).to.be.true; + } + const submission = submittedReports.data.submissions.find( (r) => r._id === '62d561606b4bb5e39601234' ); @@ -1439,6 +1502,10 @@ describe('Submitted reports', () => { maybeIt('Claims a submission', () => { cy.login(Cypress.env('e2eUsername'), Cypress.env('e2ePassword')); + if (user.adminData.email == Cypress.env('e2eUsername')) { + expect(user.roles.some((role) => ['admin', 'incident_editor'].includes(role))).to.be.true; + } + const submission = submittedReports.data.submissions.find( (r) => r._id === '5f9c3ebfd4896d392493f03c' ); @@ -1509,6 +1576,10 @@ describe('Submitted reports', () => { maybeIt('Unclaims a submission', () => { cy.login(Cypress.env('e2eUsername'), Cypress.env('e2ePassword')); + if (user.adminData.email == Cypress.env('e2eUsername')) { + expect(user.roles.some((role) => ['admin', 'incident_editor'].includes(role))).to.be.true; + } + const submission = submittedReports.data.submissions.find( (r) => r._id === '6123bf345e740c1a81850e89' ); @@ -1584,6 +1655,10 @@ describe('Submitted reports', () => { maybeIt('Should maintain current page while claiming', () => { cy.login(Cypress.env('e2eUsername'), Cypress.env('e2ePassword')); + if (user.adminData.email == Cypress.env('e2eUsername')) { + expect(user.roles.some((role) => ['admin', 'incident_editor'].includes(role))).to.be.true; + } + const submission = submittedReports.data.submissions.find( (r) => r._id === '433346160eeeeqdd5e382bei234' ); @@ -1651,4 +1726,23 @@ describe('Submitted reports', () => { }); cy.get(".pagination [aria-current='page'] button").contains('2').should('exist'); }); + + maybeIt('Should display "No reports found" if no quick adds are found', () => { + cy.conditionalIntercept( + '**/graphql', + (req) => req.body.operationName == 'AllQuickAdd', + 'AllQuickAdd', + { + data: { + quickadds: [], + }, + } + ); + + cy.visit(url); + + cy.wait('@AllQuickAdd'); + + cy.get('[data-cy="no-results"]').should('contain', 'No reports found'); + }); }); diff --git a/site/gatsby-site/cypress/e2e/integration/cite.cy.js b/site/gatsby-site/cypress/e2e/integration/cite.cy.js index 06072f4ebc..3699c3a130 100644 --- a/site/gatsby-site/cypress/e2e/integration/cite.cy.js +++ b/site/gatsby-site/cypress/e2e/integration/cite.cy.js @@ -1,9 +1,12 @@ import { maybeIt } from '../../support/utils'; import flaggedReport from '../../fixtures/reports/flagged.json'; import unflaggedReport from '../../fixtures/reports/unflagged.json'; +import upsertDuplicateClassification from '../../fixtures/classifications/upsertDuplicateClassification.json'; +import updateIncident50 from '../../fixtures/incidents/updateIncident50.json'; import { format, getUnixTime } from 'date-fns'; import updateOneIncidentFlagged from '../../fixtures/incidents/updateOneIncidentFlagged.json'; import incident10 from '../../fixtures/incidents/fullIncident10.json'; +import incident50 from '../../fixtures/incidents/fullIncident50.json'; import { transformIncidentData, deleteIncidentTypenames } from '../../../src/utils/cite'; import { transformReportData, deleteReportTypenames } from '../../../src/utils/reports'; const { gql } = require('@apollo/client'); @@ -80,14 +83,19 @@ describe('Cite pages', () => { } ); - it.skip('Should scroll to report when clicking on a report in the timeline', () => { + it('Should scroll to report when clicking on a report in the timeline', () => { cy.visit(url); cy.disableSmoothScroll(); cy.waitForStableDOM(); - cy.get('text').contains('For some Starbucks workers, job leaves bitter taste').parents('a'); + cy.get('text') + .contains('For some Starbucks workers, job leaves bitter taste') + .parents('a') + .click(); + + cy.waitForStableDOM(); cy.get('h5') .contains('For some Starbucks workers, job leaves bitter taste') @@ -217,6 +225,74 @@ describe('Cite pages', () => { cy.get('@modal').should('not.exist'); }); + maybeIt('Should remove duplicate', () => { + cy.conditionalIntercept( + '**/graphql', + (req) => req.body.operationName == 'UpsertClassification', + 'upsertClassification', + upsertDuplicateClassification + ); + cy.conditionalIntercept( + '**/graphql', + (req) => req.body.operationName == 'UpdateIncident', + 'updateIncident', + updateIncident50 + ); + cy.conditionalIntercept( + '**/graphql', + (req) => req.body.operationName == 'InsertDuplicate', + 'insertDuplicate', + { + data: { + insertOneDuplicate: { + __typename: 'Duplicate', + duplicate_incident_number: 10, + true_incident_number: 50, + }, + }, + } + ); + + cy.conditionalIntercept( + '**/graphql', + (req) => + req.body.operationName == 'FindIncident' && req.body.variables.query.incident_id == 10, + 'findIncident', + incident10 + ); + + cy.conditionalIntercept( + '**/graphql', + (req) => + req.body.operationName == 'FindIncident' && req.body.variables.query.incident_id == 10, + 'findIncident', + incident50 + ); + + cy.login(Cypress.env('e2eUsername'), Cypress.env('e2ePassword')); + cy.waitForStableDOM(); + + cy.visit('/cite/10'); + cy.waitForStableDOM(); + + cy.get('[data-cy="remove-duplicate"]').click(); + cy.waitForStableDOM(); + + cy.get('#input-duplicateIncidentId').type('50'); + cy.waitForStableDOM(); + + cy.get('#duplicateIncidentId > a[aria-label="50"]').click(); + cy.waitForStableDOM(); + + cy.get('#input-duplicateIncidentId').blur(); + cy.waitForStableDOM(); + + cy.get('[data-cy="confirm-remove-duplicate"]').click(); + cy.waitForStableDOM(); + + cy.contains('Incident 10 marked as duplicate').should('exist'); + }); + it('Should pre-fill submit report form', () => { cy.visit(url); diff --git a/site/gatsby-site/cypress/e2e/integration/citeEdit.cy.js b/site/gatsby-site/cypress/e2e/integration/citeEdit.cy.js index 3f79f81cea..33009e986b 100644 --- a/site/gatsby-site/cypress/e2e/integration/citeEdit.cy.js +++ b/site/gatsby-site/cypress/e2e/integration/citeEdit.cy.js @@ -718,28 +718,42 @@ describe('Edit report', () => { cy.wait('@updateOneReportTranslation') .its('request.body.variables') .then((variables) => { - expect(variables.input.title).to.eq('Este es el Titulo'); + expect(variables.input.title).to.eq('Este es el Título en español'); expect(variables.input.text).to.eq( - 'Este es el texto que tiene un largo mayor a ochenta caracteres!' + 'Este es un texto de prueba que tiene un largo mayor a ochenta caracteres (en español)' ); expect(variables.input.language).to.eq('es'); expect(variables.input.report_number).to.eq(23); expect(variables.input.plain_text).to.eq( - 'Este es el texto que tiene un largo mayor a ochenta caracteres!\n' + 'Este es un texto de prueba que tiene un largo mayor a ochenta caracteres (en español)\n' ); }); cy.wait('@updateOneReportTranslation') .its('request.body.variables') .then((variables) => { - expect(variables.input.title).to.eq('Este es el Titulo en frances'); + expect(variables.input.title).to.eq(`C'est le Titre en français`); expect(variables.input.text).to.eq( - 'Este es el texto que tiene un largo mayor a ochenta caracteres en frances!' + `Il s'agit d'un texte de test de plus de quatre-vingts caractères - lorem ipsum (en français)` ); expect(variables.input.language).to.eq('fr'); expect(variables.input.report_number).to.eq(23); expect(variables.input.plain_text).to.eq( - 'Este es el texto que tiene un largo mayor a ochenta caracteres en frances!\n' + `Il s'agit d'un texte de test de plus de quatre-vingts caractères - lorem ipsum (en français)\n` + ); + }); + + cy.wait('@updateOneReportTranslation') + .its('request.body.variables') + .then((variables) => { + expect(variables.input.title).to.eq('これは日本語でのタイトルです'); + expect(variables.input.text).to.eq( + '解サオライ協立なーづ民手ぶみドに即記朝ぐ奥置ぱで地更トるあて栄厚ぜづを祭屋ん来派どてゃ読速ヘ誌約カタシネ原39業理る。外ヒヱフ社第むせゆ由更混ソエ夕野しりすよ顔飛リの兆基う公言や置17謝后嘘5供フキヌア星集ヘラ辞勘壇崇さびわ。(日本語で)' + ); + expect(variables.input.language).to.eq('ja'); + expect(variables.input.report_number).to.eq(23); + expect(variables.input.plain_text).to.eq( + '解サオライ協立なーづ民手ぶみドに即記朝ぐ奥置ぱで地更トるあて栄厚ぜづを祭屋ん来派どてゃ読速ヘ誌約カタシネ原39業理る。外ヒヱフ社第むせゆ由更混ソエ夕野しりすよ顔飛リの兆基う公言や置17謝后嘘5供フキヌア星集ヘラ辞勘壇崇さびわ。(日本語で)\n' ); }); diff --git a/site/gatsby-site/cypress/e2e/integration/discover.cy.js b/site/gatsby-site/cypress/e2e/integration/discover.cy.js index db97d76102..acfcac0ec5 100644 --- a/site/gatsby-site/cypress/e2e/integration/discover.cy.js +++ b/site/gatsby-site/cypress/e2e/integration/discover.cy.js @@ -124,6 +124,38 @@ describe('The Discover app', () => { cy.get('div[data-cy="hits-container"]').children().should('have.length.at.least', 4); }); + conditionalIt(!Cypress.env('isEmptyEnvironment'), 'Shows expected filters', () => { + cy.viewport(1920, 1080); + + cy.visit(url); + + cy.waitForStableDOM(); + + cy.contains('button', 'Classifications').should('be.visible'); + cy.contains('button', 'Language').should('not.be.visible'); + cy.contains('button', 'Submitter').should('not.be.visible'); + + cy.viewport(1280, 1080); + cy.waitForStableDOM(); + + cy.contains('button', 'Classifications').should('be.visible'); + cy.contains('button', 'Language').should('be.visible'); + cy.contains('button', 'Submitter').should('not.be.visible'); + + cy.get('[data-cy=expand-filters]').click(); + + cy.contains('button', 'Classifications').should('be.visible'); + cy.contains('button', 'Language').should('be.visible'); + cy.contains('button', 'Submitter').should('be.visible'); + + cy.viewport(1920, 1080); + cy.waitForStableDOM(); + + cy.contains('button', 'Classifications').should('be.visible'); + cy.contains('button', 'Language').should('be.visible'); + cy.contains('button', 'Submitter').should('be.visible'); + }); + conditionalIt(!Cypress.env('isEmptyEnvironment'), 'Filters by Tags using top filters', () => { cy.visit(url); @@ -547,6 +579,85 @@ describe('The Discover app', () => { } ); + conditionalIt(!Cypress.env('isEmptyEnvironment'), 'Loads filters based on URL', () => { + cy.visit( + url + + '?is_incident_report=true&submitters=Anonymous&page=3&classifications=CSETv0%3AIntent%3AAccident' + ); + + cy.waitForStableDOM(); + + cy.get('form#searchForm').as('form'); + + cy.contains('button', 'Submitters', { timeout: 8000 }) + .find('span.badge', { timeout: 8000 }) + .should('contain.text', '1'); + + cy.get('[data-cy="Accident"]', { timeout: 8000 }) + .should('exist') + .find('b') + .contains('CSETv0') + .parent() + .contains('Intent') + .should('exist') + .parent() + .contains('Accident') + .should('exist') + .parent() + .should('have.class', 'active'); + + cy.contains('button', 'Anonymous').should('have.class', 'active'); + + cy.contains('li.ais-Pagination-item--selected .ais-Pagination-link', '3'); + + cy.visit( + url + + '?authors=Christopher%20Knaus&incident_id=57&is_incident_report=true&language=en&source_domain=theguardian.com' + ); + + cy.contains('button', 'Authors', { timeout: 8000 }) + .find('span.badge', { timeout: 8000 }) + .should('contain.text', '1'); + + cy.contains('button', 'Source', { timeout: 8000 }) + .find('span.badge', { timeout: 8000 }) + .should('contain.text', '1'); + + cy.contains('button', 'Incident ID', { timeout: 8000 }) + .find('span.badge', { timeout: 8000 }) + .should('contain.text', '1'); + + cy.contains('button', 'Language', { timeout: 8000 }) + .find('span.badge', { timeout: 8000 }) + .should('contain.text', '1'); + }); + + it('Should update display types', () => { + cy.visit(url + '?display=list'); + + cy.get('[data-cy="display-mode-list"]').should('have.class', 'selected'); + + cy.waitForStableDOM(); + + cy.get('[data-cy="display-mode-compact"]').click(); + + cy.waitForStableDOM(); + + cy.location('search', { timeout: 8000 }).should('contain', 'display=compact'); + + cy.get('[data-cy="display-mode-compact"]').should('have.class', 'selected'); + + cy.waitForStableDOM(); + + cy.get('[data-cy="display-mode-details"]').click(); + + cy.waitForStableDOM(); + + cy.location('search', { timeout: 8000 }).should('contain', 'display=details'); + + cy.get('[data-cy="display-mode-details"]').should('have.class', 'selected'); + }); + conditionalIt( !Cypress.env('isEmptyEnvironment'), 'Search using the classifications filter', diff --git a/site/gatsby-site/cypress/e2e/integration/landingPage.cy.js b/site/gatsby-site/cypress/e2e/integration/landingPage.cy.js index 0c389a8e99..1269e56395 100644 --- a/site/gatsby-site/cypress/e2e/integration/landingPage.cy.js +++ b/site/gatsby-site/cypress/e2e/integration/landingPage.cy.js @@ -62,40 +62,6 @@ describe('The Landing page', () => { .should('exist'); }); - conditionalIt(!Cypress.env('isEmptyEnvironment'), 'Should display common entities card', () => { - cy.visit('/'); - - cy.get('[data-cy="common-entities"]') - .scrollIntoView() - .should('be.visible') - .within(() => { - cy.contains('h2', 'Common Entities').should('exist'); - cy.contains('a', 'View all entities').should('have.attr', 'href', '/entities/'); - cy.get('.grid > a').should('have.length', 3); - - for (let i = 0; i < 3; i++) { - cy.get('.grid > a') - .eq(i) - .get('li') - .eq(0) - .contains(/Involved in \d+ incidents,/) - .should('exist'); - cy.get('.grid > a') - .eq(i) - .get('li') - .eq(1) - .contains(/allegedly harming \d+ entities,/) - .should('exist'); - cy.get('.grid > a') - .eq(i) - .get('li') - .eq(2) - .contains(/with \d+ incident responses./) - .should('exist'); - } - }); - }); - conditionalIt( !Cypress.env('isEmptyEnvironment') && Cypress.env('e2eUsername') && Cypress.env('e2ePassword'), 'Should redirect to the account page when logged in', @@ -175,4 +141,10 @@ describe('The Landing page', () => { cy.get('[data-cy="random-incidents-carousel-item"]').should('have.length', 5); }); + + it('Renders commit sha in the footer', () => { + cy.visit('/'); + + cy.get('[data-cy="commit-sha"]').should('be.visible'); + }); }); diff --git a/site/gatsby-site/cypress/e2e/integration/login.cy.js b/site/gatsby-site/cypress/e2e/integration/login.cy.js index ba310e60d6..9682e06426 100644 --- a/site/gatsby-site/cypress/e2e/integration/login.cy.js +++ b/site/gatsby-site/cypress/e2e/integration/login.cy.js @@ -95,7 +95,7 @@ describe('Login', () => { body: { error: 'confirmation required', error_code: 'AuthError', - link: 'https://realm.mongodb.com/groups/633205e6aecbcc4b2c2067c3/apps/633207f10d438f13ab3ab4d6/logs?co_id=6549772172bdb9e8eadeea95', + link: 'https://services.cloud.mongodb.com/groups/633205e6aecbcc4b2c2067c3/apps/633207f10d438f13ab3ab4d6/logs?co_id=6549772172bdb9e8eadeea95', }, } ); diff --git a/site/gatsby-site/cypress/e2e/integration/pages.cy.js b/site/gatsby-site/cypress/e2e/integration/pages.cy.js index 7f2ae0a867..1c5286af0c 100644 --- a/site/gatsby-site/cypress/e2e/integration/pages.cy.js +++ b/site/gatsby-site/cypress/e2e/integration/pages.cy.js @@ -25,6 +25,7 @@ describe('Pages', () => { '/account/', '/summaries/wordcounts/', '/about/', // doc template + '/api-spec', ]; if (!Cypress.env('isEmptyEnvironment')) { @@ -50,11 +51,16 @@ describe('Pages', () => { code: 'fr', hrefLang: 'fr', }, + { + code: 'ja', + hrefLang: 'ja', + }, ]; paths.forEach((path) => { languages.forEach(({ code }) => { - it(`/${code}${path} Should not have errors`, { defaultCommandTimeout: 30000 }, () => { + // TODO: enable when https://github.com/responsible-ai-collaborative/aiid/pull/2616 is merged and deployed + it.skip(`/${code}${path} Should not have errors`, { defaultCommandTimeout: 30000 }, () => { const canonicalPath = switchLocalizedPath({ newLang: code, path }); cy.visit(canonicalPath, { @@ -97,7 +103,7 @@ describe('Pages', () => { cy.get('[rel="canonical"]').invoke('attr', 'href').should('equal', url); - cy.get('[rel="alternate"]').should('have.length', 5); + cy.get('[rel="alternate"]').should('have.length', 6); cy.get('[rel="alternate"][hrefLang="x-default"]') .invoke('attr', 'href') diff --git a/site/gatsby-site/cypress/e2e/integration/submit.cy.js b/site/gatsby-site/cypress/e2e/integration/submit.cy.js index de216e4577..0e25ddee2a 100644 --- a/site/gatsby-site/cypress/e2e/integration/submit.cy.js +++ b/site/gatsby-site/cypress/e2e/integration/submit.cy.js @@ -892,6 +892,32 @@ describe('The Submit form', () => { cy.get('[data-cy=related-byText]').contains('Reports must have at least').should('exist'); }); + conditionalIt( + !Cypress.env('isEmptyEnvironment'), + 'Should *not* show related orphan reports', + () => { + cy.visit(url); + + const values = { + authors: 'Ashley Belanger', + }; + + for (const key in values) { + cy.get(`input[name="${key}"]`).type(values[key]); + } + + cy.clickOutside(); + + cy.get('[data-cy=related-byAuthors] [data-cy=result] a[data-cy=title]', { + timeout: 20000, + }).should( + 'not.contain', + 'Thousands scammed by AI voices mimicking loved ones in emergencies' + ); + cy.clickOutside(); + } + ); + it('Should show fallback preview image on initial load', () => { const values = { url: 'https://incidentdatabase.ai', diff --git a/site/gatsby-site/cypress/e2e/unit/functions/apiRequest.cy.js b/site/gatsby-site/cypress/e2e/unit/functions/apiRequest.cy.js index 2f6e9a1480..dd94833e2e 100644 --- a/site/gatsby-site/cypress/e2e/unit/functions/apiRequest.cy.js +++ b/site/gatsby-site/cypress/e2e/unit/functions/apiRequest.cy.js @@ -41,7 +41,7 @@ describe('Functions', () => { cy.wrap(apiRequest({ method: 'GET', path: '/something' })).then((result) => { expect(global.context.http.post.getCall(0).args[0]).to.deep.nested.include({ - url: 'https://realm.mongodb.com/api/admin/v3.0/auth/providers/mongodb-cloud/login', + url: 'https://services.cloud.mongodb.com/api/admin/v3.0/auth/providers/mongodb-cloud/login', body: { username: 'public', apiKey: 'private', @@ -50,7 +50,7 @@ describe('Functions', () => { }); expect(global.context.http.get.getCall(0).args[0]).to.deep.nested.include({ - url: 'https://realm.mongodb.com/api/admin/v3.0/groups/1/apps/1/something', + url: 'https://services.cloud.mongodb.com/api/admin/v3.0/groups/1/apps/1/something', headers: { Authorization: [`Bearer test`], }, diff --git a/site/gatsby-site/cypress/e2e/unit/locale.cy.js b/site/gatsby-site/cypress/e2e/unit/locale.cy.js new file mode 100644 index 0000000000..7507085a5a --- /dev/null +++ b/site/gatsby-site/cypress/e2e/unit/locale.cy.js @@ -0,0 +1,43 @@ +describe('Locale', () => { + it('Locale folder should contain specific JSON files for all specified languages', () => { + let availableLanguages = Cypress.env('availableLanguages'); + + let enFiles = []; + + cy.task('listFiles', `./i18n/locales/en`).then((files) => { + enFiles = files; + + if (availableLanguages) { + availableLanguages = availableLanguages.split(','); + + // check that each locale directory exists with the expected files + availableLanguages + .filter((a) => a !== 'en') + .forEach((locale) => { + cy.task('listFiles', `./i18n/locales/${locale}`).then((otherLocaleFiles) => { + expect(otherLocaleFiles.sort()).to.deep.equal( + enFiles.sort(), + `Locale ${locale} folder should contain the same files as the en folder` + ); + }); + }); + } + }); + }); + + it('should have a configuration for each available language', () => { + const configPath = './i18n/config.json'; + + cy.readFile(configPath).then((configurations) => { + expect(configurations).to.be.an('array'); + + const availableLanguages = Cypress.env('availableLanguages').split(','); + + availableLanguages.forEach((locale) => { + const hasConfig = configurations.some((config) => config.code === locale); + + expect(hasConfig, `Locale ${locale} should have configuration`).to.be.true; + }); + }); + }); +}); diff --git a/site/gatsby-site/cypress/e2e/unit/pageCreators/createCitationPages.cy.js b/site/gatsby-site/cypress/e2e/unit/pageCreators/createCitationPages.cy.js index 164daf4f49..3d843bcbb4 100644 --- a/site/gatsby-site/cypress/e2e/unit/pageCreators/createCitationPages.cy.js +++ b/site/gatsby-site/cypress/e2e/unit/pageCreators/createCitationPages.cy.js @@ -79,6 +79,14 @@ const languages = [ langDir: 'ltr', dateFormat: 'DD-MM-YYYY', }, + { + code: 'ja', + hrefLang: 'ja', + name: 'Japanese', + localName: '日本語', + langDir: 'ltr', + dateFormat: 'YYYY/MM/DD', + }, ]; describe('createCitationPages', () => { @@ -88,7 +96,7 @@ describe('createCitationPages', () => { const createPage = cy.stub(); cy.wrap(createCitationPages(graphql, createPage, { languages })).then(() => { - expect(createPage.callCount).to.eq(3); + expect(createPage.callCount).to.eq(4); cy.wrap(createPage.getCall(0).args[0]).then((page) => { expect(page.path).contain('/cite/1'); @@ -96,6 +104,7 @@ describe('createCitationPages', () => { expect(page.context.translate_es).eq(true); expect(page.context.translate_en).eq(false); expect(page.context.translate_fr).eq(true); + expect(page.context.translate_ja).eq(true); expect(page.component).contain('/templates/cite.js'); }); @@ -105,6 +114,7 @@ describe('createCitationPages', () => { expect(page.context.translate_es).eq(true); expect(page.context.translate_en).eq(false); expect(page.context.translate_fr).eq(true); + expect(page.context.translate_ja).eq(true); }); cy.wrap(createPage.getCall(2).args[0]).then((page) => { @@ -113,6 +123,16 @@ describe('createCitationPages', () => { expect(page.context.translate_es).eq(true); expect(page.context.translate_en).eq(false); expect(page.context.translate_fr).eq(true); + expect(page.context.translate_ja).eq(true); + }); + + cy.wrap(createPage.getCall(3).args[0]).then((page) => { + expect(page.path).contain('/ja/cite/1'); + expect(page.context.locale).eq('ja'); + expect(page.context.translate_es).eq(true); + expect(page.context.translate_en).eq(false); + expect(page.context.translate_fr).eq(true); + expect(page.context.translate_ja).eq(true); }); }); }); diff --git a/site/gatsby-site/cypress/e2e/unit/pageCreators/createReportPages.cy.js b/site/gatsby-site/cypress/e2e/unit/pageCreators/createReportPages.cy.js index a227c47b9f..2e43485d83 100644 --- a/site/gatsby-site/cypress/e2e/unit/pageCreators/createReportPages.cy.js +++ b/site/gatsby-site/cypress/e2e/unit/pageCreators/createReportPages.cy.js @@ -42,6 +42,14 @@ const languages = [ langDir: 'ltr', dateFormat: 'DD-MM-YYYY', }, + { + code: 'ja', + hrefLang: 'ja', + name: 'Japanese', + localName: '日本語', + langDir: 'ltr', + dateFormat: 'YYYY/MM/DD', + }, ]; describe('createReportPages', () => { @@ -51,7 +59,7 @@ describe('createReportPages', () => { const createPage = cy.stub(); cy.wrap(createReportPages(graphql, createPage, { languages })).then(() => { - expect(createPage.callCount).to.eq(6); + expect(createPage.callCount).to.eq(8); cy.wrap(createPage.getCall(0).args[0]).then((page) => { expect(page.path).contain('/reports/1/'); diff --git a/site/gatsby-site/cypress/fixtures/classifications/upsertDuplicateClassification.json b/site/gatsby-site/cypress/fixtures/classifications/upsertDuplicateClassification.json new file mode 100644 index 0000000000..5a9494c3c5 --- /dev/null +++ b/site/gatsby-site/cypress/fixtures/classifications/upsertDuplicateClassification.json @@ -0,0 +1,325 @@ +{ + "data": { + "upsertOneClassification": { + "__typename": "Classification", + "_id": "64ac2b05c70973a5bd3fa61a", + "attributes": [ + { + "__typename": "ClassificationAttribute", + "short_name": "Physical Objects", + "value_json": "\"no\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Entertainment Industry", + "value_json": "\"no\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Report, Test, or Study of data", + "value_json": "\"no\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Deployed", + "value_json": "\"yes\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Producer Test in Controlled Conditions", + "value_json": "\"no\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Producer Test in Operational Conditions", + "value_json": "\"no\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "User Test in Controlled Conditions", + "value_json": "\"no\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "User Test in Operational Conditions", + "value_json": "\"no\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Harm Domain", + "value_json": "\"yes\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Tangible Harm", + "value_json": "\"tangible harm definitively occurred\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "AI System", + "value_json": "\"yes\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Clear link to technology", + "value_json": "\"yes\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "There is a potentially identifiable specific entity that experienced the harm", + "value_json": "true" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "AI Harm Level", + "value_json": "\"AI tangible harm event\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Impact on Critical Services", + "value_json": "\"no\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Rights Violation", + "value_json": "\"no\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Involving Minor", + "value_json": "\"no\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Detrimental Content", + "value_json": "\"no\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Protected Characteristic", + "value_json": "\"no\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Harm Distribution Basis", + "value_json": "[\"none\"]" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Clear link to Technology", + "value_json": "\"yes\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Harmed Class of Entities", + "value_json": "true" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Annotator’s AI special interest intangible harm assessment", + "value_json": "\"no\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Sector of Deployment", + "value_json": "[\"accommodation and food service activities\"]" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Public Sector Deployment", + "value_json": "\"no\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Autonomy Level", + "value_json": "\"Autonomy2\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Intentional Harm", + "value_json": "\"No. Not intentionally designed to perform harm\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "AI tools and methods", + "value_json": "\"\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Peer Reviewer", + "value_json": "\"\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Quality Control", + "value_json": "false" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Annotation Status", + "value_json": "\"6. Complete and final\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Incident Number", + "value_json": "10" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Annotator", + "value_json": "\"002\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "AI Tangible Harm Level Notes", + "value_json": "\"\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Notes (special interest intangible harm)", + "value_json": "\"\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Special Interest Intangible Harm", + "value_json": "\"no\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Notes (AI special interest intangible harm)", + "value_json": "\"\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Date of Incident Year", + "value_json": "\"2014\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Date of Incident Month", + "value_json": "\"\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Date of Incident Day", + "value_json": "\"\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Estimated Date", + "value_json": "true" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Multiple AI Interaction", + "value_json": "\"no\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Embedded", + "value_json": "\"no\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Location City", + "value_json": "\"\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Location State/Province (two letters)", + "value_json": "\"\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Location Country (two letters)", + "value_json": "\"US\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Location Region", + "value_json": "\"North America\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Infrastructure Sectors", + "value_json": "[]" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Operating Conditions", + "value_json": "\"\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Notes (Environmental and Temporal Characteristics)", + "value_json": "\"\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Entities", + "value_json": "[{\"attributes\":[{\"short_name\":\"Entity\",\"value_json\":\"\\\"Starbucks\\\"\"},{\"short_name\":\"Named Entity\",\"value_json\":\"true\"},{\"short_name\":\"Entity type\",\"value_json\":\"\\\"for-profit organization\\\"\"},{\"short_name\":\"Entity Relationship to the AI\",\"value_json\":\"[\\\"deployer\\\"]\"},{\"short_name\":\"Harm Category Experienced\",\"value_json\":\"\\\"not applicable\\\"\"},{\"short_name\":\"Harm Type Experienced\",\"value_json\":\"\\\"not applicable\\\"\"}]},{\"attributes\":[{\"short_name\":\"Entity\",\"value_json\":\"\\\"Kronos\\\"\"},{\"short_name\":\"Named Entity\",\"value_json\":\"true\"},{\"short_name\":\"Entity type\",\"value_json\":\"\\\"for-profit organization\\\"\"},{\"short_name\":\"Entity Relationship to the AI\",\"value_json\":\"[\\\"developer\\\"]\"},{\"short_name\":\"Harm Category Experienced\",\"value_json\":\"\\\"not applicable\\\"\"},{\"short_name\":\"Harm Type Experienced\",\"value_json\":\"\\\"not applicable\\\"\"}]},{\"attributes\":[{\"short_name\":\"Entity\",\"value_json\":\"\\\"Kronos scheduling algorithm\\\"\"},{\"short_name\":\"Named Entity\",\"value_json\":\"false\"},{\"short_name\":\"Entity type\",\"value_json\":\"\\\"product\\\"\"},{\"short_name\":\"Entity Relationship to the AI\",\"value_json\":\"[\\\"product containing AI\\\"]\"},{\"short_name\":\"Harm Category Experienced\",\"value_json\":\"\\\"not applicable\\\"\"},{\"short_name\":\"Harm Type Experienced\",\"value_json\":\"\\\"not applicable\\\"\"}]},{\"attributes\":[{\"short_name\":\"Entity\",\"value_json\":\"\\\"Starbucks employees\\\"\"},{\"short_name\":\"Named Entity\",\"value_json\":\"false\"},{\"short_name\":\"Entity type\",\"value_json\":\"\\\"group of individuals\\\"\"},{\"short_name\":\"Notes (Characterizing Entities and the Harm)\",\"value_json\":\"\\\"7.6 - It is reasonable to expect that unpredictable schedules have led to financial loss for other Starbucks employees through lost wages or unexpected expenses like childcare to attend work on short notice.\\\"\"},{\"short_name\":\"Harm Category Experienced\",\"value_json\":\"\\\"AI tangible harm issue\\\"\"},{\"short_name\":\"Harm Type Experienced\",\"value_json\":\"\\\"financial loss\\\"\"},{\"short_name\":\"Entity Relationship to the AI\",\"value_json\":\"[\\\"affected non-users\\\"]\"}]},{\"attributes\":[{\"short_name\":\"Entity\",\"value_json\":\"\\\"Kylei Weisse\\\"\"},{\"short_name\":\"Named Entity\",\"value_json\":\"true\"},{\"short_name\":\"Entity type\",\"value_json\":\"\\\"individual\\\"\"},{\"short_name\":\"Entity Relationship to the AI\",\"value_json\":\"[\\\"affected non-user\\\"]\"},{\"short_name\":\"Harm Category Experienced\",\"value_json\":\"\\\"AI tangible harm event\\\"\"},{\"short_name\":\"Harm Type Experienced\",\"value_json\":\"\\\"financial loss\\\"\"},{\"short_name\":\"Notes (Characterizing Entities and the Harm)\",\"value_json\":\"\\\"Weisse incurred unexpected financial costs in order to make it to a shift that was assigned to him on very short notice. \\\"\"}]},{\"attributes\":[{\"short_name\":\"Entity\",\"value_json\":\"\\\"Starbucks employees\\\"\"},{\"short_name\":\"Named Entity\",\"value_json\":\"false\"},{\"short_name\":\"Entity type\",\"value_json\":\"\\\"group of individuals\\\"\"},{\"short_name\":\"Entity Relationship to the AI\",\"value_json\":\"[\\\"affected non-users\\\"]\"},{\"short_name\":\"Harm Category Experienced\",\"value_json\":\"\\\"Other harm not meeting CSET definitions\\\"\"},{\"short_name\":\"Harm Type Experienced\",\"value_json\":\"\\\"other intangible harm\\\"\"},{\"short_name\":\"Notes (Characterizing Entities and the Harm)\",\"value_json\":\"\\\"7.6 - Unpredictable schedules cause stress through financial and scheduling instability\\\"\"}]},{\"attributes\":[{\"short_name\":\"Entity\",\"value_json\":\"\\\"Jannette Navarro\\\"\"},{\"short_name\":\"Named Entity\",\"value_json\":\"true\"},{\"short_name\":\"Entity type\",\"value_json\":\"\\\"individual\\\"\"},{\"short_name\":\"Entity Relationship to the AI\",\"value_json\":\"[\\\"affected non-user\\\"]\"},{\"short_name\":\"Harm Category Experienced\",\"value_json\":\"\\\"Other harm not meeting CSET definitions\\\"\"},{\"short_name\":\"Harm Type Experienced\",\"value_json\":\"\\\"other intangible harm\\\"\"},{\"short_name\":\"Notes (Characterizing Entities and the Harm)\",\"value_json\":\"\\\"7.6 - Her unpredictable schedules caused serious stress and instability in her life.\\\"\"}]}]" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Lives Lost", + "value_json": "0" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Injuries", + "value_json": "0" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Estimated Harm Quantities", + "value_json": "false" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Notes ( Tangible Harm Quantities Information)", + "value_json": "\"\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "AI System Description", + "value_json": "\"The Kronos scheduling algorithm is designed to optimize the productivity of stores like Starbucks by scheduling workers inconsistently throughout and across weeks based on predicted store traffic.\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Data Inputs", + "value_json": "[\"schedules\",\"worker profiles\",\"store traffic\"]" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Notes (Information about AI System)", + "value_json": "\"\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Physical System Type", + "value_json": "\"\"" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "AI Task", + "value_json": "[\"scheduling\",\"productivity optimization\",\"predict store traffic\"]" + }, + { + "__typename": "ClassificationAttribute", + "short_name": "Notes (AI Functionality and Techniques)", + "value_json": "\"\"" + } + ], + "incidents": [ + { + "__typename": "Incident", + "incident_id": 50 + } + ], + "namespace": "CSETv1", + "notes": "", + "publish": true, + "reports": [] + } + } +} diff --git a/site/gatsby-site/cypress/fixtures/incidents/fullIncident50.json b/site/gatsby-site/cypress/fixtures/incidents/fullIncident50.json new file mode 100644 index 0000000000..0587fba0fc --- /dev/null +++ b/site/gatsby-site/cypress/fixtures/incidents/fullIncident50.json @@ -0,0 +1,958 @@ +{ + "data": { + "incident": { + "AllegedDeployerOfAISystem": [ + { + "__typename": "Entity", + "entity_id": "the-dao", + "name": "The DAO" + } + ], + "AllegedDeveloperOfAISystem": [ + { + "__typename": "Entity", + "entity_id": "the-dao", + "name": "The DAO" + } + ], + "AllegedHarmedOrNearlyHarmedParties": [ + { + "__typename": "Entity", + "entity_id": "dao-token-holders", + "name": "DAO Token Holders" + } + ], + "__typename": "Incident", + "date": "2016-06-17", + "description": "On June 18, 2016, an attacker successfully exploited a vulnerability in The Decentralized Autonomous Organization (The DAO) on the Ethereum blockchain to steal 3.7M Ether valued at $70M.", + "editor_dissimilar_incidents": [], + "editor_notes": null, + "editor_similar_incidents": [], + "editors": [ + { + "__typename": "User", + "first_name": "Sean", + "last_name": "McGregor", + "userId": "619b47ea5eed5334edfa3bbc" + } + ], + "embedding": { + "__typename": "IncidentEmbedding", + "from_reports": [ + 905, + 903, + 902, + 901, + 900, + 899, + 898, + 897, + 896, + 893, + 892, + 889, + 888, + 887, + 886, + 885, + 884, + 883, + 881, + 880, + 879, + 878, + 877, + 876 + ], + "vector": [ + -0.0661667212843895, + 0.09495183080434799, + 0.010774415917694569, + -0.0843186303973198, + 0.07742074877023697, + 0.002700377954170108, + -0.0008173985406756401, + 0.057413578033447266, + 0.09605775028467178, + -0.1488141417503357, + 0.004636809695512056, + 0.05968795344233513, + 0.021845035254955292, + -0.0762571468949318, + 0.04533643648028374, + -0.09069175273180008, + -0.15813405811786652, + -0.022130673751235008, + -0.042528972029685974, + -0.10905041545629501, + -0.07701637595891953, + 0.012940806336700916, + 0.018910806626081467, + 0.11774744838476181, + -0.04104795679450035, + 0.04697092995047569, + 0.12957395613193512, + 0.12819425761699677, + -0.058150216937065125, + 0.06893474608659744, + -0.018372666090726852, + -0.09186699986457825, + 0.15362109243869781, + 0.028102269396185875, + 0.025071216747164726, + 0.09713421016931534, + 0.01256798580288887, + -0.01616877131164074, + -0.041066594421863556, + -0.017975831404328346, + 0.044571682810783386, + 0.2357323318719864, + -0.03317007049918175, + -0.027484485879540443, + 0.05428558960556984, + -0.04763684794306755, + -1.0566697710601147e-05, + 0.04871894046664238, + 0.0070588416419923306, + 0.004973179195076227, + -0.026652388274669647, + -0.008015204221010208, + -0.07091150432825089, + 0.033345308154821396, + -0.09143518656492233, + 0.061592280864715576, + 0.03615380451083183, + 0.03313060477375984, + 0.07367609441280365, + -0.04913125932216644, + -0.01810459792613983, + -0.20834849774837494, + -0.05211314558982849, + -0.03780398145318031, + 0.08887007087469101, + -0.08282432705163956, + -0.02316044457256794, + 0.03807034716010094, + 0.003166689770296216, + 0.048870425671339035, + 0.053769540041685104, + -0.029292000457644463, + -0.002758365822955966, + 0.035534992814064026, + 0.01716659404337406, + -0.009857158176600933, + -0.01820841059088707, + 0.1924063116312027, + -0.10551274567842484, + 0.015695957466959953, + 0.08622416853904724, + -0.09239751845598221, + 0.3837597668170929, + -3.496369390632026e-05, + -0.06069179251790047, + -0.02606315352022648, + 0.12018977850675583, + 0.0050528384745121, + 0.03152324631810188, + 0.0403270348906517, + -0.025558656081557274, + 0.04960830882191658, + -0.05975503847002983, + -0.03103153593838215, + 0.05772930011153221, + 0.0396592952311039, + -0.0018726816633716226, + 0.0107951695099473, + -0.025373486801981926, + -0.028895430266857147, + 0.024420717731118202, + -0.07865981012582779, + 0.10167545080184937, + 0.08524877578020096, + -0.05940742790699005, + -0.006057963240891695, + 0.06243671104311943, + -0.056733157485723495, + 0.06139994040131569, + -0.07574266940355301, + 0.0216194037348032, + -0.007321906741708517, + 0.05265502631664276, + -0.025458944961428642, + 0.02595309354364872, + -0.015414812602102757, + 0.02327638864517212, + 0.03251353278756142, + 0.06957828998565674, + 0.049125488847494125, + -0.023909522220492363, + 0.057829465717077255, + 0.036426953971385956, + -0.07245929539203644, + 0.007933235727250576, + -0.059332478791475296, + -0.0435311533510685, + -0.047337573021650314, + -0.04053480550646782, + 0.03915426507592201, + -0.06534258276224136, + -0.2260957807302475, + 0.015165231190621853, + 0.060068678110837936, + -0.0034208225551992655, + -0.026531696319580078, + 0.04104552045464516, + -0.07288438826799393, + 0.018118413165211678, + -0.014951043762266636, + -0.049901094287633896, + 0.0704021230340004, + -0.017830973491072655, + 0.051336515694856644, + 0.13087646663188934, + 0.04126317426562309, + -0.06066800281405449, + -0.03640735521912575, + 0.0299614816904068, + -0.02631322294473648, + 0.10236970335245132, + -0.1225552037358284, + -0.027694450691342354, + -0.026750773191452026, + -0.022465072572231293, + 0.6963229775428772, + 0.06071530655026436, + 0.1349962204694748, + 0.0029604679439216852, + -0.010627356357872486, + 0.1805461049079895, + 0.009208586066961288, + 0.06478998810052872, + -0.04796625301241875, + -0.05369967222213745, + 0.03317221999168396, + -0.07248315960168839, + -0.04857209697365761, + 0.021922463551163673, + -0.014980182982981205, + 0.07153782248497009, + 0.033672574907541275, + 0.08822420984506607, + -0.009559323079884052, + -0.08002188056707382, + -0.02796768955886364, + 0.04889626428484917, + -0.002079806989058852, + -0.12316332012414932, + -0.00598991708829999, + 0.04790058732032776, + 0.08986284583806992, + -0.06529728323221207, + 0.0019114370224997401, + -0.03926361724734306, + 0.043254926800727844, + -0.016697514802217484, + 0.06446542590856552, + -0.015036128461360931, + 0.048525601625442505, + 0.022319965064525604, + 0.04527026414871216, + -0.020831571891903877, + -0.08953225612640381, + -0.006588423624634743, + 0.1359531283378601, + -0.002234226791188121, + -0.030231744050979614, + 0.1041426882147789, + -0.11253884434700012, + 0.0400945320725441, + 0.0055610924027860165, + 0.19018787145614624, + -0.17008160054683685, + 0.021101707592606544, + -0.00634838966652751, + -0.013233933597803116, + 0.043402597308158875, + 0.0033622318878769875, + -0.06131330132484436, + -0.056475479155778885, + 0.0574350506067276, + 0.015077848918735981, + 0.034125734120607376, + 0.07870019972324371, + -0.027285316959023476, + 0.05490930378437042, + 0.05595440790057182, + 0.019953204318881035, + -0.047013092786073685, + 0.061499033123254776, + 0.02760140411555767, + -0.006400404032319784, + -0.01763268932700157, + -0.01890098862349987, + 0.0064741335809230804, + 0.03504158556461334, + 0.001586462720297277, + 0.06483786553144455, + -0.0428876094520092, + -0.032916028052568436, + 0.01864536665380001, + 0.06462439149618149, + 0.0023124387953430414, + 0.08506456017494202, + -0.06751906871795654, + -0.027384648099541664, + -0.037361446768045425, + -0.02647651731967926, + 0.05260567367076874, + -0.014446704648435116, + 0.06518206745386124, + 0.08603981137275696, + 0.09696471691131592, + 0.0062536210753023624, + 0.048122942447662354, + 0.017186813056468964, + 0.026083774864673615, + 0.019874846562743187, + 0.07057034224271774, + -0.02904350310564041, + -0.05003984272480011, + -0.01425819844007492, + -0.001251187059096992, + 0.04657392203807831, + 0.007774615194648504, + -0.09506087750196457, + -0.020778952166438103, + -0.07087522745132446, + -0.024529092013835907, + -0.0887717679142952, + -0.060240041464567184, + 0.020624155178666115, + 0.046308714896440506, + -0.040538158267736435, + -0.09442443400621414, + -0.06354733556509018, + 0.006772881373763084, + 0.06922020763158798, + -0.00778896315023303, + -0.021353259682655334, + -0.124875009059906, + 0.004535881336778402, + -0.06257758289575577, + 0.036274638026952744, + 0.006892743986099958, + -0.021391555666923523, + -0.015682250261306763, + -0.04881167784333229, + 0.01879616267979145, + -0.014313933439552784, + -0.002905568340793252, + -0.07575004547834396, + -0.06220642849802971, + -0.032436590641736984, + -0.006158924195915461, + -0.002058455953374505, + -0.05558959022164345, + -0.005457794759422541, + 0.04193447530269623, + 0.063014455139637, + -0.027310015633702278, + -0.03688542917370796, + 0.0466887503862381, + -0.012773402035236359, + -0.009203986264765263, + 0.08859669417142868, + -0.016090862452983856, + 0.02242548018693924, + -0.02983110584318638, + -0.07793480902910233, + -0.033489566296339035, + 0.01613295078277588, + -0.03415980935096741, + 0.03627980500459671, + -0.016666151583194733, + 0.025052055716514587, + -0.03267792984843254, + 0.020628737285733223, + 0.03692276030778885, + -0.02742244303226471, + -0.09069464355707169, + -0.04986213520169258, + 0.1718524694442749, + 0.00028678213129751384, + -0.0322076715528965, + 0.02312176674604416, + -0.06042476370930672, + 0.05028273165225983, + -0.00551630137488246, + 0.012767993845045567, + 0.032750293612480164, + 0.10601982474327087, + -0.0063768420368433, + 0.033016130328178406, + 0.05911942943930626, + -0.0034290996845811605, + 0.04406482353806496, + 0.06185388192534447, + 0.4226973056793213, + -0.1968797892332077, + 0.0842713937163353, + 0.10632825642824173, + 0.0010914724553003907, + 0.039177585393190384, + -0.0801040455698967, + 0.04901694133877754, + 0.08682584017515182, + 0.10728341341018677, + 0.13156089186668396, + -0.018922606483101845, + 0.019393766298890114, + -0.04106520488858223, + 0.08649475127458572, + -0.029056930914521217, + -0.0071672541089355946, + -0.018303148448467255, + -0.06217241659760475, + -0.004366402048617601, + 0.047536689788103104, + -0.031071506440639496, + -0.00480313366279006, + -0.0061461725272238255, + -0.055548787117004395, + 0.00788793247193098, + 0.057616639882326126, + 0.031225956976413727, + 0.01318689901381731, + 0.015787797048687935, + -0.019895801320672035, + 0.03961948677897453, + 0.025899363681674004, + 0.014753241091966629, + -0.1348978728055954, + 0.03202307969331741, + -0.05162663385272026, + -0.13509045541286469, + 0.09003769606351852, + -0.003307627746835351, + 0.05749477818608284, + 0.06454337388277054, + -0.021481366828083992, + 0.028288818895816803, + -0.026615282520651817, + -0.026294425129890442, + 0.008199688978493214, + 0.06729302555322647, + 0.025896921753883362, + 0.07375463098287582, + 0.16271694004535675, + -0.041269026696681976, + -0.015906035900115967, + -0.08949262648820877, + 0.05659450963139534, + 0.13324247300624847, + -0.0464564673602581, + -0.005015434231609106, + -0.001693259458988905, + -0.002847062423825264, + -0.013766842894256115, + -0.07604783028364182, + -0.05830862745642662, + -0.02066342532634735, + -0.06560307741165161, + 0.08522600680589676, + 0.04107437655329704, + -0.04214470461010933, + -0.14534230530261993, + -0.011104445904493332, + -0.032366808503866196, + 0.03278728947043419, + 0.11380184441804886, + -0.0666615441441536, + 0.040425315499305725, + -0.005399531219154596, + 0.014014272950589657, + 0.023620227351784706, + -0.07893305271863937, + -0.009794498793780804, + -0.08585638552904129, + 0.03401630371809006, + 0.07119400054216385, + 0.06484425067901611, + -0.04560472443699837, + 0.10027354955673218, + -0.09807371348142624, + 0.09029466658830643, + -0.00776924192905426, + -0.05461972951889038, + 0.048991065472364426, + -0.039878834038972855, + 0.019989730790257454, + 0.019362283870577812, + -0.04829762503504753, + 0.06533920019865036, + -0.017562834545969963, + -0.05175589397549629, + -0.07299955189228058, + -0.07298615574836731, + -0.04072772338986397, + -0.09242146462202072, + 0.07381884753704071, + -0.06534093618392944, + 0.0010574118932709098, + -0.020853906869888306, + -0.040836818516254425, + -0.012832515873014927, + 0.02487863413989544, + 0.03318801149725914, + -0.15873613953590393, + -0.055572014302015305, + -0.021044636145234108, + 0.03568285331130028, + 0.017814001068472862, + -0.0451168566942215, + 0.005319114774465561, + 0.057521238923072815, + 0.034872833639383316, + 0.03899437189102173, + 0.023746006190776825, + -0.051500916481018066, + 0.059377770870923996, + -0.14109168946743011, + -0.3940942585468292, + 0.04678523913025856, + 0.006228484213352203, + 0.02189958095550537, + -0.015611437149345875, + -0.05416549742221832, + 0.05052398517727852, + 0.0026056349743157625, + -0.03473886474967003, + 0.0980633795261383, + -0.07380123436450958, + 0.017081940546631813, + -0.061888162046670914, + -0.060919493436813354, + -0.02053762413561344, + -0.07007520645856857, + -0.049346838146448135, + 0.041981007903814316, + 0.025222048163414, + -0.06693807244300842, + -0.08524662256240845, + 0.06733603030443192, + -0.021311646327376366, + -0.003399507375434041, + 0.0076775881461799145, + 0.024136727675795555, + -0.07568683475255966, + -0.06720703840255737, + -0.016028104349970818, + 0.061864208430051804, + 0.03237927332520485, + -0.07795371860265732, + -0.005399972666054964, + 0.038687314838171005, + 0.003363342024385929, + 0.10057994723320007, + 0.003988614305853844, + -0.015340202488005161, + -0.08878466486930847, + 0.0977032408118248, + 0.06695879250764847, + 0.18500442802906036, + -0.01678348518908024, + 0.006111804861575365, + 0.004242830444127321, + 0.11370434612035751, + 0.03940612077713013, + 0.013183747418224812, + -0.030457524582743645, + 0.01693480648100376, + -0.018341096118092537, + -0.013356991112232208, + 0.09827983379364014, + -0.05066269263625145, + -0.027613507583737373, + 0.01687728427350521, + -0.01242680475115776, + -0.023277008906006813, + -0.03319449722766876, + 0.21616916358470917, + 0.03379783406853676, + 0.042088836431503296, + 0.017735781148076057, + -0.03290579095482826, + 0.017938842996954918, + -0.10539724677801132, + -0.11517835408449173, + -0.013451620005071163, + 0.000374626339180395, + 0.021733524277806282, + -0.05304350331425667, + -0.09813041239976883, + -0.027155568823218346, + 0.013767196796834469, + -0.01930530183017254, + 0.10336603969335556, + -0.021463418379426003, + 0.03581016883254051, + -0.06046905741095543, + 0.13518653810024261, + 0.031003080308437347, + 0.017072312533855438, + 0.011110997758805752, + 0.0667453482747078, + 0.04917195439338684, + -0.0021193886641412973, + -0.051941823214292526, + -0.05759355053305626, + 0.020791461691260338, + 0.13696010410785675, + -0.04596574977040291, + 0.1332692801952362, + 0.02513316459953785, + -0.009932330809533596, + -0.054872483015060425, + 0.03171728178858757, + 0.013050459325313568, + -0.003947978373616934, + -0.44521331787109375, + -0.05231727287173271, + 0.1282065063714981, + -0.030108973383903503, + 0.025894753634929657, + 0.09331361204385757, + 0.03157180920243263, + -0.07923457771539688, + -0.030358143150806427, + -0.05153513327240944, + 0.11359219998121262, + 0.010586780495941639, + 0.06787595897912979, + -0.13399849832057953, + 0.02302604913711548, + 0.08097248524427414, + -0.043132904917001724, + -0.01535704080015421, + 0.05189881846308708, + -0.2099890559911728, + -0.004585218150168657, + -0.05359213426709175, + 0.11603052169084549, + 0.019611136987805367, + 0.03128006309270859, + 0.09810841828584671, + -0.06763505190610886, + 0.02503429353237152, + 0.054650451987981796, + 0.002728505292907357, + 0.06416928023099899, + 0.006461964920163155, + -0.02583378739655018, + 0.10828322172164917, + 0.08189579099416733, + 0.03860188275575638, + -0.03500935435295105, + 12.041316986083984, + 0.07135587930679321, + 0.07587986439466476, + -0.07815652340650558, + 0.01789211481809616, + -0.06088171899318695, + 0.042837608605623245, + -0.08220500499010086, + 0.0217966940253973, + 0.1364554613828659, + 0.0007437678868882358, + -0.04616783931851387, + -0.029968850314617157, + -0.07923655956983566, + 0.03229570388793945, + -0.02203737199306488, + -0.04797447845339775, + -0.0020305009093135595, + 0.024356653913855553, + -0.03915480151772499, + -0.06702367961406708, + 0.013569020666182041, + 0.07913649827241898, + -0.0034444101620465517, + -0.04820480942726135, + 0.028118645772337914, + 0.02363363839685917, + -0.016757983714342117, + -0.01822235994040966, + 0.06246187165379524, + -0.02062375284731388, + 0.0004203618736937642, + 0.03233122453093529, + -0.030118217691779137, + 0.06812857836484909, + 0.06541542708873749, + 0.0953434482216835, + 0.03266927972435951, + 0.0185119416564703, + 0.04870273172855377, + 0.020875677466392517, + 0.005300997290760279, + 0.02631889097392559, + 0.06798504292964935, + 0.05154086649417877, + 0.015005327761173248, + 0.017745381221175194, + 0.12363690137863159, + 0.013060785830020905, + 0.08051296323537827, + 0.09826701134443283, + -0.01794828288257122, + 0.11512423306703568, + 0.022138921543955803, + -0.016594456508755684, + 0.013868294656276703, + 0.006469572428613901, + -0.09581004828214645, + 0.12190597504377365, + 0.05028713122010231, + -0.046826597303152084, + 0.10982882231473923, + 0.025811506435275078, + 0.11328303813934326, + 0.014556948095560074, + 0.08173282444477081, + 0.0457267165184021, + 0.07863391190767288, + -0.14725281298160553, + -0.07506497949361801, + 0.023782463744282722, + -0.07605893164873123, + -0.08246233314275742, + 0.08330795168876648, + 0.10566451400518417, + -0.04493102803826332, + 0.07607607543468475, + -0.04333483800292015, + 0.003520787926390767, + -0.05823725461959839, + 0.009233443066477776, + 0.024135639891028404, + -0.03351334109902382, + 0.042286068201065063, + 0.04909465089440346, + 0.033163342624902725, + 0.08282016962766647, + 0.07227231562137604, + 0.046822961419820786, + -0.05663175508379936, + -0.0007530542206950486, + 0.10325410962104797, + -0.006014158949255943, + -0.05423947051167488, + 0.003947563003748655, + -0.04840860143303871, + 0.0478232316672802, + -0.1463749259710312, + 0.068173848092556, + 0.08410429209470749, + -0.05504782497882843, + -0.023465273901820183, + -0.028513863682746887, + 0.04851672425866127, + 0.0020922934636473656, + 0.03378622606396675, + -0.05709858611226082, + 0.0017180262366309762, + 0.010725595988333225, + 0.0572512112557888, + -0.02881232462823391, + 0.10155069082975388, + 0.07183052599430084, + -0.04418819025158882, + 0.07062981277704239, + 0.05435023829340935, + -0.03762836754322052, + -0.018741268664598465, + 0.04699109122157097, + 0.0607602559030056, + -0.05994049087166786, + -0.02827439457178116, + -0.02400636114180088, + -0.051030974835157394, + -0.03479217365384102, + -0.03554803878068924, + -0.015273932367563248, + 6.777645467082039e-05, + -0.024866431951522827, + -0.024908997118473053, + 0.04018652066588402, + 0.061754241585731506, + 0.062193069607019424, + -0.0466693639755249, + 0.039988692849874496, + -0.06996554136276245, + -0.034812234342098236, + 0.04701513424515724, + 0.05103026703000069, + 0.0690593495965004, + -0.0636117234826088, + -0.045921146869659424, + -0.05381940305233002, + -0.13033494353294373, + 0.02399160899221897, + 0.09703382849693298, + 0.05136001110076904, + 0.02009364403784275, + 0.0055291480384767056, + -0.06774132698774338, + -0.05190951004624367, + 0.0539257638156414, + 0.10736360400915146, + 0.02136417292058468, + 0.04460662975907326, + -0.052776917815208435, + -0.029110541567206383, + 0.10957958549261093, + -0.05377667769789696, + 0.013081823475658894, + -0.005934875924140215, + -0.04737425222992897, + 0.07549577951431274, + 0.13798557221889496, + 0.013311639428138733, + 0.04293627664446831, + 0.06811729818582535, + -0.006506450939923525, + 0.04009142145514488, + -0.009688236750662327, + 0.016802940517663956, + -0.02174876444041729, + -0.0929674506187439, + -0.05609692260622978, + 0.03033480793237686, + 0.11118770390748978, + 0.03098963014781475, + -0.13081684708595276, + -0.01888337731361389, + -0.042367786169052124 + ] + }, + "flagged_dissimilar_incidents": [], + "incident_id": 50, + "nlp_similar_incidents": [ + { + "__typename": "IncidentNlp_similar_incident", + "incident_id": 38, + "similarity": 0.9988240599632263 + }, + { + "__typename": "IncidentNlp_similar_incident", + "incident_id": 6, + "similarity": 0.9987120628356934 + }, + { + "__typename": "IncidentNlp_similar_incident", + "incident_id": 26, + "similarity": 0.9986885786056519 + } + ], + "reports": [ + { + "__typename": "Report", + "report_number": 905 + }, + { + "__typename": "Report", + "report_number": 903 + }, + { + "__typename": "Report", + "report_number": 902 + }, + { + "__typename": "Report", + "report_number": 901 + }, + { + "__typename": "Report", + "report_number": 900 + }, + { + "__typename": "Report", + "report_number": 899 + }, + { + "__typename": "Report", + "report_number": 898 + }, + { + "__typename": "Report", + "report_number": 897 + }, + { + "__typename": "Report", + "report_number": 896 + }, + { + "__typename": "Report", + "report_number": 893 + }, + { + "__typename": "Report", + "report_number": 892 + }, + { + "__typename": "Report", + "report_number": 889 + }, + { + "__typename": "Report", + "report_number": 888 + }, + { + "__typename": "Report", + "report_number": 887 + }, + { + "__typename": "Report", + "report_number": 886 + }, + { + "__typename": "Report", + "report_number": 885 + }, + { + "__typename": "Report", + "report_number": 884 + }, + { + "__typename": "Report", + "report_number": 883 + }, + { + "__typename": "Report", + "report_number": 881 + }, + { + "__typename": "Report", + "report_number": 880 + }, + { + "__typename": "Report", + "report_number": 879 + }, + { + "__typename": "Report", + "report_number": 878 + }, + { + "__typename": "Report", + "report_number": 877 + }, + { + "__typename": "Report", + "report_number": 876 + } + ], + "title": "The DAO Hack" + } + } +} diff --git a/site/gatsby-site/cypress/fixtures/incidents/updateIncident50.json b/site/gatsby-site/cypress/fixtures/incidents/updateIncident50.json new file mode 100644 index 0000000000..0c4182d1ef --- /dev/null +++ b/site/gatsby-site/cypress/fixtures/incidents/updateIncident50.json @@ -0,0 +1,998 @@ +{ + "data": { + "updateOneIncident": { + "AllegedDeployerOfAISystem": [ + { + "__typename": "Entity", + "entity_id": "the-dao", + "name": "The DAO" + } + ], + "AllegedDeveloperOfAISystem": [ + { + "__typename": "Entity", + "entity_id": "the-dao", + "name": "The DAO" + } + ], + "AllegedHarmedOrNearlyHarmedParties": [ + { + "__typename": "Entity", + "entity_id": "dao-token-holders", + "name": "DAO Token Holders" + } + ], + "__typename": "Incident", + "date": "2016-06-17", + "description": "On June 18, 2016, an attacker successfully exploited a vulnerability in The Decentralized Autonomous Organization (The DAO) on the Ethereum blockchain to steal 3.7M Ether valued at $70M.", + "editor_dissimilar_incidents": [], + "editor_notes": null, + "editor_similar_incidents": [], + "editors": [ + { + "__typename": "User", + "first_name": "Sean", + "last_name": "McGregor", + "userId": "619b47ea5eed5334edfa3bbc" + } + ], + "embedding": { + "__typename": "IncidentEmbedding", + "from_reports": [ + 905, + 903, + 902, + 901, + 900, + 899, + 898, + 897, + 896, + 893, + 892, + 889, + 888, + 887, + 886, + 885, + 884, + 883, + 881, + 880, + 879, + 878, + 877, + 876 + ], + "vector": [ + -0.0661667212843895, + 0.09495183080434799, + 0.010774415917694569, + -0.0843186303973198, + 0.07742074877023697, + 0.002700377954170108, + -0.0008173985406756401, + 0.057413578033447266, + 0.09605775028467178, + -0.1488141417503357, + 0.004636809695512056, + 0.05968795344233513, + 0.021845035254955292, + -0.0762571468949318, + 0.04533643648028374, + -0.09069175273180008, + -0.15813405811786652, + -0.022130673751235008, + -0.042528972029685974, + -0.10905041545629501, + -0.07701637595891953, + 0.012940806336700916, + 0.018910806626081467, + 0.11774744838476181, + -0.04104795679450035, + 0.04697092995047569, + 0.12957395613193512, + 0.12819425761699677, + -0.058150216937065125, + 0.06893474608659744, + -0.018372666090726852, + -0.09186699986457825, + 0.15362109243869781, + 0.028102269396185875, + 0.025071216747164726, + 0.09713421016931534, + 0.01256798580288887, + -0.01616877131164074, + -0.041066594421863556, + -0.017975831404328346, + 0.044571682810783386, + 0.2357323318719864, + -0.03317007049918175, + -0.027484485879540443, + 0.05428558960556984, + -0.04763684794306755, + -1.0566697710601147e-05, + 0.04871894046664238, + 0.0070588416419923306, + 0.004973179195076227, + -0.026652388274669647, + -0.008015204221010208, + -0.07091150432825089, + 0.033345308154821396, + -0.09143518656492233, + 0.061592280864715576, + 0.03615380451083183, + 0.03313060477375984, + 0.07367609441280365, + -0.04913125932216644, + -0.01810459792613983, + -0.20834849774837494, + -0.05211314558982849, + -0.03780398145318031, + 0.08887007087469101, + -0.08282432705163956, + -0.02316044457256794, + 0.03807034716010094, + 0.003166689770296216, + 0.048870425671339035, + 0.053769540041685104, + -0.029292000457644463, + -0.002758365822955966, + 0.035534992814064026, + 0.01716659404337406, + -0.009857158176600933, + -0.01820841059088707, + 0.1924063116312027, + -0.10551274567842484, + 0.015695957466959953, + 0.08622416853904724, + -0.09239751845598221, + 0.3837597668170929, + -3.496369390632026e-05, + -0.06069179251790047, + -0.02606315352022648, + 0.12018977850675583, + 0.0050528384745121, + 0.03152324631810188, + 0.0403270348906517, + -0.025558656081557274, + 0.04960830882191658, + -0.05975503847002983, + -0.03103153593838215, + 0.05772930011153221, + 0.0396592952311039, + -0.0018726816633716226, + 0.0107951695099473, + -0.025373486801981926, + -0.028895430266857147, + 0.024420717731118202, + -0.07865981012582779, + 0.10167545080184937, + 0.08524877578020096, + -0.05940742790699005, + -0.006057963240891695, + 0.06243671104311943, + -0.056733157485723495, + 0.06139994040131569, + -0.07574266940355301, + 0.0216194037348032, + -0.007321906741708517, + 0.05265502631664276, + -0.025458944961428642, + 0.02595309354364872, + -0.015414812602102757, + 0.02327638864517212, + 0.03251353278756142, + 0.06957828998565674, + 0.049125488847494125, + -0.023909522220492363, + 0.057829465717077255, + 0.036426953971385956, + -0.07245929539203644, + 0.007933235727250576, + -0.059332478791475296, + -0.0435311533510685, + -0.047337573021650314, + -0.04053480550646782, + 0.03915426507592201, + -0.06534258276224136, + -0.2260957807302475, + 0.015165231190621853, + 0.060068678110837936, + -0.0034208225551992655, + -0.026531696319580078, + 0.04104552045464516, + -0.07288438826799393, + 0.018118413165211678, + -0.014951043762266636, + -0.049901094287633896, + 0.0704021230340004, + -0.017830973491072655, + 0.051336515694856644, + 0.13087646663188934, + 0.04126317426562309, + -0.06066800281405449, + -0.03640735521912575, + 0.0299614816904068, + -0.02631322294473648, + 0.10236970335245132, + -0.1225552037358284, + -0.027694450691342354, + -0.026750773191452026, + -0.022465072572231293, + 0.6963229775428772, + 0.06071530655026436, + 0.1349962204694748, + 0.0029604679439216852, + -0.010627356357872486, + 0.1805461049079895, + 0.009208586066961288, + 0.06478998810052872, + -0.04796625301241875, + -0.05369967222213745, + 0.03317221999168396, + -0.07248315960168839, + -0.04857209697365761, + 0.021922463551163673, + -0.014980182982981205, + 0.07153782248497009, + 0.033672574907541275, + 0.08822420984506607, + -0.009559323079884052, + -0.08002188056707382, + -0.02796768955886364, + 0.04889626428484917, + -0.002079806989058852, + -0.12316332012414932, + -0.00598991708829999, + 0.04790058732032776, + 0.08986284583806992, + -0.06529728323221207, + 0.0019114370224997401, + -0.03926361724734306, + 0.043254926800727844, + -0.016697514802217484, + 0.06446542590856552, + -0.015036128461360931, + 0.048525601625442505, + 0.022319965064525604, + 0.04527026414871216, + -0.020831571891903877, + -0.08953225612640381, + -0.006588423624634743, + 0.1359531283378601, + -0.002234226791188121, + -0.030231744050979614, + 0.1041426882147789, + -0.11253884434700012, + 0.0400945320725441, + 0.0055610924027860165, + 0.19018787145614624, + -0.17008160054683685, + 0.021101707592606544, + -0.00634838966652751, + -0.013233933597803116, + 0.043402597308158875, + 0.0033622318878769875, + -0.06131330132484436, + -0.056475479155778885, + 0.0574350506067276, + 0.015077848918735981, + 0.034125734120607376, + 0.07870019972324371, + -0.027285316959023476, + 0.05490930378437042, + 0.05595440790057182, + 0.019953204318881035, + -0.047013092786073685, + 0.061499033123254776, + 0.02760140411555767, + -0.006400404032319784, + -0.01763268932700157, + -0.01890098862349987, + 0.0064741335809230804, + 0.03504158556461334, + 0.001586462720297277, + 0.06483786553144455, + -0.0428876094520092, + -0.032916028052568436, + 0.01864536665380001, + 0.06462439149618149, + 0.0023124387953430414, + 0.08506456017494202, + -0.06751906871795654, + -0.027384648099541664, + -0.037361446768045425, + -0.02647651731967926, + 0.05260567367076874, + -0.014446704648435116, + 0.06518206745386124, + 0.08603981137275696, + 0.09696471691131592, + 0.0062536210753023624, + 0.048122942447662354, + 0.017186813056468964, + 0.026083774864673615, + 0.019874846562743187, + 0.07057034224271774, + -0.02904350310564041, + -0.05003984272480011, + -0.01425819844007492, + -0.001251187059096992, + 0.04657392203807831, + 0.007774615194648504, + -0.09506087750196457, + -0.020778952166438103, + -0.07087522745132446, + -0.024529092013835907, + -0.0887717679142952, + -0.060240041464567184, + 0.020624155178666115, + 0.046308714896440506, + -0.040538158267736435, + -0.09442443400621414, + -0.06354733556509018, + 0.006772881373763084, + 0.06922020763158798, + -0.00778896315023303, + -0.021353259682655334, + -0.124875009059906, + 0.004535881336778402, + -0.06257758289575577, + 0.036274638026952744, + 0.006892743986099958, + -0.021391555666923523, + -0.015682250261306763, + -0.04881167784333229, + 0.01879616267979145, + -0.014313933439552784, + -0.002905568340793252, + -0.07575004547834396, + -0.06220642849802971, + -0.032436590641736984, + -0.006158924195915461, + -0.002058455953374505, + -0.05558959022164345, + -0.005457794759422541, + 0.04193447530269623, + 0.063014455139637, + -0.027310015633702278, + -0.03688542917370796, + 0.0466887503862381, + -0.012773402035236359, + -0.009203986264765263, + 0.08859669417142868, + -0.016090862452983856, + 0.02242548018693924, + -0.02983110584318638, + -0.07793480902910233, + -0.033489566296339035, + 0.01613295078277588, + -0.03415980935096741, + 0.03627980500459671, + -0.016666151583194733, + 0.025052055716514587, + -0.03267792984843254, + 0.020628737285733223, + 0.03692276030778885, + -0.02742244303226471, + -0.09069464355707169, + -0.04986213520169258, + 0.1718524694442749, + 0.00028678213129751384, + -0.0322076715528965, + 0.02312176674604416, + -0.06042476370930672, + 0.05028273165225983, + -0.00551630137488246, + 0.012767993845045567, + 0.032750293612480164, + 0.10601982474327087, + -0.0063768420368433, + 0.033016130328178406, + 0.05911942943930626, + -0.0034290996845811605, + 0.04406482353806496, + 0.06185388192534447, + 0.4226973056793213, + -0.1968797892332077, + 0.0842713937163353, + 0.10632825642824173, + 0.0010914724553003907, + 0.039177585393190384, + -0.0801040455698967, + 0.04901694133877754, + 0.08682584017515182, + 0.10728341341018677, + 0.13156089186668396, + -0.018922606483101845, + 0.019393766298890114, + -0.04106520488858223, + 0.08649475127458572, + -0.029056930914521217, + -0.0071672541089355946, + -0.018303148448467255, + -0.06217241659760475, + -0.004366402048617601, + 0.047536689788103104, + -0.031071506440639496, + -0.00480313366279006, + -0.0061461725272238255, + -0.055548787117004395, + 0.00788793247193098, + 0.057616639882326126, + 0.031225956976413727, + 0.01318689901381731, + 0.015787797048687935, + -0.019895801320672035, + 0.03961948677897453, + 0.025899363681674004, + 0.014753241091966629, + -0.1348978728055954, + 0.03202307969331741, + -0.05162663385272026, + -0.13509045541286469, + 0.09003769606351852, + -0.003307627746835351, + 0.05749477818608284, + 0.06454337388277054, + -0.021481366828083992, + 0.028288818895816803, + -0.026615282520651817, + -0.026294425129890442, + 0.008199688978493214, + 0.06729302555322647, + 0.025896921753883362, + 0.07375463098287582, + 0.16271694004535675, + -0.041269026696681976, + -0.015906035900115967, + -0.08949262648820877, + 0.05659450963139534, + 0.13324247300624847, + -0.0464564673602581, + -0.005015434231609106, + -0.001693259458988905, + -0.002847062423825264, + -0.013766842894256115, + -0.07604783028364182, + -0.05830862745642662, + -0.02066342532634735, + -0.06560307741165161, + 0.08522600680589676, + 0.04107437655329704, + -0.04214470461010933, + -0.14534230530261993, + -0.011104445904493332, + -0.032366808503866196, + 0.03278728947043419, + 0.11380184441804886, + -0.0666615441441536, + 0.040425315499305725, + -0.005399531219154596, + 0.014014272950589657, + 0.023620227351784706, + -0.07893305271863937, + -0.009794498793780804, + -0.08585638552904129, + 0.03401630371809006, + 0.07119400054216385, + 0.06484425067901611, + -0.04560472443699837, + 0.10027354955673218, + -0.09807371348142624, + 0.09029466658830643, + -0.00776924192905426, + -0.05461972951889038, + 0.048991065472364426, + -0.039878834038972855, + 0.019989730790257454, + 0.019362283870577812, + -0.04829762503504753, + 0.06533920019865036, + -0.017562834545969963, + -0.05175589397549629, + -0.07299955189228058, + -0.07298615574836731, + -0.04072772338986397, + -0.09242146462202072, + 0.07381884753704071, + -0.06534093618392944, + 0.0010574118932709098, + -0.020853906869888306, + -0.040836818516254425, + -0.012832515873014927, + 0.02487863413989544, + 0.03318801149725914, + -0.15873613953590393, + -0.055572014302015305, + -0.021044636145234108, + 0.03568285331130028, + 0.017814001068472862, + -0.0451168566942215, + 0.005319114774465561, + 0.057521238923072815, + 0.034872833639383316, + 0.03899437189102173, + 0.023746006190776825, + -0.051500916481018066, + 0.059377770870923996, + -0.14109168946743011, + -0.3940942585468292, + 0.04678523913025856, + 0.006228484213352203, + 0.02189958095550537, + -0.015611437149345875, + -0.05416549742221832, + 0.05052398517727852, + 0.0026056349743157625, + -0.03473886474967003, + 0.0980633795261383, + -0.07380123436450958, + 0.017081940546631813, + -0.061888162046670914, + -0.060919493436813354, + -0.02053762413561344, + -0.07007520645856857, + -0.049346838146448135, + 0.041981007903814316, + 0.025222048163414, + -0.06693807244300842, + -0.08524662256240845, + 0.06733603030443192, + -0.021311646327376366, + -0.003399507375434041, + 0.0076775881461799145, + 0.024136727675795555, + -0.07568683475255966, + -0.06720703840255737, + -0.016028104349970818, + 0.061864208430051804, + 0.03237927332520485, + -0.07795371860265732, + -0.005399972666054964, + 0.038687314838171005, + 0.003363342024385929, + 0.10057994723320007, + 0.003988614305853844, + -0.015340202488005161, + -0.08878466486930847, + 0.0977032408118248, + 0.06695879250764847, + 0.18500442802906036, + -0.01678348518908024, + 0.006111804861575365, + 0.004242830444127321, + 0.11370434612035751, + 0.03940612077713013, + 0.013183747418224812, + -0.030457524582743645, + 0.01693480648100376, + -0.018341096118092537, + -0.013356991112232208, + 0.09827983379364014, + -0.05066269263625145, + -0.027613507583737373, + 0.01687728427350521, + -0.01242680475115776, + -0.023277008906006813, + -0.03319449722766876, + 0.21616916358470917, + 0.03379783406853676, + 0.042088836431503296, + 0.017735781148076057, + -0.03290579095482826, + 0.017938842996954918, + -0.10539724677801132, + -0.11517835408449173, + -0.013451620005071163, + 0.000374626339180395, + 0.021733524277806282, + -0.05304350331425667, + -0.09813041239976883, + -0.027155568823218346, + 0.013767196796834469, + -0.01930530183017254, + 0.10336603969335556, + -0.021463418379426003, + 0.03581016883254051, + -0.06046905741095543, + 0.13518653810024261, + 0.031003080308437347, + 0.017072312533855438, + 0.011110997758805752, + 0.0667453482747078, + 0.04917195439338684, + -0.0021193886641412973, + -0.051941823214292526, + -0.05759355053305626, + 0.020791461691260338, + 0.13696010410785675, + -0.04596574977040291, + 0.1332692801952362, + 0.02513316459953785, + -0.009932330809533596, + -0.054872483015060425, + 0.03171728178858757, + 0.013050459325313568, + -0.003947978373616934, + -0.44521331787109375, + -0.05231727287173271, + 0.1282065063714981, + -0.030108973383903503, + 0.025894753634929657, + 0.09331361204385757, + 0.03157180920243263, + -0.07923457771539688, + -0.030358143150806427, + -0.05153513327240944, + 0.11359219998121262, + 0.010586780495941639, + 0.06787595897912979, + -0.13399849832057953, + 0.02302604913711548, + 0.08097248524427414, + -0.043132904917001724, + -0.01535704080015421, + 0.05189881846308708, + -0.2099890559911728, + -0.004585218150168657, + -0.05359213426709175, + 0.11603052169084549, + 0.019611136987805367, + 0.03128006309270859, + 0.09810841828584671, + -0.06763505190610886, + 0.02503429353237152, + 0.054650451987981796, + 0.002728505292907357, + 0.06416928023099899, + 0.006461964920163155, + -0.02583378739655018, + 0.10828322172164917, + 0.08189579099416733, + 0.03860188275575638, + -0.03500935435295105, + 12.041316986083984, + 0.07135587930679321, + 0.07587986439466476, + -0.07815652340650558, + 0.01789211481809616, + -0.06088171899318695, + 0.042837608605623245, + -0.08220500499010086, + 0.0217966940253973, + 0.1364554613828659, + 0.0007437678868882358, + -0.04616783931851387, + -0.029968850314617157, + -0.07923655956983566, + 0.03229570388793945, + -0.02203737199306488, + -0.04797447845339775, + -0.0020305009093135595, + 0.024356653913855553, + -0.03915480151772499, + -0.06702367961406708, + 0.013569020666182041, + 0.07913649827241898, + -0.0034444101620465517, + -0.04820480942726135, + 0.028118645772337914, + 0.02363363839685917, + -0.016757983714342117, + -0.01822235994040966, + 0.06246187165379524, + -0.02062375284731388, + 0.0004203618736937642, + 0.03233122453093529, + -0.030118217691779137, + 0.06812857836484909, + 0.06541542708873749, + 0.0953434482216835, + 0.03266927972435951, + 0.0185119416564703, + 0.04870273172855377, + 0.020875677466392517, + 0.005300997290760279, + 0.02631889097392559, + 0.06798504292964935, + 0.05154086649417877, + 0.015005327761173248, + 0.017745381221175194, + 0.12363690137863159, + 0.013060785830020905, + 0.08051296323537827, + 0.09826701134443283, + -0.01794828288257122, + 0.11512423306703568, + 0.022138921543955803, + -0.016594456508755684, + 0.013868294656276703, + 0.006469572428613901, + -0.09581004828214645, + 0.12190597504377365, + 0.05028713122010231, + -0.046826597303152084, + 0.10982882231473923, + 0.025811506435275078, + 0.11328303813934326, + 0.014556948095560074, + 0.08173282444477081, + 0.0457267165184021, + 0.07863391190767288, + -0.14725281298160553, + -0.07506497949361801, + 0.023782463744282722, + -0.07605893164873123, + -0.08246233314275742, + 0.08330795168876648, + 0.10566451400518417, + -0.04493102803826332, + 0.07607607543468475, + -0.04333483800292015, + 0.003520787926390767, + -0.05823725461959839, + 0.009233443066477776, + 0.024135639891028404, + -0.03351334109902382, + 0.042286068201065063, + 0.04909465089440346, + 0.033163342624902725, + 0.08282016962766647, + 0.07227231562137604, + 0.046822961419820786, + -0.05663175508379936, + -0.0007530542206950486, + 0.10325410962104797, + -0.006014158949255943, + -0.05423947051167488, + 0.003947563003748655, + -0.04840860143303871, + 0.0478232316672802, + -0.1463749259710312, + 0.068173848092556, + 0.08410429209470749, + -0.05504782497882843, + -0.023465273901820183, + -0.028513863682746887, + 0.04851672425866127, + 0.0020922934636473656, + 0.03378622606396675, + -0.05709858611226082, + 0.0017180262366309762, + 0.010725595988333225, + 0.0572512112557888, + -0.02881232462823391, + 0.10155069082975388, + 0.07183052599430084, + -0.04418819025158882, + 0.07062981277704239, + 0.05435023829340935, + -0.03762836754322052, + -0.018741268664598465, + 0.04699109122157097, + 0.0607602559030056, + -0.05994049087166786, + -0.02827439457178116, + -0.02400636114180088, + -0.051030974835157394, + -0.03479217365384102, + -0.03554803878068924, + -0.015273932367563248, + 6.777645467082039e-05, + -0.024866431951522827, + -0.024908997118473053, + 0.04018652066588402, + 0.061754241585731506, + 0.062193069607019424, + -0.0466693639755249, + 0.039988692849874496, + -0.06996554136276245, + -0.034812234342098236, + 0.04701513424515724, + 0.05103026703000069, + 0.0690593495965004, + -0.0636117234826088, + -0.045921146869659424, + -0.05381940305233002, + -0.13033494353294373, + 0.02399160899221897, + 0.09703382849693298, + 0.05136001110076904, + 0.02009364403784275, + 0.0055291480384767056, + -0.06774132698774338, + -0.05190951004624367, + 0.0539257638156414, + 0.10736360400915146, + 0.02136417292058468, + 0.04460662975907326, + -0.052776917815208435, + -0.029110541567206383, + 0.10957958549261093, + -0.05377667769789696, + 0.013081823475658894, + -0.005934875924140215, + -0.04737425222992897, + 0.07549577951431274, + 0.13798557221889496, + 0.013311639428138733, + 0.04293627664446831, + 0.06811729818582535, + -0.006506450939923525, + 0.04009142145514488, + -0.009688236750662327, + 0.016802940517663956, + -0.02174876444041729, + -0.0929674506187439, + -0.05609692260622978, + 0.03033480793237686, + 0.11118770390748978, + 0.03098963014781475, + -0.13081684708595276, + -0.01888337731361389, + -0.042367786169052124 + ] + }, + "flagged_dissimilar_incidents": [], + "incident_id": 50, + "nlp_similar_incidents": [ + { + "__typename": "IncidentNlp_similar_incident", + "incident_id": 38, + "similarity": 0.9988240599632263 + }, + { + "__typename": "IncidentNlp_similar_incident", + "incident_id": 6, + "similarity": 0.9987120628356934 + }, + { + "__typename": "IncidentNlp_similar_incident", + "incident_id": 26, + "similarity": 0.9986885786056519 + } + ], + "reports": [ + { + "__typename": "Report", + "report_number": 905 + }, + { + "__typename": "Report", + "report_number": 903 + }, + { + "__typename": "Report", + "report_number": 902 + }, + { + "__typename": "Report", + "report_number": 901 + }, + { + "__typename": "Report", + "report_number": 900 + }, + { + "__typename": "Report", + "report_number": 899 + }, + { + "__typename": "Report", + "report_number": 898 + }, + { + "__typename": "Report", + "report_number": 897 + }, + { + "__typename": "Report", + "report_number": 896 + }, + { + "__typename": "Report", + "report_number": 893 + }, + { + "__typename": "Report", + "report_number": 892 + }, + { + "__typename": "Report", + "report_number": 889 + }, + { + "__typename": "Report", + "report_number": 888 + }, + { + "__typename": "Report", + "report_number": 887 + }, + { + "__typename": "Report", + "report_number": 886 + }, + { + "__typename": "Report", + "report_number": 885 + }, + { + "__typename": "Report", + "report_number": 884 + }, + { + "__typename": "Report", + "report_number": 883 + }, + { + "__typename": "Report", + "report_number": 881 + }, + { + "__typename": "Report", + "report_number": 880 + }, + { + "__typename": "Report", + "report_number": 879 + }, + { + "__typename": "Report", + "report_number": 878 + }, + { + "__typename": "Report", + "report_number": 877 + }, + { + "__typename": "Report", + "report_number": 876 + }, + { + "__typename": "Report", + "report_number": 25 + }, + { + "__typename": "Report", + "report_number": 24 + }, + { + "__typename": "Report", + "report_number": 23 + }, + { + "__typename": "Report", + "report_number": 22 + }, + { + "__typename": "Report", + "report_number": 21 + }, + { + "__typename": "Report", + "report_number": 20 + }, + { + "__typename": "Report", + "report_number": 19 + }, + { + "__typename": "Report", + "report_number": 18 + }, + { + "__typename": "Report", + "report_number": 17 + }, + { + "__typename": "Report", + "report_number": 16 + } + ], + "title": "The DAO Hack" + } + } +} diff --git a/site/gatsby-site/cypress/fixtures/reports/issueWithTranslations.json b/site/gatsby-site/cypress/fixtures/reports/issueWithTranslations.json index 63d1897dc4..a304a6f318 100644 --- a/site/gatsby-site/cypress/fixtures/reports/issueWithTranslations.json +++ b/site/gatsby-site/cypress/fixtures/reports/issueWithTranslations.json @@ -24,8 +24,8 @@ "language": "en", "translations_es": { "__typename": "ReportTranslation", - "title": "Este es el Titulo", - "text": "Este es el texto que tiene un largo mayor a ochenta caracteres!" + "title": "Este es el Título en español", + "text": "Este es un texto de prueba que tiene un largo mayor a ochenta caracteres (en español)" }, "translations_en": { "__typename": "ReportTranslation", @@ -34,8 +34,13 @@ }, "translations_fr": { "__typename": "ReportTranslation", - "title": "", - "text": "" + "title": "C'est le Titre en français", + "text": "Il s'agit d'un texte de test de plus de quatre-vingts caractères - lorem ipsum (en français)" + }, + "translations_ja": { + "__typename": "ReportTranslation", + "title": "これは日本語でのタイトルです", + "text": "解サオライ協立なーづ民手ぶみドに即記朝ぐ奥置ぱで地更トるあて栄厚ぜづを祭屋ん来派どてゃ読速ヘ誌約カタシネ原39業理る。外ヒヱフ社第むせゆ由更混ソエ夕野しりすよ顔飛リの兆基う公言や置17謝后嘘5供フキヌア星集ヘラ辞勘壇崇さびわ。(日本語で)" }, "date_modified": "2023-01-01", "epoch_date_modified": 1672531200, diff --git a/site/gatsby-site/cypress/fixtures/reports/reportWithTranslations.json b/site/gatsby-site/cypress/fixtures/reports/reportWithTranslations.json index 96ddd31321..9cdcfb4a55 100644 --- a/site/gatsby-site/cypress/fixtures/reports/reportWithTranslations.json +++ b/site/gatsby-site/cypress/fixtures/reports/reportWithTranslations.json @@ -18,8 +18,8 @@ "language": "en", "translations_es": { "__typename": "ReportTranslation", - "text": "Este es el texto que tiene un largo mayor a ochenta caracteres!", - "title": "Este es el Titulo" + "text": "Este es un texto de prueba que tiene un largo mayor a ochenta caracteres (en español)", + "title": "Este es el Título en español" }, "translations_en": { "__typename": "ReportTranslation", @@ -28,8 +28,13 @@ }, "translations_fr": { "__typename": "ReportTranslation", - "text": "Este es el texto que tiene un largo mayor a ochenta caracteres en frances!", - "title": "Este es el Titulo en frances" + "text": "Il s'agit d'un texte de test de plus de quatre-vingts caractères - lorem ipsum (en français)", + "title": "C'est le Titre en français" + }, + "translations_ja": { + "__typename": "ReportTranslation", + "text": "解サオライ協立なーづ民手ぶみドに即記朝ぐ奥置ぱで地更トるあて栄厚ぜづを祭屋ん来派どてゃ読速ヘ誌約カタシネ原39業理る。外ヒヱフ社第むせゆ由更混ソエ夕野しりすよ顔飛リの兆基う公言や置17謝后嘘5供フキヌア星集ヘラ辞勘壇崇さびわ。(日本語で)", + "title": "これは日本語でのタイトルです" }, "date_modified": "2023-01-01", "epoch_date_modified": 1672531200, diff --git a/site/gatsby-site/cypress/plugins/index.js b/site/gatsby-site/cypress/plugins/index.js index 9998393446..d2fe083220 100644 --- a/site/gatsby-site/cypress/plugins/index.js +++ b/site/gatsby-site/cypress/plugins/index.js @@ -14,14 +14,40 @@ require('dotenv').config(); +const fs = require('fs'); + +const path = require('path'); + /** * @type {Cypress.PluginConfig} */ module.exports = (on, config) => { + on('task', { + listFiles(directoryPath) { + return new Promise((resolve, reject) => { + fs.readdir(directoryPath, (err, files) => { + if (err) { + reject(err); + } else { + const jsonFiles = files.filter((file) => { + return ( + path.extname(file).toLowerCase() === '.json' && + fs.statSync(path.join(directoryPath, file)).isFile() + ); + }); + + resolve(jsonFiles); + } + }); + }); + }, + }); + config.env.e2eUsername = process.env.E2E_ADMIN_USERNAME; config.env.e2ePassword = process.env.E2E_ADMIN_PASSWORD; config.env.realmAppId = process.env.GATSBY_REALM_APP_ID; config.env.isEmptyEnvironment = process.env.IS_EMPTY_ENVIRONMENT == 'true'; + config.env.availableLanguages = process.env.GATSBY_AVAILABLE_LANGUAGES; return config; }; diff --git a/site/gatsby-site/cypress/support/utils.js b/site/gatsby-site/cypress/support/utils.js index 2945a4aaba..e4871b3a78 100644 --- a/site/gatsby-site/cypress/support/utils.js +++ b/site/gatsby-site/cypress/support/utils.js @@ -21,7 +21,7 @@ export const getApolloClient = () => { const client = new ApolloClient({ link: new HttpLink({ - uri: `https://realm.mongodb.com/api/client/v2.0/app/${realmAppId}/graphql`, + uri: `https://services.cloud.mongodb.com/api/client/v2.0/app/${realmAppId}/graphql`, fetch: async (uri, options) => { options.headers.email = email; diff --git a/site/gatsby-site/github-netlify.toml b/site/gatsby-site/deploy-netlify.toml similarity index 80% rename from site/gatsby-site/github-netlify.toml rename to site/gatsby-site/deploy-netlify.toml index d5eb03f655..8299f1c9ef 100644 --- a/site/gatsby-site/github-netlify.toml +++ b/site/gatsby-site/deploy-netlify.toml @@ -1,3 +1,7 @@ +[build] + base = "/site/gatsby-site" + publish = "public" + [[plugins]] package = "@netlify/plugin-gatsby" @@ -9,6 +13,3 @@ [build.processing.html] pretty_urls = false - -[context.deploy-preview] - publish = "public/" \ No newline at end of file diff --git a/site/gatsby-site/gatsby-node.js b/site/gatsby-site/gatsby-node.js index 198df63547..20442a1b7f 100644 --- a/site/gatsby-site/gatsby-node.js +++ b/site/gatsby-site/gatsby-node.js @@ -46,6 +46,8 @@ const typeDefs = require('./typeDefs'); const googleMapsApiClient = new GoogleMapsAPIClient({}); +const LookupIndex = require('./src/utils/LookupIndex'); + exports.createPages = async ({ actions, graphql, reporter }) => { const { createRedirect, createPage } = actions; @@ -158,6 +160,12 @@ exports.onCreateNode = async ({ node, getNode, actions }) => { node, value: node.frontmatter.title || startCase(parent.name), }); + + createNodeField({ + name: 'previewText', + node, + value: node.frontmatter.previewText || startCase(parent.name), + }); } if (node.internal.type == 'mongodbAiidprodClassifications') { @@ -229,6 +237,21 @@ exports.createResolvers = ({ createResolvers }) => { createResolvers(resolvers); }; +exports.onPreInit = async ({ reporter }) => { + reporter.log('Creating lookup index...'); + + const mongoClient = new MongoClient(config.mongodb.translationsConnectionString); + + const lookupIndex = new LookupIndex({ + client: mongoClient, + filePath: path.join(__dirname, 'src', 'api', 'lookupIndex.json'), + }); + + await lookupIndex.run(); + + reporter.log('Lookup index created.'); +}; + exports.onPreBootstrap = async ({ reporter }) => { const migrationsActivity = reporter.activityTimer(`Migrations`); diff --git a/site/gatsby-site/i18n/config.json b/site/gatsby-site/i18n/config.json index e9a4105742..57fa32d873 100644 --- a/site/gatsby-site/i18n/config.json +++ b/site/gatsby-site/i18n/config.json @@ -22,5 +22,13 @@ "localName": "Français", "langDir": "ltr", "dateFormat": "DD-MM-YYYY" + }, + { + "code": "ja", + "hrefLang": "ja", + "name": "Japanese", + "localName": "日本語", + "langDir": "ltr", + "dateFormat": "YYYY/MM/DD" } ] diff --git a/site/gatsby-site/i18n/locales/es/submitted.json b/site/gatsby-site/i18n/locales/es/submitted.json index 025dd115dc..b06659ec2e 100644 --- a/site/gatsby-site/i18n/locales/es/submitted.json +++ b/site/gatsby-site/i18n/locales/es/submitted.json @@ -37,5 +37,6 @@ "There was an error claiming this submission. Please try again.": "Hubo un error al reclamar este envío. Por favor, inténtelo de nuevo.", "Claim": "Reclamar", "Claiming...": "Reclamando...", - "Reviewing": "Revisando" + "Reviewing": "Revisando", + "No reports found": "No se encontraron informes" } diff --git a/site/gatsby-site/i18n/locales/es/translation.json b/site/gatsby-site/i18n/locales/es/translation.json index f1e7baab4d..ebe7d4414a 100644 --- a/site/gatsby-site/i18n/locales/es/translation.json +++ b/site/gatsby-site/i18n/locales/es/translation.json @@ -20,6 +20,8 @@ "Filter by Incident ID #{{id}}": "Filtrar por ID de Incidente #{{id}}", "Flag Report": "Reportar", "Filters": "Filtros", + "More filters": "Ver más filtros", + "Fewer filters": "Ver menos filtros", "Options": "Opciones", "Search Options": "Opciones de Búsqueda", "1st report only": "Sólo el primer informe", @@ -68,9 +70,9 @@ "Incidents reports matched by URL: <1>{{url}}": "Informes por URL: <1>{{url}}", "AI Translated": "Traducido por IA", "View Original": "Ver Original", - "Search over 1800 reports of AI harms": "Busca en más de 1800 informes de daños de IA", - "Search 1800+ AI harm reports": "Busca +1800 daños de IA", - "Search 1800+ reports": "Buscar +1800 Informes", + "Search over 3000 reports of AI harms": "Busca en más de 3000 informes de daños de IA", + "Search 3000+ AI harm reports": "Busca +3000 daños de IA", + "Search 3000+ reports": "Buscar +3000 Informes", "Search reports": "Buscar Informes", "Discover Incidents": "Descubrir Incidentes", "Submit Incident Reports": "Enviar Informes de Incidentes", @@ -288,5 +290,10 @@ "Incident and Issue Reports": "Incidentes e Informes de Problemas", "Issue Reports": "Informes de Problemas", "found": "encontrados", - "results found": "resultados encontrados" + "results found": "resultados encontrados", + "Blog": "Blog", + "AI News Digest": "Resumen de noticias de IA", + "Remove Duplicate": "Eliminar Duplicado", + "View History": "Ver Historial", + "CSET Annotators Table": "Tabla de Anotadores de CSET" } diff --git a/site/gatsby-site/i18n/locales/es/validation.json b/site/gatsby-site/i18n/locales/es/validation.json index 435f4d8984..778cf63f7c 100644 --- a/site/gatsby-site/i18n/locales/es/validation.json +++ b/site/gatsby-site/i18n/locales/es/validation.json @@ -13,5 +13,26 @@ "Please review report. Some data is missing.": "Por favor revisa el reporte. Faltan algunos datos.", "Please review submission. Some data is missing.": "Por favor revisa el incidente. Faltan algunos datos.", "Some data is missing.": "Faltan algunos datos.", - "Please review. Some data is missing.": "Por favor revisa el formulario. Faltan algunos datos." + "Please review. Some data is missing.": "Por favor revisa el formulario. Faltan algunos datos.", + "*Title must have at least 6 characters": "*El título debe tener al menos 6 caracteres", + "*Titles can't be longer than 500 characters": "*Los títulos no pueden tener más de 500 caracteres", + "Alleged Developer must have at least 3 characters": "El desarrollador presunto debe tener al menos 3 caracteres", + "Alleged Developers can't be longer than 200 characters": "Los desarrolladores presuntos no pueden tener más de 200 caracteres", + "Alleged Deployers must have at least 3 characters": "Los implementadores presuntos deben tener al menos 3 caracteres", + "Alleged Deployers can't be longer than 200 characters": "Los implementadores presuntos no pueden tener más de 200 caracteres", + "Harmed Parties must have at least 3 characters": "Las partes perjudicadas deben tener al menos 3 caracteres", + "Harmed Parties can't be longer than 200 characters": "Las partes perjudicadas no pueden tener más de 200 caracteres", + "Description must have at least 3 characters": "La descripción debe tener al menos 3 caracteres", + "Description can't be longer than 500 characters": "La descripción no puede tener más de 500 caracteres", + "*Incident title is required": "*El título del incidente es obligatorio", + "*Alleged developers is required": "*Se requiere el desarrollador presunto del sistema de IA", + "*Alleged developer of AI system is required": "*Se requiere el desarrollador presunto del sistema de IA", + "*Alleged deployers is required": "*Se requiere el implementador presunto del sistema de IA", + "*Alleged deployer of AI system is required": "*Se requiere el implementador presunto del sistema de IA", + "*Alleged Harmed Parties is required": "*Se requieren las partes presuntamente perjudicadas o casi perjudicadas", + "*Alleged harmed or nearly harmed parties is required": "*Se requieren las partes presuntamente perjudicadas o casi perjudicadas", + "*Description is required": "*La descripción es obligatoria", + "*Incident Date is required": "*Fecha del incidente es obligatoria", + "*Incident Date required": "*Fecha del incidente es obligatoria", + "*Incident ID(s) must be a number": "*El ID del incidente debe ser un número" } diff --git a/site/gatsby-site/i18n/locales/fr/submitted.json b/site/gatsby-site/i18n/locales/fr/submitted.json index 6e67305efb..41227141c5 100644 --- a/site/gatsby-site/i18n/locales/fr/submitted.json +++ b/site/gatsby-site/i18n/locales/fr/submitted.json @@ -37,5 +37,6 @@ "There was an error claiming this submission. Please try again.": "Une erreur s'est produite lors de la réclamation de cette soumission. Veuillez réessayer.", "Claim": "Réclamer", "Claiming...": "En cours...", - "Reviewing": "Révision" + "Reviewing": "Révision", + "No reports found": "Aucun rapport trouvé" } diff --git a/site/gatsby-site/i18n/locales/fr/translation.json b/site/gatsby-site/i18n/locales/fr/translation.json index 98d3bedb7b..9acb55f1f4 100644 --- a/site/gatsby-site/i18n/locales/fr/translation.json +++ b/site/gatsby-site/i18n/locales/fr/translation.json @@ -20,6 +20,8 @@ "Filter by Incident ID #{{id}}": "Filtrer par ID d'incident #{{id}}", "Flag Report": "Signaler", "Filters": "Filtres", + "More filters": "Plus de filtres", + "Fewer filters": "Moins de filtres", "Options": "Options", "Search Options": "Options de recherche", "1st report only": "Seulement le premier rapport", @@ -68,9 +70,9 @@ "Incidents reports matched by URL: <1>{{url}}": "Rapports par URL : <1>{{url}}", "AI Translated": "Traduit par IA", "View Original": "Voir l'original", - "Search over 1800 reports of AI harms": "Recherchez parmi +1800 rapports de dégâts causés par l'IA", - "Search 1800+ AI harm reports": "Rechercher +1800 dégâts d'IA", - "Search 1800+ reports": "Rechercher +1800 rapports", + "Search over 3000 reports of AI harms": "Recherchez parmi +3000 rapports de dégâts causés par l'IA", + "Search 3000+ AI harm reports": "Rechercher +3000 dégâts d'IA", + "Search 3000+ reports": "Rechercher +3000 rapports", "Search reports": "Recherche de rapports", "Discover Incidents": "Découvrir les incidents", "Submit Incident Reports": "Soumettre des rapports d'incident", @@ -276,5 +278,10 @@ "Incident and Issue Reports": "Incidents et rapports de problèmes", "Issue Reports": "Rapports de problèmes", "found": "trouvés", - "results found": "résultats trouvés" + "results found": "résultats trouvés", + "Blog": "Blog", + "AI News Digest": "Résumé de l’Actualité sur l’IA", + "Remove Duplicate": "Supprimer le doublon", + "View History": "Voir l'historique", + "CSET Annotators Table": "Tableau des annotateurs CSET" } diff --git a/site/gatsby-site/i18n/locales/fr/validation.json b/site/gatsby-site/i18n/locales/fr/validation.json index f22ed25e6a..1701f0da92 100644 --- a/site/gatsby-site/i18n/locales/fr/validation.json +++ b/site/gatsby-site/i18n/locales/fr/validation.json @@ -7,5 +7,26 @@ "*Must enter URL in http://www.example.com/images/preview.png format": "*Vous devez entrer l'URL avec le format http://www.example.com/images/preview.png", "Incident ID {{value}} not found!": "Incident {{value}} introuvable !", "Incident ID": "ID de l'incident", - "Type and press Enter to add an item": "Ecrivez et appuyez Enter pour ajouter un élément" + "Type and press Enter to add an item": "Ecrivez et appuyez Enter pour ajouter un élément", + "*Title must have at least 6 characters": "*Le titre doit comporter au moins 6 caractères", + "*Titles can't be longer than 500 characters": "*Les titres ne peuvent pas comporter plus de 500 caractères", + "Alleged Developer must have at least 3 characters": "Le développeur présumé doit avoir au moins 3 caractères", + "Alleged Developers can't be longer than 200 characters": "Les développeurs présumés ne peuvent pas comporter plus de 200 caractères", + "Alleged Deployers must have at least 3 characters": "Les implémenteurs présumés doivent avoir au moins 3 caractères", + "Alleged Deployers can't be longer than 200 characters": "Les implémenteurs présumés ne peuvent pas comporter plus de 200 caractères", + "Harmed Parties must have at least 3 characters": "Les parties lésées doivent avoir au moins 3 caractères", + "Harmed Parties can't be longer than 200 characters": "Les parties lésées ne peuvent pas comporter plus de 200 caractères", + "Description must have at least 3 characters": "La description doit comporter au moins 3 caractères", + "Description can't be longer than 500 characters": "La description ne peut pas comporter plus de 500 caractères", + "*Incident title is required": "*Le titre de l'incident est requis", + "*Alleged developers is required": "*Le développeur présumé du système d'IA est requis", + "*Alleged developer of AI system is required": "*Le développeur présumé du système d'IA est requis", + "*Alleged deployers is required": "*Le déploiement présumé du système d'IA est requis", + "*Alleged deployer of AI system is required": "*Le déploiement présumé du système d'IA est requis", + "*Alleged Harmed Parties is required": "*Les parties présumées lésées ou presque lésées sont requises", + "*Alleged harmed or nearly harmed parties is required": "*Les parties présumées lésées ou presque lésées sont requises", + "*Description is required": "*La description est requise", + "*Incident Date is required": "*Date de l'incident requise", + "*Incident Date required": "*Date de l'incident requise", + "*Incident ID(s) must be a number": "*L'ID de l'incident doit être un nombre" } diff --git a/site/gatsby-site/i18n/locales/ja/account.json b/site/gatsby-site/i18n/locales/ja/account.json new file mode 100644 index 0000000000..d0a15ecbf5 --- /dev/null +++ b/site/gatsby-site/i18n/locales/ja/account.json @@ -0,0 +1,15 @@ +{ + "Account Details": "アカウント詳細", + "Subscriptions": "購読", + "You don't have active subscriptions to Incident updates": "インシデントアップデートの購読はありません", + "You don't have active subscriptions to Entities": "組織の購読はありません", + "Do you want to delete this subscription?": "この購読を削除しますか?", + "Updates on incident ": "インシデントの更新 ", + "Notify me of new Incidents": "新しいインシデントを通知します", + "New <2>{{name}} Entity incidents": "組織<2>{{name}}の新しいインシデント", + "First Name": "名", + "Last Name": "姓", + "About You": "自分について", + "completeInfoAlertTitle": "インシデント報告のユーザー情報管理", + "completeInfoAlertMessage": "インシデントを新しく作成したり編集すると、それらの操作はあなたのユーザーアカウントとここで入力する名前と関連づけられます。常に匿名を維持したい場合はブラウザの匿名モードでこのサイトを使用してください" +} \ No newline at end of file diff --git a/site/gatsby-site/i18n/locales/ja/actions.json b/site/gatsby-site/i18n/locales/ja/actions.json new file mode 100644 index 0000000000..f7d7e41898 --- /dev/null +++ b/site/gatsby-site/i18n/locales/ja/actions.json @@ -0,0 +1,5 @@ +{ + "flagReport": "

内容に問題がありますか?"問題"には例えば次のようなものがあります。

内容にフラグが立てられてもデータベースにはそのまま表示されますが、データベースの編集者が定期的にフラグの立っているインシデントレポートをレビューします。インシデントレポートに含まれる内容(例、新しい記事の注釈)は修正する必要も記事の間で一貫している必要もないことに注意してください。もし記事が間違っていたり、誤解を招くものであったり、虚偽である場合は、その記録を修正する新しいインシデントレポートを登録することが一番の対策です。インシデントデータベースの目的はインシデントの知識と議論の完全な状態を把握することであり、個別のインシデントで何が起きたかを決定することではありません。データベースの今後のバージョンでは、内容を分類するために追加でインシデントレポートにタグを設定できるようになる可能性もあります。

次のような理由でフラグを立てないでください

", + "Flag Report": "フラグを立てる", + "Flagged": "フラグあり" +} diff --git a/site/gatsby-site/i18n/locales/ja/entities.json b/site/gatsby-site/i18n/locales/ja/entities.json new file mode 100644 index 0000000000..22895202ef --- /dev/null +++ b/site/gatsby-site/i18n/locales/ja/entities.json @@ -0,0 +1,28 @@ +{ + "Entities": "組織", + "Common Entities": "よく取り上げられる組織", + "View all entities": "すべての組織を表示", + "Involved in <2>{{incidentsCount}} incidents,": "<2>{{incidentsCount}}回のインシデントに関連し", + "allegedly harming <2>{{harmedCount}} entities,": "<2>{{harmedCount}}の組織に影響を与えたと推定され", + "with <2>{{responsesCount}} incident responses.": "<2>{{responsesCount}}回のインシデントレスポンスがある", + "{{count}} Incident": "{{count}} インシデント", + "{{count}} Incident_plural": "{{count}} インシデント", + "{{count}} Entity": "{{count}} 組織", + "{{count}} Entity_plural": "{{count}} 組織", + "As Deployer and Developer": "提供者兼開発者として関係", + "As Deployer": "提供者として関係", + "As Developer": "開発者として関係", + "Harmed By": "被害者として関係", + "Related Entities": "関連する組織", + "Incident Responses": "インシデントレスポンス", + "Search {{count}} records...": "{{count}}件の検索結果...", + "Entity": "組織", + "{{count}} Report": "{{count}} レポート", + "{{count}} Report_plural": "{{count}} レポート", + "Incidents involved as both Developer and Deployer": "開発者と提供者の両方の立場で関わったインシデント", + "Incidents Harmed By": "影響を受けたインシデント", + "Alleged: <2> developed and deployed an AI system, which harmed <5>.": "推定: <2>が開発し提供したAIシステムで、<5>に影響を与えた", + "Alleged: <1> developed an AI system deployed by <4>, which harmed <6>.": "推定: <1>が開発し、<4>が提供したAIシステムで、<6>に影響を与えた", + "Entities involved in AI Incidents": "AIインシデントに関係する組織", + "{{count}} Incident responses": "{{count}} インシデントレスポンス" +} diff --git a/site/gatsby-site/i18n/locales/ja/footer.json b/site/gatsby-site/i18n/locales/ja/footer.json new file mode 100644 index 0000000000..4eeea0d5e5 --- /dev/null +++ b/site/gatsby-site/i18n/locales/ja/footer.json @@ -0,0 +1,23 @@ +{ + "Research": "リサーチ", + "Defining an “AI Incident”": "“AIインシデント”の定義", + "Defining an “AI Incident Response”": "“AIインシデントレスポンス”の定義", + "Database Roadmap": "データベースのロードマップ", + "Initial Collection Methodology": "最初の収集方法", + "Related Work": "関連研究", + "Download Complete Database": "全データベースのダウンロード", + "Project and Community": "プロジェクトとコミュニティ", + "About": "AIIDについて", + "Contact and Follow": "コンタクトとフォロー", + "Launch Announcement": "開始のアナウンス", + "About Apps": "アプリについて", + "Editor’s Guide": "エディタのためのガイド", + "Incidents": "インシデント", + "All Incidents in List Form": "全インシデントの一覧", + "Flagged Incidents": "フラグの立ったインシデント", + "Submission Queue": "登録待ち一覧", + "Classifications View": "クラスごとの表示", + "Taxonomies": "分類法", + "Terms of use": "利用規約", + "Privacy Policy": "プライバシーポリシー" +} \ No newline at end of file diff --git a/site/gatsby-site/i18n/locales/ja/incidents.json b/site/gatsby-site/i18n/locales/ja/incidents.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/site/gatsby-site/i18n/locales/ja/incidents.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/site/gatsby-site/i18n/locales/ja/landing.json b/site/gatsby-site/i18n/locales/ja/landing.json new file mode 100644 index 0000000000..ebeab68637 --- /dev/null +++ b/site/gatsby-site/i18n/locales/ja/landing.json @@ -0,0 +1,29 @@ +{ + "Welcome to the Artificial Intelligence Incident Database": "AIインシデントデータベースにようこそ", + "<0>Welcome to the<1>AI Incident Database": "<1>AIインシデントデータベース<0>にようこそ", + "The starting point for information about the AI Incident Database": "AIインシデントデータベースについての情報の出発点", + "Search reports": "レポートを開始する", + "Latest Incident Report": "最新のインシデントレポート", + "Latest Incident Reports": "最新のインシデントレポート", + "Quick Add New Report URL": "新しいレポートのURLをすばやく追加", + "quickaddDescription": "投稿されたリンクは<2>レビューキューに追加され、新規または既存のインシデントレポートとして登録されます。<4>詳細情報も合わせて投稿されたインシデントは、詳細情報のないURLだけの投稿よりも優先して処理されます", + "About the Database": "データベースについて", + "Latest Blog Post": "最新のブログ投稿", + "aboutLine1": "AIインシデントデータベースは人工知能システムによって現実世界が被った損失、もしくは被る可能性のあった損失の記録です。航空機事故やコンピューターセキュリティの分野にも同種のデータベースがありますが、それらと同様に、AIインシデントデータベースも過去から学び、不適切な結果にならないように考慮したり、発生したインシデントに対処できるようになることを目的としています。", + "aboutLine2": "インシデントレポートを<1>投稿しましょう。投稿はすぐに登録され、世界中の人から<4>閲覧可能になります。情報を集約し、失敗から学ぶことなしに、人工知能は人類や社会にとって有益なものになることはできません。<6>(もっと読む)", + "The Database in Print": "データベースの紹介", + "readAboutTheDatabase": "<2>PAI Blog、<5>Vice News、<8>Venture Beat、<11>Wired、<14>arXivやその他の記事でこのデータベースが紹介されています。", + "Incident Report Submission Leaderboards": "インシデントレポート投稿ランキング", + "leaderboardDescription": "インシデントレポートの作成や投稿に貢献した人や組織です。詳細については<2>ランキングページを参照してください。", + "Wordcounts": "文字数", + "wordcountsDescription": "すべてのインシデントレポートの中で最もよく使われている語幹です。詳細については<2>データサマリーページを参照してください。", + "Random Reports": "ランダムレポート", + "raicDescription": "インシデントデータベースはAIインシデントデータベースの推進を目的として設立されたResponsible AI Collaborativeによるプロジェクトです。Collaborativeのガバナンスはこの重要なプログラムの参加者を中心に構成されています。詳細については<2>設立レポートを読んでください。さらに詳しい情報は<4>委員会と貢献者にあります", + "The Responsible AI Collaborative": "Responsible AI Collaborative", + "Database Founding Sponsor": "データベースの協賛スポンサー", + "In-Kind Sponsors": "協力スポンサー", + "New Incidents Contributed": "新しいインシデントの投稿", + "Reports added to Existing Incidents": "既存のインシデントに追加されたレポート", + "Total Report Contributions": "レポートへの協力の総計", + "Organization Founding Sponsor": "組織協賛スポンサー" +} diff --git a/site/gatsby-site/i18n/locales/ja/leaderboard.json b/site/gatsby-site/i18n/locales/ja/leaderboard.json new file mode 100644 index 0000000000..513d866bab --- /dev/null +++ b/site/gatsby-site/i18n/locales/ja/leaderboard.json @@ -0,0 +1,3 @@ +{ + "leaderboardHeader": "投稿者、作者、ドメインの登録数ランキングです。レポートの内容を確認するには<1>Discoverアプリを使用してください" +} \ No newline at end of file diff --git a/site/gatsby-site/i18n/locales/ja/login.json b/site/gatsby-site/i18n/locales/ja/login.json new file mode 100644 index 0000000000..c626de094a --- /dev/null +++ b/site/gatsby-site/i18n/locales/ja/login.json @@ -0,0 +1,26 @@ +{ + "Login": "ログイン", + "Sign up": "新規登録", + "Log out": "ログアウト", + "Password": "パスワード", + "Confirm password": "パスワード確認", + "Forgot password?": "パスワードがわかりませんか?", + "Login with Facebook": "Facebookでログイン", + "Login with Google": "Googleでログイン", + "Sign up with Facebook": "Facebookアカウントで新規登録", + "Sign up with Google": "Googleアカウントで新規登録", + "Logged in as ": "次の名前でログイン ", + "Logging you out...": "ログアウト中...", + "Succesfully sent password reset email": "パスワードリセットのためのメールを送信しました", + "Account created": "アカウントが作成されました", + "Enter new password": "新しいパスワードを入力してください", + "Confirm new password": "新しいパスワードを確認してください", + "Succesfully updated password, click here to ": "パスワードを更新しました。リンクをクリックしてください ", + "Don't have an account?": "アカウントがありませんか?", + "Already have an account?": "すでにアカウントをお持ちですか?", + "Verification email sent to {{email}}": "確認メールを{{email}}に送信しました", + "Your Account": "あなたのアカウント", + "Subscribe": "購読", + "Subscribe to Major Updates": "主な更新を購読します", + "Subscribe to New Incidents": "新しいインシデントを購読します" +} diff --git a/site/gatsby-site/i18n/locales/ja/popovers.json b/site/gatsby-site/i18n/locales/ja/popovers.json new file mode 100644 index 0000000000..20daf0a06c --- /dev/null +++ b/site/gatsby-site/i18n/locales/ja/popovers.json @@ -0,0 +1,78 @@ +{ + "title": { + "title": "ヘッドライン", + "text": "ほとんどの記事にはここにそのまま入力できるタイトルがあるでしょう。記事にタイトルがなければ、個人的な意見を含めずに本文を数単語でまとめてください。このテキストはインシデントレコードで特に目立つように表示されます" + }, + "authors": { + "title": "リンクされたコンテンツの作者", + "text": "リンクされたコンテンツの作者の名前を入力してください。Enterボタンで改行できます" + }, + "submitters": { + "title": "あなたです!", + "text": "あなたの名前をここに入力してください。インシデントを収集するのに複数の人が関わっている場合は、Enterキーを押下して改行してください。データベースに記録されたくなければ投稿者として代わりに\"Anonimous\"と入力しても構いません。このフィールドの内容は公開ランキングで使用されます" + }, + "incident_date": { + "title": "このインシデントが最初に発生したのはいつですか?", + "text": "AIインシデントの多くは独立したイベントではありません(つまり、ある一定の期間にわたって発生し続けます)。さらに、最初に発生してしばらくたってから初めてレポートが公開された場合は最初に発生したのがいつかを確認することが難しいこともよくあります。このフィールドにはインシデントが最初に報告された日か、最初に発生したと思われると推測される日を入力してください。例えば、一月にローンチされた検索エンジンの機能に付随するインシデントの最初のインシデントレポートが2月に公開されたとすると、インシデント発生日は1月になるでしょう" + }, + "date_published": { + "title": "レポートが利用可能になったのはいつですか?", + "text": "レポートのURLに公開日がよく含まれていますが、なかったとしてもWayback Machineを見ると、レポートURLのインデックスが最初に登録された日を確認できます" + }, + "date_downloaded": { + "title": "レポートの内容をこのフォームにコピーしたのはいつですか?", + "text": "時間の経過にしたがってレポートはニュース会社によって更新されることがあります。この日付は内容が古くなっているかどうかを判断するために利用できます。通常は今日の日付をここに入力してください" + }, + "url": { + "title": "公開されたレポートへのリンク", + "text": "このアドレスは多くのインシデントデータベースのUIのリンクで使用されます" + }, + "image_url": { + "title": "インシデントレポートのプレビューに使用される画像", + "text": "インデックスされレポートの次に表示される画像のURLです。今はほとんどの出版物にはヘッドライン画像があり、右クリックでURLを確認できます。代わりに図の画像をリンクすることもできます。不正なURLが入力されると、フォールバック画像が代わりに使用されます" + }, + "incident_id": { + "title": "すでに登録済みのインシデントですか?", + "text": "インシデントデータベースに登録済みのインシデントについてのレポートが投稿されることがよくあります。投稿する前に、\"Discover\"アプリを使用して投稿しようとしているインシデントレポートとにているインシデントを検索し、そのインシデントがすでにデータベースに存在するかどうかを確認してください。もしレポートが扱っているインシデントが存在し、そのレポートがまだ投稿されていないなら、対応するインシデント番号をここに入力してください。インシデントレポートがすでに存在する場合は、再投稿はしないでください" + }, + "text": { + "title": "記事のテキストか動画などの内容", + "text": "インシデントの文章による説明をコピー&ペーストして上のリンクURLの内容と一致するか確認してください。広告やその他のメディアは、インデックスされてユーザーがデータベースを検索するときに使用されることがないように、事前にすべて取り除いてください" + }, + "reportAddress": { + "title": "公開されたレポートへのリンク", + "text": "このアドレスは多くのインシデントデータベースのUIのリンクで使用されます" + }, + "tags": { + "title": "インシデントレポートのタイプを表すタグ", + "text": "レポートタグの目的はインシデントの引用ページでレポートの並び替えをサポートすることです。よくわからなければ、このフィールドを空白のままにしてください。データベースに取り込むときにエディタが適切なタグを選択します" + }, + "language": { + "title": "インシデントレポートに使用されている言語", + "text": "レポートのテキストを記述するために使用されている言語です。レポートに関係する人々や国の言語ではありません。レポートはテキストを取り込んだ後でサポートされている言語に翻訳されます" + }, + "harmed_parties": { + "title": "影響を受けたもしくは影響を受ける可能性のあった組織", + "text": "複数ある場合は、Enterを押下して新しい行を追加します" + }, + "deployers": { + "title": "AIシステムを提供している組織", + "text": "複数ある場合は、Enterを押下して新しい行を追加します" + }, + "developers": { + "title": "AIシステムを開発した組織", + "text": "複数ある場合は、Enterを押下して新しい行を追加します" + }, + "description": { + "title": "説明", + "text": "インシデントに関するインシデント/問題、場所、障害についての、簡潔で、事実に基づき、ジャーナリストのように中立で、まとまった説明" + }, + "inputs_outputs": { + "title": "入力/出力", + "text": "インシデントに関係する知能システムに入力されるデータと、そのシステムによって生成される出力の流れ。チャットボットであれば、一般に人間とチャットボットの反応が交互に発生します" + }, + "submittersLoggedIn": { + "title": "あなたです!", + "text": "現在ログイン中なのでこの投稿は自動的にあなたのアカウントに関連づけられます。匿名で投稿するには、ブラウザウィンドウを匿名モードで開いて投稿してください。" + } +} diff --git a/site/gatsby-site/i18n/locales/ja/sponsors.json b/site/gatsby-site/i18n/locales/ja/sponsors.json new file mode 100644 index 0000000000..cd74a88693 --- /dev/null +++ b/site/gatsby-site/i18n/locales/ja/sponsors.json @@ -0,0 +1,12 @@ +{ + "Organization Founding Sponsor": "組織協賛スポンサー", + "Database Founding Sponsor": "データベース協賛スポンサー", + "Sponsors and Grants": "スポンサーと助成", + "In-Kind Sponsors": "協力スポンサー", + "sponsor-Waking Up Foundation": "Longview Philanthropyに従って、[Waking Up Foundation](https://www.wakingup.com/foundation)はAIインシデントデータベースに直接55万ドルの助成金を拠出しました。このうち3万3000ドルは財政スポンサーに委託され、組織の財務と税金の管理に使用されます。約5万ドルは財政スポンサーによって援助されているAIIDプログラムを指揮する非営利団体RAICを維持するために使用されます。残りの資金はスタッフがプログラミングや調査する時間を含む、プログラムに関係する成果をうみだすために使用されます", + "sponsor-Partnership on AI": "AIインシデントデータベース(AIID)の[協賛スポンサー](https://partnershiponai.org/resource/tracking-when-ai-systems-fail/)として、Partnership on AIは、Responsible AI Collaborativeの資金よりも前にプロジェクトをサポートするための基金を含め、データベースの立ち上げを援助してくれました。Partnership on AIはまた、AIIDの社会的な利益を促進するために、パートナーやそのほかの利害関係者へも投資し、その成果を支援することに継続的な関心を持っています", + "sponsor-Mozilla Foundation": "Responsible AI CollaborativeはMozilla Technology FundからAIリスクチェックリスト開発のために50,000ドルの助成を受けました。このプロジェクトの詳細については[ローンチのアナウンス](https://foundation.mozilla.org/en/blog/auditing-ai-announcing-the-2023-mozilla-technology-fund-cohort/)を開き、事前に私たちがアナウンスしたCollabブログを見てください", + "sponsor-Netlify": "[Netlify](https://www.netlify.com/)はResponsible AI Collaborativeに対して、AIインシデントデータベースに必要なホスティング、ビルド時間、アカウントを無料で提供してくれています", + "sponsor-Cloudinary": "[Cloudinary](https://www.cloudinary.com/)は画像・動画配信のためにクラウドホスティングサービスを安価に提供してくれています。データベースで多くの画像に高速にアクセスできるのはかれらのおかげです", + "sponsor-Algolia": "[Algolia](https://algolia.com/)はResponsible AI Collaborativeに対して、インシデントレポートのインスタント検索を提供してくれています" +} \ No newline at end of file diff --git a/site/gatsby-site/i18n/locales/ja/submit.json b/site/gatsby-site/i18n/locales/ja/submit.json new file mode 100644 index 0000000000..287902fb08 --- /dev/null +++ b/site/gatsby-site/i18n/locales/ja/submit.json @@ -0,0 +1,62 @@ +{ + "New Incident Report": "新しいインシデントレポート", + "New Incident Response": "新しいインシデントレスポンス", + "submitFormDescription": "以下のフォームを使用すると新しいインシデントレポートを作成できます。インシデントは<2>レビュー後にAIインシデントデータベースに登録されます。アスタリスク(️*)で始まるフィールドは必須入力です。問題の内容は注意深く記入してください(例えば、広告を間違えてコピー&ペーストしてしまわないように)。データベース登録プロセスの詳細については<5>リサーチページを確認するか<8>私たちに質問してください", + "submitFormResponseDescription1": "以下のフォームを使用するとインシデント <3>#{{incident_id}}のための新しいインシデントレスポンスを作成でき、<6>レビュー後にAIインシデントデータベースに登録されます", + "submitFormResponseDescription2": "以下のフォームを使用すると新しいインシデントレスポンスを作成でき、<2>レビュー後にAIインシデントデータベースに登録されます", + "submitFormResponseDescription3": "アスタリスク(️*)で始まるフィールドは必須入力です。問題の内容は注意深く記入してください(例えば、広告を間違えてコピー&ペーストしてしまわないように)。データベース登録プロセスの詳細については<2>リサーチページを確認するか<5>私たちに質問してください", + "Report Address": "レポートのURL", + "submitReviewDescription": "投稿されたレポートは<1>レビューキューに追加され、新しいインシデントレコードか既存のインシデントレコードになります。インシデントはある程度纏まったところでレビューされ、データベースに追加されます", + "Fetch info": "内容を取り込む", + "Fetching...": "取り込み中...", + "Title": "タイトル", + "Report title": "レポートのタイトル", + "Author(s)": "作者", + "Submitter(s)": "投稿者", + "Date Published": "公開日", + "Date Downloaded": "ダウンロード日", + "Image Address": "画像アドレス", + "Image URL": "画像URL", + "Report Language": "レポートの言語", + "Leave empty to report a new incident": "新しいインシデントをレポートする場合は、空欄のままにする", + "Incident Date": "インシデント発生日", + "Editor Notes": "エディタメモ", + "Optional context and notes about the incident": "インシデントに関する追加の情報やメモ", + "Report URL": "レポートURL", + "Incident IDs": "インシデントID", + "Language": "言語", + "Text": "言語", + "CSVDescription": "ファイルのヘッダー行はフォームの入力欄の名前とみなされます。各行は投稿前にフォームのバリデーションを確認しながらひとつずつ処理されます", + "Advanced: Add by CSV": "高度な機能: CSVで追加する", + "Was not able to create the report, please review the form and try again.": "レポートが作成できなかった場合は、フォームを確認してもう一度試してください", + "It will appear on the <2>review queue page within an hour.": "1時間以内に<2>レビューキューページに表示されます", + "Incident Description": "インシデントの説明", + "Report successfully added to review queue. You can see your submission <2>here.": "レポートはレビューキューに追加されました。<2>ここで投稿を確認できます", + "You can see your submission <2>here.": "<2>ここで投稿を確認できます", + "Alleged developer of AI system": "AIシステムの推定開発者", + "Alleged deployer of AI system": "AIシステムの推定提供者", + "Alleged harmed or nearly harmed parties": "推定される被害グループ", + "Who created or built the technology involved in the incident?": "このインシデントに関係する技術を構築したのは誰ですか?", + "Who employed or was responsible for the technology?": "この技術を採用もしくはこの技術に責任があるのは誰ですか?", + "Who experienced negative impacts?": "悪影響を受けたのは誰ですか?", + "Your name as you would like it to appear in the leaderboard": "ランキングに表示されても構わないのであれば、あなたの名前", + "The author or authors of the report": "レポートの著者", + "Description": "説明", + "Report Description": "レポートの説明", + "Tags": "タグ", + "Tell us more...": "さらに入力する...", + "Report successfully added to review queue": "レポートはレビューキューに追加されました", + "Review queue": "レビューキュー", + "Author CSV": "著者のCSV", + "Submitter CSV": "投稿者のCSV", + "Enter a valid Incident ID": "妥当なインシデントIDを入力してください", + "Step 1 - main information": "ステップ 1 - 主要な情報", + "Step 2 - additional information": "ステップ 2 - 追加の情報", + "Step 3 - Tell us more": "ステップ 3 - さらに入力", + "Adding a new report to incident {{incident_id}}": "インシデント {{incident_id}} に新しいレポートを追加", + "Adding a new response to incident {{incident_id}}": "インシデント {{incident_id}} に新しいレスポンスを追加", + "Progress saved!": "途中経過が保存されました!", + "Your changes are saved. You can continue filling out the report or come back later.": "変更が保存されました。このままレポートの入力を続けても、あとで再開しても構いません", + "Clear Form": "フォームをクリアする", + "Saving changes...": "変更を保存中..." +} diff --git a/site/gatsby-site/i18n/locales/ja/submitted.json b/site/gatsby-site/i18n/locales/ja/submitted.json new file mode 100644 index 0000000000..d46dab1936 --- /dev/null +++ b/site/gatsby-site/i18n/locales/ja/submitted.json @@ -0,0 +1,41 @@ +{ + "Submitted Incident Report List": "投稿されたインシデントレポートリスト", + "description": "以下のインシデントレポートはユーザーによって<1>投稿され、エディタによるレビュー待ちです。エディタがこの投稿をインシデントレポートに更新するまでデータベースには登録されません", + "Quick Add URLs": "かんたん追加URL", + "quickaddDescription": "これらのレポートはユーザーによってランディングページのかんたん追加フォームから匿名で追加されました", + "Loading Quick Adds...": "かんたん追加を読み込み中...", + "Successfully promoted submission to Incident {{incident_id}} and Report {{report_number}}": "投稿をインシデント {{incident_id}}とレポート{{report_number}}に更新することに成功しました", + "Successfully promoted submission to <2>Incident {{incident_id}} and Report {{report_number}}": "投稿を<2>インシデント {{incident_id}}とレポート {{report_number}}に更新することに成功しました", + "Add new Incident": "新しいインシデントを追加", + "Add to incident {{id}}": "インシデント {{id}}に追加", + "Add to incidents {{id}}": "インシデント {{id}}に追加", + "Reject New Incident": "新しいインシデントを却下", + "Reject New Report": "新しいレポートを却下", + "Loading Submissions...": "投稿を読み込み中...", + "Add as issue": "イシューを追加", + "Are you sure this is a new issue? Any data entered that is associated with incident records will not be added": "これは新しいイシューですか?インシデントレコードに関連づけられた入力データは追加されません", + "Successfully promoted submission to Issue {{report_number}}": "投稿をイシュー {{report_number}}に更新することに成功しました", + "Are you sure this is a new incident? This will create a permanent record with all the details you provided about the incident.": "これは新しいインシデントですか?インシデントについてあなたが提供した詳細情報はすべて永続的に記録されます", + "Sure you want to promote this Submission and link it to Incident {{incident_id}}?": "この投稿を更新してインシデント {{incident_id}}にリンクしますか?", + "Are you sure you want to delete “{{url}}”?": "次のURLを本当に削除しますか? “{{url}}”", + "Editing Submission": "投稿を編集中", + "Pending Review": "レビューを中断中", + "Back to Submission List": "投稿リストに戻る", + "Editors": "エディタ", + "Unassigned": "担当者未定", + "Status": "ステータス", + "In Review": "レビュー中", + "Add as new": "新規に追加", + "Accept": "受理", + "Reject": "却下", + "Promoting to incident": "インシデントに更新中", + "Promoting to issue": "イシューに更新中", + "Adding as incident": "インシデントとして追加", + "Adding as issue": "イシューとして追加", + "Are you sure you want to reject this submission? This will permanently delete the submission.": "この投稿を本当に却下しますか?投稿は完全に削除されます", + "Changes saved": "変更が保存されました", + "There was an error claiming this submission. Please try again.": "この投稿の実行にエラーが発生しました。もう一度試してください", + "Claim": "再投稿", + "Claiming...": "再投稿中...", + "Reviewing": "レビュー中" +} diff --git a/site/gatsby-site/i18n/locales/ja/translation.json b/site/gatsby-site/i18n/locales/ja/translation.json new file mode 100644 index 0000000000..056bb75961 --- /dev/null +++ b/site/gatsby-site/i18n/locales/ja/translation.json @@ -0,0 +1,291 @@ +{ + "Clear Filters": "フィルターのクリア", + "Filter Search": "フィルター", + "Type Here": "ここに入力してください", + "<0>{{count}} reports found": "<0>{{count}}件のレポートが見つかりました", + "Classifications": "クラス", + "Source": "情報源", + "Authors": "作者", + "Submitters": "投稿者", + "Incident ID": "インシデントID", + "Incident Date": "インシデント発生日", + "Published Date": "公開日", + "Flagged": "フラグあり", + "No result": "結果がありません", + "Clear": "クリア", + "From Date": "開始日", + "To Date": "終了日", + "Close": "閉じる", + "Show Details on Incident #{{id}}": "インシデント#{{id}}の詳細を表示", + "Filter by Incident ID #{{id}}": "インシデントID #{{id}}でフィルタリング", + "Flag Report": "レポートにフラグを立てる", + "Filters": "フィルタ", + "Options": "オプション", + "Search Options": "検索オプション", + "1st report only": "最初のレポートのみ", + "Suggested citation format": "推奨される引用形式", + "Incident Stats": "インシデントのステータス", + "Reports Timeline": "レポートタイムライン", + "Tools": "ツール", + "New Report": "新しいレポート", + "All Incidents": "すべてのインシデント", + "Discover": "発見する", + "Edit Incident": "インシデントを編集", + "Clone Incident": "インシデントを複製", + "BibTex Citation": "BibText引用", + "Taxonomy Details": "分類法の詳細", + "Classifications will update in production within 24 hours.": "クラスは24時間以内に本番環境で更新されます", + "Report Count": "レポート数", + "Editors": "エディタ", + "{{namespace}} Taxonomy Classifications": "{{namespace}} 分類法のクラス", + "No classifications for this taxonomy.": "この分類法のためのクラスはありません", + "Edit": "編集", + "Incidents Reports": "インシデントレポート", + "Incident Reports": "インシデントレポート", + "Previous Incident": "前のインシデント", + "Next Incident": "次のインシデント", + "Incident {{id}}": "インシデント {{id}}", + "Citation record for Incident {{id}}": "インシデント {{id}}の引用情報", + "Search": "検索する", + "Submit": "投稿する", + "Report URL": "レポートのURL", + "Welcome to the AIID": "ようこそAIIDへ", + "About": "About", + "AIID Blog": "AIIDブログ", + "Database Apps": "データベースアプリ", + "Researcher Guide": "研究者向けガイド", + "Taxonomies": "分類法", + "Contact and Follow": "コンタクトとフォロー", + "Launch Announcement": "立ち上げのアナウンス", + "Selected Image": "選択された画像", + "Previous": "前へ", + "Next": "次へ", + "Click to upload": "クリックしてアップロード", + "Delete": "削除", + "Incidents reports matched by published date: <1>{{date}}": "公開日: <1>{{date}}に一致するインシデントレポート", + "Incident matched by ID: <1>{{id}}": "ID: <1>{{id}}に一致するインシデント", + "Incidents reports matched by authors: <1>{{authors}}": "作者: <1>{{authors}}に一致するインシデントレポート", + "Incidents reports matched by URL: <1>{{url}}": "URL: <1>{{url}}に一致するインシデントレポート", + "AI Translated": "自動翻訳済み", + "View Original": "オリジナルを表示", + "Search over 3000 reports of AI harms": "AI加害の3000県以上のレポートを検索", + "Search 3000+ AI harm reports": "3000件以上のAI加害レポートを検索", + "Search 3000+ reports": "3000件以上のレポートを検索", + "Search reports": "レポート検索", + "Discover Incidents": "インシデントを発見", + "Submit Incident Reports": "インシデントレポートを投稿", + "All Incidents in List Form": "リスト形式で全てのインシデントを表示", + "Submission Leaderboard": "投稿ランキング", + "Classifications View": "クラス表示", + "Flagged Incidents": "フラグの立ったインシデント", + "Word Counts": "文字数カウント", + "Read More": "さらに読む", + "Email address": "メールアドレス", + "or": "または", + "An unknown error has occurred": "不明なエラーが発生しました", + "Invalid email": "不正なEメール", + "Passwords must match": "パスワードが一致しません", + "Required": "必須", + "Password must be at least 6 characters long": "パスワードは少なくとも6文字必要です", + "Password must be less than 128 characters long": "パスワードは128文字までです", + "user not found": "ユーザーが見つかりません", + "invalid token data": "不正なトークンデータです", + "invalid username/password": "不正なユーザ名/パスワードです", + "password must be between 6 and 128 characters": "パスワードは6文字から128文字まででなければいけません", + "name already in use": "名前はすでに使用されています", + "View the original report at its source": "情報源として元のレポートを表示", + "View the report at the Internet Archive": "インターネットアーカイブでレポートを表示", + "Similar Incidents": "よく似たインシデント", + "By textual similarity": "テキスト類似度による", + "Did our AI mess up? Flag <3> the unrelated incidents": "私たちのAIが混乱していますか?無関係のインシデントとしてフラグを立ててください", + "reports": "レポート", + "report": "レポート", + "Flag reverted.": "フラグ反転", + "Incident flagged successfully. Our editors will remove it from this list if it not relevant.": "インシデントのフラグ付けに成功しました。エディタが不適切だと判断するとリストから削除されます", + "Color by incident classifications from taxonomies": "分類法に基づいてインシデントクラスによって色付け", + "This Incident in Semantic Space": "意味空間でのこのインシデント", + "The visualization below shows incidents closer together when a <2>natural language processing system identifies their text as being semantically similar.": "以下の可視化では<2>自然言語処理システムによってテキストの意味が類似していると判断されたインシデント同士が近くに表示されます", + "tsneDescription": "上の空間ビューはデータベース内のそれぞれのインシデントがそのインシデントID番号を含む点として表示されます。インシデントはレポートのテキストが似ているもの同士が近くなるように配置されます。例えば、自動運転車に関係するインシデントは密なクラスタを構成します。インシデントの類似度は自然言語処理システムを使用して求められます。詳細については<1>その開始に関するブログ記事を参照してください", + "review": "レビュー", + "Loading...": "読み込み中...", + "Incident report {{reportNumber}} updated successfully. <4>View Incident {{incidentId}}.": "インシデントレポート {{reportNumber}}を更新しました。<4>インシデント {{incidentId}}を表示する.", + "Error updating incident report {{reportNumber}}.": "インシデントレポート {{reportNumber}}更新エラー", + "Incident report {{reportNumber}} deleted successfully.": "インシデントレポート {{reportNumber}}を削除しました", + "Error deleting incident report {{reportNumber}}.": "インシデントレポート {{reportNumber}}削除でエラーが発生しました", + "Incident {{incidentId}} updated successfully. <4>View incident {{incidentId}}.": "インシデント {{incidentId}}を更新しました。<4>インシデント {{incidentId}}を表示する.", + "Error updating incident {{incidentId}}.": "インシデント {{incidentId}}更新でエラーが発生しました", + "Error updating incident {{incident}}. \n {{message}}": "インシデント {{incident}}更新でエラーが発生しました。\n {{message}}", + "Are you sure you want to delete this report?": "このレポートを本当に削除しますか?", + "Notify Me of Updates": "更新を通知する", + "Subscribed to Updates": "更新を購読する", + "Please go to your <1>account to manage subscriptions": "購読を管理するには<1>アカウントページを表示してください", + "Please <2>log in to subscribe": "購読するには<2>ログインが必要です", + "Invalid parameters": "不正なパラメータ", + "Unsubscribe": "購読停止", + "Do you want to unsubscribe from <2>incident {{incidentId}} updates?": "<2>インシデント {{incidentId}}の更新の購読を停止しますか?", + "Do you want to unsubscribe from all notifications?": "すべての通知の購読を停止しますか?", + "Do you want to unsubscribe from new Incidents notifications?": "新しいインシデントの通知の購読を停止しますか?", + "Notify Me of New {{name}} Incidents": "新しい{{name}}インシデントを通知する", + "Unsubscribe from New {{name}} Incidents": "新しい{{name}}インシデントの購読を停止する", + "Follow": "フォローする", + "Unfollow": "アンフォローする", + "You have successfully subscribed to new {{name}} incidents": "新しい{{name}}インシデントの購読を開始しました", + "You have successfully unsubscribed to new {{name}} incidents": "新しい{{name}}インシデントの購読を停止しました", + "Confirm": "確認する", + "Continue": "続ける", + "You have successfully unsubscribed.": "購読を停止しました", + "You have successfully subscribed to updates on incident {{incidentId}}": "インシデント {{incidentId}}の更新を購読しました", + "You have successfully create Incident {{newIncidentId}}": "インシデント {{newIncidentId}}を新規作成しました", + "View all": "全て表示", + "Fetching Incidents...": "インシデント読み込み中...", + "Fetching Reports...": "レポート読み込み中...", + "Spatial Visualization": "空間的な可視化", + "Spatial View": "空間ビュー", + "Fetching...": "読み込み中...", + "Title": "タイトル", + "Description": "概要", + "Date": "日付", + "Alleged Deployer of AI System": "推定されるAIシステム提供者", + "Alleged Developer of AI System": "推定されるAIシステム開発者", + "Alleged Harmed or Nearly Harmed Parties": "推定される被害者もしくはその可能性があった者", + "Actions": "アクション", + "Search {{count}} records...": "{{count}} 件のレコードを検索...", + "Report Authorship": "レポート所有者", + "Report Domains": "レポートのドメイン", + "By": "Por", + "More": "Más", + "Thank you for verifying your account.": "アカウントを確認いただきありがとうございます", + "Read more": "さらに読む", + "Table View": "テーブル表示", + "Submitting...": "投稿中...", + "View Less": "閉じる", + "View ({{hidden}}) more": "さらに見る ({{hidden}})", + "and": "と", + "Home": "ホーム", + "Add more info": "情報をさらに追加", + "List of taxonomies": "分類法の一覧", + "This is the list of taxonomies supported in AIID": "AIIDがサポートしている分類法の一覧です", + "Applied Taxonomies": "採用された分類法", + "<0>Center for Security and Emerging Technology (CSETv1). This is a taxonomy detailing many attributes of AI incidents of relevance to the public policy community.": "<0>Center for Security and Emerging Technology (CSET). 公共政策コミュニティに関係するAIインシデントの様々な属性の詳細に関する分類法です", + "In-Development Taxonomies": "開発中の分類法", + "<0>Resources. This is a taxonomy that will associate incidents with resources that help understand, mitigate, and prevent incidents from recurring in the future.": "<0>Resources. インシデントの理解と対策、また将来インシデントが繰り返されないようにするためのリソースとインシデントを関連づけるための分類法です", + "About Taxonomies": "分類法について", + "Collapse": "閉じる", + "Expand": "開く", + "Taxonomies are contributed to the AI Incident Database by persons and organizations working to structure the data and provide views into the data. Each taxonomy must be of sufficient quality and completeness to be included in the AI Incident Database, but the taxonomies are the responsibility of the persons and organizations contributing them.": "分類法はデータを構造化してデータにさまざまな視点を導入しようとしている個人や組織によってAIインシデントデータベースに提供されます。AIインシデントデータベースに組み込まれているそれぞれの分類法は十分な品質と完全性を備えているはずですが、分類法自体の責任は提供している個人や組織にあります", + "Load more": "さらに読み込む", + "Entities": "組織", + "New Response": "新しいレスポンス", + "Response": "レスポンス", + "Responded": "レスポンスしました", + "{{authors}} post-incident response": "{{authors}}によるインシデント後のレスポンス", + "Display Issues": "イシューを表示", + "Only Issues": "イシューのみ", + "Report {{report_number}}": "レポート {{report_number}}", + "Show Details on Issue #{{id}}": "イシュー #{{id}}の詳細を表示", + "ORDER": "ORDER", + "asc": "asc", + "desc": "desc", + "Asc": "Asc", + "Desc": "Desc", + "Submitted Date": "投稿日", + "Back to Incident {{incidentId}}": "インシデント {{incidentId}}に戻る", + "Back to Report {{reportNumber}}": "レポート {{reportNumber}}に戻る", + "Editing Incident Report {{reportNumber}}": "インシデントレポート {{reportNumber}}を編集中", + "Editing Incident {{incidentId}}": "インシデント {{incidentId}}を編集中", + "{{count}} Incident Reports found": "{{count}}件のインシデントレポートが見つかりました", + "{{count}} Incidents found": "{{count}}件のインシデントが見つかりました", + "{{count}} Incident and Issue Reports found": "{{count}}件のインシデントとイシューレポートが見つかりました", + "{{count}} Issue Reports found": "{{count}}件のイシューレポートが見つかりました", + "Manufacturing": "製造業", + "Electricity, gas, steam and air conditioning supply": "電気・ガス・蒸気及び空調供給業", + "Water supply": "水供給", + "Construction": "建設業", + "Wholesale and retail trade": "卸売・小売業", + "Transportation and storage": "運輸・保管業", + "Accommodation and food service activities": "宿泊・飲食サービス業", + "Information and communication": "情報通信業", + "Financial and insurance activities": "金融・保険業", + "Real estate activities": "不動産業", + "Professional, scientific and technical activities": "専門、科学、技術サービス業", + "Administrative and support service activities": "管理・支援サービス業", + "Public administration and defence": "公務及び国防", + "Education": "教育", + "Human health and social work activities": "保健衛生及び社会事業", + "Arts, entertainment and recreation": "芸術・娯楽及びレクリエーション", + "Other service activities": "その他のサービス業", + "Activities of households as employers": "雇い主としての世帯活動", + "Activities of extraterritorial organizations and bodies": "治外法権機関及び団体", + "Sector of Deployment": "導入分野", + "Harm Distribution Basis": "危害分配基準", + "Severity": "深刻度", + "Harm Type": "危害のタイプ", + "Intent": "意図", + "Near Miss": "ニアミス", + "Problem Nature": "問題の性質", + "System Developer": "システム開発者", + "paginationKey": "{{currentPageIndex}} / {{pageOptionsLength}} ページ", + "Show {{pageSize}}": "{{pageSize}}件表示", + "Show all": "全て表示", + "Go to page:": "次のページを表示", + "Showing the": "分類を表示", + "taxonomy": "分類法", + "Reset filters": "フィルタをリセット", + "Incident {{number}}": "インシデント {{cell}}", + "Datasheets for Datasets": "データセットのためのデータシート", + "MSFT AI Fairness Checklist": "MSFT AI公正性チェックリスト", + "Publish": "公開", + "No results found": "結果が見つかりません", + "{{currentTaxonomy}} taxonomy page": "{{ currentTaxonomy }} 分類法ページ", + "Incident": "インシデント", + "Reviewer": "レビュアー", + "Quality Control": "品質コントロール", + "All": "すべて", + "Sort by": "並び替え", + "Display Option": "表示オプション", + "Export": "エクスポート", + "Export items from the current page to a CSV file.
To download the full data set, please follow this <4>link.": "現在のページからアイテムをCSVファイルとしてエクスポートします
すべてのデータセットをダウンロードするには<4>linkに従ってください", + "Relevance": "関連性", + "Newest Incident Date": "最新のインシデント発生日", + "Oldest Incident Date": "最も古いインシデント発生日", + "Newest Published Date": "最新の公開日", + "Oldest Published Date": "最も古い公開日", + "Newest Submitted Date": "最新の投稿日", + "Oldest Submitted Date": "最も古い投稿日", + "Subscribe": "購読", + "Account": "アカウント", + "Citation Info": "引用情報", + "Citing this specific format will make it possible for the Incident Database to find your research and include it on this page.": "この特定の形式で引用するとインシデントデータベースがあなたの研究を見つけてこのページに追加できます", + "Copy": "コピー", + "Suggested Citation Format": "おすすめの引用形式", + "{{submitterCite}}. ({{incidentDate}}) Incident Number {{incidentId}}. in {{editorLastName}}, {{editorFirstNameInitial}} (ed.) Artificial Intelligence Incident Database. Responsible AI Collaborative. {{retrievalString}}": "{{submitterCite}}. ({{incidentDate}}) Incidente Número {{incidentId}}. in {{editorLastName}}, {{editorFirstNameInitial}} (ed.) Artificial Intelligence Incident Database. Responsible AI Collaborative. {{retrievalString}}", + "Retrieved on {{date}} from incidentdatabase.ai/cite/{{incidentId}}.": "Retrieved on {{date}} from incidentdatabase.ai/cite/{{incidentId}}.", + "Show Live data": "ライブデータを表示", + "Posted <1> by <3>.": "<1>は<3>によって投稿されました", + "Subscribe to the AI Incident Briefing and get monthly incident round-ups along with occasional major database updates.": "AIインシデントブリーフィングを購読すると、データベースの定期更新の内容を含む、インシデントのまとめが毎月手に入ります", + "Check your inbox for the AI Incident Briefing, which includes incident round-ups along with occasional major database updates. You can manage your subscription status from the links in the email footer.": "インボックスのAIインシデントブリーフィングを確認してください。定期的なデータベースの更新を含む、月次のインシデント総括を確認できます。購読の状況はメールのフッターのリンクで管理できます", + "Image URL is invalid, using fallback image": "画像URLが不正です。フォールバック画像を使用します", + "Issue": "イシュー", + "You have successfully create Incident {{newIncidentId}}. <4>View incident.": "インシデント {{newIncidentId}}を作成しました。<4>インシデントを表示する.", + "New Incident": "新しいインシデント", + "No words found": "単語が見つかりません", + "No incidents found": "インシデントが見つかりません", + "forms": "Responsible AI Collaborativeの<2>書式990と<6>非課税証明書を確認してください", + "csetCharts": "AIIDのCSET AI危害分類法はCSETインシデント分類法の第二版です。AIインシデントに含まれる危害、組織、技術、発生状況を特徴づけます。以下の図はCSET AI危害分類法から選択されたフィールドを示します。それぞれのフィールドの詳細については<1>ここで確認してください。ただし、それぞれの図の上に簡単な説明があります", + "The taxonomy provides the CSET definition for AI harm.": "この分類法はAI危害についてのCSETによる定義を示します", + "AI harm has four elements which, once appropriately defined, enable the identification of AI harm. These key components serve to distinguish harm from non-harm and AI harm from non-AI harm. To be an AI harm, there must be:": "AI危害には適切に判定するとAI危害と判断できるようになる4つの要素があります。これらのキー要素によって危害と非危害、AI危害と非AI危害の区別が可能になります。AI危害については次が成り立たなければいけません", + "1) an <1>entity that experienced": "1) <1>組織は以下のことを被る", + "2) a <1>harm event or <2>harm issue that": "2) <1>危害が発生もしくは<2>危害が発覚", + "3) can be <1>directly linked to a consequence of the behavior of": "3) 上記は以下の振る舞いの結果と<1>直接的に関連づけることが可能", + "4) an <1>AI system.": "4) <1>AIシステム.", + "All four elements need to be present in order for there to be AI harm.": "この4つの要素がすべて存在しなければ、対象はAI危害とは言えません", + "Not every incident in AIID meets this definition of AI harm. The below bar charts show the annotated results for both all AIID incidents and incidents that meet the CSET definition of AI harm.": "AIIDに含まれる全てのインシデントがこのAI危害の定義を満たすわけではありません。以下の棒グラフはすべてのAIIDインシデントとCSETのAI危害定義を満たすインシデント両方の注釈付きの結果を示します。", + "csetChartDeveloped": "CSETは下線部について特別な定義を作成しましたが、それは他の組織とは異なる可能性があります。そのため、他の組織はある特定のAIインシデントがAI危害かどうかについて異なった評価を行う可能性があります。CSETのAI危害についての詳細については<1>ここを参照してください", + "csetChartMail": "すべてのインシデントは2人のCSETアノテーターによって独立して分類されます。アノテーションはピアレビューされ、最終的に公開に先立って品質管理のためにランダムで選択されます。この厳密なプロセスにも関わらず、誤りは起こり得るため、読者が閲覧中にエラーに遭遇した場合には<1>レポートを促されます", + "[Untitled Report]": "[タイトルのないレポート]", + "Blog": "ブログ", + "AI News Digest": "AIニュースダイジェスト", + "Remove Duplicate": "重複を削除する", + "View History": "履歴を表示", + "CSET Annotators Table": "CSETアノテーターテーブル" +} diff --git a/site/gatsby-site/i18n/locales/ja/validation.json b/site/gatsby-site/i18n/locales/ja/validation.json new file mode 100644 index 0000000000..9dcfd40b74 --- /dev/null +++ b/site/gatsby-site/i18n/locales/ja/validation.json @@ -0,0 +1,17 @@ +{ + "*URL required": "*URLは必須です", + "*Title is required": "*タイトルは必須です", + "*Author is required. Anonymous or the publication can be entered.": "*作者は必須です。Anonymousや公開元を入力しても構いません", + "*Date published is required": "*公開日は必須です", + "*Date downloaded required": "*ダウンロード日は必須です", + "*Must enter URL in http://www.example.com/images/preview.png format": "*URLは http://www.example.com/images/preview.png のような形式でなければいけません", + "Incident ID": "インシデントID", + "Incident ID {{value}} not found!": "インシデント{{value}}が見つかりません!", + "Type and press Enter to add an item": "アイテムを追加するには入力してEnterを押下してください", + "*Text must have at least 80 characters": "*テキストは少なくとも80文字必要です", + "*Text can’t be longer than 50000 characters": "*50000文字を超えるテキストは登録できません", + "Please review report. Some data is missing.": "レポートを確認してください。足りない情報があります", + "Please review submission. Some data is missing.": "投稿を確認してください。足りない情報があります", + "Some data is missing.": "足りない情報があります", + "Please review. Some data is missing.": "確認してください。足りない情報があります" +} diff --git a/site/gatsby-site/i18n/locales/ja/variants.json b/site/gatsby-site/i18n/locales/ja/variants.json new file mode 100644 index 0000000000..0d680379c5 --- /dev/null +++ b/site/gatsby-site/i18n/locales/ja/variants.json @@ -0,0 +1,37 @@ +{ + "Variants": "バリアント", + "Incident ID": "インシデントID", + "Incident Title": "インシデントタイトル", + "Status": "ステータス", + "Input and circumstances": "入力と状況", + "Output and outcomes": "出力と報酬", + "Actions": "アクション", + "Approve": "受理", + "Approving": "受理中", + "Reject": "却下", + "Rejecting": "却下中", + "Save": "保存", + "Saving": "保存中", + "Edit more fields": "他のフィールドを編集", + "Edit Variant": "バリアントを編集", + "Variant not found": "バリアントがありません", + "Variant successfully updated. Your edits will be live within 24 hours.": "バリアントの更新に成功しました。編集内容は24時間以内に反映されます", + "Do you want to delete this variant?": "このバリアントを削除しますか?", + "Variant successfully deleted. Your changes will be live within 24 hours.": "バリアントの削除に成功しました。変更は24時間以内に反映されます", + "Provide the relevant details surrounding the incident. Examples include output text from a chatbot or the nature of injuries sustained from a robot.": "インシデント周辺の関係する詳細情報を追加。例えば、チャットボットの出力テキストやロボットから被った怪我の内容など", + "Provide the relevant details producing the incident. Examples include the input prompts to a chatbot or a description of the circumstances leading to injuries sustained from a robot.": "インシデントを誘引した関連する詳細情報を追加。例えば、チャットボットに入力したプロンプトやロボットから被った怪我を引き起こした状況の説明", + "Add Variant": "バリアントを追加", + "approved": "受理", + "rejected": "却下", + "unreviewed": "レビュー前", + "Your variant has been added to the review queue and will appear on this page within 12 hours. Please continue submitting when you encounter more variants. Most of the time we won't review it in the same day, but it will appear within a day as unreviewed.": "バリアントはレビューキューに追加され、12時間以内に表示されます。別のバリアントに遭遇したらまた投稿してください。同日にレビューされることはほとんどありませんが、一日以内に未レビューとして公開されます", + "A \"variant\" is an incident that shares the same causative factors, produces similar harms, and involves the same intelligent systems as a known AI incident. Rather than index variants as entirely separate incidents, we list variations of incidents under the first similar incident submitted to the database. Unlike other submission types to the incident database, variants are not required to have reporting in evidence external to the Incident Database. <2>Learn more from the research paper.": "「バリアント」は既存のAIインシデントと同じ原因要素を共有し、同様な被害を引き起こし、同じ知的システムを含んだインシデントです。バリアントは完全に独立したインシデントとしてインデックスするのではなく、データベースに最初に投稿された同様なインシデントの元にインシデントのバリエーションとして一覧します。インシデントデータベースの他の投稿タイプとは違い、バリアントではインシデントデータベース以外の根拠のレポートは要求されません。<2>詳細についてはこの研究論文を参照してください", + "Your variant has been added to the review queue and will appear on this page within 12 hours.": "バリアントはレビューキューに追加され、12時間以内にこのページに表示されます", + "Has Variant data": "バリアントがある", + "Description of Incident Circumstances": "インシデント状況の説明", + "Journalistic reporting on the circumstances of the incident to help inform people what happened, where, involving who, when, and why.": "なにが、どこで、誰を巻き込み、いつ、なぜ起きたかを理解する助けになるインシデントの周辺状況を伝える客観的なレポート", + "Inputs / Outputs": "入力/出力", + "The sequence of data inputs into the intelligent system and outputs produced by the system involved in the incident. For a chatbot, this will generally present a back and forth between a human and the chatbot's responses.": "インシデントに関係する知的システムへのデータ入力とシステムによって生成される出力の流れ。チャットボットの場合は、一般に人間とチャットボットの反応が行き来します", + "Add Row": "行を追加", + "Delete Row": "行を削除" +} diff --git a/site/gatsby-site/i18n/locales/ja/wordcount.json b/site/gatsby-site/i18n/locales/ja/wordcount.json new file mode 100644 index 0000000000..934a94d30c --- /dev/null +++ b/site/gatsby-site/i18n/locales/ja/wordcount.json @@ -0,0 +1,3 @@ +{ + "wordcountAbout": "インシデントレポートに登場する単語の使用数のランキングです。一般的な単語(つまりストップワード)は対象に含まれません。また、実際に使用された語形ではなく語幹が表示されます。登場数が10よりも少ない単語と文字数が3より少ない単語は含まれません。レポートの内容を確認するには<1>Discoverアプリを使用してください" +} \ No newline at end of file diff --git a/site/gatsby-site/migrations/2024.02.01T20.03.56.set-incidents-submissions-reports-created_at.js b/site/gatsby-site/migrations/2024.02.01T20.03.56.set-incidents-submissions-reports-created_at.js new file mode 100644 index 0000000000..25cdd8702c --- /dev/null +++ b/site/gatsby-site/migrations/2024.02.01T20.03.56.set-incidents-submissions-reports-created_at.js @@ -0,0 +1,180 @@ +const config = require('../config'); +/** + * + * @param {{context: {client: import('mongodb').MongoClient}}} context + */ + +exports.up = async ({ context: { client } }) => { + await client.connect(); + + // New created_at field on incidents, reports, submissions collections from production db and history db + const incidentsCollection = client.db(config.realm.production_db.db_name).collection('incidents'); + + const submissionsCollection = client + .db(config.realm.production_db.db_name) + .collection('submissions'); + + const reportsCollection = client.db(config.realm.production_db.db_name).collection('reports'); + + const incidentsHistoryCollection = client + .db(config.realm.production_db.db_history_name) + .collection('incidents'); + + const submissionsHistoryCollection = client + .db(config.realm.production_db.db_history_name) + .collection('submissions'); + + const reportsHistoryCollection = client + .db(config.realm.production_db.db_history_name) + .collection('reports'); + + const incidentsCursor = incidentsCollection.find({}); + + const incidentsHistoryCursor = incidentsHistoryCollection.find({}); + + const submissionsCursor = submissionsCollection.find({}); + + const submissionsHistoryCursor = submissionsHistoryCollection.find({}); + + const reportsCursor = reportsCollection.find({}); + + const reportsHistoryCursor = reportsHistoryCollection.find({}); + + let updatedCount = 0; + + while (await incidentsCursor.hasNext()) { + const incident = await incidentsCursor.next(); + + const created_at = new Date(incident.date); + + await incidentsCollection.updateOne( + { _id: incident._id }, + { + $set: { + created_at: created_at, + }, + } + ); + + incident.created_at = created_at; + + updatedCount++; + } + + console.log(`Updated ${updatedCount} incidents with new created_at field`); + + updatedCount = 0; + + while (await incidentsHistoryCursor.hasNext()) { + const incident = await incidentsHistoryCursor.next(); + + const created_at = new Date(incident.date); + + await incidentsHistoryCollection.updateOne( + { _id: incident._id }, + { + $set: { + created_at: created_at, + }, + } + ); + + incident.created_at = created_at; + + updatedCount++; + } + + console.log(`Updated ${updatedCount} incidents history with new created_at field`); + + updatedCount = 0; + + while (await submissionsCursor.hasNext()) { + const submission = await submissionsCursor.next(); + + const created_at = new Date(submission.date_submitted); + + await submissionsCollection.updateOne( + { _id: submission._id }, + { + $set: { + created_at: created_at, + }, + } + ); + + submission.created_at = created_at; + + updatedCount++; + } + + console.log(`Updated ${updatedCount} submissions with new created_at field`); + + updatedCount = 0; + + while (await submissionsHistoryCursor.hasNext()) { + const submission = await submissionsHistoryCursor.next(); + + const created_at = new Date(submission.date_submitted); + + await submissionsHistoryCollection.updateOne( + { _id: submission._id }, + { + $set: { + created_at: created_at, + }, + } + ); + + submission.created_at = created_at; + + updatedCount++; + } + + console.log(`Updated ${updatedCount} submissions history with new created_at field`); + + updatedCount = 0; + + while (await reportsCursor.hasNext()) { + const report = await reportsCursor.next(); + + const created_at = new Date(report.date_submitted); + + await reportsCollection.updateOne( + { _id: report._id }, + { + $set: { + created_at: created_at, + }, + } + ); + + report.created_at = created_at; + + updatedCount++; + } + + console.log(`Updated ${updatedCount} reports with new created_at field`); + + updatedCount = 0; + + while (await reportsHistoryCursor.hasNext()) { + const report = await reportsHistoryCursor.next(); + + const created_at = new Date(report.date_submitted); + + await reportsHistoryCollection.updateOne( + { _id: report._id }, + { + $set: { + created_at: created_at, + }, + } + ); + + report.created_at = created_at; + + updatedCount++; + } + + console.log(`Updated ${updatedCount} reports history with new created_at field`); +}; diff --git a/site/gatsby-site/migrations/2024.02.08T20.32.57.mark-pending-notifications-as-processed.js b/site/gatsby-site/migrations/2024.02.08T20.32.57.mark-pending-notifications-as-processed.js new file mode 100644 index 0000000000..59a6e9b0b9 --- /dev/null +++ b/site/gatsby-site/migrations/2024.02.08T20.32.57.mark-pending-notifications-as-processed.js @@ -0,0 +1,16 @@ +const config = require('../config'); + +/** @type {import('umzug').MigrationFn} */ +exports.up = async ({ context: { client } }) => { + const db = client.db(config.realm.production_db.db_custom_data); + + const notifications = db.collection('notifications'); + + // Mark all pending notifications as processed + const result = await notifications.updateMany( + { processed: false }, + { $set: { processed: true } } + ); + + console.log(`All pending notifications marked as processed. Total: ${result.modifiedCount}`); +}; diff --git a/site/gatsby-site/netlify.toml b/site/gatsby-site/netlify.toml deleted file mode 100644 index 65d69fe810..0000000000 --- a/site/gatsby-site/netlify.toml +++ /dev/null @@ -1,26 +0,0 @@ -[build.environment] -CYPRESS_CACHE_FOLDER = "./node_modules/CypressBinary" -TERM = "xterm" - -[[plugins]] - package = "@netlify/plugin-gatsby" - -[[plugins]] - package = "/plugins/netlify-plugin-create-admin-user" - -[[plugins]] - package = "netlify-plugin-cypress" - [plugins.inputs] - enable = false - [plugins.inputs.postBuild] - enable = true - record = false - spa = true - start = 'gatsby serve -p 8080' - browser = 'chromium' - -[[plugins]] - package = "/plugins/netlify-plugin-process-notifications" - -[build.processing.html] - pretty_urls = false diff --git a/site/gatsby-site/package-lock.json b/site/gatsby-site/package-lock.json index 770ab0e4b9..860e61d0ec 100644 --- a/site/gatsby-site/package-lock.json +++ b/site/gatsby-site/package-lock.json @@ -67,6 +67,7 @@ "md5": "^2.3.0", "mongodb": "^4.17.0", "object-hash": "^3.0.0", + "openapi-request-validator": "^12.1.3", "prismic-reactjs": "^1.3.4", "query-string": "^7.0.1", "react": "^18.2.0", @@ -91,12 +92,14 @@ "remark": "^13.0.0", "remark-gfm": "^3.0.1", "rich-text-diff": "^0.2.3", + "rollbar": "^2.26.3", "sass": "^1.54.5", "sharp": "^0.32.6", "slugify": "^1.6.5", "stemmer": "^1.0.5", "stopword": "^1.0.7", "stream": "^0.0.2", + "stringz": "^2.1.0", "strip-markdown": "^4.2.0", "topojson-client": "^3.1.0", "tsne-js": "^1.0.3", @@ -131,6 +134,9 @@ "prism-react-renderer": "^1.2.0", "start-server-and-test": "^1.14.0", "tailwindcss": "^3.3.2" + }, + "optionalDependencies": { + "@parcel/watcher-linux-x64-glibc": "^2.4.0" } }, "node_modules/@algolia/cache-browser-local-storage": { @@ -291,17 +297,17 @@ } }, "node_modules/@apollo/client": { - "version": "3.7.10", - "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.7.10.tgz", - "integrity": "sha512-/k1MfrqPKYiPNdHcOzdxg9cEx96vhAGxAcSorzfBvV29XtFQcYW2cPNQOTjK/fpSMtqVo8UNmu5vwQAWD1gfCg==", + "version": "3.8.6", + "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.8.6.tgz", + "integrity": "sha512-FnHg3vhQP8tQzgBs6oTJCFFIbovelDGYujj6MK7CJneiHf62TJstCIO0Ot4A1h7XrgFEtgl8a/OgajQWqrTuYw==", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", - "@wry/context": "^0.7.0", - "@wry/equality": "^0.5.0", - "@wry/trie": "^0.3.0", + "@wry/context": "^0.7.3", + "@wry/equality": "^0.5.6", + "@wry/trie": "^0.4.3", "graphql-tag": "^2.12.6", "hoist-non-react-statics": "^3.3.2", - "optimism": "^0.16.1", + "optimism": "^0.17.5", "prop-types": "^15.7.2", "response-iterator": "^0.2.6", "symbol-observable": "^4.0.0", @@ -6314,66 +6320,6 @@ "darwin" ] }, - "node_modules/@lmdb/lmdb-darwin-x64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.5.2.tgz", - "integrity": "sha512-KvPH56KRLLx4KSfKBx0m1r7GGGUMXm0jrKmNE7plbHlesZMuPJICtn07HYgQhj1LNsK7Yqwuvnqh1QxhJnF1EA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@lmdb/lmdb-linux-arm": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.5.2.tgz", - "integrity": "sha512-5kQAP21hAkfW5Bl+e0P57dV4dGYnkNIpR7f/GAh6QHlgXx+vp/teVj4PGRZaKAvt0GX6++N6hF8NnGElLDuIDw==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@lmdb/lmdb-linux-arm64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.5.2.tgz", - "integrity": "sha512-aLl89VHL/wjhievEOlPocoefUyWdvzVrcQ/MHQYZm2JfV1jUsrbr/ZfkPPUFvZBf+VSE+Q0clWs9l29PCX1hTQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@lmdb/lmdb-linux-x64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.5.2.tgz", - "integrity": "sha512-xUdUfwDJLGjOUPH3BuPBt0NlIrR7f/QHKgu3GZIXswMMIihAekj2i97oI0iWG5Bok/b+OBjHPfa8IU9velnP/Q==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@lmdb/lmdb-win32-x64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.5.2.tgz", - "integrity": "sha512-zrBczSbXKxEyK2ijtbRdICDygRqWSRPpZMN5dD1T8VMEW5RIhIbwFWw2phDRXuBQdVDpSjalCIUMWMV2h3JaZA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/@mdx-js/mdx": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-2.3.0.tgz", @@ -7628,9 +7574,9 @@ } }, "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.2.0.tgz", - "integrity": "sha512-xJvJ7R2wJdi47WZBFS691RDOWvP1j/IAs3EXaWVhDI8FFITbWrWaln7KoNcR0Y3T+ZwimFY/cfb0PNht1q895g==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.4.1.tgz", + "integrity": "sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg==", "cpu": [ "x64" ], @@ -7703,6 +7649,25 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/@parcel/watcher/node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.2.0.tgz", + "integrity": "sha512-xJvJ7R2wJdi47WZBFS691RDOWvP1j/IAs3EXaWVhDI8FFITbWrWaln7KoNcR0Y3T+ZwimFY/cfb0PNht1q895g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/@parcel/watcher/node_modules/node-addon-api": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.0.0.tgz", @@ -9476,9 +9441,9 @@ } }, "node_modules/@types/react": { - "version": "18.0.28", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.28.tgz", - "integrity": "sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==", + "version": "18.2.59", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.59.tgz", + "integrity": "sha512-DE+F6BYEC8VtajY85Qr7mmhTd/79rJKIHCg99MU9SWPB4xvLb6D1za2vYflgZfmPqQVEr6UqJTnLXEwzpVPuOg==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -10021,9 +9986,9 @@ } }, "node_modules/@wry/context": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.7.0.tgz", - "integrity": "sha512-LcDAiYWRtwAoSOArfk7cuYvFXytxfVrdX7yxoUmK7pPITLk5jYh2F8knCwS7LjgYL8u1eidPlKKV6Ikqq0ODqQ==", + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.7.4.tgz", + "integrity": "sha512-jmT7Sb4ZQWI5iyu3lobQxICu2nC/vbUhP0vIdd6tHC9PTfenmRmuIFqktc6GH9cgi+ZHnsLWPvfSvc4DrYmKiQ==", "dependencies": { "tslib": "^2.3.0" }, @@ -10032,9 +9997,9 @@ } }, "node_modules/@wry/equality": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@wry/equality/-/equality-0.5.3.tgz", - "integrity": "sha512-avR+UXdSrsF2v8vIqIgmeTY0UR91UT+IyablCyKe/uk22uOJ8fusKZnH9JH9e1/EtLeNJBtagNmL3eJdnOV53g==", + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@wry/equality/-/equality-0.5.7.tgz", + "integrity": "sha512-BRFORjsTuQv5gxcXsuDXx6oGRhuVsEGwZy6LOzRRfgu+eSfxbhUQ9L9YtSEIuIjY/o7g3iWFjrc5eSY1GXP2Dw==", "dependencies": { "tslib": "^2.3.0" }, @@ -10043,9 +10008,9 @@ } }, "node_modules/@wry/trie": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@wry/trie/-/trie-0.3.2.tgz", - "integrity": "sha512-yRTyhWSls2OY/pYLfwff867r8ekooZ4UI+/gxot5Wj8EFwSf2rG+n+Mo/6LoLQm1TKA4GRj2+LCpbfS937dClQ==", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@wry/trie/-/trie-0.4.3.tgz", + "integrity": "sha512-I6bHwH0fSf6RqQcnnXLJKhkSXG45MFral3GxPaY4uAl0LYDZM+YDVDAiU9bYwjTuysy1S0IeecWtmq1SZA3M1w==", "dependencies": { "tslib": "^2.3.0" }, @@ -10205,6 +10170,42 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, "node_modules/ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", @@ -11621,12 +11622,18 @@ } }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -11783,6 +11790,14 @@ "upper-case-first": "^2.0.2" } }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "engines": { + "node": ">=10" + } + }, "node_modules/character-entities": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", @@ -12027,9 +12042,9 @@ } }, "node_modules/classnames": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", - "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" }, "node_modules/clean-stack": { "version": "2.2.0", @@ -12702,6 +12717,11 @@ "node": "^14.18.0 || >=16.10.0" } }, + "node_modules/console-polyfill": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/console-polyfill/-/console-polyfill-0.3.0.tgz", + "integrity": "sha512-w+JSDZS7XML43Xnwo2x5O5vxB0ID7T5BdqDtyqT6uiCAX2kZAgcWxNaGqT97tZfSHzfOcvrfsDAodKcJ3UvnXQ==" + }, "node_modules/constant-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz", @@ -12805,9 +12825,9 @@ } }, "node_modules/core-js-pure": { - "version": "3.29.0", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.29.0.tgz", - "integrity": "sha512-v94gUjN5UTe1n0yN/opTihJ8QBWD2O8i19RfTZR7foONPWArnjB96QA/wk5ozu1mm6ja3udQCzOzwQXTxi3xOQ==", + "version": "3.36.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.36.0.tgz", + "integrity": "sha512-cN28qmhRNgbMZZMc/RFu5w8pK9VJzpb2rJVR/lHuZJKwmXnoWOpXmMkxqBB514igkp1Hu8WGROsiOAzUcKdHOQ==", "hasInstallScript": true, "funding": { "type": "opencollective", @@ -13959,6 +13979,15 @@ } } }, + "node_modules/decache": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/decache/-/decache-3.1.0.tgz", + "integrity": "sha512-p7D6wJ5EJFFq1CcF2lu1XeqKFLBob8jRQGNAvFLTsV3CbSKBl3VtliAVlUIGz2i9H6kEFnI2Amaft5ZopIG2Fw==", + "optional": true, + "dependencies": { + "find": "^0.2.4" + } + }, "node_modules/decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", @@ -14260,6 +14289,22 @@ "node": ">=10" } }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -15090,6 +15135,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-get-iterator": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", @@ -15152,13 +15216,14 @@ } }, "node_modules/es5-ext": { - "version": "0.10.62", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", - "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", "hasInstallScript": true, "dependencies": { "es6-iterator": "^2.0.3", "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", "next-tick": "^1.1.0" }, "engines": { @@ -15807,6 +15872,25 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esniff/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==" + }, "node_modules/espree": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", @@ -16619,6 +16703,15 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/find": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/find/-/find-0.2.9.tgz", + "integrity": "sha512-7a4/LCiInB9xYMnAUEjLilL9FKclwbwK7VlXw+h5jMvT2TDFeYFCHM24O1XdnC/on/hx8mxVO3FTQkyHZnOghQ==", + "optional": true, + "dependencies": { + "traverse-chain": "~0.1.0" + } + }, "node_modules/find-cache-dir": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", @@ -17215,9 +17308,12 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/function.prototype.name": { "version": "1.1.5", @@ -19841,13 +19937,18 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", - "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -20377,11 +20478,11 @@ } }, "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dependencies": { - "get-intrinsic": "^1.1.1" + "es-define-property": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -20483,6 +20584,17 @@ "node": ">=8" } }, + "node_modules/hasown": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", + "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hast-util-excerpt": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/hast-util-excerpt/-/hast-util-excerpt-1.0.2.tgz", @@ -23350,66 +23462,6 @@ "@lmdb/lmdb-win32-x64": "2.5.3" } }, - "node_modules/lmdb/node_modules/@lmdb/lmdb-darwin-x64": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.5.3.tgz", - "integrity": "sha512-337dNzh5yCdNCTk8kPfoU7jR3otibSlPDGW0vKZT97rKnQMb9tNdto3RtWoGPsQ8hKmlRZpojOJtmwjncq1MoA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/lmdb/node_modules/@lmdb/lmdb-linux-arm": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.5.3.tgz", - "integrity": "sha512-mU2HFJDGwECkoD9dHQEfeTG5mp8hNS2BCfwoiOpVPMeapjYpQz9Uw3FkUjRZ4dGHWKbin40oWHuL0bk2bCx+Sg==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/lmdb/node_modules/@lmdb/lmdb-linux-arm64": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.5.3.tgz", - "integrity": "sha512-VJw60Mdgb4n+L0fO1PqfB0C7TyEQolJAC8qpqvG3JoQwvyOv6LH7Ib/WE3wxEW9nuHmVz9jkK7lk5HfWWgoO1Q==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/lmdb/node_modules/@lmdb/lmdb-linux-x64": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.5.3.tgz", - "integrity": "sha512-qaReO5aV8griBDsBr8uBF/faO3ieGjY1RY4p8JvTL6Mu1ylLrTVvOONqKFlNaCwrmUjWw5jnf7VafxDAeQHTow==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/lmdb/node_modules/@lmdb/lmdb-win32-x64": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.5.3.tgz", - "integrity": "sha512-cK+Elf3RjEzrm3SerAhrFWL5oQAsZSJ/LmjL1joIpTfEP1etJJ9CTRvdaV6XLYAxaEkfdhk/9hOvHLbR9yIhCA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/lmdb/node_modules/node-addon-api": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", @@ -27054,6 +27106,52 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/openapi-jsonschema-parameters": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-jsonschema-parameters/-/openapi-jsonschema-parameters-12.1.3.tgz", + "integrity": "sha512-aHypKxWHwu2lVqfCIOCZeJA/2NTDiP63aPwuoIC+5ksLK5/IQZ3oKTz7GiaIegz5zFvpMDxDvLR2DMQQSkOAug==", + "dependencies": { + "openapi-types": "^12.1.3" + } + }, + "node_modules/openapi-request-validator": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-request-validator/-/openapi-request-validator-12.1.3.tgz", + "integrity": "sha512-HW1sG00A9Hp2oS5g8CBvtaKvRAc4h5E4ksmuC5EJgmQ+eAUacL7g+WaYCrC7IfoQaZrjxDfeivNZUye/4D8pwA==", + "dependencies": { + "ajv": "^8.3.0", + "ajv-formats": "^2.1.0", + "content-type": "^1.0.4", + "openapi-jsonschema-parameters": "^12.1.3", + "openapi-types": "^12.1.3", + "ts-log": "^2.1.4" + } + }, + "node_modules/openapi-request-validator/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/openapi-request-validator/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/openapi-types": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", + "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==" + }, "node_modules/opencollective-postinstall": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", @@ -27072,12 +27170,13 @@ } }, "node_modules/optimism": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/optimism/-/optimism-0.16.2.tgz", - "integrity": "sha512-zWNbgWj+3vLEjZNIh/okkY2EUfX+vB9TJopzIZwT1xxaMqC5hRLLraePod4c5n4He08xuXNH+zhKFFCu390wiQ==", + "version": "0.17.5", + "resolved": "https://registry.npmjs.org/optimism/-/optimism-0.17.5.tgz", + "integrity": "sha512-TEcp8ZwK1RczmvMnvktxHSF2tKgMWjJ71xEFGX5ApLh67VsMSTy1ZUlipJw8W+KaqgOmQ+4pqwkeivY89j+4Vw==", "dependencies": { "@wry/context": "^0.7.0", - "@wry/trie": "^0.3.0" + "@wry/trie": "^0.4.3", + "tslib": "^2.3.0" } }, "node_modules/optional-require": { @@ -31406,6 +31505,11 @@ "node": ">=0.10" } }, + "node_modules/request-ip": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/request-ip/-/request-ip-3.3.0.tgz", + "integrity": "sha512-cA6Xh6e0fDBBBwH77SLJaJPBmD3nWVAcF9/XAcsrIHdjhFzFiB5aNQFytdjCGPezU3ROwrR11IddKAM08vohxA==" + }, "node_modules/request-progress": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", @@ -31676,6 +31780,36 @@ "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.1.tgz", "integrity": "sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==" }, + "node_modules/rollbar": { + "version": "2.26.3", + "resolved": "https://registry.npmjs.org/rollbar/-/rollbar-2.26.3.tgz", + "integrity": "sha512-Pf6PVH0zFi0dK4Yhj4MBEZX0QwIiHPZRgBHNHkhiujarhT5xunkJZ1T1QaJD0g8ML22f3zA7kKsly1tZZE7cdg==", + "dependencies": { + "async": "~3.2.3", + "console-polyfill": "0.3.0", + "error-stack-parser": "^2.0.4", + "json-stringify-safe": "~5.0.0", + "lru-cache": "~2.2.1", + "request-ip": "~3.3.0", + "source-map": "^0.5.7" + }, + "optionalDependencies": { + "decache": "^3.0.5" + } + }, + "node_modules/rollbar/node_modules/lru-cache": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.2.4.tgz", + "integrity": "sha512-Q5pAgXs+WEAfoEdw2qKQhNFFhMoFMTYqRVKKUMnzuiR7oKFHS7fWo848cPcTKw+4j/IdN17NyzdhVKgabFV0EA==" + }, + "node_modules/rollbar/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/rss": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/rss/-/rss-1.2.2.tgz", @@ -32104,6 +32238,22 @@ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, + "node_modules/set-function-length": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", + "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==", + "dependencies": { + "define-data-property": "^1.1.2", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -33352,6 +33502,14 @@ "node": ">=0.10.0" } }, + "node_modules/stringz": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/stringz/-/stringz-2.1.0.tgz", + "integrity": "sha512-KlywLT+MZ+v0IRepfMxRtnSvDCMc3nR1qqCs3m/qIbSOWkNZYT8XHQA31rS3TnKp0c5xjZu3M4GY/2aRKSi/6A==", + "dependencies": { + "char-regex": "^1.0.2" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -34518,6 +34676,12 @@ "node": ">=12" } }, + "node_modules/traverse-chain": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/traverse-chain/-/traverse-chain-0.1.0.tgz", + "integrity": "sha512-up6Yvai4PYKhpNp5PkYtx50m3KbwQrqDwbuZP/ItyL64YEWHAvH6Md83LFLV/GRSk/BoUVwwgUzX6SOQSbsfAg==", + "optional": true + }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -34568,6 +34732,11 @@ "node": ">=8" } }, + "node_modules/ts-log": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/ts-log/-/ts-log-2.2.5.tgz", + "integrity": "sha512-PGcnJoTBnVGy6yYNFxWVNkdcAuAMstvutN9MgDJIV6L0oG8fB+ZNNy1T+wJzah8RPGor1mZuPQkVfXNDpy9eHA==" + }, "node_modules/tsconfig-paths": { "version": "3.14.2", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", diff --git a/site/gatsby-site/package.json b/site/gatsby-site/package.json index 794393392f..408edcb7e2 100644 --- a/site/gatsby-site/package.json +++ b/site/gatsby-site/package.json @@ -63,6 +63,7 @@ "md5": "^2.3.0", "mongodb": "^4.17.0", "object-hash": "^3.0.0", + "openapi-request-validator": "^12.1.3", "prismic-reactjs": "^1.3.4", "query-string": "^7.0.1", "react": "^18.2.0", @@ -87,12 +88,14 @@ "remark": "^13.0.0", "remark-gfm": "^3.0.1", "rich-text-diff": "^0.2.3", + "rollbar": "^2.26.3", "sass": "^1.54.5", "sharp": "^0.32.6", "slugify": "^1.6.5", "stemmer": "^1.0.5", "stopword": "^1.0.7", "stream": "^0.0.2", + "stringz": "^2.1.0", "strip-markdown": "^4.2.0", "topojson-client": "^3.1.0", "tsne-js": "^1.0.3", @@ -158,5 +161,8 @@ "overrides": { "minimist": "1.2.8", "d3-color": "3.1.0" + }, + "optionalDependencies": { + "@parcel/watcher-linux-x64-glibc": "^2.4.0" } } diff --git a/site/gatsby-site/page-creators/createCitationPages.js b/site/gatsby-site/page-creators/createCitationPages.js index 57b36984e1..15f40c933c 100644 --- a/site/gatsby-site/page-creators/createCitationPages.js +++ b/site/gatsby-site/page-creators/createCitationPages.js @@ -88,6 +88,8 @@ const createCitationPages = async (graphql, createPage, { languages }) => { const translate_en = incident.reports.some((r) => r.language !== 'en'); + const translate_ja = incident.reports.some((r) => r.language !== 'ja'); + createPage({ path: pagePath, component: path.resolve('./src/templates/cite.js'), @@ -99,6 +101,7 @@ const createCitationPages = async (graphql, createPage, { languages }) => { translate_es, translate_fr, translate_en, + translate_ja, }, }); } diff --git a/site/gatsby-site/page-creators/createReportPages.js b/site/gatsby-site/page-creators/createReportPages.js index 8d69510ba9..e66d9a2b29 100644 --- a/site/gatsby-site/page-creators/createReportPages.js +++ b/site/gatsby-site/page-creators/createReportPages.js @@ -47,6 +47,7 @@ const createReportPages = async (graphql, createPage, { languages }) => { translate_es: context.language !== 'es', translate_fr: context.language !== 'fr', translate_en: context.language !== 'en', + translate_ja: context.language !== 'ja', }, }); } diff --git a/site/gatsby-site/plugins/gatsby-theme-i18n-react-i18next/src/wrap-page-element.js b/site/gatsby-site/plugins/gatsby-theme-i18n-react-i18next/src/wrap-page-element.js index ae091684e0..a2b1598165 100644 --- a/site/gatsby-site/plugins/gatsby-theme-i18n-react-i18next/src/wrap-page-element.js +++ b/site/gatsby-site/plugins/gatsby-theme-i18n-react-i18next/src/wrap-page-element.js @@ -12,7 +12,16 @@ const wrapPageElement = ({ element, props }, themeOptions) => { let resources = {}; i18nextOptions.ns.forEach((name) => { - const data = require(`${GATSBY_THEME_I18N_REACT_I18NEXT}/${locale}/${name}.json`); + let data = null; + + try { + data = require(`${GATSBY_THEME_I18N_REACT_I18NEXT}/${locale}/${name}.json`); + } catch (error) { + console.error( + `[gatsby-theme-i18n-react-i18next]: Failed to load translation file for ${locale}/${name}.json. Please create i18n/locales/${locale} folder and add ${name}.json there. Now defaulting to en/${name}.json` + ); + data = require(`${GATSBY_THEME_I18N_REACT_I18NEXT}/en/${name}.json`); + } resources = { ...resources, diff --git a/site/gatsby-site/plugins/gatsby-theme-i18n/gatsby-node.js b/site/gatsby-site/plugins/gatsby-theme-i18n/gatsby-node.js index 8a323c8b96..2a3cf7eec6 100644 --- a/site/gatsby-site/plugins/gatsby-theme-i18n/gatsby-node.js +++ b/site/gatsby-site/plugins/gatsby-theme-i18n/gatsby-node.js @@ -220,27 +220,45 @@ exports.onCreatePage = ({ page, actions }, themeOptions) => { const [template, mdxFile] = page.component.split(`?__contentFilePath=`); - // if the mdxFile path possesses a language, let's strip the language to it + // If the mdxFile path has a language, let's strip the language from it. // ex: index.de.mdx ==> index.mdx if (mdxFile) { - //split the filename in three parts split by the dot. - let [thePath /* lang */, , ext] = mdxFile.split(`.`); + let thePath = path.dirname(mdxFile); - if (ext === `mdx`) { - //if there's data in the third part, just keep the first and last part, removing the language - theFilePath = `${thePath}.${ext}`; - } else { - //if there's no content in the third part, it means that there's no language part. No need to remove the language + let fileName = path.basename(mdxFile); + + let ext = path.extname(mdxFile); + + if (ext !== '.mdx') { + throw new Error(`Unexpected file extension in mdx path parsing: ${mdxFile}`); + } + + // Split the filename in three parts split by the dot. We expect two or three components. + let fileNamePieces = fileName.split('.'); + + if (fileNamePieces.length == 2) { + // ex: index.mdx theFilePath = mdxFile; + } else if (fileNamePieces.length == 3) { + // ex: index.es.mdx + // Keep everything except the language code. + theFilePath = `${path.join(thePath, fileNamePieces.at(0))}${ext}`; + } else { + throw new Error(`Unexpected file format in mdx path parsing: ${mdxFile}`); } - //if we use a non-default language, and the language file is on the disk, then use it - [thePath, ext] = theFilePath.split(`.`); - if (ext === `mdx` && locale.code !== defaultLang) { - if (fs.existsSync(`${thePath}.${locale.code}.${ext}`)) { - theFilePath = `${thePath}.${locale.code}.${ext}`; + // If we use a non-default language, and the language file is on the disk, then use it. + if (ext === '.mdx' && locale.code !== defaultLang) { + // ex: /path/up/to/lang/code + let potentialPath = path.join(path.dirname(thePath), fileNamePieces.at(0)); + + // ex: /path/up/to/lang/code.es.mdx + let potentialLangfile = `${potentialPath}.${locale.code}${ext}`; + + if (fs.existsSync(potentialLangfile)) { + theFilePath = potentialLangfile; } else { - //nothing to render if file doen't exist + // Nothing to render if file doen't exist. theFilePath = ''; } } diff --git a/site/gatsby-site/plugins/netlify-plugin-create-admin-user/index.js b/site/gatsby-site/plugins/netlify-plugin-create-admin-user/index.js index 0ffd9db2a6..5092d26c26 100644 --- a/site/gatsby-site/plugins/netlify-plugin-create-admin-user/index.js +++ b/site/gatsby-site/plugins/netlify-plugin-create-admin-user/index.js @@ -18,7 +18,7 @@ const getValidAccessToken = async () => { const client = new apolloClient.ApolloClient({ link: new apolloClient.HttpLink({ - uri: `https://realm.mongodb.com/api/client/v2.0/app/${process.env.GATSBY_REALM_APP_ID}/graphql`, + uri: `https://services.cloud.mongodb.com/api/client/v2.0/app/${process.env.GATSBY_REALM_APP_ID}/graphql`, fetch: async (uri, options) => { const accessToken = await getValidAccessToken(); diff --git a/site/gatsby-site/plugins/netlify-plugin-process-notifications/index.js b/site/gatsby-site/plugins/netlify-plugin-process-notifications/index.js index dbf9e504a2..6bdc1ffc07 100644 --- a/site/gatsby-site/plugins/netlify-plugin-process-notifications/index.js +++ b/site/gatsby-site/plugins/netlify-plugin-process-notifications/index.js @@ -18,7 +18,7 @@ const getValidAccessToken = async () => { const client = new apolloClient.ApolloClient({ link: new apolloClient.HttpLink({ - uri: `https://realm.mongodb.com/api/client/v2.0/app/${process.env.GATSBY_REALM_APP_ID}/graphql`, + uri: `https://services.cloud.mongodb.com/api/client/v2.0/app/${process.env.GATSBY_REALM_APP_ID}/graphql`, fetch: async (uri, options) => { const accessToken = await getValidAccessToken(); diff --git a/site/gatsby-site/postBuild/processNotifications.js b/site/gatsby-site/postBuild/processNotifications.js index 9c0db5640a..2a7bc2949d 100644 --- a/site/gatsby-site/postBuild/processNotifications.js +++ b/site/gatsby-site/postBuild/processNotifications.js @@ -20,7 +20,7 @@ const getValidAccessToken = async () => { const client = new ApolloClient({ link: new HttpLink({ - uri: `https://realm.mongodb.com/api/client/v2.0/app/${config.realm.production_db.realm_app_id}/graphql`, + uri: `https://services.cloud.mongodb.com/api/client/v2.0/app/${config.realm.production_db.realm_app_id}/graphql`, fetch: async (uri, options) => { const accessToken = await getValidAccessToken(); diff --git a/site/gatsby-site/src/api/graphql.js b/site/gatsby-site/src/api/graphql.js index af593b7be1..aecf4a73d8 100644 --- a/site/gatsby-site/src/api/graphql.js +++ b/site/gatsby-site/src/api/graphql.js @@ -15,7 +15,7 @@ async function realmExecutor({ document, variables }) { const query = print(document); const fetchResult = await fetch( - `https://realm.mongodb.com/api/client/v2.0/app/${siteConfig.realm.production_db.realm_app_id}/graphql`, + `https://services.cloud.mongodb.com/api/client/v2.0/app/${siteConfig.realm.production_db.realm_app_id}/graphql`, { method: 'POST', headers: { diff --git a/site/gatsby-site/src/api/lookupbyurl.js b/site/gatsby-site/src/api/lookupbyurl.js new file mode 100644 index 0000000000..34c432f683 --- /dev/null +++ b/site/gatsby-site/src/api/lookupbyurl.js @@ -0,0 +1,128 @@ +import Rollbar from 'rollbar'; +import siteConfig from '../../config'; +import OpenAPIRequestValidator from 'openapi-request-validator'; +import Cors from 'cors'; +import spec from '../../static/spec.json'; +import normalizeRequest from '../../src/utils/normalizeRequest'; + +const requestValidator = new OpenAPIRequestValidator({ + parameters: spec.paths['/api/lookupbyurl'].get.parameters, +}); + +const cors = Cors(); + +const isValidURL = (string) => { + try { + new URL(string); + return true; + } catch (_) { + return false; + } +}; + +async function handler(req, res) { + normalizeRequest(req); + + const errors = requestValidator.validateRequest(req); + + if (errors) { + console.warn(req.query, errors); + rollbar.warning(req.query, errors); + + res.status(400).json(errors); + + return; + } + + const urls = req.query.urls; + + const index = require('./lookupIndex.json'); + + const results = []; + + for (const url of urls) { + const result = { url, reports: [], incidents: [] }; + + const parsedURL = new URL(url); + + const incidents = index.reduce((filtered, incident) => { + if ( + incident.reports + // some reports are missing the url, it should be fixed in the source but for now we'll filter them out + // https://github.com/responsible-ai-collaborative/aiid/issues/2664 + .filter((report) => isValidURL(report.url)) + .some((report) => { + const reportURL = new URL(report.url); + + return reportURL.host + reportURL.pathname === parsedURL.host + parsedURL.pathname; + }) + ) { + filtered.push({ + incident_id: incident.incident_id, + title: incident.title, + url: `${siteConfig.gatsby.siteUrl}/cite/${incident.incident_id}`, + }); + } + + return filtered; + }, []); + + result.incidents = incidents; + + const reports = index.reduce((filtered, incident) => { + incident.reports + .filter((report) => isValidURL(report.url)) + .forEach((report) => { + const reportURL = new URL(report.url); + + if (reportURL.host + reportURL.pathname === parsedURL.host + parsedURL.pathname) { + filtered.push({ + report_number: report.report_number, + title: report.title, + url: report.url, + }); + } + }); + + return filtered; + }, []); + + result.reports = reports; + + results.push(result); + } + + // Manually run the cors middleware + // https://www.gatsbyjs.com/docs/reference/functions/middleware-and-helpers/#custom-middleware + + await new Promise((resolve, reject) => { + cors(req, res, (result) => { + if (result instanceof Error) { + reject(result); + } + resolve(result); + }); + }); + + res.status(200).json({ results }); +} + +const rollbar = new Rollbar({ + accessToken: siteConfig.rollbar.token, + captureUncaught: true, + captureUnhandledRejections: true, + payload: { + code_version: '1.0.0', + }, +}); + +export default async function (req, res) { + try { + await handler(req, res); + } catch (error) { + console.error(error); + rollbar.error(error); + + res.status(500).send('An error occurred'); + } +} diff --git a/site/gatsby-site/src/components/RelatedIncidents.js b/site/gatsby-site/src/components/RelatedIncidents.js index 94549cfc49..c101f6b96b 100644 --- a/site/gatsby-site/src/components/RelatedIncidents.js +++ b/site/gatsby-site/src/components/RelatedIncidents.js @@ -216,10 +216,12 @@ const RelatedIncidents = ({ const result = await client.query({ query, variables }); - const reports = await column.getReports(result, client); + let reports = await column.getReports(result, client); setLoading((loading) => ({ ...loading, [key]: false })); + reports = reports.filter((r) => r.incident_id); + setRelatedReports((related) => ({ ...related, [key]: reports })); if (searchColumns[key].showIncidents) { diff --git a/site/gatsby-site/src/components/blog/PostPreview.js b/site/gatsby-site/src/components/blog/PostPreview.js index 1494d2afcd..e7667c3489 100644 --- a/site/gatsby-site/src/components/blog/PostPreview.js +++ b/site/gatsby-site/src/components/blog/PostPreview.js @@ -5,6 +5,27 @@ import { Trans } from 'react-i18next'; import DateLabel from 'components/ui/DateLabel'; function PostPreview({ post, latestPost = false }) { + let previewText = ''; + + if (post.excerpt && post.excerpt !== '') { + previewText = post.excerpt; + } else if (post.frontmatter.previewText && post.frontmatter.previewText !== '') { + previewText = post.frontmatter.previewText; + } else { + // Remove HTML tags + previewText = post?.body.replace(/<[^>]*>?/gm, ''); + + // Remove Markdown image syntax + previewText = previewText.replace(/!\[.*?\]\(.*?\)/g, ''); + + // Remove Markdown + previewText = previewText.replace(/!\[.*?\]\(.*?\)|\]\(.*?\)/g, '$1'); + + previewText = previewText.substring(0, 200); + + previewText = previewText.trim(); + } + return ( <>
@@ -35,7 +56,7 @@ function PostPreview({ post, latestPost = false }) {

-

{post.excerpt}...

+

{previewText}...

- {post.data.content.text.slice(0, 140)}...{' '} + {substring(post.data.content.text, 0, 140)}...{' '}

diff --git a/site/gatsby-site/src/components/checklists/CheckListForm.js b/site/gatsby-site/src/components/checklists/CheckListForm.js index 175075f560..5c8a18823b 100644 --- a/site/gatsby-site/src/components/checklists/CheckListForm.js +++ b/site/gatsby-site/src/components/checklists/CheckListForm.js @@ -2,15 +2,12 @@ import React, { useEffect, useState, useRef } from 'react'; import { Form } from 'formik'; import { Button, Textarea, Spinner } from 'flowbite-react'; import { Trans, useTranslation } from 'react-i18next'; -import { useMutation, useApolloClient, gql } from '@apollo/client'; +import { useQuery, useMutation, gql } from '@apollo/client'; import { LocalizedLink } from 'plugins/gatsby-theme-i18n'; import debounce from 'lodash/debounce'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faEnvelope, - faPlusCircle, - faWindowMaximize, - faWindowMinimize, faBullseye, faMicrochip, faArrowsTurnToDots, @@ -18,14 +15,7 @@ import { } from '@fortawesome/free-solid-svg-icons'; import { DELETE_CHECKLIST } from '../../graphql/checklists'; -import { - Label, - DeleteButton, - abbreviatedTag, - emptyRisk, - shouldBeGrouped, - risksEqual, -} from 'utils/checklists'; +import { Label, DeleteButton, abbreviatedTag, generateId } from 'utils/checklists'; import Tags from 'components/forms/Tags'; import EditableLabel from 'components/checklists/EditableLabel'; import ExportDropdown from 'components/checklists/ExportDropdown'; @@ -70,29 +60,93 @@ export default function CheckListForm({ } }; - const [risksLoading, setRisksLoading] = useState(false); - - const [allPrecedents, setAllPrecedents] = useState([]); - const searchTags = [ ...(values['tags_goals'] || []), ...(values['tags_methods'] || []), ...(values['tags_other'] || []), ]; - const apolloClient = useApolloClient(); + // Hits the risk management API with the specified query tags + // to populate values.risks and allPrecedents. + // + // Example resulting values.risks: + // + // [ { + // /* GraphQL API Results */ + // title: "Gaming Vulnerability", + // tags: ["GMF:Failure:Gaming Vulnerability"], + // precedents: [ + // { incident_id: 146, + // url: "https://incidentdatabase.ai/cite/146", + // title: "Research Prototype AI, Delphi, Reportedly Gave Racially Biased Answers on Ethics", + // description: "A publicly accessible research model [...] moral judgments.", + // tags: [ "GMF:Known AI Technology:Language Modeling", ], + // }, + // ], + // + // /* Defaults Risk Annotations */ + // risk_status: "Not Mitigated", + // risk_notes: "", + // severity: "", + // + // + // /* UI properties*/ + // startClosed: true, + // touched: false, // TODO: Remove these database-side. + // generated: true, + // } + // ] + // + // TODO: Group known and potential in GMF Taxonomy + const { + data: generatedRisksData, + loading: generatedRisksLoading, + errors: generatedRisksErrors, + } = useQuery( + gql` + query { + risks(input: { tags: [${searchTags.map((t) => `"${t}"`).join(', ')}] }) { + tags + title + precedents { + incident_id + title + description + tags + } + } + } + `, + { skip: searchTags.length == 0 } + ); - useEffect(() => { - searchRisks({ - values, - setFieldValue, - setRisksLoading, - setAllPrecedents, - addToast, - t, - apolloClient, + if (generatedRisksErrors) { + addToast({ + message: t('Failure searching for risks.'), + severity: SEVERITY.danger, }); - }, [values['tags_goals'], values['tags_methods'], values['tags_other']]); + } + + const generatedRisks = (generatedRisksData?.risks || []).map((result) => ({ + title: result.title, + tags: result.tags, + precedents: result.precedents, + description: result.description, + risk_status: 'Not Mitigated', + risk_notes: '', + severity: '', + likelihood: '', + })); + + const allPrecedents = generatedRisks.reduce((allPrecedents, generatedRisk) => { + const newPrecedents = generatedRisk.precedents.filter((precedent) => + allPrecedents.every( + (existingPrecedent) => existingPrecedent.incident_id != precedent.incident_id + ) + ); + + return allPrecedents.concat(newPrecedents); + }, []); useEffect(() => { if (userIsOwner) { @@ -109,21 +163,30 @@ export default function CheckListForm({ ); }; + const addRisk = (newRisk) => { + setFieldValue('risks', [newRisk].concat(values.risks)); + }; + const changeSort = (sortFunction) => (event) => { event.preventDefault(); - setFieldValue('risks', values.risks.sort(sortFunction)); + setFieldValue('risks', [...values.risks].sort(sortFunction)); }; const updateRisk = (risk, attributeValueMap) => { const updatedRisks = [...values.risks]; - const updatedRisk = updatedRisks.find((r) => risksEqual(r, risk)); + const updatedRisk = updatedRisks.find((r) => r.id == risk.id); - for (const attribute in attributeValueMap) { - if (attribute != 'precedents') { - updatedRisk.generated = false; + if (updatedRisk) { + for (const attribute in attributeValueMap) { + if (attribute != 'precedents') { + updatedRisk.generated = false; + } + updatedRisk[attribute] = attributeValueMap[attribute]; } - updatedRisk[attribute] = attributeValueMap[attribute]; + } else { + // A generated risk being promoted to a manual one + updatedRisks.push({ ...risk, ...attributeValueMap, id: generateId() }); } setFieldValue('risks', updatedRisks); @@ -163,7 +226,7 @@ export default function CheckListForm({ Delete )} - + This feature is in development. Data entered will not be retained. @@ -177,64 +240,20 @@ export default function CheckListForm({
-
-

Risks

-
- - - {userIsOwner && ( - - )} -
-
- - {!risksLoading && values.risks?.length == 0 && ( - No risks yet. Try adding some system tags. - )} @@ -280,67 +299,76 @@ const QueryTagInput = ({ userIsOwner, icon, trimTaxonomy = false, -}) => ( -
- - include(tag.split(':')))} - onChange={(tagInputArray) => { - // - // Example tagInputArray: - // - // ["GMF:Known AI Technology:Transformer", "Language Model"] - // | | - // , | Not fully-qualified, entered by direct text entry - // | when `trimTaxonomy` is enabled. Needs to be resolved to: - // | "GMF:Known AI Technology:Language Model" - // | - // Fully-qualified, entered from menu - // - if (trimTaxonomy) { - // If `trimTaxonomy` is enabled, then - // "GMF:Known AI Technology:Transformer" - // displays in the menu as just "Transformer". - // Users would therefore expect that typing "Transformer" - // will mean the same thing as clicking "Transformer" in the menu. - // So we have to convert it to its fully-qualified version. - const selectedTags = []; - - for (const tagInput of tagInputArray) { - let selectedTag; - - if (tagInput.includes(':')) { - // If there's a colon, it's already fully-qualified, - selectedTag = tagInput; - } else { - // If there's no colon, then it's not fully-qualified, - // so we find the full tag which abbreviates - // to the unqualified one. - selectedTag = tags.find((t) => abbreviatedTag(t) == tagInput); - } - if (selectedTag) { - selectedTags.push(selectedTag); +}) => { + const [realValue, setRealValue] = useState(idValue); + + useEffect(() => { + setFieldValue(id, realValue); + }, [realValue]); + + return ( +
+ + include(tag.split(':')))} + onChange={(tagInputArray) => { + // + // Example tagInputArray: + // + // ["GMF:Known AI Technology:Transformer", "Language Model"] + // | | + // , | Not fully-qualified, entered by direct text entry + // | when `trimTaxonomy` is enabled. Needs to be resolved to: + // | "GMF:Known AI Technology:Language Model" + // | + // Fully-qualified, entered from menu + // + if (trimTaxonomy) { + // If `trimTaxonomy` is enabled, then + // "GMF:Known AI Technology:Transformer" + // displays in the menu as just "Transformer". + // Users would therefore expect that typing "Transformer" + // will mean the same thing as clicking "Transformer" in the menu. + // So we have to convert it to its fully-qualified version. + const selectedTags = []; + + for (const tagInput of tagInputArray) { + let selectedTag; + + if (tagInput.includes(':')) { + // If there's a colon, it's already fully-qualified, + selectedTag = tagInput; + } else { + // If there's no colon, then it's not fully-qualified, + // so we find the full tag which abbreviates + // to the unqualified one. + selectedTag = tags.find((t) => abbreviatedTag(t) == tagInput); + } + if (selectedTag) { + selectedTags.push(selectedTag); + } } + setRealValue(selectedTags); + } else { + // If `trimTaxonomy` is disabled, + // then we can leave the input as it is. + setRealValue(tagInputArray); } - setFieldValue(id, selectedTags); - } else { - // If `trimTaxonomy` is disabled, - // then we can leave the input as it is. - setFieldValue(id, tagInputArray); - } - }} - labelKey={trimTaxonomy ? abbreviatedTag : (a) => a} - placeHolder={placeHolder} - disabled={!userIsOwner} - allowNew={false} - /> -
-); + }} + labelKey={trimTaxonomy ? abbreviatedTag : (a) => a} + placeHolder={placeHolder} + disabled={!userIsOwner} + allowNew={false} + /> +
+ ); +}; const GoalsTagInput = ({ values, tags, setFieldValue, userIsOwner }) => ( ); } - -// Hits the risk management API with the specified query tags -// to populate values.risks and allPrecedents. -// -// Example resulting values.risks: -// -// [ { -// /* GraphQL API Results */ -// title: "Gaming Vulnerability", -// tags: ["GMF:Failure:Gaming Vulnerability"], -// precedents: [ -// { incident_id: 146, -// url: "https://incidentdatabase.ai/cite/146", -// title: "Research Prototype AI, Delphi, Reportedly Gave Racially Biased Answers on Ethics", -// description: "A publicly accessible research model [...] moral judgments.", -// tags: [ "GMF:Known AI Technology:Language Modeling", ], -// }, -// ], -// -// /* Defaults Risk Annotations */ -// risk_status: "Not Mitigated", -// risk_notes: "", -// severity: "", -// -// /* UI properties*/ -// startClosed: true, -// touched: false, -// generated: true, -// } -// ] -// -// TODO: Group known and potential in GMF Taxonomy -const searchRisks = async ({ - values, - setFieldValue, - setRisksLoading, - setAllPrecedents, - addToast, - t, - apolloClient, -}) => { - const queryTags = [ - ...(values['tags_goals'] || []), - ...(values['tags_methods'] || []), - ...(values['tags_other'] || []), - ]; - - if (queryTags.length == 0) return; - - setRisksLoading(true); - - const risksResponse = await apolloClient.query({ - query: gql` - query findRisks { - risks(input: { tags: [${queryTags.map((t) => `"${t}"`).join(', ')}] }) { - tags - title - precedents { - incident_id - title - description - tags - } - } - } - `, - }); - - const allPrecedents = []; - - if (risksResponse.data) { - const results = risksResponse.data.risks; - - const risksToAdd = []; - - for (let i = 0; i < results.length; i++) { - const result = results[i]; - - const newRisk = { - ...emptyRisk(), - title: result.title, - tags: result.tags, - precedents: result.precedents, - description: result.description, - startClosed: true, - }; - - const notDuplicate = [...risksToAdd, ...(values.risks || [])].every( - (existingRisk) => !areDuplicates(existingRisk, newRisk) - ); - - if (notDuplicate) { - risksToAdd.push(newRisk); - } - for (const precedent of result.precedents) { - if (allPrecedents.every((p) => p.incident_id != precedent.incident_id)) { - allPrecedents.push(precedent); - } - } - } - - setAllPrecedents(allPrecedents); - - setFieldValue('risks', values.risks.concat(risksToAdd)); - } else { - addToast({ - message: t('Failure searching for risks.'), - severity: SEVERITY.danger, - }); - } - - setRisksLoading(false); -}; - -function areDuplicates(A, B) { - return ( - A.tags.length == B.tags.length && - A.tags.every((aTag) => B.tags.some((bTag) => shouldBeGrouped(bTag, aTag))) && - B.tags.every((bTag) => A.tags.some((aTag) => shouldBeGrouped(aTag, bTag))) - ); -} diff --git a/site/gatsby-site/src/components/checklists/ChecklistsIndex.js b/site/gatsby-site/src/components/checklists/ChecklistsIndex.js index bbc851aba6..4e5115a6ff 100644 --- a/site/gatsby-site/src/components/checklists/ChecklistsIndex.js +++ b/site/gatsby-site/src/components/checklists/ChecklistsIndex.js @@ -20,7 +20,6 @@ import { useUserContext } from '../../contexts/userContext'; import ExportDropdown from 'components/checklists/ExportDropdown'; import { DeleteButton, - removeTypename, statusIcon, statusColor, generateId, @@ -267,7 +266,7 @@ const CheckListCard = ({ checklist, setChecklists, owner }) => { try { await insertChecklist({ - variables: { checklist: removeTypename(newChecklist) }, + variables: { checklist: newChecklist }, }); setChecklists((checklists) => { const newChecklists = [...checklists]; diff --git a/site/gatsby-site/src/components/checklists/EditableLabel.js b/site/gatsby-site/src/components/checklists/EditableLabel.js index a5b1acc9fa..44cac607e0 100644 --- a/site/gatsby-site/src/components/checklists/EditableLabel.js +++ b/site/gatsby-site/src/components/checklists/EditableLabel.js @@ -21,7 +21,7 @@ const EditableLabel = ({ title, onChange, textClasses, iconClasses, disabled }) className={`${textClasses} py-0 border-none flex-shrink-1`} /> ) : ( - {displayTitle} + {displayTitle} )} {!disabled && (
); -const updatePrecedents = async ({ risk, setPrecedents, allPrecedents }) => { - const updatedPrecedents = []; - - for (const precedent of allPrecedents) { - for (const tag of precedent.tags) { - if ((risk.tags || []).includes(tag)) { - updatedPrecedents.push(precedent); - break; - } - } - } - setPrecedents(updatedPrecedents); -}; - function ProgressCircle({ progress, className }) { const r = 20; diff --git a/site/gatsby-site/src/components/checklists/RiskSections.js b/site/gatsby-site/src/components/checklists/RiskSections.js index 0b0881be4e..b7a32e045c 100644 --- a/site/gatsby-site/src/components/checklists/RiskSections.js +++ b/site/gatsby-site/src/components/checklists/RiskSections.js @@ -1,22 +1,40 @@ -import React from 'react'; -import { Spinner } from 'flowbite-react'; +import React, { useState } from 'react'; +import { Spinner, Button } from 'flowbite-react'; import { Trans } from 'react-i18next'; +import { + faWindowMaximize, + faWindowMinimize, + faPlusCircle, +} from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import RiskSection from 'components/checklists/RiskSection'; +import { generateId, tagsIdentifier } from 'utils/checklists'; const RiskSections = ({ risks, + generatedRisks, + generatedRisksLoading, setFieldValue, submitForm, tags, searchTags, allPrecedents, - risksLoading, removeRisk, changeSort, updateRisk, userIsOwner, + addRisk, }) => { + // Contains strings yielded by tagIdentifiers, + // used to persist open or closed state of sections + // across manual and generated risks. + const [openSections, setOpenSections] = useState([]); + + // We want to filter out the generated risks + // that match manually-annotated risks by tags. + const manualRiskIdentifiers = risks.map((risk) => tagsIdentifier(risk)); + const riskSectionProps = { setFieldValue, submitForm, @@ -30,27 +48,77 @@ const RiskSections = ({ }; return ( -
- {risksLoading ? ( - <> - {(risks || []) - .filter((risk) => !risk.generated) - .map((risk) => ( - - ))} -
- - - Searching for risks matching tags… - -
- - ) : ( - (risks || []).map((risk) => ( - - )) - )} -
+
+
+

Risks

+
+ + + {userIsOwner && ( + + )} +
+
+
+ {(risks || []).map((risk) => ( + + ))} + + {generatedRisks + // If `tagsIdentifier(risk)` is in `manualRiskIdentifiers`, + // then the tags of `risks` exactly match + // those of some manually-annotated risk. + // We don't want to show a generated risk with the same tags. + .filter((risk) => !manualRiskIdentifiers.includes(tagsIdentifier(risk))) + .map((risk) => ( + + ))} + + {generatedRisksLoading && } +
+
); }; diff --git a/site/gatsby-site/src/components/cite/RemoveDuplicateModal.js b/site/gatsby-site/src/components/cite/RemoveDuplicateModal.js new file mode 100644 index 0000000000..f44b51522d --- /dev/null +++ b/site/gatsby-site/src/components/cite/RemoveDuplicateModal.js @@ -0,0 +1,192 @@ +import React from 'react'; +import { useMutation, useQuery } from '@apollo/client/react/hooks'; +import { FIND_INCIDENT, UPDATE_INCIDENT } from '../../graphql/incidents'; +import { INSERT_DUPLICATE } from '../../graphql/duplicates'; +import { UPSERT_CLASSIFICATION, FIND_CLASSIFICATION } from '../../graphql/classifications'; +import { UPSERT_SUBSCRIPTION, FIND_FULL_SUBSCRIPTIONS } from '../../graphql/subscriptions'; +import IncidentsField from 'components/incidents/IncidentsField'; +import { Formik, Form } from 'formik'; +import { Button, Modal } from 'flowbite-react'; +import { Trans } from 'react-i18next'; +import useToast, { SEVERITY } from '../../hooks/useToast'; + +export default function RemoveDuplicateModal({ incident, show, onClose }) { + const addToast = useToast(); + + const [updateIncident] = useMutation(UPDATE_INCIDENT); + + const [insertDuplicate] = useMutation(INSERT_DUPLICATE); + + const [updateClassification] = useMutation(UPSERT_CLASSIFICATION); + + const [updateSubscription] = useMutation(UPSERT_SUBSCRIPTION); + + const { data: classificationsData, loading: classificationsLoading } = useQuery( + FIND_CLASSIFICATION, + { variables: { query: { incidents: { incident_id: incident.incident_id } } } } + ); + + const { data: subscriptionsData, loading: subscriptionsLoading } = useQuery( + FIND_FULL_SUBSCRIPTIONS, + { variables: { query: { incident_id: { incident_id: incident.incident_id } } } } + ); + + return ( + + + Remove Duplicate + + + + {({ values, isSubmitting, setSubmitting }) => { + const { data: duplicateIncidentData, loading: duplicateIncidentLoading } = useQuery( + FIND_INCIDENT, + { variables: { query: { incident_id: values.duplicateIncidentId?.[0] } } } + ); + + const submitBlocked = + duplicateIncidentLoading || + !duplicateIncidentData || + !values.duplicateIncidentId || + values.duplicateIncidentId.length == 0 || + classificationsLoading || + !classificationsData || + !subscriptionsData || + subscriptionsLoading || + isSubmitting; + + const submit = async () => { + setSubmitting(true); + const reportIds = duplicateIncidentData.incident.reports + .concat(incident.reports) + .map((report) => report.report_number); + + const duplicate_incident_number = incident.incident_id; + + const true_incident_number = values.duplicateIncidentId[0]; + + let error = false; + + try { + await insertDuplicate({ + variables: { + duplicate: { + duplicate_incident_number, + true_incident_number, + }, + }, + }); + } catch (e) { + addToast({ + message: `Could not insert duplicate. Aborting.`, + severity: SEVERITY.danger, + error: e, + }); + error = true; + } + + try { + await updateIncident({ + variables: { + query: { incident_id: true_incident_number }, + set: { reports: { link: reportIds } }, + }, + }); + } catch (e) { + addToast({ + message: `Could not transfer reports to incident ${true_incident_number}.`, + severity: SEVERITY.danger, + error: e, + }); + error = true; + } + + try { + for (const classification of classificationsData.classifications) { + await updateClassification({ + variables: { + query: { _id: classification._id }, + data: { + ...classification, + incidents: { + link: classification.incidents + .map((incident) => incident.incident_id) + .filter((incident_id) => incident_id != duplicate_incident_number) + .concat(true_incident_number), + }, + reports: { + link: classification.reports.map((report) => report.report_number), + }, + }, + }, + }); + } + } catch (e) { + addToast({ + message: `Could not transfer classifications to incident ${true_incident_number}.`, + severity: SEVERITY.danger, + error: e, + }); + error = true; + } + try { + for (const subscription of subscriptionsData.subscriptions) { + await updateSubscription({ + variables: { + query: { _id: subscription._id }, + subscription: { + userId: { link: subscription.userId.userId }, + incident_id: { link: true_incident_number }, + type: subscription.type, + }, + }, + }); + } + } catch (e) { + addToast({ + message: `Could not transfer subscription to incident ${true_incident_number}.`, + severity: SEVERITY.danger, + error: e, + }); + error = true; + } + + setSubmitting(false); + onClose(); + + if (!error) { + addToast({ + severity: SEVERITY.success, + message: `Incident ${incident.incident_id} marked as duplicate of ${values.duplicateIncidentId[0]}. Its page will updated within 24 hours.`, + }); + setTimeout(() => (window.location.pathname = '/'), 5000); + } + }; + + return ( +
+ + + + + ); + }} +
+
+
+ ); +} diff --git a/site/gatsby-site/src/components/cite/Tools.js b/site/gatsby-site/src/components/cite/Tools.js index 8599e4f504..35e7ddb31e 100644 --- a/site/gatsby-site/src/components/cite/Tools.js +++ b/site/gatsby-site/src/components/cite/Tools.js @@ -1,8 +1,10 @@ +import React, { useEffect, useState } from 'react'; import { faEdit, faPlus, faSearch, faClone, + faTrash, faClockRotateLeft, } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; @@ -10,11 +12,11 @@ import { useUserContext } from 'contexts/userContext'; import { format } from 'date-fns'; import Card from 'elements/Card'; import { Button, ToggleSwitch } from 'flowbite-react'; -import React, { useEffect, useState } from 'react'; import { Trans, useTranslation } from 'react-i18next'; import { RESPONSE_TAG } from 'utils/entities'; import CitationFormat from './CitationFormat'; import NotifyButton from './NotifyButton'; +import RemoveDuplicateModal from 'components/cite/RemoveDuplicateModal'; function Tools({ incident, @@ -27,6 +29,8 @@ function Tools({ }) { const [isUserLoggedIn, setIsUserLoggedIn] = useState(false); + const [showRemoveDuplicateModal, setShowRemoveDuplicateModal] = useState(false); + const { t } = useTranslation(); const { isRole, user } = useUserContext(); @@ -92,19 +96,43 @@ function Tools({ {isUserLoggedIn && isRole('incident_editor') && ( - + <> + + + {showRemoveDuplicateModal && ( + setShowRemoveDuplicateModal(false)} + /> + )} + )} {isUserLoggedIn && isRole('taxonomy_editor') && ( - +
+
+ + Clear Filters + +
+
+
-
- -
- + +
+ + +
); }; diff --git a/site/gatsby-site/src/components/discover/Discover.js b/site/gatsby-site/src/components/discover/Discover.js index f62fa393e9..24a2cfc1f2 100644 --- a/site/gatsby-site/src/components/discover/Discover.js +++ b/site/gatsby-site/src/components/discover/Discover.js @@ -6,7 +6,7 @@ import algoliasearch from 'algoliasearch/lite'; import config from '../../../config'; import { navigate } from 'gatsby'; import { useLocalization } from 'plugins/gatsby-theme-i18n'; -import { InstantSearch } from 'react-instantsearch'; +import { Configure, InstantSearch } from 'react-instantsearch'; import SearchBox from 'components/discover/SearchBox'; import Hits from 'components/discover/Hits'; import Controls from './Controls'; @@ -37,13 +37,28 @@ export default function Discover() { const [width, setWidth] = useState(0); + const [currentPage, setCurrentPage] = useState(0); + const handleWindowSizeChange = useRef( debounce(() => { setWidth(window.innerWidth); }, 1000) ).current; + const [display, setDisplay] = useState(''); + useEffect(() => { + const queryString = window.location.search; + + const urlParams = new URLSearchParams(queryString); + + const display = urlParams.get('display'); + + setDisplay((prev) => { + if (display && display !== prev) { + return display; + } + }); window.addEventListener('resize', handleWindowSizeChange); handleWindowSizeChange(); @@ -53,6 +68,15 @@ export default function Discover() { }; }, []); + useEffect(() => { + const params = new URLSearchParams(window.location.search); + + const page = parseInt(params.get('page'), 10); + + // Set the current page from the URL, defaulting to 0 (Algolia's pagination is zero-based) + setCurrentPage(!isNaN(page) ? page - 1 : 0); + }, []); + if (width == 0) { return null; } @@ -72,8 +96,9 @@ export default function Discover() { return window.location; }, parseURL: ({ location }) => parseURL({ location, indexName, queryConfig, taxa }), - createURL: ({ routeState }) => - createURL({ indexName, locale, queryConfig, routeState, taxa }), + createURL: ({ routeState }) => { + return createURL({ indexName, locale, queryConfig, routeState, taxa, display }); + }, push: (url) => { navigate(`?${url}`); }, @@ -81,7 +106,8 @@ export default function Discover() { stateMapping: mapping(), }} > - + + diff --git a/site/gatsby-site/src/components/discover/DisplayModeSwitch.js b/site/gatsby-site/src/components/discover/DisplayModeSwitch.js index 3f59e67fcd..23f2c283aa 100644 --- a/site/gatsby-site/src/components/discover/DisplayModeSwitch.js +++ b/site/gatsby-site/src/components/discover/DisplayModeSwitch.js @@ -1,9 +1,10 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import { useQueryParam } from 'use-query-params'; import { DisplayModeEnumParam } from './queryParams'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faTh, faThList, faInfo } from '@fortawesome/free-solid-svg-icons'; import { Button } from 'flowbite-react'; +import { useInstantSearch } from 'react-instantsearch'; const modes = { details: { @@ -20,8 +21,30 @@ const modes = { export default function DisplayModeSwitch() { const [display, setDisplay] = useQueryParam('display', DisplayModeEnumParam); + const { indexUiState, setIndexUiState } = useInstantSearch(); + + const [, setConfigure] = useState({ ...indexUiState.configure }); + + useEffect(() => { + setConfigure((configure) => ({ ...configure, ...indexUiState.configure })); + }, [indexUiState]); + const onChange = (key) => { setDisplay(key); + setIndexUiState((previousState) => { + return { + ...previousState, + refinementList: { + ...previousState.refinementList, + display: [key], + }, + configure: { + ...previousState.configure, + }, + }; + }); + + setConfigure((configure) => ({ ...configure })); }; return ( @@ -32,8 +55,11 @@ export default function DisplayModeSwitch() { onClick={() => onChange(key)} size="sm" className={`${ - key == display ? 'bg-gray-700 hover:bg-gray-800' : 'bg-gray-500 hover:bg-gray-700' + key == display + ? 'bg-gray-700 hover:bg-gray-800 selected' + : 'bg-gray-500 hover:bg-gray-700' } text-white w-8`} + data-cy={`display-mode-${key}`} > diff --git a/site/gatsby-site/src/components/discover/Filter.js b/site/gatsby-site/src/components/discover/Filter.js index d70c57f65a..7a82cf0bec 100644 --- a/site/gatsby-site/src/components/discover/Filter.js +++ b/site/gatsby-site/src/components/discover/Filter.js @@ -103,7 +103,7 @@ function ButtonToggle({ label, faIcon, touched, type, filterProps }) { id="dropdown" className={`z-10 ${ toggled ? 'hidden' : 'block ' - } bg-white divide-y divide-gray-100 rounded-lg shadow w-44 dark:bg-gray-700`} + } bg-white divide-y divide-gray-100 rounded-lg shadow dark:bg-gray-700`} > diff --git a/site/gatsby-site/src/components/discover/Filters.js b/site/gatsby-site/src/components/discover/Filters.js index 43ff61efd1..e8d3d81b1e 100644 --- a/site/gatsby-site/src/components/discover/Filters.js +++ b/site/gatsby-site/src/components/discover/Filters.js @@ -1,12 +1,9 @@ import React from 'react'; import REFINEMENT_LISTS from 'components/discover/REFINEMENT_LISTS'; import Filter from './Filter'; -import { useMenuContext } from 'contexts/MenuContext'; import { graphql, useStaticQuery } from 'gatsby'; -function Filters() { - const { isCollapsed } = useMenuContext(); - +function Filters({ expandFilters }) { const { taxa: { nodes: taxa }, } = useStaticQuery(graphql` @@ -22,20 +19,36 @@ function Filters() { } `); + const firstRow = REFINEMENT_LISTS.slice(0, 5); + return ( -
- {REFINEMENT_LISTS.map((list) => ( -
- -
- ))} -
+ <> + {REFINEMENT_LISTS.map((list, i) => { + const secondRowNotExpanded = !expandFilters && !firstRow.includes(list); + + const isFirstFew = i < 2; + + let className = 'flex-0-0-auto px-1 order-4 w-full md:w-1/2 xl:w-1/5'; + + if (list.hidden) { + className += ' hidden'; + } + if (!expandFilters && !isFirstFew) { + className += ' 3xl:hidden'; + } + if (secondRowNotExpanded) { + className += ' hidden'; + } + if (isFirstFew && !expandFilters) { + className += ' 3xl:order-1 3xl:w-[unset]'; + } + return ( +
+ +
+ ); + })} + ); } diff --git a/site/gatsby-site/src/components/discover/REFINEMENT_LISTS.js b/site/gatsby-site/src/components/discover/REFINEMENT_LISTS.js index 17a48e7191..076346f978 100644 --- a/site/gatsby-site/src/components/discover/REFINEMENT_LISTS.js +++ b/site/gatsby-site/src/components/discover/REFINEMENT_LISTS.js @@ -36,24 +36,29 @@ const REFINEMENT_LISTS = [ showMoreLimit: 50, }, { - attribute: 'authors', + attribute: 'epoch_incident_date', placeholder: 'Type Here', - label: 'Authors', - faIcon: faIdCard, - faClasses: 'far fa-id-card', - type: 'refinement', - - // algolia specific - showMore: true, - showMoreLimit: 50, + label: 'Incident Date', + faIcon: faCalendarAlt, + faClasses: 'far fa-calendar-alt', + type: 'range', }, { - attribute: 'submitters', + attribute: 'epoch_date_published', + placeholder: 'none', + label: 'Published Date', + faIcon: faCalendarAlt, + faClasses: 'far fa-calendar-alt', + type: 'range', + }, + { + attribute: 'language', placeholder: 'Type Here', - label: 'Submitters', - faIcon: faUserShield, - faClasses: 'fas fa-user-shield', + label: 'Language', + faIcon: faGlobe, + faClasses: 'far fa-globe', type: 'refinement', + hidden: false, // algolia specific showMore: true, @@ -72,20 +77,28 @@ const REFINEMENT_LISTS = [ showMoreLimit: 50, }, { - attribute: 'epoch_incident_date', + attribute: 'authors', placeholder: 'Type Here', - label: 'Incident Date', - faIcon: faCalendarAlt, - faClasses: 'far fa-calendar-alt', - type: 'range', + label: 'Authors', + faIcon: faIdCard, + faClasses: 'far fa-id-card', + type: 'refinement', + + // algolia specific + showMore: true, + showMoreLimit: 50, }, { - attribute: 'epoch_date_published', - placeholder: 'none', - label: 'Published Date', - faIcon: faCalendarAlt, - faClasses: 'far fa-calendar-alt', - type: 'range', + attribute: 'submitters', + placeholder: 'Type Here', + label: 'Submitters', + faIcon: faUserShield, + faClasses: 'fas fa-user-shield', + type: 'refinement', + + // algolia specific + showMore: true, + showMoreLimit: 50, }, { attribute: 'flag', @@ -113,19 +126,16 @@ const REFINEMENT_LISTS = [ type: 'refinement', hidden: false, }, - { - attribute: 'language', - placeholder: 'Type Here', - label: 'Language', - faIcon: faGlobe, - faClasses: 'far fa-globe', - type: 'refinement', - hidden: false, - - // algolia specific - showMore: true, - showMoreLimit: 50, - }, ]; -export default REFINEMENT_LISTS; +const FIRST_ROW = REFINEMENT_LISTS.filter((refinement) => + [ + 'classifications', + 'epoch_incident_date', + 'epoch_date_published', + 'source_domain', + 'language', + ].includes(refinement.attribute) +); + +export { REFINEMENT_LISTS as default, FIRST_ROW }; diff --git a/site/gatsby-site/src/components/discover/SORTING_LISTS.js b/site/gatsby-site/src/components/discover/SORTING_LISTS.js index b4768d0686..c39a690e6d 100644 --- a/site/gatsby-site/src/components/discover/SORTING_LISTS.js +++ b/site/gatsby-site/src/components/discover/SORTING_LISTS.js @@ -8,6 +8,7 @@ const SORTING_LIST = [ value_en: 'instant_search-en-featured', value_es: 'instant_search-es-featured', value_fr: 'instant_search-fr-featured', + value_ja: 'instant_search-ja-featured', label: 'Relevance', faIcon: faCalendarAlt, faClasses: 'far fa-calendar-alt', @@ -19,6 +20,7 @@ const SORTING_LIST = [ value_en: 'instant_search-en_epoch_incident_date_desc', value_es: 'instant_search-es_epoch_incident_date_desc', value_fr: 'instant_search-fr_epoch_incident_date_desc', + value_ja: 'instant_search-ja_epoch_incident_date_desc', label: 'Newest Incident Date', faIcon: faCalendarAlt, faClasses: 'far fa-calendar-alt', @@ -30,6 +32,7 @@ const SORTING_LIST = [ value_en: 'instant_search-en_epoch_incident_date_asc', value_es: 'instant_search-es_epoch_incident_date_asc', value_fr: 'instant_search-fr_epoch_incident_date_asc', + value_ja: 'instant_search-ja_epoch_incident_date_asc', label: 'Oldest Incident Date', faIcon: faCalendarAlt, faClasses: 'far fa-calendar-alt', @@ -42,6 +45,7 @@ const SORTING_LIST = [ value_en: 'instant_search-en_epoch_date_published_desc', value_es: 'instant_search-es_epoch_date_published_desc', value_fr: 'instant_search-fr_epoch_date_published_desc', + value_ja: 'instant_search-ja_epoch_date_published_desc', label: 'Newest Published Date', faIcon: faCalendarAlt, faClasses: 'far fa-calendar-alt', @@ -53,6 +57,7 @@ const SORTING_LIST = [ value_en: 'instant_search-en_epoch_date_published_asc', value_es: 'instant_search-es_epoch_date_published_asc', value_fr: 'instant_search-fr_epoch_date_published_asc', + value_ja: 'instant_search-ja_epoch_date_published_asc', label: 'Oldest Published Date', faIcon: faCalendarAlt, faClasses: 'far fa-calendar-alt', @@ -65,6 +70,7 @@ const SORTING_LIST = [ value_en: 'instant_search-en_epoch_date_submitted_desc', value_es: 'instant_search-es_epoch_date_submitted_desc', value_fr: 'instant_search-fr_epoch_date_submitted_desc', + value_ja: 'instant_search-ja_epoch_date_submitted_desc', label: 'Newest Submitted Date', faIcon: faCalendarAlt, faClasses: 'far fa-calendar-alt', @@ -76,6 +82,7 @@ const SORTING_LIST = [ value_en: 'instant_search-en_epoch_date_submitted_asc', value_es: 'instant_search-es_epoch_date_submitted_asc', value_fr: 'instant_search-fr_epoch_date_submitted_asc', + value_ja: 'instant_search-ja_epoch_date_submitted_asc', label: 'Oldest Submitted Date', faIcon: faCalendarAlt, faClasses: 'far fa-calendar-alt', diff --git a/site/gatsby-site/src/components/discover/Stats.js b/site/gatsby-site/src/components/discover/Stats.js index 621ce388c7..3f520caf9d 100644 --- a/site/gatsby-site/src/components/discover/Stats.js +++ b/site/gatsby-site/src/components/discover/Stats.js @@ -1,16 +1,12 @@ import React from 'react'; import { Trans } from 'react-i18next'; import { useStats } from 'react-instantsearch'; -import DisplayOptions from './DisplayOptions'; export default function Stats({ className, ...props }) { const { nbHits: count } = useStats(props); return (
- - -
{count} results found
diff --git a/site/gatsby-site/src/components/discover/createURL.js b/site/gatsby-site/src/components/discover/createURL.js index 49ca492009..e2eb8824c0 100644 --- a/site/gatsby-site/src/components/discover/createURL.js +++ b/site/gatsby-site/src/components/discover/createURL.js @@ -43,6 +43,8 @@ const convertRangeToQueryString = (range) => { const getQueryFromState = ({ state, locale, taxa }) => { let query = {}; + if (!state) return query; + if (state.query !== '') { query.s = state.query; } @@ -93,14 +95,18 @@ const getQueryFromState = ({ state, locale, taxa }) => { return query; }; -export default function ({ routeState, indexName, locale, queryConfig, taxa }) { +export default function ({ routeState, indexName, locale, queryConfig, taxa, display }) { const state = routeState[indexName] || {}; const query = getQueryFromState({ state, locale, taxa }); const encoded = encodeQueryParams(queryConfig, query); - const stringified = stringify(encoded); + let stringified = stringify(encoded); + + if (display) { + stringified += `&display=${display}`; + } return stringified; } diff --git a/site/gatsby-site/src/components/discover/filterTypes/Classifications.js b/site/gatsby-site/src/components/discover/filterTypes/Classifications.js index 837523484c..81540aa853 100644 --- a/site/gatsby-site/src/components/discover/filterTypes/Classifications.js +++ b/site/gatsby-site/src/components/discover/filterTypes/Classifications.js @@ -141,7 +141,7 @@ function SelectedRefinement({ attribute }) { .map((item) => (
refine(item.value)} diff --git a/site/gatsby-site/src/components/discover/hitTypes/List.js b/site/gatsby-site/src/components/discover/hitTypes/List.js index 9a6db15cea..bf03e32f38 100644 --- a/site/gatsby-site/src/components/discover/hitTypes/List.js +++ b/site/gatsby-site/src/components/discover/hitTypes/List.js @@ -5,7 +5,7 @@ import TranslationBadge from 'components/i18n/TranslationBadge'; import { VIEW_TYPES } from 'utils/discover'; import ReportCard from 'components/reports/ReportCard'; -export default function Details({ item, toggleFilterByIncidentId, viewType }) { +export default function List({ item, toggleFilterByIncidentId, viewType }) { const actions = ; item.title = viewType === VIEW_TYPES.INCIDENTS ? item.incident_title : item.title; diff --git a/site/gatsby-site/src/components/doc/PrismicDocPost.js b/site/gatsby-site/src/components/doc/PrismicDocPost.js index f14527eac5..6d94ad2a02 100644 --- a/site/gatsby-site/src/components/doc/PrismicDocPost.js +++ b/site/gatsby-site/src/components/doc/PrismicDocPost.js @@ -19,6 +19,8 @@ const PrismicDocPost = ({ doc, location }) => { Sponsors: , }; + if (!doc) return <>; + const metaTitle = doc.data.metatitle; const metaDescription = doc.data.metadescription; diff --git a/site/gatsby-site/src/components/i18n/LanguageSwitcher.js b/site/gatsby-site/src/components/i18n/LanguageSwitcher.js index 0540dbdbc4..2d1b3e52f9 100644 --- a/site/gatsby-site/src/components/i18n/LanguageSwitcher.js +++ b/site/gatsby-site/src/components/i18n/LanguageSwitcher.js @@ -3,6 +3,8 @@ import { useLocalization } from 'plugins/gatsby-theme-i18n'; import useLocalizePath from './useLocalizePath'; import { Badge, Dropdown } from 'flowbite-react'; +const isBetaLocale = ({ code }) => code === 'fr' || code === 'ja'; + export default function LanguageSwitcher({ className = '' }) { const { locale: currentLang, config } = useLocalization(); @@ -38,7 +40,7 @@ export default function LanguageSwitcher({ className = '' }) { label={ {currentLocale.localName} - {currentLocale.code === 'fr' && ( + {isBetaLocale(currentLocale) && ( Beta @@ -55,7 +57,7 @@ export default function LanguageSwitcher({ className = '' }) { className="flex" > {locale.localName} - {locale.code === 'fr' && ( + {isBetaLocale(locale) && ( Beta diff --git a/site/gatsby-site/src/components/incidents/IncidentsField.js b/site/gatsby-site/src/components/incidents/IncidentsField.js index d8a7dce64a..af5e5f1408 100644 --- a/site/gatsby-site/src/components/incidents/IncidentsField.js +++ b/site/gatsby-site/src/components/incidents/IncidentsField.js @@ -10,7 +10,7 @@ const filterBy = (option, text) => { ); }; -export default function IncidentsField({ id, name, placeHolder = '' }) { +export default function IncidentsField({ id, name, placeHolder = '', multiple = true, className }) { const [{ value }, , { setTouched, setValue }] = useField({ name }); const { data } = useQuery(FIND_INCIDENTS_TITLE); @@ -57,13 +57,13 @@ export default function IncidentsField({ id, name, placeHolder = '' }) { return ( <> true} id={id} inputProps={{ id: 'input-' + id, name }} selected={selected} options={options} - multiple + multiple={multiple} labelKey={(option) => `${option.id}`} isLoading={loading} onSearch={handleSearch} diff --git a/site/gatsby-site/src/components/landing/QuickSearch.js b/site/gatsby-site/src/components/landing/QuickSearch.js index 867c9df3bb..324f545e0b 100644 --- a/site/gatsby-site/src/components/landing/QuickSearch.js +++ b/site/gatsby-site/src/components/landing/QuickSearch.js @@ -14,11 +14,11 @@ export default function QuickSearch() { const width = window.innerWidth; if (width >= 350 && width < 450) { - setSearchPlaceholder(t('Search 2000+ reports')); + setSearchPlaceholder(t('Search 3000+ reports')); } else if (width >= 450 && width < 500) { - setSearchPlaceholder(t('Search 2000+ AI harm reports')); + setSearchPlaceholder(t('Search 3000+ AI harm reports')); } else if (width >= 500) { - setSearchPlaceholder(t('Search over 2000 reports of AI harms')); + setSearchPlaceholder(t('Search over 3000 reports of AI harms')); } else { setSearchPlaceholder(t('Search reports')); } @@ -82,7 +82,7 @@ export default function QuickSearch() { onKeyPress={(e) => { e.key === 'Enter' && submit(e); }} - aria-label={t('Search over 1800 reports of AI harms')} + aria-label={t('Search over 3000 reports of AI harms')} />
diff --git a/site/gatsby-site/src/components/layout/Footer.js b/site/gatsby-site/src/components/layout/Footer.js index 442e239d0a..399676148e 100644 --- a/site/gatsby-site/src/components/layout/Footer.js +++ b/site/gatsby-site/src/components/layout/Footer.js @@ -115,7 +115,7 @@ export default function Footer() { id="main-footer" className="bg-text-light-gray relative sm:grid sm:grid-cols-2 md:grid-cols-4 gap-5 p-5 z-50" > - {footerContent.map((group) => { + {footerContent.map((group, i) => { const title = group.title; const items = group.items; @@ -203,6 +203,14 @@ export default function Footer() { })}
)} + + {i == footerContent.length - 1 && process.env.GATSBY_COMMIT_SHA && ( +
  • +
    + {process.env.GATSBY_COMMIT_SHA.toString().substring(0, 7)} +
    +
  • + )}
    ); @@ -210,7 +218,7 @@ export default function Footer() { {allPrismicFooter.edges.length <= 0 && (
    -

    2023 - AI Incident Database

    +

    2024 - AI Incident Database

    Terms of use diff --git a/site/gatsby-site/src/components/reports/ReportCard.js b/site/gatsby-site/src/components/reports/ReportCard.js index 8343befc8b..c63be93492 100644 --- a/site/gatsby-site/src/components/reports/ReportCard.js +++ b/site/gatsby-site/src/components/reports/ReportCard.js @@ -24,7 +24,7 @@ const ReportCard = ({ incidentId = null, readOnly = false, }) => { - item.incident_id = incidentId; + item.incident_id = incidentId || item.incident_id; const { t } = useTranslation(); diff --git a/site/gatsby-site/src/components/submissions/SubmissionEditForm.js b/site/gatsby-site/src/components/submissions/SubmissionEditForm.js index a408c69103..56a7140ffe 100644 --- a/site/gatsby-site/src/components/submissions/SubmissionEditForm.js +++ b/site/gatsby-site/src/components/submissions/SubmissionEditForm.js @@ -55,7 +55,7 @@ const SubmissionEditForm = ({ handleSubmit, saving, setSaving, userLoading, user const addToast = useToastContext(); - const { i18n, t } = useTranslation(['submitted']); + const { i18n, t } = useTranslation(['submitted', 'validation']); const [promoteSubmissionToReport] = useMutation(PROMOTE_SUBMISSION, { fetchPolicy: 'network-only', @@ -92,7 +92,7 @@ const SubmissionEditForm = ({ handleSubmit, saving, setSaving, userLoading, user const { user, isRole } = useUserContext(); - const isSubmitter = isRole('submitter'); + const canEditSubmissions = isRole('submitter') || isRole('incident_editor') || isRole('admin'); const subscribeToNewReports = async (incident_id) => { if (user) { @@ -429,7 +429,7 @@ const SubmissionEditForm = ({ handleSubmit, saving, setSaving, userLoading, user