Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CORL-2970]: DSA - Display related reports on single report screen #4434

Merged
merged 3 commits into from
Dec 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions client/src/core/client/admin/routes/Reports/RelatedReports.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.label {
font-size: var(--font-size-1);
text-transform: uppercase;
}

.button {
background-color: var(--palette-grey-200);
color: var(--palette-grey-500);
text-align: left;
}

.reportIDLabel {
text-transform: uppercase;
}

.referenceID {
margin-left: var(--spacing-2);
text-decoration: underline;
}

.arrowIcon {
margin-left: auto;
}
85 changes: 85 additions & 0 deletions client/src/core/client/admin/routes/Reports/RelatedReports.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { Localized } from "@fluent/react/compat";
import React, { FunctionComponent } from "react";
import { graphql } from "react-relay";

import { withFragmentContainer } from "coral-framework/lib/relay";
import { ArrowRightIcon, SvgIcon } from "coral-ui/components/icons";
import { Flex } from "coral-ui/components/v2";
import { Button } from "coral-ui/components/v3";

import { RelatedReports_dsaReport } from "coral-admin/__generated__/RelatedReports_dsaReport.graphql";

import styles from "./RelatedReports.css";

interface Props {
dsaReport: RelatedReports_dsaReport;
}

const RelatedReports: FunctionComponent<Props> = ({ dsaReport }) => {
const relatedReports = dsaReport.relatedReports.edges.map(
(edge) => edge.node
);

if (relatedReports.length === 0) {
return null;
}

return (
<Flex direction="column">
<Localized id="reports-relatedReports-label">
<div className={styles.label}>Related Reports</div>
</Localized>
{relatedReports.map((report) => {
return (
<Flex marginTop={2} key={report.id}>
<Button
className={styles.button}
fullWidth
color="none"
variant="flat"
href={`/admin/reports/report/${report.id}`}
>
<Flex>
<Flex>
<Localized id="reports-relatedReports-reportIDLabel">
<span className={styles.reportIDLabel}>Report ID</span>
</Localized>
<span className={styles.referenceID}>
{report.referenceID}
</span>
</Flex>
<Flex className={styles.arrowIcon}>
<SvgIcon Icon={ArrowRightIcon} />
</Flex>
</Flex>
</Button>
</Flex>
);
})}
</Flex>
);
};

const enhanced = withFragmentContainer<Props>({
dsaReport: graphql`
fragment RelatedReports_dsaReport on DSAReport
@argumentDefinitions(
count: { type: "Int", defaultValue: 10 }
cursor: { type: "Cursor" }
orderBy: { type: "REPORT_SORT", defaultValue: CREATED_AT_DESC }
) {
id
relatedReports(first: $count, after: $cursor, orderBy: $orderBy)
@connection(key: "RelatedReports_relatedReports") {
edges {
node {
id
referenceID
}
}
}
}
`,
})(RelatedReports);

export default enhanced;
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import styles from "./SingleReportRoute.css";

