diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml
index 56e8448b0c..0cf9e1d9d5 100644
--- a/.github/workflows/scorecards.yml
+++ b/.github/workflows/scorecards.yml
@@ -57,6 +57,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
- uses: github/codeql-action/upload-sarif@f079b8493333aace61c81488f8bd40919487bd9f # tag=v3.25.7
+ uses: github/codeql-action/upload-sarif@23acc5c183826b7a8a97bce3cecc52db901f8251 # tag=v3.25.10
with:
sarif_file: results.sarif
diff --git a/.github/workflows/test-checks.yaml b/.github/workflows/test-checks.yaml
index 5f128e5e52..e9a9dd0b94 100644
--- a/.github/workflows/test-checks.yaml
+++ b/.github/workflows/test-checks.yaml
@@ -41,7 +41,7 @@ jobs:
ignore-unfixed: false
severity: UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL
- name: Upload Trivy scan results to GitHub Security tab
- uses: github/codeql-action/upload-sarif@f079b8493333aace61c81488f8bd40919487bd9f
+ uses: github/codeql-action/upload-sarif@23acc5c183826b7a8a97bce3cecc52db901f8251
with:
sarif_file: 'trivy-results.sarif'
@@ -61,13 +61,13 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
- name: Initialize CodeQL
- uses: github/codeql-action/init@f079b8493333aace61c81488f8bd40919487bd9f
+ uses: github/codeql-action/init@23acc5c183826b7a8a97bce3cecc52db901f8251
with:
languages: ${{ matrix.language }}
- name: Autobuild
- uses: github/codeql-action/autobuild@f079b8493333aace61c81488f8bd40919487bd9f
+ uses: github/codeql-action/autobuild@23acc5c183826b7a8a97bce3cecc52db901f8251
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@f079b8493333aace61c81488f8bd40919487bd9f
+ uses: github/codeql-action/analyze@23acc5c183826b7a8a97bce3cecc52db901f8251
cocogitto:
runs-on: ubuntu-latest
@@ -92,7 +92,7 @@ jobs:
- uses: actions/checkout@v4
- run: ./.bin/install-gitleaks-linux-x64.sh
- run: ./gitleaks detect --exit-code 0 --report-format sarif --report-path "gitleaks.sarif"
- - uses: github/codeql-action/upload-sarif@f079b8493333aace61c81488f8bd40919487bd9f
+ - uses: github/codeql-action/upload-sarif@23acc5c183826b7a8a97bce3cecc52db901f8251
with:
sarif_file: 'gitleaks.sarif'
diff --git a/.github/workflows/test-code.yaml b/.github/workflows/test-code.yaml
index 8c53f1430c..b092a2418a 100644
--- a/.github/workflows/test-code.yaml
+++ b/.github/workflows/test-code.yaml
@@ -59,7 +59,7 @@ jobs:
fs.writeFileSync('results.sarif', JSON.stringify(sarifJson, null, 2));
EOF
working-directory: ./app
- - uses: github/codeql-action/upload-sarif@f079b8493333aace61c81488f8bd40919487bd9f
+ - uses: github/codeql-action/upload-sarif@23acc5c183826b7a8a97bce3cecc52db901f8251
with:
sarif_file: app/results.sarif
diff --git a/.github/workflows/test-containers.yaml b/.github/workflows/test-containers.yaml
index 5cac7b4619..2bd0112a0f 100644
--- a/.github/workflows/test-containers.yaml
+++ b/.github/workflows/test-containers.yaml
@@ -37,7 +37,7 @@ jobs:
severity: CRITICAL
timeout: 10m0s
- name: Upload Trivy scan results to GitHub Security tab
- uses: github/codeql-action/upload-sarif@f079b8493333aace61c81488f8bd40919487bd9f
+ uses: github/codeql-action/upload-sarif@23acc5c183826b7a8a97bce3cecc52db901f8251
with:
sarif_file: 'trivy-results.sarif'
- name: Get Results Length From Sarif
@@ -64,7 +64,7 @@ jobs:
severity: CRITICAL
timeout: 10m0s
- name: Upload Trivy scan results to GitHub Security tab
- uses: github/codeql-action/upload-sarif@f079b8493333aace61c81488f8bd40919487bd9f
+ uses: github/codeql-action/upload-sarif@23acc5c183826b7a8a97bce3cecc52db901f8251
with:
sarif_file: 'trivy-results.sarif'
- name: Get Results Length From Sarif
diff --git a/app/Dockerfile b/app/Dockerfile
index 8087788e1a..016ea37128 100644
--- a/app/Dockerfile
+++ b/app/Dockerfile
@@ -1,4 +1,4 @@
-FROM registry.access.redhat.com/ubi9/s2i-base@sha256:9af1318d4d016b4aab0723aafdaf739972065919559107eadaccac4c8f350f37
+FROM registry.access.redhat.com/ubi9/s2i-base@sha256:798d3d983bde082429eaced15475722585c994612ba062dbce6428877ee3ca32
ENV SUMMARY="An image for the CONN-CCBC-portal app" \
DESCRIPTION="This image contains the compiled CONN-CCBC-portal node app"
diff --git a/app/components/Analyst/RFI/RFIAnalystUpload.tsx b/app/components/Analyst/RFI/RFIAnalystUpload.tsx
index 882da3027e..832a689593 100644
--- a/app/components/Analyst/RFI/RFIAnalystUpload.tsx
+++ b/app/components/Analyst/RFI/RFIAnalystUpload.tsx
@@ -13,6 +13,8 @@ import styled from 'styled-components';
import { useCreateNewFormDataMutation } from 'schema/mutations/application/createNewFormData';
import useHHCountUpdateEmail from 'lib/helpers/useHHCountUpdateEmail';
import useRfiCoverageMapKmzUploadedEmail from 'lib/helpers/useRfiCoverageMapKmzUploadedEmail';
+import { useToast } from 'components/AppProvider';
+import Link from 'next/link';
const Flex = styled('header')`
display: flex;
@@ -20,6 +22,10 @@ const Flex = styled('header')`
width: 100%;
`;
+const StyledLink = styled(Link)`
+ color: ${(props) => props.theme.color.white};
+`;
+
const RfiAnalystUpload = ({ query }) => {
const queryFragment = useFragment(
graphql`
@@ -52,6 +58,7 @@ const RfiAnalystUpload = ({ query }) => {
rowId: applicationId,
ccbcNumber,
} = applicationByRowId;
+ const { showToast, hideToast } = useToast();
const { rfiNumber } = rfiDataByRowId;
@@ -94,9 +101,30 @@ const RfiAnalystUpload = ({ query }) => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [templateData]);
+ const getToastMessage = () => {
+ return (
+ <>
+ {' '}
+ `Template {templateData?.templateNumber} data changed successfully, new
+ values for{' '}
+ {templateData?.templateNumber === 1
+ ? 'Total Households and Indigenous Households'
+ : 'Total eligible costs and Total project costs'}{' '}
+ data in the application now reflect template uploads. Please see{' '}
+
+ history page
+ {' '}
+ for details.`
+ >
+ );
+ };
+
const handleSubmit = () => {
const updatedExcelFields = excelImportFields.join(', ');
const reasonForChange = `Auto updated from upload of ${updatedExcelFields} for RFI: ${rfiNumber}`;
+ hideToast();
updateRfi({
variables: {
input: {
@@ -129,6 +157,12 @@ const RfiAnalystUpload = ({ query }) => {
}
);
}
+ if (
+ templateData?.templateNumber === 1 ||
+ templateData?.templateNumber === 2
+ ) {
+ showToast(getToastMessage(), 'success', 100000000);
+ }
},
});
}
diff --git a/app/components/AppProvider.tsx b/app/components/AppProvider.tsx
new file mode 100644
index 0000000000..91ccd6d17b
--- /dev/null
+++ b/app/components/AppProvider.tsx
@@ -0,0 +1,63 @@
+import React, {
+ createContext,
+ useContext,
+ useState,
+ useCallback,
+ useMemo,
+ ReactNode,
+} from 'react';
+import Toast, { ToastType } from 'components/Toast';
+
+type AppContextType = {
+ showToast?: (message: ReactNode, type?: ToastType, timeout?: number) => void;
+ hideToast?: () => void;
+};
+
+const AppContext = createContext({});
+
+export const useToast = () => {
+ return useContext(AppContext);
+};
+
+export const AppProvider = ({ children }) => {
+ /**
+ * handling global toast messages
+ */
+ const [toast, setToast] = useState<{
+ visible: boolean;
+ message?: ReactNode;
+ type?: ToastType;
+ timeout?: number;
+ }>({ visible: false });
+
+ const showToast = useCallback(
+ (
+ message: ReactNode,
+ type: ToastType = 'success',
+ timeout: number = 10000
+ ) => {
+ setToast({ visible: true, message, type, timeout });
+ },
+ []
+ );
+
+ const hideToast = useCallback(() => {
+ setToast({ visible: false });
+ }, []);
+
+ const contextValue = useMemo(
+ () => ({ showToast, hideToast }),
+ [showToast, hideToast]
+ );
+
+ return (
+
+ {children}
+ {toast?.visible && (
+
+ {toast.message}
+
+ )}
+
+ );
+};
diff --git a/app/components/Toast.tsx b/app/components/Toast.tsx
index d14edf9f04..c1f8c6333a 100644
--- a/app/components/Toast.tsx
+++ b/app/components/Toast.tsx
@@ -9,7 +9,7 @@ import {
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { theme } from 'styles/GlobalTheme';
-type ToastType = 'success' | 'warning' | 'error';
+export type ToastType = 'success' | 'warning' | 'error';
type ToastDirection = 'left' | 'right';
diff --git a/app/lib/theme/widgets/FileWidget.tsx b/app/lib/theme/widgets/FileWidget.tsx
index c0b7bca6ad..9dd1a5bcb7 100644
--- a/app/lib/theme/widgets/FileWidget.tsx
+++ b/app/lib/theme/widgets/FileWidget.tsx
@@ -13,6 +13,8 @@ import bytesToSize from 'utils/bytesToText';
import FileComponent from 'lib/theme/components/FileComponent';
import useDisposeOnRouteChange from 'lib/helpers/useDisposeOnRouteChange';
import { DateTime } from 'luxon';
+import { useToast } from 'components/AppProvider';
+import { ToastType } from 'components/Toast';
type File = {
id: string | number;
@@ -65,6 +67,7 @@ const FileWidget: React.FC = ({
const maxFileSizeInBytes = 104857600;
const fileId = isFiles && value[0].id;
const { setTemplateData } = formContext;
+ const { showToast, hideToast } = useToast();
useEffect(() => {
if (rawErrors?.length > 0) {
@@ -73,6 +76,7 @@ const FileWidget: React.FC = ({
}, [rawErrors, setErrors]);
const getValidatedFile = async (file: any, formId: number) => {
+ let isTemplateValid = true;
if (templateValidate) {
const fileFormData = new FormData();
if (file) {
@@ -92,6 +96,8 @@ const FileWidget: React.FC = ({
data,
});
});
+ } else {
+ isTemplateValid = false;
}
});
}
@@ -109,6 +115,7 @@ const FileWidget: React.FC = ({
}
return {
+ isTemplateValid,
input: {
attachment: {
file,
@@ -153,6 +160,19 @@ const FileWidget: React.FC = ({
});
};
+ const showToastMessage = (files, type: ToastType = 'success') => {
+ const fields =
+ templateNumber === 1
+ ? 'Total Households and Indigenous Households data'
+ : 'Total eligible costs and Total project costs data';
+ const message =
+ type === 'success'
+ ? `Template ${templateNumber} validation successful, new values for ${fields} data in the application will update upon 'Save'`
+ : `Template ${templateNumber} validation failed: ${files.join(', ')} did not validate due to formatting issues. ${fields} in the application will not update.`;
+
+ showToast(message, type, 100000000);
+ };
+
const handleChange = async (e: React.ChangeEvent) => {
const transaction = Sentry.startTransaction({ name: 'ccbc.function' });
const span = transaction.startChild({
@@ -161,6 +181,7 @@ const FileWidget: React.FC = ({
});
if (loading) return;
+ hideToast();
const formId =
parseInt(router?.query?.id as string, 10) ||
parseInt(router?.query?.applicationId as string, 10);
@@ -177,6 +198,8 @@ const FileWidget: React.FC = ({
const validatedFiles = resp.filter((file) => file.input);
setErrors(resp.filter((file) => file.error));
+ const validationErrors = resp.filter((file) => !file.isTemplateValid);
+
const uploadResponse = await Promise.all(
validatedFiles.map(async (payload) => handleUpload(payload))
);
@@ -190,6 +213,20 @@ const FileWidget: React.FC = ({
} else {
span.setStatus('ok');
}
+
+ if (templateValidate) {
+ if (validationErrors.length > 0) {
+ showToastMessage(
+ validationErrors.map(
+ (error) => error.fileName || error.input?.attachment?.fileName
+ ),
+ 'error'
+ );
+ } else if (validationErrors.length === 0 && uploadErrors.length === 0) {
+ showToastMessage(fileDetails.map((file) => file.name));
+ }
+ }
+
span.finish();
transaction.finish();
diff --git a/app/package.json b/app/package.json
index 6ae3d62528..ca6269be92 100644
--- a/app/package.json
+++ b/app/package.json
@@ -65,7 +65,7 @@
"connect-pg-simple": "^7.0.0",
"convict": "^6.2.4",
"cookie-parser": "^1.4.6",
- "dayjs": "^1.11.8",
+ "dayjs": "^1.11.11",
"debug": "^4.1.7",
"delay": "^5.0.0",
"dotenv": "^16.3.1",
@@ -151,7 +151,7 @@
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-relay": "^1.8.3",
"fse": "^4.0.1",
- "happo-cypress": "^4.1.1",
+ "happo-cypress": "^4.2.0",
"happo-e2e": "^2.6.0",
"happo.io": "^8.3.3",
"jest": "^28.1.0",
diff --git a/app/pages/_app.tsx b/app/pages/_app.tsx
index 0736cdfc67..ae8816b045 100644
--- a/app/pages/_app.tsx
+++ b/app/pages/_app.tsx
@@ -18,6 +18,7 @@ import GlobalStyle from 'styles/GobalStyles';
import GlobalTheme from 'styles/GlobalTheme';
import BCGovTypography from 'components/BCGovTypography';
import { SessionExpiryHandler } from 'components';
+import { AppProvider } from 'components/AppProvider';
config.autoAddCss = false;
@@ -94,8 +95,10 @@ const MyApp = ({ Component, pageProps }: AppProps) => {
}>
- {typeof window !== 'undefined' && }
- {component}
+
+ {typeof window !== 'undefined' && }
+ {component}
+
diff --git a/app/tests/components/Analyst/RFI/RFIAnalystUpload.test.ts b/app/tests/components/Analyst/RFI/RFIAnalystUpload.test.ts
index 2ef65710e1..c47c6179b4 100644
--- a/app/tests/components/Analyst/RFI/RFIAnalystUpload.test.ts
+++ b/app/tests/components/Analyst/RFI/RFIAnalystUpload.test.ts
@@ -200,6 +200,8 @@ describe('The RFIAnalystUpload component', () => {
expect(screen.getByText('template_one.xlsx')).toBeInTheDocument();
+ expect(screen.getByText(/Template 1 validation successful/)).toBeVisible();
+
const saveButton = screen.getByRole('button', {
name: 'Save',
});
@@ -318,5 +320,160 @@ describe('The RFIAnalystUpload component', () => {
);
expect(mockNotifyRfiCoverageMapKmzUploaded).toHaveBeenCalledTimes(1);
+ expect(
+ screen.getByText(/Template 1 data changed successfully/)
+ ).toBeVisible();
+ });
+
+ it('should render success toast for template two when upload successful', async () => {
+ componentTestingHelper.loadQuery();
+ componentTestingHelper.renderComponent();
+
+ // @ts-ignore
+ global.fetch = jest.fn(() =>
+ Promise.resolve({
+ ok: true,
+ status: 200,
+ json: () =>
+ Promise.resolve({
+ result: {
+ totalEligibleCosts: 92455,
+ totalProjectCosts: 101230,
+ },
+ }),
+ })
+ );
+
+ const dateInput = screen.getAllByPlaceholderText('YYYY-MM-DD')[0];
+
+ await act(async () => {
+ fireEvent.change(dateInput, {
+ target: {
+ value: '2025-07-01',
+ },
+ });
+ });
+
+ const file = new File([new ArrayBuffer(1)], 'template_two.xlsx', {
+ type: 'application/excel',
+ });
+
+ const inputFile = screen.getAllByTestId('file-test')[1];
+
+ await act(async () => {
+ fireEvent.change(inputFile, { target: { files: [file] } });
+ });
+
+ componentTestingHelper.expectMutationToBeCalled(
+ 'createAttachmentMutation',
+ {
+ input: {
+ attachment: {
+ file: expect.anything(),
+ fileName: 'template_two.xlsx',
+ fileSize: '1 Bytes',
+ fileType: 'application/excel',
+ applicationId: expect.anything(),
+ },
+ },
+ }
+ );
+
+ await act(async () => {
+ componentTestingHelper.environment.mock.resolveMostRecentOperation({
+ data: {
+ createAttachment: {
+ attachment: {
+ rowId: 1,
+ file: 'string',
+ },
+ },
+ },
+ });
+ });
+
+ expect(screen.getByText('template_two.xlsx')).toBeInTheDocument();
+
+ expect(screen.getByText(/Template 2 validation successful/)).toBeVisible();
+
+ const saveButton = screen.getByRole('button', {
+ name: 'Save',
+ });
+
+ await act(async () => {
+ fireEvent.click(saveButton);
+ });
+
+ componentTestingHelper.expectMutationToBeCalled(
+ 'updateWithTrackingRfiMutation',
+ {
+ input: {
+ jsonData: {
+ rfiType: [],
+ rfiAdditionalFiles: {
+ detailedBudgetRfi: true,
+ eligibilityAndImpactsCalculatorRfi: true,
+ detailedBudget: expect.anything(),
+ geographicCoverageMapRfi: true,
+ geographicCoverageMap: expect.anything(),
+ },
+ },
+ rfiRowId: 1,
+ },
+ }
+ );
+
+ act(() => {
+ componentTestingHelper.environment.mock.resolveMostRecentOperation({
+ data: {
+ updateWithTrackingRfi: {
+ rfiData: {
+ rowId: 1,
+ jsonData: {
+ rfiAdditionalFiles: {
+ detailedBudgetRfi: true,
+ eligibilityAndImpactsCalculatorRfi: true,
+ detailedBudget: expect.anything(),
+ geographicCoverageMapRfi: true,
+ geographicCoverageMap: expect.anything(),
+ },
+ },
+ },
+ },
+ },
+ });
+ });
+
+ componentTestingHelper.expectMutationToBeCalled(
+ 'createNewFormDataMutation',
+ {
+ input: {
+ applicationRowId: 1,
+ jsonData: {
+ benefits: {
+ householdsImpactedIndigenous: 13,
+ numberOfHouseholds: 12,
+ },
+ budgetDetails: {
+ totalEligibleCosts: 92455,
+ totalProjectCost: 101230,
+ },
+ },
+ reasonForChange:
+ 'Auto updated from upload of Template 2 for RFI: RFI-01',
+ formSchemaId: 1,
+ },
+ }
+ );
+
+ act(() => {
+ componentTestingHelper.environment.mock.resolveMostRecentOperation({
+ data: {},
+ });
+ });
+
+ expect(
+ screen.getByText(/Template 2 data changed successfully/)
+ ).toBeVisible();
});
});
diff --git a/app/tests/components/Form/FileWidget.test.tsx b/app/tests/components/Form/FileWidget.test.tsx
index 6ce3a775c6..108c70c09d 100644
--- a/app/tests/components/Form/FileWidget.test.tsx
+++ b/app/tests/components/Form/FileWidget.test.tsx
@@ -52,6 +52,7 @@ const componentTestingHelper = new ComponentTestingHelper({
application: data.application,
pageNumber: getFormPage(uiSchema['ui:order'], 'coverage'),
query: data.query,
+ formContext: { setTemplateData: jest.fn() },
}),
});
@@ -535,6 +536,55 @@ describe('The FileWidget', () => {
{ body: formData, method: 'POST' }
);
});
+
+ it('displays an error toast when template validation fails', async () => {
+ componentTestingHelper.loadQuery();
+ componentTestingHelper.renderComponent((data) => ({
+ application: data.application,
+ pageNumber: 11,
+ query: data.query,
+ }));
+
+ const mockFetchPromiseTemplateOne = Promise.resolve({
+ json: () => Promise.resolve(null),
+ });
+
+ global.fetch = jest.fn(() => {
+ return mockFetchPromiseTemplateOne;
+ });
+
+ const file = new File([new ArrayBuffer(1)], 'file.xlsx', {
+ type: 'application/vnd.ms-excel',
+ });
+
+ const inputFile = screen.getAllByTestId('file-test')[0];
+ await act(async () => {
+ fireEvent.change(inputFile, { target: { files: [file] } });
+ });
+ const formData = new FormData();
+ formData.append('file', file);
+ expect(global.fetch).toHaveBeenCalledOnce();
+ expect(global.fetch).toHaveBeenCalledWith(
+ '/api/applicant/template?templateNumber=1',
+ { body: formData, method: 'POST' }
+ );
+
+ await act(async () => {
+ componentTestingHelper.environment.mock.resolveMostRecentOperation({
+ data: {
+ createAttachment: {
+ attachment: {
+ rowId: 1,
+ file: 'string',
+ },
+ },
+ },
+ });
+ });
+
+ expect(screen.getByText(/Template 1 validation failed/)).toBeVisible();
+ });
+
afterEach(() => {
jest.clearAllMocks();
});
diff --git a/app/tests/utils/componentTestingHelper.tsx b/app/tests/utils/componentTestingHelper.tsx
index ce2fc8871b..df545a65a8 100644
--- a/app/tests/utils/componentTestingHelper.tsx
+++ b/app/tests/utils/componentTestingHelper.tsx
@@ -10,6 +10,7 @@ import { MockResolvers } from 'relay-test-utils/lib/RelayMockPayloadGenerator';
import GlobalTheme from 'styles/GlobalTheme';
import GlobalStyle from 'styles/GobalStyles';
import { RouterContext } from 'next/dist/shared/lib/router-context.shared-runtime';
+import { AppProvider } from 'components/AppProvider';
import TestingHelper from './TestingHelper';
interface ComponentTestingHelperOptions {
@@ -85,10 +86,12 @@ class ComponentTestingHelper<
-
+
+
+
diff --git a/app/tests/utils/pageTestingHelper.tsx b/app/tests/utils/pageTestingHelper.tsx
index 4ca685c3bb..0fc9d94a6c 100644
--- a/app/tests/utils/pageTestingHelper.tsx
+++ b/app/tests/utils/pageTestingHelper.tsx
@@ -10,6 +10,7 @@ import { ConcreteRequest, OperationType } from 'relay-runtime';
import { MockResolvers } from 'relay-test-utils/lib/RelayMockPayloadGenerator';
import GlobalTheme from 'styles/GlobalTheme';
import { RouterContext } from 'next/dist/shared/lib/router-context.shared-runtime';
+import { AppProvider } from 'components/AppProvider';
import TestingHelper from './TestingHelper';
interface PageTestingHelperOptions {
@@ -66,10 +67,12 @@ class PageTestingHelper extends TestingHelper {
-
+
+
+
diff --git a/app/yarn.lock b/app/yarn.lock
index 51e12c331c..ebcd4f50a0 100644
--- a/app/yarn.lock
+++ b/app/yarn.lock
@@ -6491,11 +6491,11 @@ brace-expansion@^2.0.1:
balanced-match "^1.0.0"
braces@^3.0.2, braces@~3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
- integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
+ integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
dependencies:
- fill-range "^7.0.1"
+ fill-range "^7.1.1"
browser-process-hrtime@^1.0.0:
version "1.0.0"
@@ -7369,15 +7369,10 @@ data-urls@^3.0.1:
whatwg-mimetype "^3.0.0"
whatwg-url "^11.0.0"
-dayjs@^1.10.4:
- version "1.11.2"
- resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.2.tgz#fa0f5223ef0d6724b3d8327134890cfe3d72fbe5"
- integrity sha512-F4LXf1OeU9hrSYRPTTj/6FbO4HTjPKXvEIC1P2kcnFurViINCVk3ZV0xAS3XVx9MkMsXbbqlK6hjseaYbgKEHw==
-
-dayjs@^1.11.8:
- version "1.11.8"
- resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.8.tgz#4282f139c8c19dd6d0c7bd571e30c2d0ba7698ea"
- integrity sha512-LcgxzFoWMEPO7ggRv1Y2N31hUf2R0Vj7fuy/m+Bg1K8rr+KAs1AEy4y9jd5DXe8pbHgX+srkHNS7TH6Q6ZhYeQ==
+dayjs@^1.10.4, dayjs@^1.11.11:
+ version "1.11.11"
+ resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.11.tgz#dfe0e9d54c5f8b68ccf8ca5f72ac603e7e5ed59e"
+ integrity sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==
debug@2.6.9:
version "2.6.9"
@@ -8597,10 +8592,10 @@ file-entry-cache@^6.0.1:
dependencies:
flat-cache "^3.0.4"
-fill-range@^7.0.1:
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
- integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
+fill-range@^7.1.1:
+ version "7.1.1"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
+ integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
dependencies:
to-regex-range "^5.0.1"
@@ -9185,10 +9180,10 @@ gray-percentage@^2.0.0:
resolved "https://registry.yarnpkg.com/gray-percentage/-/gray-percentage-2.0.0.tgz#b72a274d1b1379104a0050b63b207dc53fe56f99"
integrity sha1-tyonTRsTeRBKAFC2OyB9xT/lb5k=
-happo-cypress@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/happo-cypress/-/happo-cypress-4.1.1.tgz#d10f064fad72a6a733a22f2baa234518e582b6bc"
- integrity sha512-qMSjOOlCGjGis+i/VTzcL8/2te73I2jrNcQkx+rJgcbgYV7x13tiEVVo/MrR5lCg7kHtXiNNXAXgw7XUxNh3pQ==
+happo-cypress@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/happo-cypress/-/happo-cypress-4.2.0.tgz#899c6e2e16af197e8b65a89b6f056c541df6be7f"
+ integrity sha512-58OheJOeZpfXE78FkMJ4qv0LI5IjUcPyUaDrBAKkqlgAYtt6ZhCYSUH2V3AYDIIz+tWqAE4roF93/5sueggy5Q==
happo-e2e@^2.6.0:
version "2.6.0"
diff --git a/yarn.lock b/yarn.lock
index 468b63427b..6aa65220aa 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -406,11 +406,11 @@ brace-expansion@^1.1.7:
concat-map "0.0.1"
braces@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
- integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
+ integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
dependencies:
- fill-range "^7.0.1"
+ fill-range "^7.1.1"
buffer-from@^1.0.0:
version "1.1.2"
@@ -1140,10 +1140,10 @@ file-uri-to-path@2:
resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz#7b415aeba227d575851e0a5b0c640d7656403fba"
integrity sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==
-fill-range@^7.0.1:
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
- integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
+fill-range@^7.1.1:
+ version "7.1.1"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
+ integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
dependencies:
to-regex-range "^5.0.1"