diff --git a/site/gatsby-site/cypress/e2e/integration/apps/checklistsIndex.cy.js b/site/gatsby-site/cypress/e2e/integration/apps/checklistsIndex.cy.js index 760edaffd4..73009e13ae 100644 --- a/site/gatsby-site/cypress/e2e/integration/apps/checklistsIndex.cy.js +++ b/site/gatsby-site/cypress/e2e/integration/apps/checklistsIndex.cy.js @@ -7,6 +7,13 @@ describe('Checklists App Index', () => { const newChecklistButtonQuery = '#new-checklist-button'; + const testError = { + 0: { + message: 'Test error', + locations: [{ line: 1, column: 1 }], + }, + }; + const usersQuery = { query: gql` { @@ -91,4 +98,118 @@ describe('Checklists App Index', () => { cy.get('[data-cy="checklist-card"]:last-child button').contains('Delete').should('not.exist'); }); }); + + it('Should show toast on error fetching checklists', () => { + cy.conditionalIntercept( + '**/graphql', + (req) => req.body.operationName == 'findChecklists', + 'findChecklists', + { errors: [testError] } + ); + + cy.visit(url); + + cy.get('[data-cy="toast"]').contains('Could not fetch checklists').should('exist'); + }); + + it('Should show toast on error fetching risks', () => { + cy.query(usersQuery).then(({ data: { users } }) => { + const user = users.find((user) => user.adminData.email == Cypress.env('e2eUsername')); + + cy.conditionalIntercept( + '**/graphql', + (req) => req.body.operationName == 'findChecklists', + 'findChecklists', + { + data: { + checklists: [ + { + about: '', + id: 'fakeChecklist1', + name: 'My Checklist', + owner_id: user.userId, + risks: [], + tags_goals: ['GMF:Known AI Goal:Translation'], + tags_methods: [], + tags_other: [], + }, + { + about: '', + id: 'fakeChecklist2', + name: "Somebody Else's Checklist", + owner_id: 'aFakeUserId', + risks: [], + tags_goals: [], + tags_methods: [], + tags_other: [], + }, + ], + }, + } + ); + + cy.conditionalIntercept('**/graphql', (req) => req.body.query.includes('GMF'), 'risks', { + errors: [testError], + }); + + cy.login(Cypress.env('e2eUsername'), Cypress.env('e2ePassword')); + + cy.visit(url); + + cy.get('[data-cy="toast"]').contains('Failure searching for risks').should('exist'); + }); + }); + + maybeIt('Should show toast on error creating checklist', () => { + cy.query(usersQuery).then(({ data: { users } }) => { + const user = users.find((user) => user.adminData.email == Cypress.env('e2eUsername')); + + cy.conditionalIntercept( + '**/graphql', + (req) => req.body.operationName == 'insertChecklist', + 'insertChecklist', + { errors: [testError] } + ); + + cy.conditionalIntercept( + '**/graphql', + (req) => req.body.operationName == 'findChecklists', + 'findChecklists', + { + data: { + checklists: [ + { + about: '', + id: 'fakeChecklist1', + name: 'My Checklist', + owner_id: user.userId, + risks: [], + tags_goals: [], + tags_methods: [], + tags_other: [], + }, + { + about: '', + id: 'fakeChecklist2', + name: "Somebody Else's Checklist", + owner_id: 'aFakeUserId', + risks: [], + tags_goals: [], + tags_methods: [], + tags_other: [], + }, + ], + }, + } + ); + + cy.login(Cypress.env('e2eUsername'), Cypress.env('e2ePassword')); + + cy.visit(url); + + cy.get(newChecklistButtonQuery).click(); + + cy.get('[data-cy="toast"]').contains('Could not create checklist.').should('exist'); + }); + }); }); diff --git a/site/gatsby-site/cypress/e2e/integration/apps/reports.cy.js b/site/gatsby-site/cypress/e2e/integration/apps/reports.cy.js index 10688207a0..5e2f740336 100644 --- a/site/gatsby-site/cypress/e2e/integration/apps/reports.cy.js +++ b/site/gatsby-site/cypress/e2e/integration/apps/reports.cy.js @@ -1,21 +1,16 @@ -import reports from '../../../fixtures/reports/reports.json'; - describe('Reports App', () => { - const url = '/apps/reports'; + const url = '/apps/incidents'; - it('Successfully loads', () => { - cy.visit(url); + it('Successfully loads reports', () => { + cy.visit(url + '?view=reports'); }); - it('Filters a report by title ', () => { - cy.visit(url); + it('Successfully loads issue reports', () => { + cy.visit(url + '?view=issueReports'); + }); - cy.conditionalIntercept( - '**/graphql', - (req) => req.body.operationName == 'ReportsQuery', - 'ReportsQuery', - reports - ); + it('Filters a report by title ', () => { + cy.visit(url + '?view=reports'); cy.get('[data-cy="filter"]', { timeout: 15000 }) .eq(1) diff --git a/site/gatsby-site/cypress/e2e/integration/cite.cy.js b/site/gatsby-site/cypress/e2e/integration/cite.cy.js index 3699c3a130..66e740bd03 100644 --- a/site/gatsby-site/cypress/e2e/integration/cite.cy.js +++ b/site/gatsby-site/cypress/e2e/integration/cite.cy.js @@ -199,7 +199,7 @@ describe('Cite pages', () => { expect(variables.query.report_number).to.equal(23); expect(variables.set).deep.eq({ flag: true, - date_modified: format(now, 'yyyy-MM-dd'), + date_modified: now.toISOString(), epoch_date_modified: getUnixTime(now), }); }); @@ -212,7 +212,7 @@ describe('Cite pages', () => { ); expectedReport.modifiedBy = ''; - expectedReport.date_modified = format(now, 'yyyy-MM-dd'); + expectedReport.date_modified = now.toISOString(); expectedReport.epoch_date_modified = getUnixTime(now); expect(input).to.deep.eq(expectedReport); diff --git a/site/gatsby-site/cypress/e2e/integration/citeEdit.cy.js b/site/gatsby-site/cypress/e2e/integration/citeEdit.cy.js index 33009e986b..dff0592ca8 100644 --- a/site/gatsby-site/cypress/e2e/integration/citeEdit.cy.js +++ b/site/gatsby-site/cypress/e2e/integration/citeEdit.cy.js @@ -156,6 +156,8 @@ describe('Edit report', () => { cy.get(`[name=${key}]`).clear().type(updates[key]); }); + cy.get(`[name="quiet"]`).click(); + cy.setEditorText( '## This is text in English\n\nthat is longer that eighty characters, yes eighty characters!', '[data-cy="text"] .CodeMirror' @@ -215,6 +217,7 @@ describe('Edit report', () => { source_domain: 'test.com', editor_notes: 'Pro iustitia tantum', language: 'en', + quiet: true, }; cy.wait('@updateReport').then((xhr) => { diff --git a/site/gatsby-site/cypress/e2e/integration/discover.cy.js b/site/gatsby-site/cypress/e2e/integration/discover.cy.js index acfcac0ec5..3e6f12f24c 100644 --- a/site/gatsby-site/cypress/e2e/integration/discover.cy.js +++ b/site/gatsby-site/cypress/e2e/integration/discover.cy.js @@ -2,7 +2,7 @@ import flaggedReport from '../../fixtures/reports/flagged.json'; import unflaggedReport from '../../fixtures/reports/unflagged.json'; import config from '../../../config'; import path from 'path'; -import { format, getUnixTime } from 'date-fns'; +import { getUnixTime } from 'date-fns'; import { deleteReportTypenames, transformReportData } from '../../../src/utils/reports'; import { conditionalIt } from '../../support/utils'; @@ -267,7 +267,7 @@ describe('The Discover app', () => { expect(variables.query.report_number).to.equal(23); expect(variables.set).deep.eq({ flag: true, - date_modified: format(now, 'yyyy-MM-dd'), + date_modified: now.toISOString(), epoch_date_modified: getUnixTime(now), }); }); @@ -280,7 +280,7 @@ describe('The Discover app', () => { ); expectedReport.modifiedBy = ''; - expectedReport.date_modified = format(now, 'yyyy-MM-dd'); + expectedReport.date_modified = now.toISOString(); expectedReport.epoch_date_modified = getUnixTime(now); expect(input).to.deep.eq(expectedReport); diff --git a/site/gatsby-site/cypress/e2e/unit/functions/promoteSubmissionToReport.cy.js b/site/gatsby-site/cypress/e2e/unit/functions/promoteSubmissionToReport.cy.js index 6bc67a8a00..4a6be30bd9 100644 --- a/site/gatsby-site/cypress/e2e/unit/functions/promoteSubmissionToReport.cy.js +++ b/site/gatsby-site/cypress/e2e/unit/functions/promoteSubmissionToReport.cy.js @@ -35,6 +35,7 @@ const submission = { editor_similar_incidents: [], tags: [], user: 'user1', + quiet: false, }; const submission_with_embedding = { @@ -68,6 +69,7 @@ const submission_with_embedding = { editor_similar_incidents: [], tags: [], user: 'user1', + quiet: false, embedding: { vector: [1, 2, 3], from_reports: [1], @@ -244,6 +246,7 @@ describe('Functions', () => { language: 'en', tags: [], user: 'user1', + quiet: false, }; expect(reportsCollection.insertOne.firstCall.args[0]).to.deep.eq(expectedReport); @@ -404,6 +407,7 @@ describe('Functions', () => { language: 'en', tags: [], user: 'user1', + quiet: false, embedding: { vector: [1, 2, 3], from_reports: [1], @@ -561,6 +565,7 @@ describe('Functions', () => { language: 'en', tags: [], user: 'user1', + quiet: false, }; expect(reportsCollection.insertOne.firstCall.args[0]).to.deep.eq(expectedReport); @@ -862,6 +867,7 @@ describe('Functions', () => { source_domain: 'projects.tampabay.com', language: 'en', tags: [], + quiet: false, }; expect(reportsCollection.insertOne.firstCall.args[0]).to.deep.eq(expectedReport); diff --git a/site/gatsby-site/cypress/fixtures/reports/flagged.json b/site/gatsby-site/cypress/fixtures/reports/flagged.json index c743218911..f68ddbb23e 100644 --- a/site/gatsby-site/cypress/fixtures/reports/flagged.json +++ b/site/gatsby-site/cypress/fixtures/reports/flagged.json @@ -33,7 +33,8 @@ "epoch_date_downloaded": 1559347200, "date_submitted": "2019-06-01", "date_modified": "2019-06-02", - "language": "en" + "language": "en", + "quiet": false } } } diff --git a/site/gatsby-site/cypress/fixtures/reports/unflagged.json b/site/gatsby-site/cypress/fixtures/reports/unflagged.json index 4bda34cb45..ac899774f1 100644 --- a/site/gatsby-site/cypress/fixtures/reports/unflagged.json +++ b/site/gatsby-site/cypress/fixtures/reports/unflagged.json @@ -33,7 +33,8 @@ "epoch_date_modified": 1559347200, "epoch_date_downloaded": 1559347200, "date_submitted": "2019-06-01", - "date_modified": "2019-06-02" + "date_modified": "2019-06-02", + "quiet": false } } } diff --git a/site/gatsby-site/gatsby-node.js b/site/gatsby-site/gatsby-node.js index 20442a1b7f..9bd99f9177 100644 --- a/site/gatsby-site/gatsby-node.js +++ b/site/gatsby-site/gatsby-node.js @@ -14,6 +14,8 @@ const createCitationPages = require('./page-creators/createCitationPages'); const createWordCountsPages = require('./page-creators/createWordCountsPage'); +const createLandingPage = require('./page-creators/createLandingPage'); + const createBackupsPage = require('./page-creators/createBackupsPage'); const createTaxonomyPages = require('./page-creators/createTaxonomyPages'); @@ -76,6 +78,7 @@ exports.createPages = async ({ actions, graphql, reporter }) => { createBlogPages, createCitationPages, createWordCountsPages, + createLandingPage, createBackupsPage, createTaxonomyPages, createDownloadIndexPage, diff --git a/site/gatsby-site/i18n/locales/en/popovers.json b/site/gatsby-site/i18n/locales/en/popovers.json index 77e0e186e4..f3bebfbea1 100644 --- a/site/gatsby-site/i18n/locales/en/popovers.json +++ b/site/gatsby-site/i18n/locales/en/popovers.json @@ -74,5 +74,9 @@ "submittersLoggedIn": { "title": "This is you!", "text": "You are currently logged in so this submission will automatically be associated with your account. If you would like to remain anonymous, please open a private browsing window to submit." + }, + "quiet": { + "title": "Quiet", + "text": "Quiet reports are those that will not be published in the 'Latest Reports' section of the homepage. Quiet reports are used for reports that are useful for internal data but do not need to be promoted. If you are unsure, leave this field blank." } } diff --git a/site/gatsby-site/i18n/locales/es/popovers.json b/site/gatsby-site/i18n/locales/es/popovers.json index afcb8c27bc..a7a0c6179f 100644 --- a/site/gatsby-site/i18n/locales/es/popovers.json +++ b/site/gatsby-site/i18n/locales/es/popovers.json @@ -74,5 +74,9 @@ "submittersLoggedIn": { "title": "¡Este eres tú!", "text": "Actualmente estás conectado, por lo que este reporte se asociará automáticamente con tu cuenta. Si deseas permanecer anónimo, por favor abre una ventana de navegación privada." + }, + "quiet": { + "title": "¿Es un informe silencioso?", + "text": "Los informes silenciosos son aquellos que no se publicarán en la sección 'Últimos informes' de la página de inicio. Los informes silenciosos se utilizan para informes que son útiles para datos internos pero que no necesitan promocionarse. Si no está seguro, deje este campo en blanco." } } diff --git a/site/gatsby-site/i18n/locales/es/translation.json b/site/gatsby-site/i18n/locales/es/translation.json index 77290f5c55..eaaf4fcbbc 100644 --- a/site/gatsby-site/i18n/locales/es/translation.json +++ b/site/gatsby-site/i18n/locales/es/translation.json @@ -291,6 +291,8 @@ "Issue Reports": "Informes de Problemas", "found": "encontrados", "results found": "resultados encontrados", + "Displaying {{pageLength}} of {{allResultsCount}} reports": "Mostrando {{pageLength}} de {{allResultsCount}} informes", + "Displaying {{pageLength}} of {{allResultsCount}} incidents": "Mostrando {{pageLength}} de {{allResultsCount}} incidentes", "Blog": "Blog", "AI News Digest": "Resumen de noticias de IA", "Remove Duplicate": "Eliminar Duplicado", diff --git a/site/gatsby-site/i18n/locales/fr/popovers.json b/site/gatsby-site/i18n/locales/fr/popovers.json index 385218d842..206584a553 100644 --- a/site/gatsby-site/i18n/locales/fr/popovers.json +++ b/site/gatsby-site/i18n/locales/fr/popovers.json @@ -62,5 +62,9 @@ "submittersLoggedIn": { "title": "C'est vous !", "text": "Vous êtes actuellement connecté, donc cette soumission sera automatiquement associée à votre compte. Si vous souhaitez rester anonyme, veuillez ouvrir une fenêtre de navigation privée pour soumettre." + }, + "quiet": { + "title": "Est-ce un rapport silencieux ?", + "text": "Les rapports silencieux sont ceux qui ne seront pas publiés dans la section « Derniers rapports » de la page d'accueil. Les rapports silencieux sont utilisés pour les rapports utiles pour les données internes mais qui n'ont pas besoin d'être promus. Si vous n'êtes pas sûr, laissez ce champ vide." } } \ No newline at end of file diff --git a/site/gatsby-site/i18n/locales/fr/translation.json b/site/gatsby-site/i18n/locales/fr/translation.json index 6b3a2eddac..9f050b8dcc 100644 --- a/site/gatsby-site/i18n/locales/fr/translation.json +++ b/site/gatsby-site/i18n/locales/fr/translation.json @@ -279,6 +279,8 @@ "Issue Reports": "Rapports de problèmes", "found": "trouvés", "results found": "résultats trouvés", + "Displaying {{pageLength}} of {{allResultsCount}} reports": "Affichage de {{pageLength}} sur {{allResultsCount}} rapports", + "Displaying {{pageLength}} of {{allResultsCount}} incidents": "Affichage de {{pageLength}} sur {{allResultsCount}} incidents", "Blog": "Blog", "AI News Digest": "Résumé de l’Actualité sur l’IA", "Remove Duplicate": "Supprimer le doublon", diff --git a/site/gatsby-site/page-creators/createLandingPage.js b/site/gatsby-site/page-creators/createLandingPage.js new file mode 100644 index 0000000000..aa81571bf0 --- /dev/null +++ b/site/gatsby-site/page-creators/createLandingPage.js @@ -0,0 +1,86 @@ +const path = require('path'); + +const createLandingPage = async (graphql, createPage) => { + const result = await graphql(` + query LandingPage { + latestIncidents: allMongodbAiidprodIncidents( + filter: { + reports: { elemMatch: { is_incident_report: { eq: true }, quiet: { in: [null, false] } } } + } + sort: { reports: { epoch_date_submitted: DESC } } + limit: 5 + ) { + nodes { + title + incident_id + reports { + cloudinary_id + epoch_date_submitted + image_url + report_number + source_domain + text + title + url + } + } + } + + sponsors: allPrismicSponsor(sort: { data: { order: { text: ASC } } }) { + edges { + node { + data { + title { + text + richText + } + order { + text + } + language { + text + } + items { + name { + text + } + description { + richText + } + logo { + gatsbyImageData + url + } + link { + url + } + } + } + } + } + } + } + `); + + const latestIncidents = result.data.latestIncidents.nodes; + + const latestIncidentsReportNumbers = result.data.latestIncidents.nodes.map((node) => { + const sortedArray = node.reports.sort((a, b) => { + return a.epoch_date_submitted - b.epoch_date_submitted; + }); + + return sortedArray[0].report_number; + }); + + createPage({ + path: '/', + component: path.resolve('./src/templates/landingPage.js'), + context: { + latestIncidents, + latestIncidentsReportNumbers, + sponsors: result.data.sponsors.edges, + }, + }); +}; + +module.exports = createLandingPage; diff --git a/site/gatsby-site/page-creators/createWordCountsPage.js b/site/gatsby-site/page-creators/createWordCountsPage.js index 07cfeeeb91..ac0d5ee541 100644 --- a/site/gatsby-site/page-creators/createWordCountsPage.js +++ b/site/gatsby-site/page-creators/createWordCountsPage.js @@ -11,10 +11,6 @@ const PAGES_WITH_WORDCOUNT = [ path: '/summaries/wordcounts', componentPath: './src/templates/wordcounts.js', }, - { - path: '/', - componentPath: './src/templates/landingPage.js', - }, ]; const createWordCountsPage = async (graphql, createPage) => { @@ -25,59 +21,6 @@ const createWordCountsPage = async (graphql, createPage) => { text } } - latestReport: allMongodbAiidprodReports( - filter: { is_incident_report: { eq: true } } - sort: { epoch_date_submitted: DESC } - limit: 1 - ) { - nodes { - report_number - } - } - latestReports: allMongodbAiidprodIncidents( - filter: { reports: { elemMatch: { is_incident_report: { eq: true } } } } - sort: { reports: { epoch_date_submitted: DESC } } - limit: 5 - ) { - nodes { - reports { - report_number - } - } - } - sponsors: allPrismicSponsor(sort: { data: { order: { text: ASC } } }) { - edges { - node { - data { - title { - text - richText - } - order { - text - } - language { - text - } - items { - name { - text - } - description { - richText - } - logo { - gatsbyImageData - url - } - link { - url - } - } - } - } - } - } } `); @@ -125,14 +68,6 @@ const createWordCountsPage = async (graphql, createPage) => { } } - const latestReportNumbers = result.data.latestReports.nodes.map((node) => { - const sortedArray = node.reports.sort((a, b) => { - return a.epoch_date_submitted - b.epoch_date_submitted; - }); - - return sortedArray[0].report_number; - }); - PAGES_WITH_WORDCOUNT.forEach((page) => { createPage({ path: page.path, @@ -141,12 +76,6 @@ const createWordCountsPage = async (graphql, createPage) => { wordClouds, wordCountsSorted, wordsPerCloud, - latestReportNumber: - result.data.latestReport.nodes.length > 0 - ? result.data.latestReport.nodes[0].report_number - : 0, - latestReportNumbers, - sponsors: result.data.sponsors.edges, }, }); }); diff --git a/site/gatsby-site/src/components/checklists/CheckListForm.js b/site/gatsby-site/src/components/checklists/CheckListForm.js index 4c5b0bee63..0d2871afe5 100644 --- a/site/gatsby-site/src/components/checklists/CheckListForm.js +++ b/site/gatsby-site/src/components/checklists/CheckListForm.js @@ -101,7 +101,7 @@ export default function CheckListForm({ const { data: generatedRisksData, loading: generatedRisksLoading, - errors: generatedRisksErrors, + error: generatedRisksErrors, } = useQuery( gql` query { @@ -124,6 +124,7 @@ export default function CheckListForm({ addToast({ message: t('Failure searching for risks.'), severity: SEVERITY.danger, + error: generatedRisksErrors, }); } diff --git a/site/gatsby-site/src/components/checklists/ChecklistsIndex.js b/site/gatsby-site/src/components/checklists/ChecklistsIndex.js index 4e5115a6ff..563d3fc457 100644 --- a/site/gatsby-site/src/components/checklists/ChecklistsIndex.js +++ b/site/gatsby-site/src/components/checklists/ChecklistsIndex.js @@ -40,11 +40,23 @@ const ChecklistsIndex = ({ users }) => { const [insertChecklist] = useMutation(INSERT_CHECKLIST); /************************** Get Checklists **************************/ - const { data: checklistsData, loading: checklistsLoading } = useQuery(FIND_CHECKLISTS, { + const { + data: checklistsData, + loading: checklistsLoading, + error: checklistsErrors, + } = useQuery(FIND_CHECKLISTS, { variables: { query: { owner_id: user?.id } }, skip: !user?.id, }); + if (checklistsErrors) { + addToast({ + message: t('Could not fetch checklists'), + severity: SEVERITY.danger, + error: checklistsErrors, + }); + } + // In useState so that on deleting a checklist, // we can remove it from display immediately. const [checklists, setChecklists] = useState([]); @@ -104,7 +116,17 @@ const ChecklistsIndex = ({ users }) => { } `; - const { data: risksData } = useQuery(gql(riskQuery), { skip: skipRisksQuery }); + const { data: risksData, error: risksErrors } = useQuery(gql(riskQuery), { + skip: skipRisksQuery, + }); + + if (risksErrors) { + addToast({ + message: t('Failure searching for risks.'), + severity: SEVERITY.danger, + error: risksErrors, + }); + } /************************ Prepare Display ***************************/ const [sortBy, setSortBy] = useState('alphabetical'); diff --git a/site/gatsby-site/src/components/discover/Actions.js b/site/gatsby-site/src/components/discover/Actions.js index 970f8d607d..93d64aeee6 100644 --- a/site/gatsby-site/src/components/discover/Actions.js +++ b/site/gatsby-site/src/components/discover/Actions.js @@ -17,7 +17,7 @@ import CustomButton from '../../elements/Button'; import { Modal } from 'flowbite-react'; import { useUserContext } from 'contexts/userContext'; import { useLogReportHistory } from '../../hooks/useLogReportHistory'; -import { format, getUnixTime } from 'date-fns'; +import { getUnixTime } from 'date-fns'; import useLocalizePath from 'components/i18n/useLocalizePath'; function FlagModalContent({ reportNumber }) { @@ -36,7 +36,7 @@ function FlagModalContent({ reportNumber }) { const updated = { flag: true, - date_modified: format(now, 'yyyy-MM-dd'), + date_modified: now, epoch_date_modified: getUnixTime(now), }; diff --git a/site/gatsby-site/src/components/forms/IncidentReportForm.js b/site/gatsby-site/src/components/forms/IncidentReportForm.js index ddb75ab2ca..0fea80a5da 100644 --- a/site/gatsby-site/src/components/forms/IncidentReportForm.js +++ b/site/gatsby-site/src/components/forms/IncidentReportForm.js @@ -1,5 +1,5 @@ import React, { useCallback, useEffect, useState } from 'react'; -import { Select } from 'flowbite-react'; +import { Checkbox, Select } from 'flowbite-react'; import { Form, useFormikContext } from 'formik'; import * as yup from 'yup'; import TextInputGroup from '../../components/forms/TextInputGroup'; @@ -425,6 +425,21 @@ const IncidentReportForm = () => { {...TextInputGroupProps} /> +
+
+
+
+ { + setFieldValue('quiet', e.target.checked); + }} + /> +
+
+

Translations

{config diff --git a/site/gatsby-site/src/components/incidents/IncidentsTable.js b/site/gatsby-site/src/components/incidents/IncidentsTable.js index 2a6674dd69..75eaf0724c 100644 --- a/site/gatsby-site/src/components/incidents/IncidentsTable.js +++ b/site/gatsby-site/src/components/incidents/IncidentsTable.js @@ -2,10 +2,17 @@ import { useUserContext } from 'contexts/userContext'; import React, { useState } from 'react'; import { useFilters, usePagination, useSortBy, useTable } from 'react-table'; import IncidentEditModal from './IncidentEditModal'; -import { useTranslation } from 'react-i18next'; +import { Trans, useTranslation } from 'react-i18next'; import Link from 'components/ui/Link'; import { Button, ToggleSwitch } from 'flowbite-react'; -import Table, { DefaultColumnFilter, DefaultColumnHeader } from 'components/ui/Table'; +import Table, { + DefaultColumnFilter, + DefaultColumnHeader, + SelectDatePickerFilter, + filterDate, + formatDateField, + sortDateField, +} from 'components/ui/Table'; function ListCell({ cell }) { return ( @@ -78,6 +85,12 @@ export default function IncidentsTable({ data, isLiveData, setIsLiveData }) { { title: t('Date'), accessor: 'date', + Cell: ({ value }) => formatDateField(value), + Filter: SelectDatePickerFilter, + sortType: (rowA, rowB) => { + return sortDateField(rowA, rowB, 'date'); + }, + filter: (rows, id, filterValue) => filterDate(rows, id, filterValue), }, { title: t('Alleged Deployer of AI System'), @@ -134,18 +147,32 @@ export default function IncidentsTable({ data, isLiveData, setIsLiveData }) { usePagination ); + const pageLength = table.page.length; + + const allResultsCount = data.length; + return ( <> -
- { - setIsLiveData(checked); - }} - name="live-data-switch" - /> +
+
+ { + setIsLiveData(checked); + }} + name="live-data-switch" + /> +
+
+

+ + Displaying {{ pageLength }} of {{ allResultsCount }} incidents + +

{incidentIdToEdit !== 0 && ( diff --git a/site/gatsby-site/src/components/landing/LatestIncidentReport.js b/site/gatsby-site/src/components/landing/LatestIncidentReport.js index 04ede8c7d6..70b3014747 100644 --- a/site/gatsby-site/src/components/landing/LatestIncidentReport.js +++ b/site/gatsby-site/src/components/landing/LatestIncidentReport.js @@ -7,92 +7,170 @@ import { LocalizedLink } from 'plugins/gatsby-theme-i18n'; import DateLabel from 'components/ui/DateLabel'; import Link from 'components/ui/Link'; -const LatestIncidentReport = ({ report, key, isLatest = false }) => { +const LatestIncidentReport = ({ incident, key, isLatest = false }) => { + const report = incident.reports[0]; + const { image_url, cloudinary_id, title, text, epoch_date_submitted, - incident_id, report_number, source_domain, url, } = report; + const incident_id = incident.incident_id; + const { t } = useTranslation(); const reportLink = `/cite/${incident_id}#r${report_number}`; return ( -
-
- - - -
-
-
- -
- {title} - {isLatest && ( - - Latest Incident Report - - )} -
-
- - - {source_domain} - -
-
- -
-
- - Read More - - -
-
-
-
+ + + + + ); +}; + +const Card = (props) => { + const className = ` + flex flex-col lg:flex-row items-center + bg-white rounded-lg border shadow-md dark:border-gray-700 dark:bg-gray-800 h-full + `; + + return
{props.children}
; +}; + +const CardImage = ({ reportLink, cloudinary_id, image_url, title, t, incident_id }) => { + return ( +
+ + +
); }; +const CardBody = ({ + report, + incident, + isLatest, + reportLink, + epoch_date_submitted, + url, + source_domain, + text, +}) => { + return ( +
+ +

+ Incident {incident.incident_id}: {incident.title} +

+
+ +
+ ); +}; + +const ReportPreview = ({ + reportLink, + report, + isLatest, + source_domain, + url, + epoch_date_submitted, + text, +}) => ( +
+ +
+ “{report.title}”{isLatest && } +
+
+
+ + {source_domain} + + +
+
+ +
+
+ +
+
+); + +const ReadMoreButton = ({ reportLink, className }) => ( + + Read More + + +); + +const LatestIncidentBadge = () => ( + + Latest Incident Report + +); + export default LatestIncidentReport; diff --git a/site/gatsby-site/src/components/landing/LatestReports.js b/site/gatsby-site/src/components/landing/LatestReports.js index a1f7ab16ae..f78a2c4bcf 100644 --- a/site/gatsby-site/src/components/landing/LatestReports.js +++ b/site/gatsby-site/src/components/landing/LatestReports.js @@ -4,7 +4,7 @@ import { Carousel } from 'flowbite-react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faArrowCircleLeft, faArrowCircleRight } from '@fortawesome/free-solid-svg-icons'; -export default function LatestReports({ latestReports }) { +export default function LatestReports({ latestIncidents }) { return ( <> } > - {latestReports.map((report, index) => ( + {latestIncidents.map((incident, index) => ( ))} diff --git a/site/gatsby-site/src/components/reports/ReportsTable.js b/site/gatsby-site/src/components/reports/ReportsTable.js new file mode 100644 index 0000000000..b460ffd8c7 --- /dev/null +++ b/site/gatsby-site/src/components/reports/ReportsTable.js @@ -0,0 +1,183 @@ +import { useUserContext } from 'contexts/userContext'; +import React from 'react'; +import { useFilters, usePagination, useSortBy, useTable } from 'react-table'; +import { Trans, useTranslation } from 'react-i18next'; +import { Button, ToggleSwitch } from 'flowbite-react'; +import Table, { + DefaultColumnFilter, + DefaultColumnHeader, + SelectColumnFilter, + SelectDatePickerFilter, + filterDate, + formatDateField, + sortDateField, +} from 'components/ui/Table'; + +export default function ReportsTable({ data, isLiveData, setIsLiveData }) { + const { isLoggedIn, isRole } = useUserContext(); + + const { t } = useTranslation(); + + const defaultColumn = React.useMemo( + () => ({ + className: 'min-w-[120px]', + Filter: DefaultColumnFilter, + Header: DefaultColumnHeader, + }), + [] + ); + + const columns = React.useMemo(() => { + const columns = [ + { + title: t('Report Number'), + accessor: 'report_number', + Cell: ({ row: { values } }) => ( + + Report {values.report_number} + + ), + }, + { + className: 'min-w-[340px]', + title: t('Title'), + accessor: 'title', + }, + { + title: t('Date Submitted'), + accessor: 'date_submitted', + Cell: ({ value }) => formatDateField(value), + Filter: SelectDatePickerFilter, + sortType: (rowA, rowB) => { + return sortDateField(rowA, rowB, 'date_submitted'); + }, + filter: (rows, id, filterValue) => filterDate(rows, id, filterValue), + }, + { + title: t('Date Published'), + accessor: 'date_published', + Cell: ({ value }) => formatDateField(value), + Filter: SelectDatePickerFilter, + sortType: (rowA, rowB) => { + return sortDateField(rowA, rowB, 'date_published'); + }, + filter: (rows, id, filterValue) => filterDate(rows, id, filterValue), + }, + { + title: t('Date Modified'), + accessor: 'date_modified', + Cell: ({ value }) => formatDateField(value), + Filter: SelectDatePickerFilter, + sortType: (rowA, rowB) => { + return sortDateField(rowA, rowB, 'date_modified'); + }, + filter: (rows, id, filterValue) => filterDate(rows, id, filterValue), + }, + { + title: t('Language'), + accessor: 'language', + Filter: SelectColumnFilter, + }, + { + title: t('Submitters'), + accessor: 'submitters', + Filter: SelectColumnFilter, + }, + { + title: t('Authors'), + id: 'authors', + accessor: 'authors', + Filter: SelectColumnFilter, + }, + { + title: t('Tags'), + id: 'tags', + accessor: 'tags', + Filter: SelectColumnFilter, + }, + { + title: t('Flagged'), + accessor: 'flag', + Filter: SelectColumnFilter, + Cell: ({ row: { values } }) => { + return <>{values.flag}; + }, + }, + { + title: t('Is Issue Report?'), + accessor: 'is_incident_report', + Filter: SelectColumnFilter, + Cell: ({ row: { values } }) => { + return <>{values.is_incident_report}; + }, + }, + ]; + + if (isRole('incident_editor')) { + columns.push( + { + title: t('Editor Notes'), //TODO: only show if user is editor + accessor: 'editor_notes', + }, + { + title: t('Actions'), + id: 'actions', + className: 'min-w-[120px]', + Cell: ({ row: { values } }) => ( + + ), + } + ); + } + + return columns; + }, [isLoggedIn]); + + const table = useTable( + { + columns, + data, + defaultColumn, + }, + useFilters, + useSortBy, + usePagination + ); + + const pageLength = table.page.length; + + const allResultsCount = data.length; + + return ( + <> +
+
+ { + setIsLiveData(checked); + }} + name="live-data-switch" + /> +
+ +
+

+ + Displaying {{ pageLength }} of {{ allResultsCount }} reports + +

+
+ + ); +} diff --git a/site/gatsby-site/src/components/submissions/SubmissionForm.js b/site/gatsby-site/src/components/submissions/SubmissionForm.js index 889e222582..6a350eb142 100644 --- a/site/gatsby-site/src/components/submissions/SubmissionForm.js +++ b/site/gatsby-site/src/components/submissions/SubmissionForm.js @@ -34,7 +34,7 @@ import { faTenge, } from '@fortawesome/free-solid-svg-icons'; import FlowbiteSearchInput from 'components/forms/FlowbiteSearchInput'; -import { Select } from 'flowbite-react'; +import { Checkbox, Select } from 'flowbite-react'; import IncidentsField from 'components/incidents/IncidentsField'; import { graphql, useStaticQuery } from 'gatsby'; @@ -348,6 +348,20 @@ const SubmissionForm = ({ onChange = null }) => { columns={['byIncidentId']} /> +
+
+
+
+ { + setFieldValue('quiet', e.target.checked); + }} + /> +
+
+ {(!values.incident_ids || values.incident_ids.length === 0) && (

diff --git a/site/gatsby-site/src/components/ui/Table.js b/site/gatsby-site/src/components/ui/Table.js index 548e91d0ef..8678633edb 100644 --- a/site/gatsby-site/src/components/ui/Table.js +++ b/site/gatsby-site/src/components/ui/Table.js @@ -230,6 +230,40 @@ export function formatDateField(date) { } } +export function sortDateField(rowA, rowB, fieldName) { + if ( + rowA.original[fieldName] && + rowA.original[fieldName] !== '' && + rowB.original[fieldName] && + rowB.original[fieldName] !== '' + ) { + const dateRowA = new Date(rowA.original[fieldName]); + + const dateRowB = new Date(rowB.original[fieldName]); + + if (dateRowA > dateRowB) { + return 1; + } + + if (dateRowA < dateRowB) { + return -1; + } + + return 0; + } +} + +export function filterDate(rows, id, filterValue) { + return rows.filter((row) => { + const rowValue = row.values[id]; + + if (!rowValue) return false; + const filterValueDate = new Date(rowValue).getTime(); + + return filterValueDate >= filterValue[0] && filterValueDate <= filterValue[1]; + }); +} + export default function Table({ table, showPagination = true, diff --git a/site/gatsby-site/src/components/users/UsersTable.js b/site/gatsby-site/src/components/users/UsersTable.js index fe476c8fb0..7c513be1f3 100644 --- a/site/gatsby-site/src/components/users/UsersTable.js +++ b/site/gatsby-site/src/components/users/UsersTable.js @@ -4,6 +4,7 @@ import Table, { DefaultColumnFilter, DefaultColumnHeader, SelectDatePickerFilter, + filterDate, } from 'components/ui/Table'; import { Badge, Button } from 'flowbite-react'; import UserEditModal from './UserEditModal'; @@ -40,16 +41,6 @@ export default function UsersTable({ data, className = '', ...props }) { const client = useApolloClient(); - const filterDate = (rows, id, filterValue) => - rows.filter((row) => { - const rowValue = row.values[id]; - - if (!rowValue) return false; - const filterValueDate = new Date(rowValue).getTime(); - - return filterValueDate >= filterValue[0] && filterValueDate <= filterValue[1]; - }); - useEffect(() => { const fetchUserAdminData = async () => { if (data) { diff --git a/site/gatsby-site/src/graphql/incidents.js b/site/gatsby-site/src/graphql/incidents.js index 87302391ff..084183e780 100644 --- a/site/gatsby-site/src/graphql/incidents.js +++ b/site/gatsby-site/src/graphql/incidents.js @@ -67,6 +67,9 @@ export const FIND_INCIDENTS_TABLE = gql` entity_id name } + reports { + report_number + } } } `; diff --git a/site/gatsby-site/src/graphql/reports.js b/site/gatsby-site/src/graphql/reports.js index ec247bea73..3a197086d3 100644 --- a/site/gatsby-site/src/graphql/reports.js +++ b/site/gatsby-site/src/graphql/reports.js @@ -34,6 +34,7 @@ export const FIND_REPORT = gql` from_text_hash vector } + quiet } } `; @@ -58,6 +59,7 @@ export const FIND_REPORT_WITH_TRANSLATIONS = gql` language is_incident_report inputs_outputs + quiet translations_es: translations(input: "es") { title text @@ -99,6 +101,7 @@ export const UPDATE_REPORT = gql` report_number editor_notes language + quiet } } `; @@ -176,6 +179,7 @@ export const FIND_REPORT_HISTORY = gql` url source_domain user + quiet } } `; @@ -202,3 +206,31 @@ export const FIND_REPORTS = gql` } } `; + +export const FIND_REPORTS_TABLE = gql` + query FindReports($query: ReportQueryInput!) { + reports(query: $query, sort: { report_number: DESC }, limit: 999) { + _id + submitters + date_published + date_downloaded + date_submitted + date_modified + report_number + title + description + url + image_url + cloudinary_id + source_domain + text + authors + epoch_date_submitted + language + tags + inputs_outputs + editor_notes + is_incident_report + } + } +`; diff --git a/site/gatsby-site/src/graphql/submissions.js b/site/gatsby-site/src/graphql/submissions.js index 731f84671e..249384d4e9 100644 --- a/site/gatsby-site/src/graphql/submissions.js +++ b/site/gatsby-site/src/graphql/submissions.js @@ -59,6 +59,7 @@ export const FIND_SUBMISSIONS = gql` user { userId } + quiet } } `; @@ -110,6 +111,7 @@ export const FIND_SUBMISSION = gql` editor_similar_incidents editor_dissimilar_incidents status + quiet } } `; diff --git a/site/gatsby-site/src/pages/apps/incidents.js b/site/gatsby-site/src/pages/apps/incidents.js index 6bbad492a6..2392bf684f 100644 --- a/site/gatsby-site/src/pages/apps/incidents.js +++ b/site/gatsby-site/src/pages/apps/incidents.js @@ -7,41 +7,99 @@ import AiidHelmet from '../../components/AiidHelmet'; import ListSkeleton from 'elements/Skeletons/List'; import { graphql } from 'gatsby'; import { makeEntitiesHash } from 'utils/entities'; +import { Button } from 'flowbite-react'; +import ReportsTable from 'components/reports/ReportsTable'; +import { FIND_REPORTS_TABLE } from '../../graphql/reports'; +import { useQueryParam } from 'use-query-params'; const IncidentsPage = ({ data, ...props }) => { - const { data: incidents, loading } = useQuery(FIND_INCIDENTS_TABLE); + const [view] = useQueryParam('view'); + + const { data: incidents, loading: incidentsLoading } = useQuery(FIND_INCIDENTS_TABLE); + + const { data: reports, loading: reportsLoading } = useQuery(FIND_REPORTS_TABLE, { + variables: { + query: { + is_incident_report: true, + }, + }, + }); + + const { data: issueReports, loading: issueReportsLoading } = useQuery(FIND_REPORTS_TABLE, { + variables: { + query: { + is_incident_report: false, + }, + }, + }); const [incidentsData, setIncidentsData] = useState(null); + const [issueReportsData, setIssueReportsData] = useState(null); + + const [reportsData, setReportsData] = useState(null); + const [isLiveData, setIsLiveData] = useState(false); + const [selectedView, setSelectedView] = useState(null); + useEffect(() => { - if (isLiveData) { - if (incidents) { - setIncidentsData(incidents.incidents); - } - } else if (data?.incidents?.nodes) { - const entitiesHash = makeEntitiesHash(data?.entities?.nodes); - - const incidents = []; - - for (const incident of data.incidents.nodes) { - incident.AllegedDeployerOfAISystem = incident.Alleged_deployer_of_AI_system.map( - (entity_id) => entitiesHash[entity_id] - ); - incident.AllegedDeveloperOfAISystem = incident.Alleged_developer_of_AI_system.map( - (entity_id) => entitiesHash[entity_id] - ); - incident.AllegedHarmedOrNearlyHarmedParties = - incident.Alleged_harmed_or_nearly_harmed_parties.map( - (entity_id) => entitiesHash[entity_id] - ); - incidents.push(incident); - } + if (view) { + setSelectedView(view); + } else { + setSelectedView('incidents'); + } + }, [view]); - setIncidentsData(incidents); + useEffect(() => { + switch (selectedView) { + case 'incidents': + if (isLiveData && incidents) { + setIncidentsData(incidents.incidents); + } else if (data?.incidents?.nodes) { + const entitiesHash = makeEntitiesHash(data?.entities?.nodes); + + const processedIncidents = data.incidents.nodes.map((incident) => ({ + ...incident, + AllegedDeployerOfAISystem: incident.Alleged_deployer_of_AI_system.map( + (id) => entitiesHash[id] + ), + AllegedDeveloperOfAISystem: incident.Alleged_developer_of_AI_system.map( + (id) => entitiesHash[id] + ), + AllegedHarmedOrNearlyHarmedParties: + incident.Alleged_harmed_or_nearly_harmed_parties.map((id) => entitiesHash[id]), + })); + + setIncidentsData(processedIncidents); + } + break; + case 'issueReports': + if (isLiveData && issueReports) { + setIssueReportsData(transformReports(issueReports.reports)); + } else if (data?.issueReports?.nodes) { + setIssueReportsData(transformReports(data.issueReports.nodes)); + } + break; + + case 'reports': + if (isLiveData && reports) { + setReportsData(transformReports(reports.reports)); + } else if (data?.reports?.nodes) { + setReportsData(transformReports(data.reports.nodes)); + } + break; + default: } - }, [isLiveData, incidents, data]); + }, [isLiveData, incidents, data, selectedView]); + + function transformReports(reports) { + return reports.map((report) => ({ + ...report, + flag: report.flag ? 'Yes' : 'No', + is_incident_report: report.is_incident_report ? 'No' : 'Yes', + })); + } const { t } = useTranslation(); @@ -51,18 +109,97 @@ const IncidentsPage = ({ data, ...props }) => { {t('Incidents')}
- {(incidentsData && !isLiveData) || (incidentsData && isLiveData && !loading) ? ( -
- -
- ) : ( -
- -
+ + + + + + {selectedView === 'incidents' && ( + <> + {(incidentsData && !isLiveData) || + (incidentsData && isLiveData && !incidentsLoading) ? ( +
+ +
+ ) : ( +
+ +
+ )} + + )} + {selectedView === 'issueReports' && ( + <> + {(issueReportsData && !isLiveData) || + (issueReportsData && isLiveData && !issueReportsLoading) ? ( +
+ +
+ ) : ( +
+ +
+ )} + + )} + {selectedView === 'reports' && ( + <> + {(reportsData && !isLiveData) || (reportsData && isLiveData && !reportsLoading) ? ( +
+ +
+ ) : ( +
+ +
+ )} + )}
@@ -93,6 +230,51 @@ export const query = graphql` name } } + reports: allMongodbAiidprodReports( + filter: { is_incident_report: { eq: true } } + sort: { report_number: DESC } + ) { + nodes { + report_number + title + url + authors + date_downloaded + date_modified + date_published + date_submitted + description + flag + image_url + language + source_domain + submitters + is_incident_report + } + } + + issueReports: allMongodbAiidprodReports( + filter: { is_incident_report: { eq: false } } + sort: { report_number: DESC } + ) { + nodes { + report_number + title + url + authors + date_downloaded + date_modified + date_published + date_submitted + description + flag + image_url + language + source_domain + submitters + is_incident_report + } + } } `; diff --git a/site/gatsby-site/src/pages/apps/reports.js b/site/gatsby-site/src/pages/apps/reports.js deleted file mode 100644 index 614c82f01d..0000000000 --- a/site/gatsby-site/src/pages/apps/reports.js +++ /dev/null @@ -1,230 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import AiidHelmet from '../../components/AiidHelmet'; -import Link from '../../components/ui/Link'; -import { faLink } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { useTable, useFilters, usePagination, useSortBy } from 'react-table'; -import { gql, useQuery } from '@apollo/client'; -import { useMenuContext } from 'contexts/MenuContext'; -import ListSkeleton from 'elements/Skeletons/List'; -import { useTranslation } from 'react-i18next'; -import { Button } from 'flowbite-react'; -import Table, { - DefaultColumnFilter, - DefaultColumnHeader, - formatDateField, - SelectColumnFilter, - SelectDatePickerFilter, -} from 'components/ui/Table'; - -const query = gql` - query ReportsQuery { - incidents(sortBy: INCIDENT_ID_ASC, limit: 9999) { - incident_id - reports { - title - source_domain - url - authors - submitters - epoch_date_submitted - epoch_date_modified - epoch_date_downloaded - report_number - flag - date_downloaded - date_modified - date_submitted - } - } - } -`; - -export default function Incidents(props) { - const [tableData, setTableData] = useState([]); - - const { data, loading } = useQuery(query); - - const { t } = useTranslation(); - - useEffect(() => { - if (!data) return; - - const incidentDataToCellMap = (data) => { - const tableData = data.incidents.reduce((accumulator, incident) => { - for (const report of incident.reports) { - accumulator.push({ - ...report, - incident_id: incident.incident_id, - flag: report.flag === true ? 'Yes' : 'No', - authors: report.authors.join(', '), - __typename: undefined, - }); - } - return accumulator; - }, []); - - return tableData; - }; - - setTableData(incidentDataToCellMap(data)); - }, [data]); - - const cellData = React.useMemo(() => tableData, [tableData]); - - const columns = React.useMemo(() => { - const columns = [ - { - title: t('Incident ID'), - accessor: 'incident_id', - Cell: ({ row: { values } }) => ( - - Incident {values.incident_id} - - - ), - }, - { - className: 'min-w-[240px] max-w-[400px]', - title: t('Incident Title'), - accessor: 'title', - Cell: (cell) => ( -
- {cell.row.values.title} -
- ), - }, - { - className: 'min-w-[240px]', - title: t('Source Domain'), - accessor: 'source_domain', - width: 240, - }, - { - className: 'min-w-[240px]', - title: t('Authors'), - accessor: 'authors', - width: 240, - }, - { - className: 'min-w-[240px]', - title: t('Submitters'), - accessor: 'submitters', - width: 240, - Filter: SelectColumnFilter, - }, - { - className: 'min-w-[240px]', - title: t('Date Submitted'), - accessor: 'date_submitted', - width: 240, - Filter: SelectDatePickerFilter, - Cell: ({ row: { values } }) => { - return <>{formatDateField(values.date_submitted)}; - }, - }, - { - className: 'min-w-[240px]', - title: t('Date Modified'), - accessor: 'date_modified', - width: 240, - Filter: SelectDatePickerFilter, - Cell: ({ row: { values } }) => { - return <>{formatDateField(values.date_modified)}; - }, - }, - { - className: 'min-w-[240px]', - title: t('Date Downloaded'), - accessor: 'date_downloaded', - width: 240, - Filter: SelectDatePickerFilter, - Cell: ({ row: { values } }) => { - return <>{formatDateField(values.date_downloaded)}; - }, - }, - { - className: 'min-w-[240px]', - title: t('Report ID'), - accessor: 'report_number', - width: 240, - }, - { - className: 'min-w-[240px]', - title: t('Flagged'), - accessor: 'flag', - width: 240, - Filter: SelectColumnFilter, - Cell: ({ row: { values } }) => { - return <>{values.flag}; - }, - }, - ]; - - return columns; - }, []); - - const defaultColumn = React.useMemo( - () => ({ - Filter: DefaultColumnFilter, - Header: DefaultColumnHeader, - }), - [] - ); - - const filterDateFunction = (rows, id, filterValue) => { - const start = filterValue[0]; - - const end = filterValue[1]; - - return rows.filter((val) => { - return val.original[id] >= start && val.original[id] <= end; - }); - }; - - const filterTypes = { - epoch_date_submitted: filterDateFunction, - epoch_date_modified: filterDateFunction, - date_downloaded: filterDateFunction, - }; - - const table = useTable( - { - columns, - data: cellData, - defaultColumn, - filterTypes, - initialState: { pageIndex: 0, pageSize: 100 }, - }, - useFilters, - useSortBy, - usePagination - ); - - const { isCollapsed } = useMenuContext(); - - return ( -
- - Incident List - - - {loading && } - {!loading && ( -
-

Incident Report Table

- -
-
- - - )} - - ); -} diff --git a/site/gatsby-site/src/pages/cite/edit.js b/site/gatsby-site/src/pages/cite/edit.js index b0e41f8da7..9bc3bbf5fc 100644 --- a/site/gatsby-site/src/pages/cite/edit.js +++ b/site/gatsby-site/src/pages/cite/edit.js @@ -57,6 +57,7 @@ const reportFields = [ 'url', 'embedding', 'inputs_outputs', + 'quiet', ]; function EditCitePage(props) { @@ -66,7 +67,7 @@ function EditCitePage(props) { const [reportNumber] = useQueryParam('report_number', withDefault(NumberParam, 1)); - const [incidentId] = useQueryParam('incident_id', withDefault(NumberParam, 1)); + const [incidentId] = useQueryParam('incident_id'); const { data: reportData, @@ -280,11 +281,24 @@ function EditCitePage(props) {

Editing Incident Report {{ reportNumber }}

- - - + {incidentId ? ( + + + + ) : ( + + + + )} )} diff --git a/site/gatsby-site/src/templates/landingPage.js b/site/gatsby-site/src/templates/landingPage.js index 9c554b68ad..1ad197e623 100644 --- a/site/gatsby-site/src/templates/landingPage.js +++ b/site/gatsby-site/src/templates/landingPage.js @@ -21,9 +21,9 @@ import PostPreviewNew from 'components/blog/PrismicPostPreview'; const LandingPage = (props) => { const { data } = props; - let { latestPrismicPost, latestPostOld, latestReportIncidents } = data; + const { latestIncidents, latestIncidentsReportNumbers, sponsors } = props.pageContext; - const { latestReportNumbers } = props.pageContext; + let { latestPrismicPost, latestPostOld } = data; let latestBlogPost = null; @@ -40,15 +40,15 @@ const LandingPage = (props) => { latestBlogPost = mdxDate > prismicDate ? latestPostOld : latestPrismicPost; } - let { sponsors } = props.pageContext; - const { locale: language } = useLocalization(); - const latestReports = latestReportIncidents.edges.map((incident) => { - const report = incident.node.reports.find((r) => latestReportNumbers.includes(r.report_number)); + const latestIncidentsTranslated = latestIncidents.map((incident) => { + const report = incident.reports.find((r) => + latestIncidentsReportNumbers.includes(r.report_number) + ); if (report.language !== language) { - const translation = data[`latestReports_${language}`]?.edges.find( + const translation = data[`latestIncidentsReports_${language}`]?.edges.find( (translation) => translation.node.report_number === report.report_number ); @@ -60,8 +60,8 @@ const LandingPage = (props) => { } } const updatedIncident = { - incident_id: incident.node.incident_id, - ...report, + ...incident, + reports: [report], }; return updatedIncident; @@ -79,10 +79,10 @@ const LandingPage = (props) => { - {latestReports.length > 0 && ( + {latestIncidents.length > 0 && (
- +
)} @@ -126,7 +126,7 @@ const LandingPage = (props) => {
- {latestReports.length > 0 && ( + {latestIncidents.length > 0 && (
@@ -184,7 +184,11 @@ export function Head({ location }) { } export const query = graphql` - query LandingPageQuery($latestReportNumber: Int, $latestReportNumbers: [Int], $locale: String!) { + query LandingPageQuery( + $latestReportNumber: Int + $latestIncidentsReportNumbers: [Int] + $locale: String! + ) { latestReportIncident: allMongodbAiidprodIncidents( filter: { reports: { elemMatch: { report_number: { eq: $latestReportNumber } } } } ) { @@ -195,7 +199,7 @@ export const query = graphql` } } latestReportIncidents: allMongodbAiidprodIncidents( - filter: { reports: { elemMatch: { report_number: { in: $latestReportNumbers } } } } + filter: { reports: { elemMatch: { report_number: { in: $latestIncidentsReportNumbers } } } } ) { edges { node { @@ -215,7 +219,7 @@ export const query = graphql` } } } - latestReport: mongodbAiidprodReports(report_number: { in: $latestReportNumbers }) { + latestReport: mongodbAiidprodReports(report_number: { in: $latestIncidentsReportNumbers }) { title text epoch_date_submitted @@ -224,8 +228,8 @@ export const query = graphql` cloudinary_id language } - latestReports_es: allMongodbTranslationsReportsEs( - filter: { report_number: { in: $latestReportNumbers } } + latestIncidentsReports_es: allMongodbTranslationsReportsEs( + filter: { report_number: { in: $latestIncidentsReportNumbers } } ) { edges { node { @@ -235,8 +239,8 @@ export const query = graphql` } } } - latestReports_fr: allMongodbTranslationsReportsFr( - filter: { report_number: { in: $latestReportNumbers } } + latestIncidentsReports_fr: allMongodbTranslationsReportsFr( + filter: { report_number: { in: $latestIncidentsReportNumbers } } ) { edges { node { @@ -246,8 +250,8 @@ export const query = graphql` } } } - latestReports_ja: allMongodbTranslationsReportsJa( - filter: { report_number: { in: $latestReportNumbers } } + latestIncidentsReports_ja: allMongodbTranslationsReportsJa( + filter: { report_number: { in: $latestIncidentsReportNumbers } } ) { edges { node { @@ -257,8 +261,8 @@ export const query = graphql` } } } - latestReports_en: allMongodbTranslationsReportsEn( - filter: { report_number: { in: $latestReportNumbers } } + latestIncidentsReports_en: allMongodbTranslationsReportsEn( + filter: { report_number: { in: $latestIncidentsReportNumbers } } ) { edges { node { diff --git a/site/gatsby-site/typeDefs.js b/site/gatsby-site/typeDefs.js index 29c3ef5886..fd6d1bc251 100644 --- a/site/gatsby-site/typeDefs.js +++ b/site/gatsby-site/typeDefs.js @@ -83,6 +83,7 @@ const typeDefs = ` report_number: Int is_incident_report: Boolean flag: Boolean + quiet: Boolean } type mongodbAiidprodTaxaField_list implements Node { diff --git a/site/realm/data_sources/mongodb-atlas/aiidprod/reports/schema.json b/site/realm/data_sources/mongodb-atlas/aiidprod/reports/schema.json index 7ddd931ff9..a8f2951459 100644 --- a/site/realm/data_sources/mongodb-atlas/aiidprod/reports/schema.json +++ b/site/realm/data_sources/mongodb-atlas/aiidprod/reports/schema.json @@ -106,6 +106,9 @@ }, "user": { "bsonType": "string" + }, + "quiet": { + "bsonType": "bool" } }, "required": [ diff --git a/site/realm/data_sources/mongodb-atlas/aiidprod/submissions/schema.json b/site/realm/data_sources/mongodb-atlas/aiidprod/submissions/schema.json index 25c0c79fea..b3866addfd 100644 --- a/site/realm/data_sources/mongodb-atlas/aiidprod/submissions/schema.json +++ b/site/realm/data_sources/mongodb-atlas/aiidprod/submissions/schema.json @@ -147,6 +147,9 @@ }, "status": { "bsonType": "string" + }, + "quiet": { + "bsonType": "bool" } }, "required": [ diff --git a/site/realm/data_sources/mongodb-atlas/history/reports/schema.json b/site/realm/data_sources/mongodb-atlas/history/reports/schema.json index d250f7343f..899cff521d 100644 --- a/site/realm/data_sources/mongodb-atlas/history/reports/schema.json +++ b/site/realm/data_sources/mongodb-atlas/history/reports/schema.json @@ -109,6 +109,9 @@ }, "user": { "bsonType": "string" + }, + "quiet": { + "bsonType": "bool" } }, "required": [ diff --git a/site/realm/functions/promoteSubmissionToReport.js b/site/realm/functions/promoteSubmissionToReport.js index 7cd0189b39..398e3a7656 100644 --- a/site/realm/functions/promoteSubmissionToReport.js +++ b/site/realm/functions/promoteSubmissionToReport.js @@ -153,6 +153,7 @@ exports = async (input) => { source_domain: submission.source_domain, language: submission.language, tags: submission.tags, + quiet: submission.quiet || false }; if (submission.embedding) { newReport.embedding = submission.embedding;