diff --git a/.github/workflows/mongodb-clone.yml b/.github/workflows/mongodb-clone.yml index 3e7f910d8f..19a71d6423 100644 --- a/.github/workflows/mongodb-clone.yml +++ b/.github/workflows/mongodb-clone.yml @@ -25,5 +25,8 @@ jobs: - name: "Restore Staging database collection: translations" run: mongorestore ${{ secrets.DB_STAGING_CONNECTION_STRING }}/translations ./dump/translations --drop --noOptionsRestore + - name: "Restore Staging database collection: history" + run: mongorestore ${{ secrets.DB_STAGING_CONNECTION_STRING }}/history ./dump/history --drop --noOptionsRestore + - name: Trigger Staging Netlify build run: curl -X POST -d {} ${{ secrets.NETLIFY_BUILD_STAGING_URL }} \ No newline at end of file diff --git a/site/gatsby-site/cypress/e2e/integration/admin.cy.js b/site/gatsby-site/cypress/e2e/integration/admin.cy.js index f89e822c1c..77bbee0e6b 100644 --- a/site/gatsby-site/cypress/e2e/integration/admin.cy.js +++ b/site/gatsby-site/cypress/e2e/integration/admin.cy.js @@ -5,7 +5,8 @@ const { gql } = require('@apollo/client'); describe('Admin', () => { const baseUrl = '/admin'; - it('Should show not enough permissions message', () => { + //TODO: (Issue #2272): Temporarily skip flaky test. + it.skip('Should show not enough permissions message', () => { cy.visit(baseUrl); cy.contains('Not enough permissions').should('be.visible'); diff --git a/site/gatsby-site/cypress/e2e/integration/apps/csettool.cy.js b/site/gatsby-site/cypress/e2e/integration/apps/csettool.cy.js index a20525b420..390befb5e7 100644 --- a/site/gatsby-site/cypress/e2e/integration/apps/csettool.cy.js +++ b/site/gatsby-site/cypress/e2e/integration/apps/csettool.cy.js @@ -245,7 +245,7 @@ describe('CSET tool', () => { expect(xhr.request.body.variables.data).to.deep.eq({ incidents: { link: [52] }, - reports: [], + reports: { link: [] }, namespace: 'CSETv1', notes: 'Annotator 1: \n\n This a note from the annotator 1\n\nAnnotator 2: \n\n This a note from the annotator 2', diff --git a/site/gatsby-site/cypress/e2e/integration/incidents/history.cy.js b/site/gatsby-site/cypress/e2e/integration/incidents/history.cy.js index 3ae0c6bd07..c61d4a7bd7 100644 --- a/site/gatsby-site/cypress/e2e/integration/incidents/history.cy.js +++ b/site/gatsby-site/cypress/e2e/integration/incidents/history.cy.js @@ -1,5 +1,6 @@ import { format, fromUnixTime, getUnixTime } from 'date-fns'; import incidentHistory from '../../../fixtures/history/incidentHistory.json'; +import versionReports from '../../../fixtures/history/versionReports.json'; import { maybeIt } from '../../../support/utils'; const { gql } = require('@apollo/client'); @@ -359,4 +360,143 @@ describe('Incidents', () => { cy.get('[data-cy="restoring-message"]').should('not.exist'); }); + + it('Should display the Version History details modal', () => { + cy.visit(url); + + cy.conditionalIntercept( + '**/graphql', + (req) => req.body.operationName == 'FindIncidentHistory', + 'FindIncidentHistory', + incidentHistory + ); + + cy.conditionalIntercept( + '**/graphql', + (req) => req.body.operationName == 'FindUsers', + 'FindUsers', + { + data: { + users: [ + { userId: '1', first_name: 'Sean', last_name: 'McGregor', roles: [] }, + { userId: '2', first_name: 'Pablo', last_name: 'Costa', roles: [] }, + ], + }, + } + ); + + cy.conditionalIntercept( + '**/graphql', + (req) => req.body.operationName == 'FindEntities', + 'FindEntities', + { + data: { + entities: [ + { __typename: 'Entity', entity_id: 'youtube', name: 'Youtube' }, + { __typename: 'Entity', entity_id: 'google', name: 'Google' }, + { __typename: 'Entity', entity_id: 'tesla', name: 'Tesla' }, + ], + }, + } + ); + + cy.conditionalIntercept( + '**/graphql', + (req) => req.body.operationName == 'FindReports', + 'FindReports', + versionReports + ); + + cy.wait(['@FindIncidentHistory', '@FindEntities', '@FindUsers']); + + cy.waitForStableDOM(); + + // Click the 2nd version + cy.get('[data-cy="history-row"]') + .eq(1) + .within(() => { + cy.get('[data-cy="view-full-version-button"]').click(); + }); + + cy.wait('@FindReports').then((xhr) => { + expect(xhr.request.body.variables.query).to.deep.eq({ + report_number_in: incidentHistory.data.history_incidents[1].reports, + }); + }); + + cy.get('[data-cy="version-view-modal"]').as('modal').should('be.visible'); + + cy.get('[data-cy="version-view-modal"]').within(() => { + const version = incidentHistory.data.history_incidents[1]; + + cy.contains('View Version details').should('exist'); + cy.contains(version.title).should('exist'); + cy.contains('Modified by: Sean McGregor').should('exist'); + cy.contains( + `Modified on: ${format(fromUnixTime(version.epoch_date_modified), 'yyyy-MM-dd hh:mm a')}` + ).should('exist'); + cy.contains(`Description: ${version.description}`).should('exist'); + if (version.editor_notes) { + cy.contains(`Editor Notes: ${version.editor_notes}`).should('exist'); + } + cy.get('[data-cy="alleged-entities"]').within(() => { + cy.contains( + 'Alleged: developed an AI system deployed by Youtube, which harmed Google.' + ).should('exist'); + }); + cy.get('[data-cy="citation"]').within(() => { + cy.contains(`${version.incident_id}`).should('exist'); + cy.contains(`${version.reports.length}`).should('exist'); + cy.contains(`${version.date}`).should('exist'); + cy.contains('Sean McGregor, Pablo Costa').should('exist'); + }); + cy.get('[data-cy="classifications-editor"]').should('not.exist'); + cy.get('button').contains('Close').click(); + }); + cy.get('[data-cy="version-view-modal"]').should('not.exist'); + + // Click the latest version + cy.get('[data-cy="history-row"]') + .eq(0) + .within(() => { + cy.get('[data-cy="view-full-version-button"]').click(); + }); + + cy.wait('@FindReports').then((xhr) => { + expect(xhr.request.body.variables.query).to.deep.eq({ + report_number_in: incidentHistory.data.history_incidents[0].reports, + }); + }); + + cy.get('[data-cy="version-view-modal"]').as('modal').should('be.visible'); + + cy.get('[data-cy="version-view-modal"]').within(() => { + const version = incidentHistory.data.history_incidents[0]; + + cy.contains('View Version details').should('exist'); + cy.contains(version.title).should('exist'); + cy.contains('Modified by: Sean McGregor').should('exist'); + cy.contains( + `Modified on: ${format(fromUnixTime(version.epoch_date_modified), 'yyyy-MM-dd hh:mm a')}` + ).should('exist'); + cy.contains(`Description: ${version.description}`).should('exist'); + if (version.editor_notes) { + cy.contains(`Editor Notes: ${version.editor_notes}`).should('exist'); + } + cy.get('[data-cy="alleged-entities"]').within(() => { + cy.contains( + 'Alleged: developed an AI system deployed by Youtube, which harmed Google.' + ).should('exist'); + }); + cy.get('[data-cy="citation"]').within(() => { + cy.contains(`${version.incident_id}`).should('exist'); + cy.contains(`${version.reports.length}`).should('exist'); + cy.contains(`${version.date}`).should('exist'); + cy.contains('Sean McGregor, Pablo Costa').should('exist'); + }); + cy.get('[data-cy="classifications-editor"]').should('not.exist'); + cy.get('button').contains('Close').click(); + }); + cy.get('[data-cy="version-view-modal"]').should('not.exist'); + }); }); diff --git a/site/gatsby-site/cypress/e2e/integration/reportHistory.cy.js b/site/gatsby-site/cypress/e2e/integration/reportHistory.cy.js index 0077115a7b..7162758646 100644 --- a/site/gatsby-site/cypress/e2e/integration/reportHistory.cy.js +++ b/site/gatsby-site/cypress/e2e/integration/reportHistory.cy.js @@ -2,6 +2,7 @@ import { format, fromUnixTime, getUnixTime } from 'date-fns'; import reportHistory from '../../fixtures/history/reportHistory.json'; import updateOneReport from '../../fixtures/reports/updateOneReport.json'; import { maybeIt } from '../../support/utils'; +import supportedLanguages from '../../../src/components/i18n/languages.json'; const { gql } = require('@apollo/client'); describe('Report History', () => { @@ -283,4 +284,156 @@ describe('Report History', () => { cy.wait('@FindReportHistory'); }); + + it('Should display the Report Version History details modal', () => { + cy.visit(url); + + cy.conditionalIntercept( + '**/graphql', + (req) => req.body.operationName == 'FindReport', + 'FindReport', + { + data: { + report: reportHistory.data.history_reports[0], + }, + } + ); + + cy.conditionalIntercept( + '**/graphql', + (req) => req.body.operationName == 'FindReportHistory', + 'FindReportHistory', + reportHistory + ); + + cy.conditionalIntercept( + '**/graphql', + (req) => req.body.operationName == 'FindUsers', + 'FindUsers', + { + data: { + users: [ + { userId: '1', first_name: 'Sean', last_name: 'McGregor', roles: [] }, + { userId: '2', first_name: 'Pablo', last_name: 'Costa', roles: [] }, + ], + }, + } + ); + + cy.wait(['@FindReport', '@FindReportHistory', '@FindUsers']); + + cy.waitForStableDOM(); + + // Click the 2nd version + cy.get('[data-cy="history-row"]') + .eq(1) + .within(() => { + cy.get('[data-cy="view-full-version-button"]').click(); + }); + + cy.get('[data-cy="version-view-modal"]').as('modal').should('be.visible'); + + cy.get('[data-cy="version-view-modal"]').within(() => { + const version = reportHistory.data.history_reports[1]; + + cy.contains('Version details').should('exist'); + cy.contains( + `Modified on: ${format(fromUnixTime(version.epoch_date_modified), 'yyyy-MM-dd hh:mm a')}` + ).should('exist'); + cy.contains('Modified by: Sean McGregor').should('exist'); + let index = 0; + + cy.get('.tw-row').eq(index).contains('Report Address:').should('exist'); + cy.get('.tw-row').eq(index).contains(version.url).should('exist'); + cy.get('.tw-row').eq(++index).contains('Title:').should('exist'); + cy.get('.tw-row').eq(index).contains(version.title).should('exist'); + cy.get('.tw-row').eq(++index).contains('Author CSV:').should('exist'); + cy.get('.tw-row').eq(index).contains(version.authors.join(', ')).should('exist'); + cy.get('.tw-row').eq(++index).contains('Submitter CSV:').should('exist'); + cy.get('.tw-row').eq(index).contains(version.submitters.join(', ')).should('exist'); + cy.get('.tw-row').eq(++index).contains('Date Published:').should('exist'); + cy.get('.tw-row').eq(index).contains(version.date_published).should('exist'); + cy.get('.tw-row').eq(++index).contains('Date Downloaded:').should('exist'); + cy.get('.tw-row').eq(index).contains(version.date_downloaded).should('exist'); + cy.get('.tw-row').eq(++index).contains('Image Address:').should('exist'); + cy.get('.tw-row').eq(index).contains(version.image_url).should('exist'); + cy.get('.tw-row') + .eq(++index) + .find('[data-cy="cloudinary-image"]') + .should('have.attr', 'src') + .and('include', version.cloudinary_id); + cy.get('.tw-row').eq(++index).contains('Text:').should('exist'); + cy.get('.tw-row').eq(index).contains('By Aimee Picchi').should('exist'); + cy.get('.tw-row').eq(++index).contains('Language:').should('exist'); + cy.get('.tw-row') + .eq(index) + .contains(supportedLanguages.find((l) => l.code == version.language)?.name) + .should('exist'); + cy.get('.tw-row').eq(++index).contains('Tags:').should('exist'); + for (const tag of version.tags) { + cy.get('.tw-row').eq(index).contains(tag).should('exist'); + } + cy.get('.tw-row').eq(++index).contains('Editor Notes:').should('exist'); + cy.get('.tw-row').eq(index).contains(version.editor_notes).should('exist'); + + cy.get('button').contains('Close').click(); + }); + cy.get('[data-cy="version-view-modal"]').should('not.exist'); + + // Click the latest version + cy.get('[data-cy="history-row"]') + .eq(0) + .within(() => { + cy.get('[data-cy="view-full-version-button"]').click(); + }); + + cy.get('[data-cy="version-view-modal"]').as('modal').should('be.visible'); + + cy.get('[data-cy="version-view-modal"]').within(() => { + const version = reportHistory.data.history_reports[0]; + + cy.contains('Version details').should('exist'); + cy.contains( + `Modified on: ${format(fromUnixTime(version.epoch_date_modified), 'yyyy-MM-dd hh:mm a')}` + ).should('exist'); + cy.contains('Modified by: Sean McGregor').should('exist'); + let index = 0; + + cy.get('.tw-row').eq(index).contains('Report Address:').should('exist'); + cy.get('.tw-row').eq(index).contains(version.url).should('exist'); + cy.get('.tw-row').eq(++index).contains('Title:').should('exist'); + cy.get('.tw-row').eq(index).contains(version.title).should('exist'); + cy.get('.tw-row').eq(++index).contains('Author CSV:').should('exist'); + cy.get('.tw-row').eq(index).contains(version.authors.join(', ')).should('exist'); + cy.get('.tw-row').eq(++index).contains('Submitter CSV:').should('exist'); + cy.get('.tw-row').eq(index).contains(version.submitters.join(', ')).should('exist'); + cy.get('.tw-row').eq(++index).contains('Date Published:').should('exist'); + cy.get('.tw-row').eq(index).contains(version.date_published).should('exist'); + cy.get('.tw-row').eq(++index).contains('Date Downloaded:').should('exist'); + cy.get('.tw-row').eq(index).contains(version.date_downloaded).should('exist'); + cy.get('.tw-row').eq(++index).contains('Image Address:').should('exist'); + cy.get('.tw-row').eq(index).contains(version.image_url).should('exist'); + cy.get('.tw-row') + .eq(++index) + .find('[data-cy="cloudinary-image"]') + .should('have.attr', 'src') + .and('include', version.cloudinary_id); + cy.get('.tw-row').eq(++index).contains('Text:').should('exist'); + cy.get('.tw-row').eq(index).contains('By Aimee Picchi').should('exist'); + cy.get('.tw-row').eq(++index).contains('Language:').should('exist'); + cy.get('.tw-row') + .eq(index) + .contains(supportedLanguages.find((l) => l.code == version.language)?.name) + .should('exist'); + cy.get('.tw-row').eq(++index).contains('Tags:').should('exist'); + for (const tag of version.tags) { + cy.get('.tw-row').eq(index).contains(tag).should('exist'); + } + cy.get('.tw-row').eq(++index).contains('Editor Notes:').should('exist'); + cy.get('.tw-row').eq(index).contains(version.editor_notes).should('exist'); + + cy.get('button').contains('Close').click(); + }); + cy.get('[data-cy="version-view-modal"]').should('not.exist'); + }); }); diff --git a/site/gatsby-site/cypress/fixtures/history/versionReports.json b/site/gatsby-site/cypress/fixtures/history/versionReports.json new file mode 100644 index 0000000000..32540363a4 --- /dev/null +++ b/site/gatsby-site/cypress/fixtures/history/versionReports.json @@ -0,0 +1,44 @@ +{ + "data": { + "reports": [ + { + "__typename": "Report", + "_id": "5d34b8c29ced494f010ed472", + "authors": ["Caroline O'Donovan"], + "cloudinary_id": "reports/img.buzzfeed.com/buzzfeed-static/static/2015-06/2/17/campaign_images/webdr02/kronos-makes-changes-to-software-accused-of-produ-2-14421-1433279634-2_dblbig.jpg", + "date_published": "2015-06-03", + "description": "Kronos, a workforce management company, thinks giving managers more data can make scheduling practices more fair. But ultimately, the underpinnings of the problem may go deeper than the algorit", + "epoch_date_submitted": 1559347200, + "image_url": "https://img.buzzfeed.com/buzzfeed-static/static/2015-06/2/17/campaign_images/webdr02/kronos-makes-changes-to-software-accused-of-produ-2-14421-1433279634-2_dblbig.jpg", + "inputs_outputs": null, + "language": "en", + "report_number": 3205, + "source_domain": "buzzfeednews.com", + "submitters": ["Catherine Olsson"], + "tags": [], + "text": "In April, the New York attorney general's office launched an [investigation](http://www.reuters.com/article/2015/04/13/us-retail-workers-nyag-idUSKBN0N40G420150413) into the scheduling practices of 13 national retail chains, distributing a letter to the Gap, Target, J.C. Penney, and 10 other companies. The letter asked, among other things, whether these companies' store managers use software manufactured by a company called Kronos to algorithmically generate schedules.\n\nA few months later, Kronos was also featured prominently in an [article](http://www.nytimes.com/interactive/2014/08/13/us/starbucks-workers-scheduling-hours.html) published by the _New York Times_ about the ill effects of erratic scheduling on Starbucks employees, especially one particular family. In a [follow-up piece](http://www.nytimes.com/times-insider/2014/08/22/times-article-changes-a-policy-fast/), the author, Jodi Kantor, points directly to Kronos' scheduling software as the root of the problem. \"I saw that her life was coming apart and that the Starbucks software had contributed to the crisis,\" Kantor wrote of one of the story's subjects.\n\nThe piece's argument centered around the financial and scheduling unpredictability engendered by platforms like Kronos. When you don't know if your shift might be canceled, if or when you'll be called in, or what your hours will look like next week or the week after, it becomes [very difficult](http://www.buzzfeed.com/sapna/victorias-secret-keeps-workers-on-call-and-unpaid#.wspVMPngB) to make even the most\n\nbasic plans for your future. This can have devastating long-term financial and emotional impacts on workers. According to a [recent study](http://www.epi.org/publication/irregular-work-scheduling-and-its-consequences/) by the Economic Policy Institute, a left-leaning think tank in Washington, D.C., 17 percent of the American workforce is negatively affected by unstable schedules.\n\nFor their part, Kronos representatives argue that the algorithm is far from the root of the problem. \"The populist view is that scheduling is evil, in that it's causing erratic schedules for employees, and so forth,\" Charlie DeWitt, vice president of business development for Kronos, told BuzzFeed News. \"The fact of the matter is it's an algorithm. It does whatever you want it to do.\"\n\nAnd you don't necessarily need to work for Kronos to believe that in a competitive retail climate, the problem is more complicated than technology alone. [Lonnie Golden](http://www.abington.psu.edu/academics/faculty/dr-lonnie-golden), a Penn State economist who has extensively studied the impact of erratic scheduling, acknowledges that Kronos' product itself is less to blame than the managers who make staffing decisions based on the data it provides. \"It's not necessarily the technology that's responsible for minimum to no advance notice,\" he said. \"It's the way in which it's applied.\"\n\nBut, he added, \"where there's a technology problem, there's usually a technology solution.\" And while Kronos maintains that managers, and not the software, are responsible for early dismissals and last-minute shift cancellations, the company is nonetheless pursuing some technological solutions.\n\nKronos wants to help managers better understand how scheduling adjustments affect workers and, ultimately, the bottom line. Though the company maintains that its software doesn't produce the kind of erratic schedules that hurt wage workers, DeWitt said there was nonetheless an interest in figuring out why that perception existed — and, if possible, fixing it.\n\nTo that end, earlier this month at a [retail conference in Philadelphia](http://www.kronos.com/microsites/RetailExecSummitSpring15/), the company announced that it's working on a new plug-in that will give managers better insight into workers' schedule stability, equity of hours worked among employees, and the consistency of schedules from week to week. In addition, Kronos is improving a feature meant to help give employees more control over their schedules: Though the software already incorporates employee availability and preferences into its scheduling calculations, improvements to a shift-swapping feature on its employee-facing web and mobile apps will theoretically allow employees to work around conflicts among themselves.\n\nGolden said increased employee input and control would be a good thing. But some retailers, DeWitt pointed out, are uncomfortable making workers use an app outside of work hours; indeed, the practice could be seen as a shift of management responsibilities onto lower-paid individuals.\n\nPart of the idea behind the new Kronos plug-in is to help companies tie fairer scheduling practices to reduction in absenteeism and turnover, which can be enormously costly. In other words, if Kronos can help executives see the connection between treating workers fairly and a store's ability to increase revenue, DeWitt said, managers will have an impetus to create more predictable, stable schedules.\n\nAnd just because companies are looking at this kind of data doesn't mean they have to use it. \"Companies like Kronos and Workplace Systems are starting to integrate some of these principles into their software,\" said [Carrie Gleason](http://populardemocracy.org/carrie-gleason), director of the Fair Workweek Initiative at the Center for Popular Democracy, \"but it's all optional, so companies can decide not to do it.\" While [12 states](http://populardemocracy.org/campaign/restoring-fair-workweek) are currently considering legislation that would create new labor standards around the workweek, Gleason said the technology alone lacks a mechanism for enforcement.\n\nGiven market pressures and standard management practices, it's unlikely that any change to Kronos' technology would give workers more power — especially because, given the [competitive retail climate](http://www.buzzfeed.com/sapna/retail-winter-of-death#.krGlE3qDm) at the moment, the bottom line tends to be the priority. \"It's not just bad managers. They have extreme pressure to increase productivity on an ever-shrinking labor budget,\" Gleason said.\n\nWith these changes, Kronos has taken logical steps toward both repairing its reputation and making sure its software creates sustainable work environments. But while the company cannot control exactly how the algorithm that forecasts schedules and optimizes workforces is deployed inside different workplaces, the Kronos engineers who designed the product are nonetheless the partial architects of work environments that have been proven to be untenable for low-wage workers. The Kronos scheduling algorithm isn't designed to serve those people; it's designed to be sold to their bosses, and as such, will ultimately be shaped to serve the needs of management — until regulations exist that compel them to change how it's used.", + "title": "Report 3205 title", + "url": "https://www.buzzfeednews.com/article/carolineodonovan/kronos-makes-changes-to-software-accused-of-producing-bad-sc" + }, + { + "__typename": "Report", + "_id": "5d34b8c29ced494f010ed471", + "authors": ["Alain Sherter"], + "cloudinary_id": "reports/cbsnews2.cbsistatic.com/hub/i/r/2014/09/25/aa2708c1-7e84-4573-8f79-add177a690cd/thumbnail/1200x630/2505bd91ab74f8e2ce3e7c6f8a5d77f3/starbucks.jpg", + "date_published": "2014-09-26", + "description": "Baristas at the coffee chain worry the company won't fulfill its promise to improve working conditions", + "epoch_date_submitted": 1559347200, + "image_url": "https://cbsnews2.cbsistatic.com/hub/i/r/2014/09/25/aa2708c1-7e84-4573-8f79-add177a690cd/thumbnail/1200x630/2505bd91ab74f8e2ce3e7c6f8a5d77f3/starbucks.jpg", + "inputs_outputs": null, + "language": "en", + "report_number": 3206, + "source_domain": "cbsnews.com", + "submitters": ["Catherine Olsson"], + "tags": [], + "text": "Liberte Locke, a 32-year-old \"barista\" at a Starbucks (SBUX) in New York City, is fed up.\n\n\"Starbucks' attitude is that there's always someone else who can do the job,\" she said in running through her complaints about life at the java giant.\n\nIf that isn't necessarily the consensus among Starbucks workers, interviews with nine current and former baristas at the company make clear it's not an isolated opinion, either. Even those who say they like their job paint a picture of a business that underpays front-line workers, enforces work rules arbitrarily, and too often fails to strike a balance between corporate goals and employee needs.\n\nOf course, such complaints are nothing new in retail, where low pay and erratic schedules are the norm. But by its own account, Starbucks is no ordinary company and is ostensibly a far cry from the fast-food outlets now facing a nationwide uprising by employees tired of working for peanuts.\n\nThat's evident in the company's recruitment pitch. Starbucks invites job-seekers to \"become a part of something bigger and inspire positive change in the world,\" describing it as a chance to discover a \"deep sense of purpose.\"\n\nDamage control\n\nThat image suffered a serious blow last month after The New York Times vividly chronicled a Starbucks worker struggling with the company's scheduling practices. The story, which centered on a 22-year-old barista and single mother, amounted to a public relations nightmare for Starbucks. Perhaps not coincidentally, within days of the story's publication top executives were promising reform.\n\nIn a memo to employees earlier this month, for instance, Chief Operating Officer Troy Alstead vowed to \"transform the U.S. partner experience,\" referring to Starbucks' more than 130,000 baristas. Inviting worker feedback, he said Starbucks will examine its approach to employee pay, revisit its dress code, make it easier for people to ask for time off, and consider other changes aimed at helping baristas balance work and their personal lives.\n\nAmong other changes, the company said it would end the practice of \"clopening,\" when an employee responsible for closing a store late at night is also assigned to open it early in the morning.\n\n\"We recognize that we can do more for our partners who wear the apron every day,\" he wrote.\n\nSome baristas did not feel this August memo from Starbucks went far enough in proposing ways to improve work conditions, so they marked it up with their own ideas. CBS\n\nAlthough Starbucks workers welcome this pledge to respect the apron, they fear the company is more intent on dousing the PR flames than on genuinely improving employees' experience. After the retailer last month sent an email to workers outlining possible solutions to the kind of scheduling problems and related issues detailed by the Times, a group of baristas gave the proposal a C- and posted online a marked-up version of the memo listing their own demands (see image above).\n\n\"We hope you're ready for a commitment to give us schedules that don't mess with taking care of kids, going to school or holding onto that second job we need because Sbux wages don't make ends meet,\" wrote the baristas, who are working with a union-backed labor group, the Center for Popular Democracy.\n\nRetail jungle\n\nDespite the recent media focus on Starbucks, the company's labor practices are generally no worse than those of many large retailers. In some ways they're better, with the company offering health care to part-time, as well as full-time, workers; unusually generous 401(k) matching contributions; annual stock grants to employees; and tuition reimbursement.\n\nStarbucks highlights such benefits as an example of its commitment to employees. \"Sharing success with one another has been core to the company's heritage for more than 40 years,\" Alstead said in the September memo.\n\nMeanwhile, some baristas say they enjoy their work and feel valued by Starbucks. \"It's a decent place to work, and my manager and co-workers are great,\" said one employee who asked not to be identified.\n\nBut other current and former workers claim Starbucks has changed in recent years, saying that corporate leaders' intense focus on slashing costs has short-circuited its professed commitment to workers. Mostly, they say Starbucks doesn't listen to employees and even punishes those who identify problems.\n\n\"The biggest problem is that baristas don't have a voice,\" said Sarah Madden, a former Starbucks barista who left the company this spring after two years with the coffee vendor. \"They can't speak to issues that they know exist. Workers know how to fix them, but when [they] speak up there are serious repercussions -- your hours get cut, you're transferred to another store or isolated from other people.\"\n\nEmployees interviewed for this article said one result of Starbucks' cost-containment push is that stores are frequently understaffed, hurting customer service and forcing managers to scramble to find staff. That problem is common across the big-box s", + "title": "Report 3206 title", + "url": "https://www.cbsnews.com/news/for-some-starbucks-workers-job-leaves-bitter-taste/" + } + ] + } +} diff --git a/site/gatsby-site/i18n/locales/es/translation.json b/site/gatsby-site/i18n/locales/es/translation.json index 97bcab5936..d4d306a66b 100644 --- a/site/gatsby-site/i18n/locales/es/translation.json +++ b/site/gatsby-site/i18n/locales/es/translation.json @@ -279,5 +279,6 @@ "All four elements need to be present in order for there to be AI harm.": "Los cuatro elementos deben estar presentes para que haya daño de IA.", "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.": "No todos los incidentes en AIID cumplen con esta definición de daño de IA. Los gráficos de barras a continuación muestran los resultados anotados tanto para todos los incidentes de AIID como para los incidentes que cumplen con la definición de daño de IA de CSET.", "csetChartDeveloped": "CSET ha desarrollado definiciones específicas para las frases subrayadas que pueden diferir de las definiciones de otras organizaciones. Como resultado, otras organizaciones pueden hacer diferentes evaluaciones sobre si un incidente de IA en particular es (o no) un daño de IA. Los detalles sobre las definiciones de CSET para el daño de la IA se pueden encontrar <1>aquí1>.", - "csetChartMail": "Cada incidente es clasificado de forma independiente por dos anotadores CSET. Las anotaciones se revisan por pares y finalmente se seleccionan al azar para el control de calidad antes de la publicación. A pesar de este riguroso proceso, ocurren errores y se invita a los lectores a <1>informar1> de cualquier error que puedan descubrir mientras navegan." + "csetChartMail": "Cada incidente es clasificado de forma independiente por dos anotadores CSET. Las anotaciones se revisan por pares y finalmente se seleccionan al azar para el control de calidad antes de la publicación. A pesar de este riguroso proceso, ocurren errores y se invita a los lectores a <1>informar1> de cualquier error que puedan descubrir mientras navegan.", + "[Untitled Report]": "[Informe sin título]" } diff --git a/site/gatsby-site/i18n/locales/fr/translation.json b/site/gatsby-site/i18n/locales/fr/translation.json index 67fe7f7984..9ece79754e 100644 --- a/site/gatsby-site/i18n/locales/fr/translation.json +++ b/site/gatsby-site/i18n/locales/fr/translation.json @@ -266,5 +266,6 @@ "All four elements need to be present in order for there to be AI harm.": "Les quatre éléments doivent être présents pour qu'il y ait un préjudice causé par l'IA.", "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.": "Tous les incidents de l'AIID ne répondent pas à cette définition du préjudice causé par l'IA. Les graphiques à barres ci-dessous montrent les résultats annotés pour tous les incidents de l'AIID et les incidents qui répondent à la définition CSET du préjudice causé par l'IA.", "csetChartDeveloped": "Le CSET a développé des définitions spécifiques pour les phrases soulignées qui peuvent différer des définitions d'autres organisations. Par conséquent, d'autres organisations peuvent procéder à des évaluations différentes pour déterminer si un incident d'IA particulier est (ou n'est pas) un préjudice lié à l'IA. Des détails sur les définitions du CSET pour les dommages causés par l'IA peuvent être trouvés <1>ici1>.", - "csetChartMail": "Chaque incident est classé indépendamment par deux annotateurs CSET. Les annotations sont examinées par des pairs et finalement sélectionnées au hasard pour un contrôle qualité avant publication. Malgré ce processus rigoureux, des erreurs se produisent et les lecteurs sont invités à <1>signaler1> toute erreur qu'ils pourraient découvrir en naviguant." + "csetChartMail": "Chaque incident est classé indépendamment par deux annotateurs CSET. Les annotations sont examinées par des pairs et finalement sélectionnées au hasard pour un contrôle qualité avant publication. Malgré ce processus rigoureux, des erreurs se produisent et les lecteurs sont invités à <1>signaler1> toute erreur qu'ils pourraient découvrir en naviguant.", + "[Untitled Report]": "[Rapport sans titre]" } diff --git a/site/gatsby-site/package-lock.json b/site/gatsby-site/package-lock.json index e791ac0351..3145c3915e 100644 --- a/site/gatsby-site/package-lock.json +++ b/site/gatsby-site/package-lock.json @@ -66,7 +66,7 @@ "is-absolute-url": "^3.0.3", "json-diff-ts": "^1.2.6", "md5": "^2.3.0", - "mongodb": "^4.2.1", + "mongodb": "^4.17.0", "object-hash": "^3.0.0", "query-string": "^7.0.1", "react": "^18.2.0", @@ -107,7 +107,7 @@ "@tailwindcss/typography": "^0.5.8", "autoprefixer": "^10.4.7", "babel-eslint": "^10.1.0", - "cypress": "^12.0.2", + "cypress": "^13.0.0", "cypress-wait-for-stable-dom": "^0.1.0", "eslint": "^7.17.0", "eslint-config-prettier": "^7.1.0", @@ -3021,9 +3021,9 @@ } }, "node_modules/@cypress/request": { - "version": "2.88.11", - "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.11.tgz", - "integrity": "sha512-M83/wfQ1EkspjkE2lNWNV5ui2Cv7UCv1swW1DqljahbzLVWltcsexQh8jYtuS/vzFXP+HySntGM83ZXA9fn17w==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.0.tgz", + "integrity": "sha512-GKFCqwZwMYmL3IBoNeR2MM1SnxRIGERsQOTWeQKoYBt2JLqcqiy7JXqO894FLrpjZYqGxW92MNwRH2BN56obdQ==", "dev": true, "dependencies": { "aws-sign2": "~0.7.0", @@ -3041,7 +3041,7 @@ "performance-now": "^2.1.0", "qs": "~6.10.3", "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", + "tough-cookie": "^4.1.3", "tunnel-agent": "^0.6.0", "uuid": "^8.3.2" }, @@ -4525,6 +4525,15 @@ "node": ">=12.0.0" } }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.0.tgz", + "integrity": "sha512-Xfijy7HvfzzqiOAhAepF4SGN5e9leLkMvg/OPOF97XemjfVCYN/oWa75wnkc6mltMSTwY+XlbhWgUOJmkFspSw==", + "optional": true, + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz", @@ -10928,15 +10937,15 @@ } }, "node_modules/cypress": { - "version": "12.17.2", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-12.17.2.tgz", - "integrity": "sha512-hxWAaWbqQBzzMuadSGSuQg5PDvIGOovm6xm0hIfpCVcORsCAj/gF2p0EvfnJ4f+jK2PCiDgP6D2eeE9/FK4Mjg==", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.0.0.tgz", + "integrity": "sha512-nWHU5dUxP2Wm/zrMd8SWTTl706aJex/l+H4vi/tbu2SWUr17BUcd/sIYeqyxeoSPW1JFV2pT1pf4JEImH/POMg==", "dev": true, "hasInstallScript": true, "dependencies": { - "@cypress/request": "^2.88.11", + "@cypress/request": "^3.0.0", "@cypress/xvfb": "^1.2.4", - "@types/node": "^14.14.31", + "@types/node": "^16.18.39", "@types/sinonjs__fake-timers": "8.1.1", "@types/sizzle": "^2.3.2", "arch": "^2.2.0", @@ -10969,6 +10978,7 @@ "minimist": "^1.2.8", "ospath": "^1.2.2", "pretty-bytes": "^5.6.0", + "process": "^0.11.10", "proxy-from-env": "1.0.0", "request-progress": "^3.0.0", "semver": "^7.5.3", @@ -10981,7 +10991,7 @@ "cypress": "bin/cypress" }, "engines": { - "node": "^14.0.0 || ^16.0.0 || >=18.0.0" + "node": "^16.0.0 || ^18.0.0 || >=20.0.0" } }, "node_modules/cypress-wait-for-stable-dom": { @@ -10990,6 +11000,12 @@ "integrity": "sha512-iVJc6CDzlu1xUnTcZph+zbkOlImaDelpvRv4G+3naugvjkF6b9EFpDmRCC/16xL1pqpkFq4rFyfhuNw4C3PQjw==", "dev": true }, + "node_modules/cypress/node_modules/@types/node": { + "version": "16.18.46", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.46.tgz", + "integrity": "sha512-Mnq3O9Xz52exs3mlxMcQuA7/9VFe/dXcrgAyfjLkABIqxXKOgBRjyazTxUbjsxDa4BP7hhPliyjVTP9RDP14xg==", + "dev": true + }, "node_modules/cypress/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -22854,12 +22870,12 @@ "integrity": "sha512-dVgXe6b6DLnv4CHG7a1zUe5mSXaIZ3c6lSHm/EKeVeQI2/4pwe0VRde8OyoCE1Ro2lKT5P6uT9JElF7KDLV+jw==" }, "node_modules/mongodb": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.14.0.tgz", - "integrity": "sha512-coGKkWXIBczZPr284tYKFLg+KbGPPLlSbdgfKAb6QqCFt5bo5VFZ50O3FFzsw4rnkqjwT6D8Qcoo9nshYKM7Mg==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.17.0.tgz", + "integrity": "sha512-LZGMIPjPfWEfhPJATk1s9IvVTD18tyfKdT/0blCMih5vGagk2SwA9wFAUPMdtJpTrhXmyfGgwAaMkvneX2bn2A==", "dependencies": { - "bson": "^4.7.0", - "mongodb-connection-string-url": "^2.5.4", + "bson": "^4.7.2", + "mongodb-connection-string-url": "^2.6.0", "socks": "^2.7.1" }, "engines": { @@ -22867,7 +22883,7 @@ }, "optionalDependencies": { "@aws-sdk/credential-providers": "^3.186.0", - "saslprep": "^1.0.3" + "@mongodb-js/saslprep": "^1.1.0" } }, "node_modules/mongodb-connection-string-url": { @@ -25830,6 +25846,15 @@ "stream-parser": "~0.3.1" } }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -31637,16 +31662,27 @@ "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==" }, "node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", "dev": true, "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" }, "engines": { - "node": ">=0.8" + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" } }, "node_modules/tr46": { diff --git a/site/gatsby-site/package.json b/site/gatsby-site/package.json old mode 100755 new mode 100644 index 10937196dd..d1895951c6 --- a/site/gatsby-site/package.json +++ b/site/gatsby-site/package.json @@ -62,7 +62,7 @@ "is-absolute-url": "^3.0.3", "json-diff-ts": "^1.2.6", "md5": "^2.3.0", - "mongodb": "^4.2.1", + "mongodb": "^4.17.0", "object-hash": "^3.0.0", "query-string": "^7.0.1", "react": "^18.2.0", @@ -116,7 +116,7 @@ "@tailwindcss/typography": "^0.5.8", "autoprefixer": "^10.4.7", "babel-eslint": "^10.1.0", - "cypress": "^12.0.2", + "cypress": "^13.0.0", "cypress-wait-for-stable-dom": "^0.1.0", "eslint": "^7.17.0", "eslint-config-prettier": "^7.1.0", diff --git a/site/gatsby-site/src/components/RelatedIncidents.js b/site/gatsby-site/src/components/RelatedIncidents.js index 6fd8571170..94549cfc49 100644 --- a/site/gatsby-site/src/components/RelatedIncidents.js +++ b/site/gatsby-site/src/components/RelatedIncidents.js @@ -45,14 +45,20 @@ const reportsWithIncidentIds = async (reports, client) => { }, }); - return reports.map((report) => ({ - ...report, - incident_id: response.data.incidents.filter((incident) => + return reports.map((report) => { + const incident = response.data.incidents.find((incident) => incident.reports .map((incidentReport) => incidentReport.report_number) .includes(report.report_number) - )[0]?.incident_id, - })); + ); + + return { + ...report, + title: report.title, + incident_title: incident?.title, + incident_id: incident?.incident_id, + }; + }); }; const allSearchColumns = { diff --git a/site/gatsby-site/src/components/RelatedIncidentsArea.js b/site/gatsby-site/src/components/RelatedIncidentsArea.js index 86ed8e058b..91cfadb3d3 100644 --- a/site/gatsby-site/src/components/RelatedIncidentsArea.js +++ b/site/gatsby-site/src/components/RelatedIncidentsArea.js @@ -103,7 +103,14 @@ const RelatedIncidentsArea = ({ target="_blank" rel="noreferrer" > - {val.title} + {!val.title && ( + <> + + {t('[Untitled Report]')} + {' '} + > + )} + {val.title || val.incident_title}