import NotFound from "../NotFound";
import ChangeStatusModal from "./ChangeStatusModal";
import RelatedReports from "./RelatedReports";
import ReportedComment from "./ReportedComment";
import ReportHistory from "./ReportHistory";
import ReportMakeDecisionModal from "./ReportMakeDecisionModal";
Expand Down Expand Up @@ -235,6 +236,7 @@ const SingleReportRoute: FunctionComponent<Props> & {
dsaReport={dsaReport}
onShowUserDrawer={onShowUserDrawer}
/>
<RelatedReports dsaReport={dsaReport} />
{dsaReport.decision && (
<>
<Divider />
Expand Down Expand Up @@ -381,6 +383,7 @@ SingleReportRoute.routeConfig = createRouteConfig<
...ReportShareButton_dsaReport
...ReportMakeDecisionModal_dsaReport
...ReportedComment_dsaReport
...RelatedReports_dsaReport
}
}
`,
Expand Down
2 changes: 2 additions & 0 deletions client/src/core/client/admin/test/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -851,6 +851,7 @@ export const dsaReports = createFixtures<GQLDSAReport>([
additionalInformation:
"The additional information supporting why that law is alleged to have been broken",
history: [],
relatedReports: { edges: [], pageInfo: { hasNextPage: false } },
},
{
id: "dsa-report-2",
Expand All @@ -869,6 +870,7 @@ export const dsaReports = createFixtures<GQLDSAReport>([
"A detailed explanation of why it is a violation of Law number 2",
},
history: [],
relatedReports: { edges: [], pageInfo: { hasNextPage: false } },
},
]);

Expand Down
3 changes: 3 additions & 0 deletions locales/en-US/admin.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -1909,6 +1909,9 @@ reports-decisionModal-detailedExplanationLabel = Detailed explanation
reports-decisionModal-detailedExplanationTextarea =
.placeholder = Add explanation...

reports-relatedReports-label = Related reports
reports-relatedReports-reportIDLabel = Report ID

# Control panel

controlPanel-redis-redis = Redis
Expand Down
18 changes: 18 additions & 0 deletions server/src/core/server/graph/loaders/DSAReports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import {
DSAReportConnectionInput,
find,
retrieveDSAReportConnection,
retrieveDSAReportRelatedReportsConnection,
} from "coral-server/models/dsaReport";

import GraphContext from "../context";
import { createManyBatchLoadFn } from "./util";

import {
DSAReportToRelatedReportsArgs,
GQLDSAREPORT_STATUS_FILTER,
GQLREPORT_SORT,
QueryToDsaReportsArgs,
Expand Down Expand Up @@ -53,4 +55,20 @@ export default (ctx: GraphContext) => ({
cache: !ctx.disableCaching,
}
),
relatedReports: (
submissionID: string,
id: string,
{ first, orderBy, after }: DSAReportToRelatedReportsArgs
) =>
retrieveDSAReportRelatedReportsConnection(
ctx.mongo,
ctx.tenant.id,
submissionID,
id,
{
first: defaultTo(first, 10),
orderBy: defaultTo(orderBy, GQLREPORT_SORT.CREATED_AT_DESC),
after,
}
),
});
14 changes: 13 additions & 1 deletion server/src/core/server/graph/resolvers/DSAReport.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { defaultTo } from "lodash";

import * as dsaReport from "coral-server/models/dsaReport";

import { GQLDSAReportTypeResolver } from "coral-server/graph/schema/__generated__/types";
import {
GQLDSAReportTypeResolver,
GQLREPORT_SORT,
} from "coral-server/graph/schema/__generated__/types";

export const DSAReport: GQLDSAReportTypeResolver<dsaReport.DSAReport> = {
reporter: (report, args, ctx) => {
Expand Down Expand Up @@ -33,4 +38,11 @@ export const DSAReport: GQLDSAReportTypeResolver<dsaReport.DSAReport> = {
return null;
}
},
relatedReports: ({ submissionID, id }, { first, after, orderBy }, ctx) => {
return ctx.loaders.DSAReports.relatedReports(submissionID, id, {
first: defaultTo(first, 10),
after,
orderBy: defaultTo(orderBy, GQLREPORT_SORT.CREATED_AT_DESC),
});
},
};
10 changes: 10 additions & 0 deletions server/src/core/server/graph/schema/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -3661,6 +3661,16 @@ type DSAReport {
such as a note added, status changed, or decision made
"""
lastUpdated: Time

"""
relatedReports are DSAReports that share a submissionID and were submitted at the same time
in one illegal content report
"""
relatedReports(
first: Int = 10 @constraint(max: 50)
orderBy: REPORT_SORT = CREATED_AT_DESC
after: Cursor
): DSAReportsConnection!
}

type CommentRevisionPerspectiveMetadata {
Expand Down
17 changes: 17 additions & 0 deletions server/src/core/server/models/dsaReport/report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,23 @@ export async function retrieveDSAReportConnection(
return retrieveConnection(input, query);
}

export async function retrieveDSAReportRelatedReportsConnection(
mongo: MongoContext,
tenantID: string,
submissionID: string,
id: string,
input: DSAReportConnectionInput
): Promise<Readonly<Connection<Readonly<DSAReport>>>> {
// Create the query.
const query = new Query(mongo.dsaReports()).where({
tenantID,
submissionID,
id: { $ne: id },
});

return retrieveConnection(input, query);
}

export async function retrieveDSAReport(
mongo: MongoContext,
tenantID: string,
Expand Down