Skip to content
Draft
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
2 changes: 2 additions & 0 deletions clients/admin-ui/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ declare module globalThis {
let fidesDebugger: (...args: unknown[]) => void;
}

declare module "*.ttf";

interface Window {
// Cypress is available on window when running in Cypress tests
Cypress?: any;
Expand Down
1 change: 1 addition & 0 deletions clients/admin-ui/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ module.exports = {
transformIgnorePatterns: [
"/node_modules/(?!(react-hotkeys-hook|@ant-design/x-markdown)/)",
"^.+\\.module\\.(css|sass|scss)$",
"^.+.(ttf)$",
],
watchPathIgnorePatterns: ["node_modules"],
};
8 changes: 8 additions & 0 deletions clients/admin-ui/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ const nextConfig = {
resolveAlias: {
antd: "antd/lib",
},
rules: {
"*.ttf": {
type: "asset",
},
"*.woff2": {
type: "asset",
},
},
},
webpack: (config) => {
config.resolve.alias = {
Expand Down
2 changes: 2 additions & 0 deletions clients/admin-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"@json-render/core": "^0.18.0",
"@json-render/react": "^0.18.0",
"@monaco-editor/react": "^4.6.0",
"@react-pdf/renderer": "^4.5.1",
"@reduxjs/toolkit": "^2.6.0",
"@tanstack/react-table": "^8.10.7",
"@types/dagre": "^0.7.52",
Expand Down Expand Up @@ -78,6 +79,7 @@
"react-hotkeys-hook": "^5.2.1",
"react-phone-number-input": "^3.4.1",
"react-redux": "^9.1.2",
"recharts": "^3.7.0",
"redux-persist": "^6.0.0",
"valibot": "^1.2.0",
"yup": "^1.4.0",
Expand Down
3 changes: 3 additions & 0 deletions clients/admin-ui/src/features/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ export const getBrandIconUrl = (domain: string, size = 24) => {
return `https://cdn.brandfetch.io/${domain}/icon/theme/light/fallback/404/h/${size}/w/${size}?c=1idbRjELpikqQ1PLiqb`;
};

export const getBrandLogoUrl = (domain: string, size = 300) =>
`https://cdn.brandfetch.io/domain/${domain}/type/logo.png/theme/dark/fallback/404/h/${size}/w/${size * 3}?c=1idbRjELpikqQ1PLiqb`;

export const getDomain = (urlOrDomain: string): string => {
try {
// Try to parse as URL first
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ import {
import { AggregateStatisticsResponse } from "~/types/api/models/AggregateStatisticsResponse";
import { APIMonitorType } from "~/types/api/models/APIMonitorType";
import { BaseStagedResourcesRequest } from "~/types/api/models/BaseStagedResourcesRequest";
import { ClassificationBreakdownResponse } from "~/types/api/models/ClassificationBreakdownResponse";
import { ConditionalTotalCursorPage_DatastoreStagedResourceTreeAPIResponse_ } from "~/types/api/models/ConditionalTotalCursorPage_DatastoreStagedResourceTreeAPIResponse_";
import { DatastoreMonitorResourcesDynamicFilters } from "~/types/api/models/DatastoreMonitorResourcesDynamicFilters";
import { DatastoreStagedResourceTreeAPIResponse } from "~/types/api/models/DatastoreStagedResourceTreeAPIResponse";
import { ExecutionLogStatus } from "~/types/api/models/ExecutionLogStatus";
import { MonitorActionResponse } from "~/types/api/models/MonitorActionResponse";
import { MonitorTaskResponse } from "~/types/api/models/MonitorTaskResponse";
import { VendorBreakdownResponse } from "~/types/api/models/VendorBreakdownResponse";
import {
PaginatedResponse,
PaginationQueryParams,
Expand Down Expand Up @@ -545,7 +547,34 @@ const actionCenterApi = baseApi.injectEndpoints({
},
providesTags: ["Monitor Tasks"],
}),

getVendors: build.query<
VendorBreakdownResponse,
{
monitor_config_id?: string;
}
>({
query: ({ ...params }) => {
return {
url: `/plus/discovery-monitor/report/vendors`,
params,
};
},
// providesTags: ["Monitor Statistics"],
}),
getClassifications: build.query<
ClassificationBreakdownResponse,
{
monitor_config_id?: string;
}
>({
query: ({ ...params }) => {
return {
url: `/plus/discovery-monitor/report/classifications`,
params,
};
},
// providesTags: ["Monitor Statistics"],
}),
getAggregateStatistics: build.query<
AggregateStatisticsResponse,
{
Expand Down Expand Up @@ -680,6 +709,7 @@ export const {
useLazyGetMonitorTreeQuery,
useLazyGetMonitorTreeAncestorsStatusesQuery,
useGetMonitorConfigQuery,
useLazyGetMonitorConfigQuery,
useGetDatastoreFiltersQuery,
useClassifyStagedResourcesMutation,
useGetStagedResourceDetailsQuery,
Expand All @@ -689,5 +719,9 @@ export const {
useGetAggregateStatisticsQuery,
useGetConnectionQuery,
useCalcAggregateStatisticsMutation,
useGetVendorsQuery,
useLazyGetVendorsQuery,
useGetClassificationsQuery,
useLazyGetClassificationsQuery,
util: actionCenterUtil,
} = actionCenterApi;
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import { Page, StyleSheet, Text, View } from "@react-pdf/renderer";
import { palette } from "fidesui/src/palette/palette";

import { PdfFooter } from "~/features/pdf/Footer";
import { PdfHeader } from "~/features/pdf/Header";
import { HeaderStyles } from "~/features/pdf/PdfStyles";
import { TableOfContentsPdf } from "~/features/pdf/TableOfContents";
import { TitlePage } from "~/features/pdf/TitlePage";
import { PdfWrapper } from "~/features/pdf/Wrapper";
import { AggregateStatisticsResponse } from "~/types/api";
import { ClassificationBreakdownItem } from "~/types/api/models/ClassificationBreakdownItem";
import { VendorBreakdownItem } from "~/types/api/models/VendorBreakdownItem";

import { MonitorReportDataElements } from "./sections/MonitorReportDataElements";
import { MonitorReportSummary } from "./sections/MonitorReportSummary";
import { MonitorReportsThirdParties } from "./sections/MonitorReportThirdParties";

const styles = StyleSheet.create({
page: {
paddingHorizontal: 40,
paddingTop: 40,
flexDirection: "column",
backgroundColor: palette.FIDESUI_BG_WHITE,
justifyContent: "space-evenly",
},
section: {
fontFamily: "BasierSquare",
fontSize: 12,
margin: 10,
padding: 10,
flexGrow: 1,
},
});

const SECTIONS = [
{
title: "Summary",
description:
"Dashboard of detected systems, scripts, cookies, and consent issues.",
},
// {
// title: 'Policy Checks',
// description: 'GPC honor, Google Consent Mode, regulatory links.'
// },
// {
// title: 'Findings',
// description: 'Every finding where consent was absent, grouped by third party.'
// },
{
title: "Third Parties",
description: "All vendors observed, categorized with data they receive.",
},
// {
// title: 'Scripts',
// description: 'Browser requests and JavaScript tags, with consent behavior.'
// },
{
title: "Data Elements",
description:
"Fides data-use taxonomy labels and the vendors receiving each.",
},
// {
// title: 'Cookies',
// description: 'First and thrid-party cookies observed across scanned pages.'
// }
] as const;

export const MonitorReport = ({
monitorTitle,
imageSrc,
vendorsChart,
classificationsChart,
vendors,
classifications,
stats,
author,
location,
}: {
monitorTitle: string;
author: string;
location: string;
imageSrc: string;
vendorsChart: string;
classificationsChart: string;
vendors: Array<VendorBreakdownItem>;
classifications: Array<ClassificationBreakdownItem>;
stats: AggregateStatisticsResponse;
}) => (
<PdfWrapper>
<TitlePage
imageString={imageSrc}
monitorTitle={monitorTitle}
location={location}
author={author}
/>
<Page size="A4" style={styles.page}>
<PdfHeader title="Ethyca" />
<View style={styles.section}>
<Text style={HeaderStyles.h4}>Contents</Text>
<Text style={HeaderStyles.h1}>Report details</Text>
<Text style={[HeaderStyles.h4, { fontSize: 12 }]}>
Table of contents
</Text>
<TableOfContentsPdf sections={SECTIONS} />
</View>
<PdfFooter />
</Page>
{SECTIONS.map(({ title }, sectionIndex) => (
<Page size="A4" style={styles.page} key={title}>
<PdfHeader
section={{ title, index: sectionIndex + 1 }}
title="Ethyca"
/>
<View style={styles.section}>
<Text style={HeaderStyles.h5}>{`Chapter ${sectionIndex + 1}`}</Text>
<Text style={HeaderStyles.h1}>{title}</Text>
{title === "Summary" && (
<MonitorReportSummary
classifications={classifications}
vendors={vendors}
stats={stats}
monitorTitle={monitorTitle}
/>
)}
{title === "Data Elements" && (
<MonitorReportDataElements
classifications={classifications}
classificationsChart={classificationsChart}
/>
)}
{title === "Third Parties" && (
<MonitorReportsThirdParties
vendors={vendors}
vendorsChart={vendorsChart}
/>
)}
</View>
<PdfFooter />
</Page>
))}
</PdfWrapper>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Button, Icons, Tooltip } from "fidesui";
import { useRouter } from "next/router";

import { useMonitorReportDownload } from "./useMonitorReportDownload";

const MonitorReportDownload = () => {
const router = useRouter();
const monitorId = decodeURIComponent(router.query.monitorId as string);
const { isGenerating, generate } = useMonitorReportDownload(monitorId);

return (
<Tooltip title="Generate Report">
<Button
aria-label="Generate Report"
icon={<Icons.Document />}
onClick={() => generate()}
loading={isGenerating}
disabled={isGenerating}
/>
</Tooltip>
);
};

export default MonitorReportDownload;
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Pie, PieChart } from "recharts";

import { VISUAL_COLORS } from "~/features/pdf/PdfStyles";
import { ClassificationBreakdownItem } from "~/types/api/models/ClassificationBreakdownItem";

const MonitorReportClassificationsChart = ({
classifications,
}: {
classifications: Array<ClassificationBreakdownItem>;
}) => (
<PieChart
barCategoryGap="10%"
barGap={4}
height={1200}
width={1200}
responsive
style={{ aspectRatio: 1 }}
endAngle={360}
startAngle={0}
>
<Pie
data={classifications?.map(({ vendors, name }, i) => ({
vendorsCount: vendors?.length,
name,
fill: VISUAL_COLORS[i],
}))}
dataKey="vendorsCount"
nameKey="name"
isAnimationActive={false}
innerRadius="30%"
/>
</PieChart>
);

export default MonitorReportClassificationsChart;
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Pie, PieChart } from "recharts";

import { VISUAL_COLORS } from "~/features/pdf/PdfStyles";
import { VendorBreakdownItem } from "~/types/api/models/VendorBreakdownItem";

const MonitorReportVendorsChart = ({
vendors,
}: {
vendors: Array<VendorBreakdownItem>;
}) => (
<PieChart
barCategoryGap="10%"
barGap={4}
height={1200}
width={1200}
responsive
style={{ aspectRatio: 1 }}
endAngle={360}
startAngle={0}
>
<Pie
data={vendors?.map(({ resource_count, name }, i) => ({
resource_count,
name,
fill: VISUAL_COLORS[i],
}))}
dataKey="resource_count"
nameKey="name"
isAnimationActive={false}
innerRadius="30%"
/>
</PieChart>
);

export default MonitorReportVendorsChart;
Loading
Loading