diff --git a/.circleci/config.yml b/.circleci/config.yml index 3ba4d647..6d7f4f90 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -8,6 +8,7 @@ jobs: docker: - image: cimg/node:14.19.3 working_directory: ~/repo + resource_class: large steps: - checkout - run: @@ -34,7 +35,9 @@ jobs: - run: name: Test command: | - yarn test:unit + yarn test:unit:ci + - store_test_results: + path: ./coverage/clover.xml - codecov/upload: flags: unittest file: diff --git a/README.md b/README.md index 578e3c02..25d52e36 100644 --- a/README.md +++ b/README.md @@ -42,8 +42,9 @@ A plugin for [Strapi Headless CMS](https://github.com/strapi/strapi) that provid - [Plugin file](#in-v202-and-older--default-configuration-state-for-v203-and-newer) 5. [πŸ•ΈοΈ Public API - REST](#%EF%B8%8F-public-rest-api-specification) 6. [πŸ•ΈοΈ Public API - GraphQL](#%EF%B8%8F-public-graphql-specification) -7. [🀝 Contributing](#-contributing) -8. [πŸ‘¨β€πŸ’» Community support](#-community-support) +7. [βš—οΈ Custom fields](#-custom-fields) +8. [🀝 Contributing](#-contributing) +9. [πŸ‘¨β€πŸ’» Community support](#-community-support) ## ✨ Features @@ -828,6 +829,14 @@ _Available reason enums:_ `BAD_WORDS`, `OTHER`, `DISCRIMINATION` (want more? See Live example of plugin usage can be found in the [VirtusLab Strapi Examples](https://github.com/VirtusLab/strapi-examples/tree/master/strapi-v4-plugin-comments) repository. +## βš—οΈ Custom fields + +**THIS IS AN UNSTABLE FEATURE** + +For developers who upgrades their Strapi instance custom field from Comments plugin is available. Custom field can be picked from content types' edit page or added in definition file. + +Read more about this feature in [Strapi's docs](https://docs-next.strapi.io/user-docs/latest/plugins/introduction-to-plugins.html#custom-fields). + ## 🀝 Contributing
diff --git a/admin/src/custom-fields/comments/components/icon.tsx b/admin/src/custom-fields/comments/components/icon.tsx new file mode 100644 index 00000000..5840c47e --- /dev/null +++ b/admin/src/custom-fields/comments/components/icon.tsx @@ -0,0 +1,29 @@ +import React from "react"; + +export const CustomFieldIcon = () => ( + + + + + + +); diff --git a/admin/src/custom-fields/comments/components/index.ts b/admin/src/custom-fields/comments/components/index.ts new file mode 100644 index 00000000..ebf016df --- /dev/null +++ b/admin/src/custom-fields/comments/components/index.ts @@ -0,0 +1,2 @@ +export * from "./icon"; +export * from "./input"; diff --git a/admin/src/custom-fields/comments/components/input/__tests__/utils.test.ts b/admin/src/custom-fields/comments/components/input/__tests__/utils.test.ts new file mode 100644 index 00000000..0f9644d3 --- /dev/null +++ b/admin/src/custom-fields/comments/components/input/__tests__/utils.test.ts @@ -0,0 +1,435 @@ +import { Dispatch, SetStateAction } from "react"; +import { CommentsFieldValue } from "../types"; +import { + assertCorrectState, + asString, + fromInput, + getApprovalStatusOptions, + getFilterByOptions, + getRenderTypeOptions, + getSortByDateOptions, + handlePopulateChange, + handleStateSliceChange, + toOutput, +} from "../utils"; + +jest.mock("axios", () => ({ + create: () => ({ + interceptors: { + request: { use: jest.fn() }, + response: { use: jest.fn() }, + }, + }), +})); + +jest.mock("@strapi/helper-plugin", () => ({ + auth: { getToken: jest.fn() }, +})); + +const state: CommentsFieldValue = { + commentsNumber: 99, +}; +const createSetter: ( + initialState: typeof state +) => Dispatch> = + (initialState) => (action) => { + if (action instanceof Function) { + return action(initialState); + } + + return action; + }; + +describe("Custom fields", () => { + describe("Comments", () => { + describe("asString()", () => { + it("should return standard result", () => { + expect(asString()).toMatchInlineSnapshot(`""`); + }); + }); + describe("fromInput()", () => { + it("should validate input", () => { + expect(() => fromInput("")).toThrow(); + expect(() => fromInput(undefined)).toThrow(); + expect(() => fromInput(null)).toThrow(); + }); + it("should prepare input for consumption", () => { + const state = fromInput( + `{ "commentsNumber": 35, "filterBy": "DATE_CREATED", "filterByValue": "${new Date( + 2022, + 7, + 7 + )}" }` + ); + + expect(state.filterByValue).toBeInstanceOf(Date); + }); + }); + describe("toOutput()", () => { + it("should serialize state", () => { + const state: CommentsFieldValue = { + commentsNumber: 1, + populate: [], + sortByDate: "ASC", + }; + + expect(toOutput(state)).toMatchInlineSnapshot( + `"{\\"commentsNumber\\":1,\\"populate\\":[],\\"sortByDate\\":\\"ASC\\"}"` + ); + }); + }); + describe("assertCorrectState()", () => { + it("should validate commentsNumber", () => { + expect(() => assertCorrectState({})).toThrow(); + expect(() => assertCorrectState({ commentsNumber: 1 })).not.toThrow(); + }); + it("should validate renderType", () => { + expect(() => assertCorrectState({})).toThrow(); + expect(() => assertCorrectState({ commentsNumber: 1 })).not.toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, renderType: 1 }) + ).toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, renderType: [] }) + ).toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, renderType: {} }) + ).toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, renderType: "TREE" }) + ).not.toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, renderType: "LIST" }) + ).not.toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, renderType: "TEST" }) + ).not.toThrow(); + }); + it("should validate sortByDate", () => { + expect(() => assertCorrectState({})).toThrow(); + expect(() => assertCorrectState({ commentsNumber: 1 })).not.toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, sortByDate: 1 }) + ).toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, sortByDate: [] }) + ).toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, sortByDate: {} }) + ).toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, renderType: "ASC" }) + ).not.toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, renderType: "DESC" }) + ).not.toThrow(); + }); + it("should validate filterBy", () => { + expect(() => assertCorrectState({})).toThrow(); + expect(() => assertCorrectState({ commentsNumber: 1 })).not.toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, filterBy: 1 }) + ).toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, filterBy: [] }) + ).toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, filterBy: {} }) + ).toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, filterBy: "DATE_CREATED" }) + ).not.toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, filterBy: "APPROVAL_STATUS" }) + ).not.toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, filterBy: "TEST" }) + ).not.toThrow(); + }); + it("should validate filterByValue", () => { + expect(() => assertCorrectState({})).toThrow(); + expect(() => assertCorrectState({ commentsNumber: 1 })).not.toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, filterByValue: 1 }) + ).toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, filterByValue: [] }) + ).toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, filterByValue: {} }) + ).toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, filterByValue: "any" }) + ).not.toThrow(); + }); + it("should validate populate", () => { + expect(() => assertCorrectState({})).toThrow(); + expect(() => assertCorrectState({ commentsNumber: 1 })).not.toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, populate: 1 }) + ).toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, populate: {} }) + ).toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, populate: "any" }) + ).toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, populate: [] }) + ).not.toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, populate: ["avatar"] }) + ).not.toThrow(); + expect(() => + assertCorrectState({ commentsNumber: 1, populate: ["author"] }) + ).not.toThrow(); + expect(() => + assertCorrectState({ + commentsNumber: 1, + populate: ["author", "avatar"], + }) + ).not.toThrow(); + }); + }); + describe("handleStateSliceChange()", () => { + const setter = createSetter(state); + + it("should handle state slice", () => { + expect(handleStateSliceChange("commentsNumber", setter)(1)) + .toMatchInlineSnapshot(` + Object { + "commentsNumber": 1, + } + `); + expect(handleStateSliceChange("filterBy", setter)("FOO")) + .toMatchInlineSnapshot(` + Object { + "commentsNumber": 99, + "filterBy": "FOO", + } + `); + expect(handleStateSliceChange("filterByValue", setter)("VALUE")) + .toMatchInlineSnapshot(` + Object { + "commentsNumber": 99, + "filterByValue": "VALUE", + } + `); + expect(handleStateSliceChange("renderType", setter)("TREE")) + .toMatchInlineSnapshot(` + Object { + "commentsNumber": 99, + "renderType": "TREE", + } + `); + expect(handleStateSliceChange("sortByDate", setter)("ASC")) + .toMatchInlineSnapshot(` + Object { + "commentsNumber": 99, + "sortByDate": "ASC", + } + `); + }); + }); + describe("handlePopulateChange", () => { + it("should handle populate change", () => { + expect(handlePopulateChange("author", createSetter(state))()) + .toMatchInlineSnapshot(` + Object { + "commentsNumber": 99, + "populate": Array [ + "author", + ], + } + `); + expect(handlePopulateChange("avatar", createSetter(state))()) + .toMatchInlineSnapshot(` + Object { + "commentsNumber": 99, + "populate": Array [ + "avatar", + ], + } + `); + expect( + handlePopulateChange( + "author", + createSetter({ + ...state, + populate: [], + }) + )() + ).toMatchInlineSnapshot(` + Object { + "commentsNumber": 99, + "populate": Array [ + "author", + ], + } + `); + expect( + handlePopulateChange( + "author", + createSetter({ + ...state, + populate: ["author"], + }) + )() + ).toMatchInlineSnapshot(` + Object { + "commentsNumber": 99, + "populate": Array [], + } + `); + expect( + handlePopulateChange( + "author", + createSetter({ + ...state, + populate: ["avatar"], + }) + )() + ).toMatchInlineSnapshot(` + Object { + "commentsNumber": 99, + "populate": Array [ + "avatar", + "author", + ], + } + `); + expect( + handlePopulateChange( + "avatar", + createSetter({ + ...state, + populate: [], + }) + )() + ).toMatchInlineSnapshot(` + Object { + "commentsNumber": 99, + "populate": Array [ + "avatar", + ], + } + `); + expect( + handlePopulateChange( + "avatar", + createSetter({ + ...state, + populate: ["author"], + }) + )() + ).toMatchInlineSnapshot(` + Object { + "commentsNumber": 99, + "populate": Array [ + "author", + "avatar", + ], + } + `); + expect( + handlePopulateChange( + "avatar", + createSetter({ + ...state, + populate: ["avatar"], + }) + )() + ).toMatchInlineSnapshot(` + Object { + "commentsNumber": 99, + "populate": Array [], + } + `); + }); + }); + describe("getRenderTypeOptions()", () => { + it("should render options", () => { + expect(getRenderTypeOptions(({ id }) => `translated.${id}`)) + .toMatchInlineSnapshot(` + Array [ + Object { + "label": "translated.customField.comments.input.renderType.option.tree.label", + "value": "TREE", + }, + Object { + "label": "translated.customField.comments.input.renderType.option.flat.label", + "value": "FLAT", + }, + ] + `); + }); + }); + describe("getSortByDateOptions()", () => { + it("should render options", () => { + expect(getSortByDateOptions(({ id }) => `translated.${id}`)) + .toMatchInlineSnapshot(` + Array [ + Object { + "label": "", + "value": undefined, + }, + Object { + "label": "translated.customField.comments.input.sortByDate.option.asc.label", + "value": "ASC", + }, + Object { + "label": "translated.customField.comments.input.sortByDate.option.desc.label", + "value": "DESC", + }, + ] + `); + }); + }); + describe("getFilterByOptions()", () => { + it("should render options", () => { + expect(getFilterByOptions(({ id }) => `translated.${id}`)) + .toMatchInlineSnapshot(` + Array [ + Object { + "label": "", + "value": undefined, + }, + Object { + "label": "translated.customField.comments.input.filterBy.option.dateCreated.label", + "value": "DATE_CREATED", + }, + Object { + "label": "translated.customField.comments.input.filterBy.option.approvalStatus.label", + "value": "APPROVAL_STATUS", + }, + ] + `); + }); + }); + describe("getApprovalStatusOptions()", () => { + it("should render options", () => { + expect(getApprovalStatusOptions(({ id }) => `translated.${id}`)) + .toMatchInlineSnapshot(` + Array [ + Object { + "label": "", + "value": undefined, + }, + Object { + "label": "translated.customField.comments.input.filterBy.option.approvalStatus.option.approved.label", + "value": "APPROVED", + }, + Object { + "label": "translated.customField.comments.input.filterBy.option.approvalStatus.option.pending.label", + "value": "PENDING", + }, + Object { + "label": "translated.customField.comments.input.filterBy.option.approvalStatus.option.rejected.label", + "value": "REJECTED", + }, + ] + `); + }); + }); + }); +}); diff --git a/admin/src/custom-fields/comments/components/input/index.ts b/admin/src/custom-fields/comments/components/input/index.ts new file mode 100644 index 00000000..0f15f9aa --- /dev/null +++ b/admin/src/custom-fields/comments/components/input/index.ts @@ -0,0 +1,3 @@ +import { CustomFieldInput } from "./input"; + +export default CustomFieldInput; diff --git a/admin/src/custom-fields/comments/components/input/input.tsx b/admin/src/custom-fields/comments/components/input/input.tsx new file mode 100644 index 00000000..71f467b2 --- /dev/null +++ b/admin/src/custom-fields/comments/components/input/input.tsx @@ -0,0 +1,278 @@ +import React, { useCallback, useEffect, useState } from "react"; +// @ts-ignore +import { Stack } from "@strapi/design-system/Stack"; +// @ts-ignore +import { Typography } from "@strapi/design-system/Typography"; +// @ts-ignore +import { Flex } from "@strapi/design-system/Flex"; +// @ts-ignore +import { Box } from "@strapi/design-system/Box"; +import { + Field, + FieldError, + FieldHint, + FieldLabel, + // @ts-ignore +} from "@strapi/design-system/Field"; +// @ts-ignore +import { Option, Select } from "@strapi/design-system/Select"; +// @ts-ignore +import { NumberInput } from "@strapi/design-system/NumberInput"; +// @ts-ignore +import { Checkbox } from "@strapi/design-system/Checkbox"; +// @ts-ignore +import { DatePicker } from "@strapi/design-system/DatePicker"; +import { CustomFieldInputProps } from "strapi-typed"; +// @ts-ignore +import { Grid, GridItem } from "@strapi/design-system/Grid"; +import { CommentsFieldValue } from "./types"; +import { + asString, + fromInput, + getApprovalStatusOptions, + getFilterByOptions, + getRenderTypeOptions, + getSortByDateOptions, + handleStateSliceChange, + handlePopulateChange, + toOutput, +} from "./utils"; +import { getMessage } from "../../../../utils"; +import { useIntl } from "react-intl"; + +const DEFAULTS: CommentsFieldValue = { + commentsNumber: 30, + populate: [], + renderType: "FLAT", +}; + +export const CustomFieldInput: React.FC = ({ + attribute, + description, + disabled, + error, + intlLabel, + labelAction, + name, + onChange, + required, + value, +}) => { + const { formatMessage } = useIntl(); + const [currentState, setCurrentState] = useState( + value ? fromInput(value) : DEFAULTS + ); + + const onCommentsNumberChange = useCallback( + handleStateSliceChange("commentsNumber", setCurrentState), + [setCurrentState] + ); + + const onRenderTypeChange = useCallback( + handleStateSliceChange("renderType", setCurrentState), + [setCurrentState] + ); + + const onSortByDateChange = useCallback( + handleStateSliceChange("sortByDate", setCurrentState), + [setCurrentState] + ); + + const onFilterByChange = useCallback( + (filterBy: CommentsFieldValue["filterBy"]) => { + setCurrentState((current) => ({ + ...current, + filterBy, + filterByValue: undefined, + })); + }, + [setCurrentState] + ); + + const onFilterByValueChange = useCallback( + handleStateSliceChange("filterByValue", setCurrentState), + [setCurrentState] + ); + + const onPopulateAuthorChange = useCallback( + handlePopulateChange("author", setCurrentState), + [setCurrentState] + ); + + const onPopulateAvatarChange = useCallback( + handlePopulateChange("avatar", setCurrentState), + [setCurrentState] + ); + + useEffect(() => { + const nextValue = toOutput(currentState); + const initialValue = value ? toOutput(fromInput(value)) : ""; + + if (initialValue !== nextValue && onChange) { + onChange({ + target: { + name, + value: nextValue, + type: attribute.type, + }, + }); + } + }, [currentState, value]); + + return ( + + + + + {formatMessage(intlLabel)} + + {labelAction && {labelAction}} + + + + + + + + + + + + + + + + + + {currentState.filterBy === "APPROVAL_STATUS" ? ( + + ) : null} + {currentState.filterBy === "DATE_CREATED" ? ( + + ) : null} + + + + + {getMessage( + "customField.comments.input.populate.label", + "Populate" + )} + + + + + + + + + + + + + ); +}; diff --git a/admin/src/custom-fields/comments/components/input/types.ts b/admin/src/custom-fields/comments/components/input/types.ts new file mode 100644 index 00000000..579f22d8 --- /dev/null +++ b/admin/src/custom-fields/comments/components/input/types.ts @@ -0,0 +1,10 @@ +export type PopulateField = "avatar" | "author"; + +export type CommentsFieldValue = { + commentsNumber: number; + renderType?: "FLAT" | "TREE"; + sortByDate?: "ASC" | "DESC"; + filterBy?: "DATE_CREATED" | "APPROVAL_STATUS"; + filterByValue?: string | Date; + populate?: Array; +}; diff --git a/admin/src/custom-fields/comments/components/input/utils.ts b/admin/src/custom-fields/comments/components/input/utils.ts new file mode 100644 index 00000000..0a8203e8 --- /dev/null +++ b/admin/src/custom-fields/comments/components/input/utils.ts @@ -0,0 +1,169 @@ +import { SetStateAction, Dispatch } from "react"; +import { uniq } from "lodash"; +import { + getMessage, + APPROVAL_STATUS, + ValidationError, + assertString, +} from "../../../../utils"; +import { CommentsFieldValue, PopulateField } from "./types"; + +export const asString = () => ""; + +export const fromInput = (value: unknown) => { + assertString(value); + + const state = JSON.parse(value); + + assertCorrectState(state); + + if (state.filterBy === "DATE_CREATED" && state.filterByValue) { + state.filterByValue = new Date(state.filterByValue); + } + + return state; +}; + +export const toOutput = (state: CommentsFieldValue) => JSON.stringify(state); + +export function assertCorrectState( + state: any +): asserts state is CommentsFieldValue { + if (typeof state.commentsNumber !== "number") { + throw new ValidationError("Comments number is not a number"); + } + + if (state.populate && !Array.isArray(state.populate)) { + throw new ValidationError("Comments populate is not an array"); + } + + stringFields.forEach((field) => { + if (state[field] && typeof state[field] !== "string") { + assertString(state[field]); + } + }); +} + +export const handleStateSliceChange = + ( + key: keyof CommentsFieldValue, + setState: Dispatch> + ) => + (value: CommentsFieldValue[typeof key]) => { + return setState((current) => ({ + ...current, + [key]: value, + })); + }; + +export const handlePopulateChange = + ( + key: PopulateField, + setState: Dispatch> + ) => + () => { + return setState((current) => { + const populate = current.populate || []; + + return { + ...current, + populate: populate.includes(key) + ? populate.filter((field) => field !== key) + : uniq(populate.concat(key)), + }; + }); + }; + +export const getRenderTypeOptions = (translate: typeof getMessage) => [ + { + value: "TREE", + label: translate({ + id: "customField.comments.input.renderType.option.tree.label", + defaultMessage: "Tree", + }), + }, + { + value: "FLAT", + label: translate({ + id: "customField.comments.input.renderType.option.flat.label", + defaultMessage: "Flat list", + }), + }, +]; + +export const getSortByDateOptions = (translate: typeof getMessage) => [ + { + value: undefined, + label: "", + }, + { + value: "ASC", + label: translate({ + id: "customField.comments.input.sortByDate.option.asc.label", + defaultMessage: "Ascending", + }), + }, + { + value: "DESC", + label: translate({ + id: "customField.comments.input.sortByDate.option.desc.label", + defaultMessage: "Descending", + }), + }, +]; + +export const getFilterByOptions = (translate: typeof getMessage) => [ + { + value: undefined, + label: "", + }, + { + value: "DATE_CREATED", + label: translate({ + id: "customField.comments.input.filterBy.option.dateCreated.label", + defaultMessage: "Creation date", + }), + }, + { + value: "APPROVAL_STATUS", + label: translate({ + id: "customField.comments.input.filterBy.option.approvalStatus.label", + defaultMessage: "Approval Status", + }), + }, +]; + +export const getApprovalStatusOptions = (translate: typeof getMessage) => [ + { + value: undefined, + label: "", + }, + { + value: APPROVAL_STATUS.APPROVED, + label: translate({ + id: "customField.comments.input.filterBy.option.approvalStatus.option.approved.label", + defaultMessage: "Approved", + }), + }, + { + value: APPROVAL_STATUS.PENDING, + label: translate({ + id: "customField.comments.input.filterBy.option.approvalStatus.option.pending.label", + defaultMessage: "Pending", + }), + }, + { + value: APPROVAL_STATUS.REJECTED, + label: translate({ + id: "customField.comments.input.filterBy.option.approvalStatus.option.rejected.label", + defaultMessage: "Rejected", + }), + }, +]; + +const stringFields = [ + "renderType", + "sortByDate", + "filterBy", + "filterByValue", +] as const; diff --git a/admin/src/custom-fields/comments/index.ts b/admin/src/custom-fields/comments/index.ts new file mode 100644 index 00000000..1d3a2a7d --- /dev/null +++ b/admin/src/custom-fields/comments/index.ts @@ -0,0 +1,28 @@ +import { StrapiAdminCustomFieldRegisterInput } from "strapi-typed"; +import { pluginId } from "../../pluginId"; +import { CustomFieldIcon } from "./components"; + +export const commentsCustomField: StrapiAdminCustomFieldRegisterInput = { + name: "comments", + pluginId, + type: "json", + icon: CustomFieldIcon, + intlLabel: { + defaultMessage: "Comments", + description: "", + id: `${pluginId}.customField.comments.label`, + }, + intlDescription: { + defaultMessage: "Specify comments query params", + description: "", + id: `${pluginId}.customField.comments.description`, + }, + components: { + Input: async () => import("./components/input"), + }, + options: { + base: [], + advanced: [], + validator: () => ({}), + }, +}; diff --git a/admin/src/custom-fields/index.ts b/admin/src/custom-fields/index.ts new file mode 100644 index 00000000..c6e2cfd8 --- /dev/null +++ b/admin/src/custom-fields/index.ts @@ -0,0 +1,12 @@ +import { StrapiAdminInstance } from "strapi-typed"; +import { commentsCustomField } from "./comments"; + +export const registerCustomFields = (app: StrapiAdminInstance) => { + if (!canRegister(app)) { + return; + } + + app.customFields.register(commentsCustomField); +}; + +const canRegister = (app: StrapiAdminInstance) => !!app.customFields; diff --git a/admin/src/index.ts b/admin/src/index.ts index 03d9eafd..30e5761e 100644 --- a/admin/src/index.ts +++ b/admin/src/index.ts @@ -1,5 +1,6 @@ // @ts-ignore import { prefixPluginTranslations } from "@strapi/helper-plugin"; +import { StrapiAdminInstance } from "strapi-typed"; import * as pluginPkg from "../../package.json"; import { pluginId } from "./pluginId"; import Initializer from "./components/Initializer"; @@ -7,11 +8,12 @@ import PluginIcon from "./components/PluginIcon"; import pluginPermissions from "./permissions"; import reducers from "./reducers"; import { ToBeFixed } from "../../types"; +import { registerCustomFields } from "./custom-fields"; const { name, displayName } = pluginPkg.strapi; export default { - register(app: ToBeFixed) { + register(app: StrapiAdminInstance) { app.addMenuLink({ to: `/plugins/${pluginId}`, badgeContent: 1, @@ -65,6 +67,8 @@ export default { isReady: false, name, }); + + registerCustomFields(app); }, // bootstrap(app: ToBeFixed) { diff --git a/admin/src/translations/en.json b/admin/src/translations/en.json index faf6b5c9..eb65d9cf 100644 --- a/admin/src/translations/en.json +++ b/admin/src/translations/en.json @@ -166,5 +166,25 @@ "compontents.author.unknown": "Author removed", "components.reason.unknown": "Reason not provided", "components.content.unknown": "Content not provided", - "components.notAccessPage.back": "Back to homepage" + "components.notAccessPage.back": "Back to homepage", + "customField.comments.label": "Comments", + "customField.comments.description": "Specify comments query params", + "customField.comments.input.commentsNumber.label": "Number of comments", + "customField.comments.input.renderType.label": "Render comments as", + "customField.comments.input.renderType.option.tree.label": "Tree", + "customField.comments.input.renderType.option.flat.label": "Flat list", + "customField.comments.input.sortByDate.label": "Sort by creation date", + "customField.comments.input.sortByDate.option.asc.label": "Ascending", + "customField.comments.input.sortByDate.option.desc.label": "Descending", + "customField.comments.input.filterBy.label": "Filter by", + "customField.comments.input.filterBy.option.dateCreated.label": "Creation date", + "customField.comments.input.filterBy.option.dateCreated.label.details.label": "Specify date", + "customField.comments.input.filterBy.option.approvalStatus.label": "Approval Status", + "customField.comments.input.filterBy.option.approvalStatus.label.details.label": "Specify status", + "customField.comments.input.filterBy.option.approvalStatus.option.pending.label": "Pending", + "customField.comments.input.filterBy.option.approvalStatus.option.approved.label": "Approved", + "customField.comments.input.filterBy.option.approvalStatus.option.rejected.label": "Rejected", + "customField.comments.input.populate.label": "Populate", + "customField.comments.input.populate.author.label": "Populate author field", + "customField.comments.input.populate.avatar.label": "Populate avatar field" } diff --git a/admin/src/utils/__tests__/functions.test.ts b/admin/src/utils/__tests__/functions.test.ts new file mode 100644 index 00000000..645ca22f --- /dev/null +++ b/admin/src/utils/__tests__/functions.test.ts @@ -0,0 +1,15 @@ +import { assertString } from "../functions"; + +describe("assertString()", () => { + it("should allow strings", () => { + expect(() => assertString("Content")).not.toThrow(); + }); + + it("should reject everything that is not a string", () => { + expect(() => assertString(1)).toThrow(); + expect(() => assertString(null)).toThrow(); + expect(() => assertString(undefined)).toThrow(); + expect(() => assertString({})).toThrow(); + expect(() => assertString(new Error("Error"))).toThrow(); + }); +}); diff --git a/admin/src/utils/__tests__/getApiUrl.test.ts b/admin/src/utils/__tests__/getApiUrl.test.ts new file mode 100644 index 00000000..c66b05bb --- /dev/null +++ b/admin/src/utils/__tests__/getApiUrl.test.ts @@ -0,0 +1,7 @@ +import getApiURL from "../getApiUrl"; + +describe("getApiURL()", () => { + it("should return valid URL", () => { + expect(getApiURL("comments")).toMatchInlineSnapshot(`"/comments/comments"`); + }); +}); diff --git a/admin/src/utils/__tests__/getMessage.test.ts b/admin/src/utils/__tests__/getMessage.test.ts new file mode 100644 index 00000000..127c0666 --- /dev/null +++ b/admin/src/utils/__tests__/getMessage.test.ts @@ -0,0 +1,58 @@ +import getMessage from "../getMessage"; + +jest.mock("react-intl", () => ({ + useIntl: () => ({ + formatMessage: (x: any, y: any) => ({ + ...x, + ...y, + }), + }), +})); + +describe("getMessage()", () => { + it("should handle simple string", () => { + expect(getMessage("message.key")).toMatchInlineSnapshot(` + Object { + "defaultMessage": "", + "id": "comments.message.key", + } + `); + expect(getMessage("message.key", "message.default")).toMatchInlineSnapshot(` + Object { + "defaultMessage": "message.default", + "id": "comments.message.key", + } + `); + }); + it("should handle config object", () => { + expect( + getMessage( + { + id: "message.key", + }, + "message.default" + ) + ).toMatchInlineSnapshot(` + Object { + "defaultMessage": "message.default", + "id": "comments.message.key", + } + `); + }); + it("should allow out of scope translates", () => { + expect( + getMessage( + { + id: "message.key", + }, + "message.key.default", + false + ) + ).toMatchInlineSnapshot(` + Object { + "defaultMessage": "message.key.default", + "id": "app.components.message.key", + } + `); + }); +}); diff --git a/admin/src/utils/__tests__/getUrl.test.ts b/admin/src/utils/__tests__/getUrl.test.ts new file mode 100644 index 00000000..d7a55265 --- /dev/null +++ b/admin/src/utils/__tests__/getUrl.test.ts @@ -0,0 +1,10 @@ +import getUrl from "../getUrl"; + +describe("getUrl()", () => { + it("should return valid URL", () => { + expect(getUrl("comments")).toMatchInlineSnapshot( + `"/plugins/comments/comments"` + ); + expect(getUrl(undefined)).toMatchInlineSnapshot(`"/plugins/comments/"`); + }); +}); diff --git a/admin/src/utils/__tests__/handleAPIError.test.ts b/admin/src/utils/__tests__/handleAPIError.test.ts new file mode 100644 index 00000000..3fb229c2 --- /dev/null +++ b/admin/src/utils/__tests__/handleAPIError.test.ts @@ -0,0 +1,28 @@ +import handleAPIError from "../handleAPIError"; + +describe("handleAPIError()", () => { + it("should re-throw error", () => { + const err = new Error("Error"); + + expect(() => handleAPIError(null, jest.fn)).toThrowError(Error); + expect(() => handleAPIError(undefined, jest.fn)).toThrowError(); + expect(() => handleAPIError(err, undefined)).toThrowError(Error); + expect(() => handleAPIError(err, jest.fn)).toThrowError(err); + }); + + it("should notify app", () => { + const err = new Error("Error"); + const notify = jest.fn(); + + expect(() => handleAPIError(err, notify, "message")).toThrowError(err); + expect(notify).toHaveBeenCalled(); + expect(notify.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "message": "comments.message", + "type": "warning", + }, + ] + `); + }); +}); diff --git a/admin/src/utils/__tests__/perseRegExp.test.ts b/admin/src/utils/__tests__/perseRegExp.test.ts new file mode 100644 index 00000000..15d509a1 --- /dev/null +++ b/admin/src/utils/__tests__/perseRegExp.test.ts @@ -0,0 +1,12 @@ +import parseRegExp from "../parseRegExp"; + +describe("parseRegExp()", () => { + it("should parse regexp", () => { + expect(parseRegExp("/[a-z]/gi")).toMatchInlineSnapshot(` + Object { + "flags": "gi", + "value": "[a-z]", + } + `); + }); +}); diff --git a/admin/src/utils/__tests__/resolveCommentStatus.test.ts b/admin/src/utils/__tests__/resolveCommentStatus.test.ts new file mode 100644 index 00000000..4aacafbf --- /dev/null +++ b/admin/src/utils/__tests__/resolveCommentStatus.test.ts @@ -0,0 +1,49 @@ +import { COMMENT_STATUS } from "../constants"; +import resolveCommentStatus from "../resolveCommentStatus"; + +describe("resolveCommentStatus()", () => { + it("should handle removed comments", () => { + expect( + resolveCommentStatus({ + removed: true, + }) + ).toMatchInlineSnapshot(`"REMOVED"`); + }); + it("should handle blocked comments", () => { + expect( + resolveCommentStatus({ + blocked: true, + }) + ).toMatchInlineSnapshot(`"BLOCKED"`); + expect( + resolveCommentStatus({ + blockedThread: true, + }) + ).toMatchInlineSnapshot(`"BLOCKED"`); + }); + it.each(Object.values(COMMENT_STATUS))( + "should handle %s comment's status", + (approvalStatus) => { + expect( + resolveCommentStatus({ + approvalStatus, + }) + ).toEqual(approvalStatus); + } + ); + it("should handle unknown status", () => { + expect( + resolveCommentStatus({ + approvalStatus: "FOO", + }) + ).toMatchInlineSnapshot(`"UNKNOWN"`); + }); + it("should handle review comment", () => { + expect( + resolveCommentStatus({ reviewFlowEnabled: true }) + ).toMatchInlineSnapshot(`"TO_REVIEW"`); + }); + it("should empty input", () => { + expect(resolveCommentStatus({})).toMatchInlineSnapshot(`"OPEN"`); + }); +}); diff --git a/admin/src/utils/errors.ts b/admin/src/utils/errors.ts new file mode 100644 index 00000000..cdb64238 --- /dev/null +++ b/admin/src/utils/errors.ts @@ -0,0 +1,3 @@ +export class UIError extends Error {} + +export class ValidationError extends UIError {} diff --git a/admin/src/utils/functions.ts b/admin/src/utils/functions.ts new file mode 100644 index 00000000..7b5fbe18 --- /dev/null +++ b/admin/src/utils/functions.ts @@ -0,0 +1,7 @@ +import { ValidationError } from "./errors"; + +export function assertString(value: unknown): asserts value is string { + if (typeof value !== "string") { + throw new ValidationError(`String expected, but "${typeof value}" given`); + } +} diff --git a/admin/src/utils/getRelatedGroups.ts b/admin/src/utils/getRelatedGroups.ts index 74c96bcc..b59ac4cc 100644 --- a/admin/src/utils/getRelatedGroups.ts +++ b/admin/src/utils/getRelatedGroups.ts @@ -1,6 +1,10 @@ -import { ToBeFixed } from "../../../types"; +type Config = { + regex: { + relatedUid: string; + }; +}; -const getRelatedGroups = (related: string, config: ToBeFixed) => +const getRelatedGroups = (related: string, config: Config) => related.split(config.regex.relatedUid).filter((s) => s && s.length > 0); export default getRelatedGroups; diff --git a/admin/src/utils/handleAPIError.ts b/admin/src/utils/handleAPIError.ts index 2d3a6cf6..cfe36f30 100644 --- a/admin/src/utils/handleAPIError.ts +++ b/admin/src/utils/handleAPIError.ts @@ -2,7 +2,7 @@ import { ToBeFixed } from "../../../types"; import { pluginId } from "../pluginId"; const handleAPIError = ( - err = null, + err: Error | null = null, toggleNotification: ToBeFixed = null, message = "app.components.notification.error" ) => { diff --git a/admin/src/utils/index.ts b/admin/src/utils/index.ts index f6a8d576..adf8238f 100644 --- a/admin/src/utils/index.ts +++ b/admin/src/utils/index.ts @@ -11,3 +11,6 @@ export {default as resolveCommentStatusColor} from './resolveCommentStatusColor' export {default as resolveReportStatus} from './resolveReportStatus'; export {default as resolveReportStatusColor} from './resolveReportStatusColor'; export {default as parseRegExp} from './parseRegExp'; +export { APPROVAL_STATUS } from './constants' +export { UIError, ValidationError } from './errors' +export { assertString } from './functions' diff --git a/admin/src/utils/resolveCommentStatus.ts b/admin/src/utils/resolveCommentStatus.ts index dd5da4e1..6f167c31 100644 --- a/admin/src/utils/resolveCommentStatus.ts +++ b/admin/src/utils/resolveCommentStatus.ts @@ -1,14 +1,21 @@ import { isNil } from "lodash"; -import { ToBeFixed } from "../../../types"; import { COMMENT_STATUS } from "./constants"; +type Config = { + removed?: boolean; + blocked?: boolean; + blockedThread?: boolean; + approvalStatus?: string; + reviewFlowEnabled?: boolean; +}; + const resolveCommentStatus = ({ removed, blocked, blockedThread, approvalStatus, reviewFlowEnabled, -}: ToBeFixed) => { +}: Config) => { const gotApprovalFlow = !isNil(approvalStatus); if (removed) { diff --git a/package.json b/package.json index 374c49da..81e9c134 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "strapi-plugin-comments", - "version": "2.2.0-beta.1", + "version": "2.2.0-beta.0", "description": "Strapi - Comments plugin", "strapi": { "name": "comments", @@ -18,6 +18,7 @@ "clean": "rm -rf build", "develop": "nodemon --exec \"yarn build:dev\"", "test:unit": "jest --verbose --coverage", + "test:unit:ci": "CI=true jest --ci --verbose --coverage", "lint": "prettier --check .", "format": "prettier --write ." }, @@ -34,6 +35,7 @@ "bad-words": "^3.0.4" }, "devDependencies": { + "@strapi/helper-plugin": "^4.3.8", "@types/bad-words": "^3.0.1", "@types/jest": "^27.4.1", "codecov": "^3.7.2", @@ -46,7 +48,7 @@ "nodemon": "^2.0.15", "prettier": "^2.6.0", "rimraf": "^3.0.2", - "strapi-typed": "^1.0.12", + "strapi-typed": "^1.0.14", "ts-jest": "^27.1.3", "ts-node": "^10.7.0", "typescript": "^4.6.3" diff --git a/server/register.ts b/server/register.ts deleted file mode 100644 index 32fad849..00000000 --- a/server/register.ts +++ /dev/null @@ -1,3 +0,0 @@ -export = () => { - // register phase -}; diff --git a/server/register/custom-fields/__tests__/index.test.ts b/server/register/custom-fields/__tests__/index.test.ts new file mode 100644 index 00000000..dc4fd667 --- /dev/null +++ b/server/register/custom-fields/__tests__/index.test.ts @@ -0,0 +1,37 @@ +import { IStrapi } from "strapi-typed"; +import { registerCustomFields } from ".."; + +describe("registerCustomFields()", () => { + it("should apply custom field when strapi supports it", () => { + const strapi: Pick = { + customFields: { + register: jest.fn(), + }, + }; + + registerCustomFields({ strapi } as any); + + expect(strapi.customFields.register).toHaveBeenCalled(); + expect((strapi.customFields.register as jest.Mock).mock.calls[0][0]) + .toMatchInlineSnapshot(` + Object { + "name": "comments", + "plugin": "comments", + "type": "json", + } + `); + }); + it("should not require custom fields functionality to bootstrap comments plugin", () => { + expect(() => + registerCustomFields({ strapi: { log: { warn: jest.fn() } } } as any) + ).not.toThrow(); + }); + it("should notify about custom field option", () => { + const warn = jest.fn(); + + expect(() => + registerCustomFields({ strapi: { log: { warn } } } as any) + ).not.toThrow(); + expect(warn).toHaveBeenCalled(); + }); +}); diff --git a/server/register/custom-fields/comments.ts b/server/register/custom-fields/comments.ts new file mode 100644 index 00000000..b815d19d --- /dev/null +++ b/server/register/custom-fields/comments.ts @@ -0,0 +1,5 @@ +export const commentsCustomField = { + name: "comments", + plugin: "comments", + type: "json", +} as const; diff --git a/server/register/custom-fields/index.ts b/server/register/custom-fields/index.ts new file mode 100644 index 00000000..46fa827c --- /dev/null +++ b/server/register/custom-fields/index.ts @@ -0,0 +1,16 @@ +import { StrapiContext } from "strapi-typed"; +import { commentsCustomField } from "./comments"; + +export const registerCustomFields = ({ strapi }: StrapiContext) => { + if (!canRegister({ strapi })) { + strapi.log.warn( + "[Comments Plugin] Custom fields disabled. Upgrade Strapi to use custom fields." + ); + + return; + } + + strapi.customFields.register(commentsCustomField); +}; + +const canRegister = ({ strapi }: StrapiContext) => !!strapi.customFields; diff --git a/server/register/index.ts b/server/register/index.ts new file mode 100644 index 00000000..d7e2473e --- /dev/null +++ b/server/register/index.ts @@ -0,0 +1,8 @@ +import { StrapiContext } from "strapi-typed"; +import { registerCustomFields } from "./custom-fields"; + +const register = (context: StrapiContext) => { + registerCustomFields(context); +}; + +export default register; diff --git a/server/services/__tests__/client.test.ts b/server/services/__tests__/client.test.ts index 69cb2abd..7a7e7e5d 100644 --- a/server/services/__tests__/client.test.ts +++ b/server/services/__tests__/client.test.ts @@ -1,4 +1,4 @@ -import { StrapiUser } from "strapi-typed"; +import { Id, StrapiUser } from "strapi-typed"; import { IServiceClient } from "../../../types"; import { Comment } from "../../../types/contentTypes"; import { setupStrapi, resetStrapi } from "../../../__mocks__/initSetup"; @@ -59,7 +59,7 @@ describe("Test Comments service - Client", () => { }, ]; const relatedEntity = { id: 1, title: "Test", uid: collection }; - const adminUser = { id: 1, username: "Admin", email: "admin@example.com" } + const adminUser = { id: 1, username: "Admin", email: "admin@example.com" }; const errorThrown = (e: unknown, message: string, status: number = 400) => { expect(e).toBeInstanceOf(PluginError); @@ -833,7 +833,7 @@ describe("Test Comments service - Client", () => { await getPluginService("client").markAsRemoved( 1, "api::not-enabled.relation:1", - undefined, + undefined as unknown as Id, undefined ); } catch (e) { @@ -964,7 +964,7 @@ describe("Test Comments service - Client", () => { const result = await getPluginService( "client" - ).markAsRemoved(1, related, undefined, user); + ).markAsRemoved(1, related, undefined as unknown as Id, user); expect(result).toHaveProperty(["id"], 4); expect(result).toHaveProperty(["related"], related); @@ -1078,7 +1078,7 @@ describe("Test Comments service - Client", () => { default: return resolve([related]); } - }), + }), create: async (args: any) => new Promise((resolve) => { return resolve({ @@ -1089,13 +1089,12 @@ describe("Test Comments service - Client", () => { })); const spyPluginEmail = jest - .spyOn(global.strapi.plugins.email.services.email, 'send') + .spyOn(global.strapi.plugins.email.services.email, "send") // @ts-ignore .mockImplementation((args: any) => ({ - status: 200, - params: args, - }) - ); + status: 200, + params: args, + })); const result = await getPluginService( "client" @@ -1107,9 +1106,18 @@ describe("Test Comments service - Client", () => { expect(result).toHaveProperty(["reason"], payload.reason); expect(spyPluginEmail).toHaveBeenCalledTimes(1); - expect(spyPluginEmail.mock.results[0].value.params).toHaveProperty(["from"], adminUser.email); - expect(spyPluginEmail.mock.results[0].value.params).toHaveProperty(["to", 0], adminUser.email); - expect(spyPluginEmail.mock.results[0].value.params).toHaveProperty(["subject"], "New abuse report on comment"); + expect(spyPluginEmail.mock.results[0].value.params).toHaveProperty( + ["from"], + adminUser.email + ); + expect(spyPluginEmail.mock.results[0].value.params).toHaveProperty( + ["to", 0], + adminUser.email + ); + expect(spyPluginEmail.mock.results[0].value.params).toHaveProperty( + ["subject"], + "New abuse report on comment" + ); spyQuery.mockRestore(); spyPluginEmail.mockRestore(); @@ -1119,24 +1127,26 @@ describe("Test Comments service - Client", () => { describe("Inform about response", () => { const clientSettings = { - url: 'http://testsite.com', - contactEmail: 'contact@example.com', + url: "http://testsite.com", + contactEmail: "contact@example.com", }; beforeEach(() => - setupStrapi({ enabledCollections: [collection], client: { ...clientSettings } }, true, { - "plugins::comments": db, - "api::collection": [ - relatedEntity, - { id: 2, title: "Test 2", uid: collection }, - ], - }) + setupStrapi( + { enabledCollections: [collection], client: { ...clientSettings } }, + true, + { + "plugins::comments": db, + "api::collection": [ + relatedEntity, + { id: 2, title: "Test 2", uid: collection }, + ], + } + ) ); describe("Successful path", () => { - test("Should sent e-mail with proper content to comment author", async () => { - const spyQuery = jest .spyOn(global.strapi.db, "query") // @ts-ignore @@ -1162,29 +1172,43 @@ describe("Test Comments service - Client", () => { default: return resolve([related]); } - }), + }), })); const spyPluginEmail = jest - .spyOn(global.strapi.plugins.email.services.email, 'send') + .spyOn(global.strapi.plugins.email.services.email, "send") // @ts-ignore .mockImplementation((args: any) => ({ - status: 200, - params: args, - }) - ); + status: 200, + params: args, + })); const result = await getPluginService( "client" ).sendResponseNotification(db[1]); expect(spyPluginEmail).toHaveBeenCalledTimes(1); - expect(spyPluginEmail.mock.results[0].value.params).toHaveProperty(["from"], clientSettings.contactEmail); - expect(spyPluginEmail.mock.results[0].value.params).toHaveProperty(["to", 0], db[0].authorEmail); - expect(spyPluginEmail.mock.results[0].value.params).toHaveProperty(["subject"], "You've got a new response to your comment"); - expect(spyPluginEmail.mock.results[0].value.params.text).toContain(db[0].authorName); - expect(spyPluginEmail.mock.results[0].value.params.text).toContain(db[1].authorName); - expect(spyPluginEmail.mock.results[0].value.params.text).toContain(clientSettings.url); + expect(spyPluginEmail.mock.results[0].value.params).toHaveProperty( + ["from"], + clientSettings.contactEmail + ); + expect(spyPluginEmail.mock.results[0].value.params).toHaveProperty( + ["to", 0], + db[0].authorEmail + ); + expect(spyPluginEmail.mock.results[0].value.params).toHaveProperty( + ["subject"], + "You've got a new response to your comment" + ); + expect(spyPluginEmail.mock.results[0].value.params.text).toContain( + db[0].authorName + ); + expect(spyPluginEmail.mock.results[0].value.params.text).toContain( + db[1].authorName + ); + expect(spyPluginEmail.mock.results[0].value.params.text).toContain( + clientSettings.url + ); spyQuery.mockRestore(); spyPluginEmail.mockRestore(); diff --git a/server/utils/__tests__/error.test.ts b/server/utils/__tests__/error.test.ts new file mode 100644 index 00000000..6743f52c --- /dev/null +++ b/server/utils/__tests__/error.test.ts @@ -0,0 +1,40 @@ +import PluginError from "../error"; + +describe("PluginError", () => { + describe("toString()", () => { + it("should serialize error", () => { + expect( + new PluginError(404, "Not found", { + item: "comment", + random: "value", + }).toString() + ).toMatchInlineSnapshot(`"Strapi:Plugin:Comments - Not found"`); + expect(new PluginError(0, "").toString()).toMatchInlineSnapshot( + `"Strapi:Plugin:Comments - Internal error"` + ); + }); + }); + describe("toJSON()", () => { + it("should serialize an error", () => { + expect( + new PluginError(404, "Not found", { + item: "comment", + random: "value", + }).toJSON() + ).toMatchInlineSnapshot(` + Object { + "item": "comment", + "message": "Not found", + "name": "Strapi:Plugin:Comments", + "random": "value", + } + `); + expect(new PluginError(404, "Not found").toJSON()).toMatchInlineSnapshot( + `[Strapi:Plugin:Comments: Not found]` + ); + expect(new PluginError(0, "").toJSON()).toMatchInlineSnapshot( + `[Strapi:Plugin:Comments: Internal error]` + ); + }); + }); +}); diff --git a/server/utils/__tests__/functions.test.ts b/server/utils/__tests__/functions.test.ts index d299396a..66345422 100644 --- a/server/utils/__tests__/functions.test.ts +++ b/server/utils/__tests__/functions.test.ts @@ -1,5 +1,10 @@ import { setupStrapi, resetStrapi } from "../../../__mocks__/initSetup"; -import { getPluginService } from "../functions"; +import { + assertNotEmpty, + assertParamsPresent, + getPluginService, + parseParams, +} from "../functions"; beforeEach(setupStrapi); afterEach(resetStrapi); @@ -10,4 +15,39 @@ describe("Test plugin functions utils", () => { expect(getPluginService("common")).toHaveProperty("findAllFlat"); }); }); + describe("parseParams()", () => { + it("should parse params", () => { + expect( + parseParams({ + id: "1", + name: "NAME", + }) + ).toMatchInlineSnapshot(` + Object { + "id": 1, + "name": "NAME", + } + `); + }); + }); + describe("assertParamsPresent()", () => { + it("should assert params", () => { + expect(() => assertParamsPresent(1, ["id"])).toThrow(); + expect(() => assertParamsPresent(null, ["id"])).toThrow(); + expect(() => assertParamsPresent(undefined, ["id"])).toThrow(); + expect(() => assertParamsPresent("", ["id"])).toThrow(); + expect(() => assertParamsPresent("a text", ["id"])).toThrow(); + expect(() => assertParamsPresent({}, ["id"])).toThrow(); + expect(() => assertParamsPresent({ id: "1" }, ["id"])).not.toThrow(); + }); + }); + describe("assertNotEmpty()", () => { + it("should assert non empty value", () => { + expect(() => assertNotEmpty(null)).toThrow(); + expect(() => assertNotEmpty(undefined)).toThrow(); + expect(() => assertNotEmpty(0)).toThrow(); + expect(() => assertNotEmpty(1)).not.toThrow(); + expect(() => assertNotEmpty({ id: 1 })).not.toThrow(); + }); + }); }); diff --git a/server/utils/error.ts b/server/utils/error.ts index b7cb744c..f98c2a83 100644 --- a/server/utils/error.ts +++ b/server/utils/error.ts @@ -34,9 +34,9 @@ export default class PluginError extends Error implements IPluginError { toJSON() { if (this.payload) { return { + ...this.payload, name: this.name, message: this.message, - ...(this.payload || {}), }; } return this; diff --git a/types/__tests__/utils.test.ts b/types/__tests__/utils.test.ts new file mode 100644 index 00000000..4552de32 --- /dev/null +++ b/types/__tests__/utils.test.ts @@ -0,0 +1,14 @@ +import { assertComment } from "../utils"; + +describe("Types", () => { + describe("Utils", () => { + describe("assertComment()", () => { + it("should validate input", () => { + expect(() => assertComment(undefined)).toThrow(); + expect(() => assertComment(null)).toThrow(); + expect(() => assertComment({})).toThrow(); + expect(() => assertComment({ id: 1, content: "A comment" })).not.toThrow(); + }); + }); + }); +}); diff --git a/types/utils.ts b/types/utils.ts index 205e6082..066a40bd 100644 --- a/types/utils.ts +++ b/types/utils.ts @@ -2,7 +2,7 @@ import { Comment } from "./contentTypes"; // TODO => change to arrow function export function assertComment(value: any): asserts value is Comment { - if (!(value.id && value.content)) { + if (!(value?.id && value?.content)) { throw new Error("Provided value is not Comment type"); } } diff --git a/yarn.lock b/yarn.lock index 2719f10f..0be6d620 100644 --- a/yarn.lock +++ b/yarn.lock @@ -140,6 +140,13 @@ "@jridgewell/gen-mapping" "^0.3.2" jsesc "^2.5.1" +"@babel/helper-annotate-as-pure@^7.16.0": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" + integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA== + dependencies: + "@babel/types" "^7.18.6" + "@babel/helper-compilation-targets@^7.19.1": version "7.19.1" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.1.tgz#7f630911d83b408b76fe584831c98e5395d7a17c" @@ -170,7 +177,7 @@ dependencies: "@babel/types" "^7.18.6" -"@babel/helper-module-imports@^7.18.6": +"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.16.0", "@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== @@ -283,6 +290,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" +"@babel/plugin-syntax-jsx@^7.17.12": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0" + integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" @@ -339,7 +353,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.18.6" -"@babel/runtime@^7.10.5", "@babel/runtime@^7.12.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2": +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.5", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7": version "7.19.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.0.tgz#22b11c037b094d27a8a2504ea4dcff00f50e2259" integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA== @@ -355,7 +369,7 @@ "@babel/parser" "^7.18.10" "@babel/types" "^7.18.10" -"@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.7.2": +"@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.4.5", "@babel/traverse@^7.7.2": version "7.19.1" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.19.1.tgz#0fafe100a8c2a603b4718b1d9bf2568d1d193347" integrity sha512-0j/ZfZMxKukDaag2PtOPDbwuELqIar6lLskVPPJDjXMXjfLb1Obo/1yjxIGqqAJrmfaTIY3z2wFLAQ7qSkLsuA== @@ -392,6 +406,136 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" +"@emotion/babel-plugin@^11.10.0": + version "11.10.2" + resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.10.2.tgz#879db80ba622b3f6076917a1e6f648b1c7d008c7" + integrity sha512-xNQ57njWTFVfPAc3cjfuaPdsgLp5QOSuRsj9MA6ndEhH/AzuZM86qIQzt6rq+aGBwj3n5/TkLmU5lhAfdRmogA== + dependencies: + "@babel/helper-module-imports" "^7.16.7" + "@babel/plugin-syntax-jsx" "^7.17.12" + "@babel/runtime" "^7.18.3" + "@emotion/hash" "^0.9.0" + "@emotion/memoize" "^0.8.0" + "@emotion/serialize" "^1.1.0" + babel-plugin-macros "^3.1.0" + convert-source-map "^1.5.0" + escape-string-regexp "^4.0.0" + find-root "^1.1.0" + source-map "^0.5.7" + stylis "4.0.13" + +"@emotion/cache@^11.0.0", "@emotion/cache@^11.10.0": + version "11.10.3" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.10.3.tgz#c4f67904fad10c945fea5165c3a5a0583c164b87" + integrity sha512-Psmp/7ovAa8appWh3g51goxu/z3iVms7JXOreq136D8Bbn6dYraPnmL6mdM8GThEx9vwSn92Fz+mGSjBzN8UPQ== + dependencies: + "@emotion/memoize" "^0.8.0" + "@emotion/sheet" "^1.2.0" + "@emotion/utils" "^1.2.0" + "@emotion/weak-memoize" "^0.3.0" + stylis "4.0.13" + +"@emotion/css@^11.0.0": + version "11.10.0" + resolved "https://registry.yarnpkg.com/@emotion/css/-/css-11.10.0.tgz#270b4fdf2419e59cb07081d0e9f7940d88b8b443" + integrity sha512-dH9f+kSCucc8ilMg0MUA1AemabcyzYpe5EKX24F528PJjD7HyIY/VBNJHxfUdc8l400h2ncAjR6yEDu+DBj2cg== + dependencies: + "@emotion/babel-plugin" "^11.10.0" + "@emotion/cache" "^11.10.0" + "@emotion/serialize" "^1.1.0" + "@emotion/sheet" "^1.2.0" + "@emotion/utils" "^1.2.0" + +"@emotion/hash@^0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.0.tgz#c5153d50401ee3c027a57a177bc269b16d889cb7" + integrity sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ== + +"@emotion/is-prop-valid@^0.8.8": + version "0.8.8" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a" + integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA== + dependencies: + "@emotion/memoize" "0.7.4" + +"@emotion/memoize@0.7.4": + version "0.7.4" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb" + integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== + +"@emotion/memoize@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.0.tgz#f580f9beb67176fa57aae70b08ed510e1b18980f" + integrity sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA== + +"@emotion/react@^11.1.1": + version "11.10.4" + resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.10.4.tgz#9dc6bccbda5d70ff68fdb204746c0e8b13a79199" + integrity sha512-j0AkMpr6BL8gldJZ6XQsQ8DnS9TxEQu1R+OGmDZiWjBAJtCcbt0tS3I/YffoqHXxH6MjgI7KdMbYKw3MEiU9eA== + dependencies: + "@babel/runtime" "^7.18.3" + "@emotion/babel-plugin" "^11.10.0" + "@emotion/cache" "^11.10.0" + "@emotion/serialize" "^1.1.0" + "@emotion/use-insertion-effect-with-fallbacks" "^1.0.0" + "@emotion/utils" "^1.2.0" + "@emotion/weak-memoize" "^0.3.0" + hoist-non-react-statics "^3.3.1" + +"@emotion/serialize@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.0.tgz#b1f97b1011b09346a40e9796c37a3397b4ea8ea8" + integrity sha512-F1ZZZW51T/fx+wKbVlwsfchr5q97iW8brAnXmsskz4d0hVB4O3M/SiA3SaeH06x02lSNzkkQv+n3AX3kCXKSFA== + dependencies: + "@emotion/hash" "^0.9.0" + "@emotion/memoize" "^0.8.0" + "@emotion/unitless" "^0.8.0" + "@emotion/utils" "^1.2.0" + csstype "^3.0.2" + +"@emotion/sheet@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.0.tgz#771b1987855839e214fc1741bde43089397f7be5" + integrity sha512-OiTkRgpxescko+M51tZsMq7Puu/KP55wMT8BgpcXVG2hqXc0Vo0mfymJ/Uj24Hp0i083ji/o0aLddh08UEjq8w== + +"@emotion/stylis@^0.8.4": + version "0.8.5" + resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04" + integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ== + +"@emotion/unitless@^0.7.4": + version "0.7.5" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" + integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== + +"@emotion/unitless@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.0.tgz#a4a36e9cbdc6903737cd20d38033241e1b8833db" + integrity sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw== + +"@emotion/use-insertion-effect-with-fallbacks@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz#ffadaec35dbb7885bd54de3fa267ab2f860294df" + integrity sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A== + +"@emotion/utils@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.0.tgz#9716eaccbc6b5ded2ea5a90d65562609aab0f561" + integrity sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw== + +"@emotion/weak-memoize@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz#ea89004119dc42db2e1dba0f97d553f7372f6fcb" + integrity sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg== + +"@formatjs/ecma402-abstract@1.11.4": + version "1.11.4" + resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.4.tgz#b962dfc4ae84361f9f08fbce411b4e4340930eda" + integrity sha512-EBikYFp2JCdIfGEb5G9dyCkTGDmC57KSHhRQOC3aYxoPWVZvfWCDjZwkGYHN7Lis/fmuWl906bnNTJifDQ3sXw== + dependencies: + "@formatjs/intl-localematcher" "0.2.25" + tslib "^2.1.0" + "@formatjs/ecma402-abstract@1.12.0": version "1.12.0" resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.12.0.tgz#2fb5e8983d5fae2fad9ec6c77aec1803c2b88d8e" @@ -400,6 +544,13 @@ "@formatjs/intl-localematcher" "0.2.31" tslib "2.4.0" +"@formatjs/fast-memoize@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-1.2.1.tgz#e6f5aee2e4fd0ca5edba6eba7668e2d855e0fc21" + integrity sha512-Rg0e76nomkz3vF9IPlKeV+Qynok0r7YZjL6syLz4/urSg0IbjPZCB/iYUMNsYA643gh4mgrX3T7KEIFIxJBQeg== + dependencies: + tslib "^2.1.0" + "@formatjs/fast-memoize@1.2.6": version "1.2.6" resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-1.2.6.tgz#a442970db7e9634af556919343261a7bbe5e88c3" @@ -407,6 +558,15 @@ dependencies: tslib "2.4.0" +"@formatjs/icu-messageformat-parser@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.1.0.tgz#a54293dd7f098d6a6f6a084ab08b6d54a3e8c12d" + integrity sha512-Qxv/lmCN6hKpBSss2uQ8IROVnta2r9jd3ymUEIjm2UyIkUCHVcbUVRGL/KS/wv7876edvsPe+hjHVJ4z8YuVaw== + dependencies: + "@formatjs/ecma402-abstract" "1.11.4" + "@formatjs/icu-skeleton-parser" "1.3.6" + tslib "^2.1.0" + "@formatjs/icu-messageformat-parser@2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.1.7.tgz#35dc556c13a0544cc730300c8ddb730ba7f44bd4" @@ -424,6 +584,23 @@ "@formatjs/ecma402-abstract" "1.12.0" tslib "2.4.0" +"@formatjs/icu-skeleton-parser@1.3.6": + version "1.3.6" + resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.6.tgz#4ce8c0737d6f07b735288177049e97acbf2e8964" + integrity sha512-I96mOxvml/YLrwU2Txnd4klA7V8fRhb6JG/4hm3VMNmeJo1F03IpV2L3wWt7EweqNLES59SZ4d6hVOPCSf80Bg== + dependencies: + "@formatjs/ecma402-abstract" "1.11.4" + tslib "^2.1.0" + +"@formatjs/intl-displaynames@5.4.3": + version "5.4.3" + resolved "https://registry.yarnpkg.com/@formatjs/intl-displaynames/-/intl-displaynames-5.4.3.tgz#e468586694350c722c7efab1a31fcde68aeaed8b" + integrity sha512-4r12A3mS5dp5hnSaQCWBuBNfi9Amgx2dzhU4lTFfhSxgb5DOAiAbMpg6+7gpWZgl4ahsj3l2r/iHIjdmdXOE2Q== + dependencies: + "@formatjs/ecma402-abstract" "1.11.4" + "@formatjs/intl-localematcher" "0.2.25" + tslib "^2.1.0" + "@formatjs/intl-displaynames@6.1.3": version "6.1.3" resolved "https://registry.yarnpkg.com/@formatjs/intl-displaynames/-/intl-displaynames-6.1.3.tgz#c9d283db518cd721c0855e9854bfadb9ba304b6a" @@ -433,6 +610,15 @@ "@formatjs/intl-localematcher" "0.2.31" tslib "2.4.0" +"@formatjs/intl-listformat@6.5.3": + version "6.5.3" + resolved "https://registry.yarnpkg.com/@formatjs/intl-listformat/-/intl-listformat-6.5.3.tgz#f29da613a8062dc3e4e3d847ba890c3ea745f051" + integrity sha512-ozpz515F/+3CU+HnLi5DYPsLa6JoCfBggBSSg/8nOB5LYSFW9+ZgNQJxJ8tdhKYeODT+4qVHX27EeJLoxLGLNg== + dependencies: + "@formatjs/ecma402-abstract" "1.11.4" + "@formatjs/intl-localematcher" "0.2.25" + tslib "^2.1.0" + "@formatjs/intl-listformat@7.1.2": version "7.1.2" resolved "https://registry.yarnpkg.com/@formatjs/intl-listformat/-/intl-listformat-7.1.2.tgz#3c5145436434795fa834150d0b6b6dc577aa6964" @@ -442,6 +628,13 @@ "@formatjs/intl-localematcher" "0.2.31" tslib "2.4.0" +"@formatjs/intl-localematcher@0.2.25": + version "0.2.25" + resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.2.25.tgz#60892fe1b271ec35ba07a2eb018a2dd7bca6ea3a" + integrity sha512-YmLcX70BxoSopLFdLr1Ds99NdlTI2oWoLbaUW2M406lxOIPzE1KQhRz2fPUkq34xVZQaihCoU29h0KK7An3bhA== + dependencies: + tslib "^2.1.0" + "@formatjs/intl-localematcher@0.2.31": version "0.2.31" resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.2.31.tgz#aada2b1e58211460cedba56889e3c489117eb6eb" @@ -449,6 +642,19 @@ dependencies: tslib "2.4.0" +"@formatjs/intl@2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@formatjs/intl/-/intl-2.2.1.tgz#6daf4dabed055b17f467f0aa1bc073a626bc9189" + integrity sha512-vgvyUOOrzqVaOFYzTf2d3+ToSkH2JpR7x/4U1RyoHQLmvEaTQvXJ7A2qm1Iy3brGNXC/+/7bUlc3lpH+h/LOJA== + dependencies: + "@formatjs/ecma402-abstract" "1.11.4" + "@formatjs/fast-memoize" "1.2.1" + "@formatjs/icu-messageformat-parser" "2.1.0" + "@formatjs/intl-displaynames" "5.4.3" + "@formatjs/intl-listformat" "6.5.3" + intl-messageformat "9.13.0" + tslib "^2.1.0" + "@formatjs/intl@2.4.1": version "2.4.1" resolved "https://registry.yarnpkg.com/@formatjs/intl/-/intl-2.4.1.tgz#3e8ae8542e827c55cb1b7298bd72d4a009c2224d" @@ -462,6 +668,49 @@ intl-messageformat "10.1.4" tslib "2.4.0" +"@fortawesome/fontawesome-common-types@6.1.2": + version "6.1.2" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.1.2.tgz#c1095b1bbabf19f37f9ff0719db38d92a410bcfe" + integrity sha512-wBaAPGz1Awxg05e0PBRkDRuTsy4B3dpBm+zreTTyd9TH4uUM27cAL4xWyWR0rLJCrRwzVsQ4hF3FvM6rqydKPA== + +"@fortawesome/fontawesome-common-types@^0.2.36": + version "0.2.36" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.36.tgz#b44e52db3b6b20523e0c57ef8c42d315532cb903" + integrity sha512-a/7BiSgobHAgBWeN7N0w+lAhInrGxksn13uK7231n2m8EDPE3BMCl9NZLTGrj9ZXfCmC6LM0QLqXidIizVQ6yg== + +"@fortawesome/fontawesome-free@^5.15.2": + version "5.15.4" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.4.tgz#ecda5712b61ac852c760d8b3c79c96adca5554e5" + integrity sha512-eYm8vijH/hpzr/6/1CJ/V/Eb1xQFW2nnUKArb3z+yUWv7HTwj6M7SP957oMjfZjAHU6qpoNc2wQvIxBLWYa/Jg== + +"@fortawesome/fontawesome-svg-core@6.1.2": + version "6.1.2" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.1.2.tgz#11e2e8583a7dea75d734e4d0e53d91c63fae7511" + integrity sha512-853G/Htp0BOdXnPoeCPTjFrVwyrJHpe8MhjB/DYE9XjwhnNDfuBCd3aKc2YUYbEfHEcBws4UAA0kA9dymZKGjA== + dependencies: + "@fortawesome/fontawesome-common-types" "6.1.2" + +"@fortawesome/free-brands-svg-icons@^5.15.2": + version "5.15.4" + resolved "https://registry.yarnpkg.com/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.15.4.tgz#ec8a44dd383bcdd58aa7d1c96f38251e6fec9733" + integrity sha512-f1witbwycL9cTENJegcmcZRYyawAFbm8+c6IirLmwbbpqz46wyjbQYLuxOc7weXFXfB7QR8/Vd2u5R3q6JYD9g== + dependencies: + "@fortawesome/fontawesome-common-types" "^0.2.36" + +"@fortawesome/free-solid-svg-icons@^5.15.3": + version "5.15.4" + resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.4.tgz#2a68f3fc3ddda12e52645654142b9e4e8fbb6cc5" + integrity sha512-JLmQfz6tdtwxoihXLg6lT78BorrFyCf59SAwBM6qV/0zXyVeDygJVb3fk+j5Qat+Yvcxp1buLTY5iDh1ZSAQ8w== + dependencies: + "@fortawesome/fontawesome-common-types" "^0.2.36" + +"@fortawesome/react-fontawesome@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz#d90dd8a9211830b4e3c08e94b63a0ba7291ddcf4" + integrity sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw== + dependencies: + prop-types "^15.8.1" + "@graphql-tools/merge@8.3.1": version "8.3.1" resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.3.1.tgz#06121942ad28982a14635dbc87b5d488a041d722" @@ -860,7 +1109,35 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@strapi/plugin-graphql@^4.3.0", "@strapi/plugin-graphql@^4.3.8": +"@strapi/helper-plugin@^4.3.8": + version "4.3.8" + resolved "https://registry.yarnpkg.com/@strapi/helper-plugin/-/helper-plugin-4.3.8.tgz#e9053e3fa00e43aaeadbbb8e06eee7aead92ed41" + integrity sha512-qEv1YnDwDMe8nNH9m6drUcnfGLPmt7TiLaD+sg2fcwNwILO3Imis7l4vy/qKraOmj4iWiB+j160+J5oiiN3a3w== + dependencies: + "@fortawesome/fontawesome-free" "^5.15.2" + "@fortawesome/fontawesome-svg-core" "6.1.2" + "@fortawesome/free-brands-svg-icons" "^5.15.2" + "@fortawesome/free-solid-svg-icons" "^5.15.3" + "@fortawesome/react-fontawesome" "^0.2.0" + axios "0.27.2" + date-fns "2.29.2" + formik "^2.2.6" + immer "9.0.6" + invariant "^2.2.1" + lodash "4.17.21" + match-sorter "^4.0.2" + qs "6.10.1" + react "^17.0.2" + react-dom "^17.0.2" + react-helmet "^6.1.0" + react-intl "5.25.1" + react-router "^5.2.0" + react-router-dom "5.2.0" + react-select "4.0.2" + styled-components "5.3.3" + whatwg-fetch "^3.6.2" + +"@strapi/plugin-graphql@^4.3.8": version "4.3.8" resolved "https://registry.yarnpkg.com/@strapi/plugin-graphql/-/plugin-graphql-4.3.8.tgz#1cd0ac23f1a373a63c6de687c0e4991cde009347" integrity sha512-nHXWEje3nqF5v1NHQFqcfjJRbzk1B1HNZknKwiESeQ5IfiiDKSEx2Hq0pTT7FMeJx568SdbZaHT30R2Jih5eNQ== @@ -882,7 +1159,7 @@ pluralize "^8.0.0" subscriptions-transport-ws "0.9.19" -"@strapi/utils@4.3.8", "@strapi/utils@^4.3.0", "@strapi/utils@^4.3.8": +"@strapi/utils@4.3.8", "@strapi/utils@^4.3.8": version "4.3.8" resolved "https://registry.yarnpkg.com/@strapi/utils/-/utils-4.3.8.tgz#10212a2deba66be85aabc3214f9ed5eb945cfed5" integrity sha512-Ckgd3B+gOLRXyuAt2hFiXQQ7nay5UtsqAcy8On25gvsidz+5LK70k+afXG9A02Hg6pNeNU3goU/Ah3gpRho7fg== @@ -1136,6 +1413,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw== +"@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + "@types/prettier@^2.1.5": version "2.7.0" resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.0.tgz#ea03e9f0376a4446f44797ca19d9c46c36e352dc" @@ -1467,7 +1749,7 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -axios@*: +axios@*, axios@0.27.2: version "0.27.2" resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== @@ -1510,6 +1792,31 @@ babel-plugin-jest-hoist@^27.5.1: "@types/babel__core" "^7.0.0" "@types/babel__traverse" "^7.0.6" +babel-plugin-macros@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1" + integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg== + dependencies: + "@babel/runtime" "^7.12.5" + cosmiconfig "^7.0.0" + resolve "^1.19.0" + +"babel-plugin-styled-components@>= 1.12.0": + version "2.0.7" + resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-2.0.7.tgz#c81ef34b713f9da2b7d3f5550df0d1e19e798086" + integrity sha512-i7YhvPgVqRKfoQ66toiZ06jPNA3p6ierpfUuEWxNF+fV27Uv5gxBkf8KZLHUCc1nFA9j6+80pYoIpqCeyW3/bA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-module-imports" "^7.16.0" + babel-plugin-syntax-jsx "^6.18.0" + lodash "^4.17.11" + picomatch "^2.3.0" + +babel-plugin-syntax-jsx@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" + integrity sha512-qrPaCSo9c8RHNRHIotaufGbuOBN8rtdC4QrrFFc43vyWCCz7Kl7GL1PGaXtMGQZUXrkCjNEgxDfmAuAabr/rlw== + babel-preset-current-node-syntax@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" @@ -1674,10 +1981,15 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== +camelize@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b" + integrity sha512-W2lPwkBkMZwFlPCXhIlYgxu+7gC/NUlCtdK652DAJ1JdgV0sTrvuPFshNPrFa1TY2JOkLhgdeEBplB4ezEa+xg== + caniuse-lite@^1.0.30001400: - version "1.0.30001409" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001409.tgz#6135da9dcab34cd9761d9cdb12a68e6740c5e96e" - integrity sha512-V0mnJ5dwarmhYv8/MzhJ//aW68UpvnQBXv8lJ2QUsvn2pHcmAuNtu8hQEDz37XnA1iE+lRR9CIfGWWpgJ5QedQ== + version "1.0.30001408" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001408.tgz#8f5e96bd9c5fd1a8c629e4415cdbaf556333a591" + integrity sha512-DdUCktgMSM+1ndk9EFMZcavsGszV7zxV9O7MtOHniTa/iyAIwJCF0dFVBdU9SijJbfh29hC9bCs07wu8pjnGJQ== chalk@^2.0.0: version "2.4.2" @@ -1819,7 +2131,7 @@ content-type@^1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== -convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: +convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: version "1.8.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== @@ -1862,6 +2174,17 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== +cosmiconfig@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" + integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.2.1" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.10.0" + create-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" @@ -1876,6 +2199,20 @@ cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +css-color-keywords@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05" + integrity sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg== + +css-to-react-native@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.0.0.tgz#62dbe678072a824a689bcfee011fc96e02a7d756" + integrity sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ== + dependencies: + camelize "^1.0.0" + css-color-keywords "^1.0.0" + postcss-value-parser "^4.0.2" + cssfilter@0.0.10: version "0.0.10" resolved "https://registry.yarnpkg.com/cssfilter/-/cssfilter-0.0.10.tgz#c6d2672632a2e5c83e013e6864a42ce8defd20ae" @@ -1951,6 +2288,11 @@ deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== +deepmerge@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170" + integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA== + deepmerge@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" @@ -2008,6 +2350,14 @@ diff@^4.0.1: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== +dom-helpers@^5.0.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" + integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== + dependencies: + "@babel/runtime" "^7.8.7" + csstype "^3.0.2" + domexception@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" @@ -2165,6 +2515,11 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +find-root@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" + integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== + find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" @@ -2196,6 +2551,19 @@ form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" +formik@^2.2.6: + version "2.2.9" + resolved "https://registry.yarnpkg.com/formik/-/formik-2.2.9.tgz#8594ba9c5e2e5cf1f42c5704128e119fc46232d0" + integrity sha512-LQLcISMmf1r5at4/gyJigGn0gOwFbeEAlji+N9InZF6LIMXnFNkO42sCI8Jt84YZggpD4cPWObAZaxpEFtSzNA== + dependencies: + deepmerge "^2.1.1" + hoist-non-react-statics "^3.3.0" + lodash "^4.17.21" + lodash-es "^4.17.21" + react-fast-compare "^2.0.1" + tiny-warning "^1.0.2" + tslib "^1.10.0" + fresh@~0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" @@ -2358,7 +2726,19 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" -hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: +history@^4.9.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" + integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== + dependencies: + "@babel/runtime" "^7.1.2" + loose-envify "^1.2.0" + resolve-pathname "^3.0.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + value-equal "^1.0.1" + +hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -2453,6 +2833,19 @@ ignore-walk@3.0.4: dependencies: minimatch "^3.0.4" +immer@9.0.6: + version "9.0.6" + resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.6.tgz#7a96bf2674d06c8143e327cbf73539388ddf1a73" + integrity sha512-G95ivKpy+EvVAnAab4fVa4YGYn24J1SpEktnJX7JJ45Bd7xqME/SCplFzYFmTbrkwZbQ4xJK1xMTUYBkN6pWsQ== + +import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + import-local@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" @@ -2494,6 +2887,23 @@ intl-messageformat@10.1.4: "@formatjs/icu-messageformat-parser" "2.1.7" tslib "2.4.0" +intl-messageformat@9.13.0: + version "9.13.0" + resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-9.13.0.tgz#97360b73bd82212e4f6005c712a4a16053165468" + integrity sha512-7sGC7QnSQGa5LZP7bXLDhVDtQOeKGeBFGHF2Y8LVBwYZoQZCgWeKoPGTa5GMG8g/TzDgeXuYJQis7Ggiw2xTOw== + dependencies: + "@formatjs/ecma402-abstract" "1.11.4" + "@formatjs/fast-memoize" "1.2.1" + "@formatjs/icu-messageformat-parser" "2.1.0" + tslib "^2.1.0" + +invariant@^2.2.1: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" @@ -3041,7 +3451,7 @@ js-sha3@0.8.0: resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== -js-tokens@^4.0.0: +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== @@ -3189,7 +3599,7 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" -lodash-es@^4.17.15: +lodash-es@^4.17.15, lodash-es@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== @@ -3209,7 +3619,7 @@ lodash.sortby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA== -lodash@4.17.21, lodash@^4.17.20, lodash@^4.7.0: +lodash@4.17.21, lodash@^4.17.11, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -3224,6 +3634,13 @@ long@^4.0.0: resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -3255,6 +3672,14 @@ makeerror@1.0.12: dependencies: tmpl "1.0.5" +match-sorter@^4.0.2: + version "4.2.1" + resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-4.2.1.tgz#575b4b3737185ba9518b67612b66877ea0b37358" + integrity sha512-s+3h9TiZU9U1pWhIERHf8/f4LmBN6IXaRgo2CI17+XGByGS1GvG5VvXK9pcGyCjGe3WM3mSYRC3ipGrd5UEVgw== + dependencies: + "@babel/runtime" "^7.10.5" + remove-accents "0.4.2" + match-sorter@^6.0.2: version "6.3.1" resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-6.3.1.tgz#98cc37fda756093424ddf3cbc62bfe9c75b92bda" @@ -3268,6 +3693,11 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== +memoize-one@^5.0.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" + integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== + merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -3303,6 +3733,14 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +mini-create-react-context@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz#072171561bfdc922da08a60c2197a497cc2d1d5e" + integrity sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ== + dependencies: + "@babel/runtime" "^7.12.1" + tiny-warning "^1.0.3" + minimatch@^3.0.3, minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -3420,6 +3858,11 @@ nwsapi@^2.2.0: resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.2.tgz#e5418863e7905df67d51ec95938d67bf801f0bb0" integrity sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw== +object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + object-inspect@^1.9.0: version "1.12.2" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" @@ -3492,7 +3935,14 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -parse-json@^5.2.0: +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.0.0, parse-json@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== @@ -3532,12 +3982,24 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-to-regexp@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" + integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== + dependencies: + isarray "0.0.1" + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + picocolors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.0, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -3559,6 +4021,11 @@ pluralize@^8.0.0: resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== +postcss-value-parser@^4.0.2: + version "4.2.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -3591,6 +4058,15 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" +prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + property-expr@^2.0.4: version "2.0.5" resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.5.tgz#278bdb15308ae16af3e3b9640024524f4dc02cb4" @@ -3616,6 +4092,13 @@ punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +qs@6.10.1: + version "6.10.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.1.tgz#4931482fa8d647a5aab799c5271d2133b981fb6a" + integrity sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg== + dependencies: + side-channel "^1.0.4" + qs@^6.5.2: version "6.11.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" @@ -3638,6 +4121,42 @@ raw-body@^2.3.3: iconv-lite "0.4.24" unpipe "1.0.0" +react-dom@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" + integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + scheduler "^0.20.2" + +react-fast-compare@^2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9" + integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== + +react-fast-compare@^3.1.1: + version "3.2.0" + resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" + integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== + +react-helmet@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-6.1.0.tgz#a750d5165cb13cf213e44747502652e794468726" + integrity sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw== + dependencies: + object-assign "^4.1.1" + prop-types "^15.7.2" + react-fast-compare "^3.1.1" + react-side-effect "^2.1.0" + +react-input-autosize@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-3.0.0.tgz#6b5898c790d4478d69420b55441fcc31d5c50a85" + integrity sha512-nL9uS7jEs/zu8sqwFE5MAPx6pPkNAriACQ2rGLlqmKr2sPGtN7TXTyDdQt4lbNXVx7Uzadb40x8qotIuru6Rhg== + dependencies: + prop-types "^15.5.8" + react-intl@*: version "6.1.1" resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-6.1.1.tgz#9c9b613f8de8a7d08311455d6a901806da005f8d" @@ -3654,7 +4173,23 @@ react-intl@*: intl-messageformat "10.1.4" tslib "2.4.0" -react-is@^16.7.0: +react-intl@5.25.1: + version "5.25.1" + resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-5.25.1.tgz#68a73aefc485c9bf70062381ae7f6f4791680879" + integrity sha512-pkjdQDvpJROoXLMltkP/5mZb0/XqrqLoPGKUCfbdkP8m6U9xbK40K51Wu+a4aQqTEvEK5lHBk0fWzUV72SJ3Hg== + dependencies: + "@formatjs/ecma402-abstract" "1.11.4" + "@formatjs/icu-messageformat-parser" "2.1.0" + "@formatjs/intl" "2.2.1" + "@formatjs/intl-displaynames" "5.4.3" + "@formatjs/intl-listformat" "6.5.3" + "@types/hoist-non-react-statics" "^3.3.1" + "@types/react" "16 || 17 || 18" + hoist-non-react-statics "^3.3.2" + intl-messageformat "9.13.0" + tslib "^2.1.0" + +react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -3673,6 +4208,88 @@ react-query@*: broadcast-channel "^3.4.1" match-sorter "^6.0.2" +react-router-dom@5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.2.0.tgz#9e65a4d0c45e13289e66c7b17c7e175d0ea15662" + integrity sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA== + dependencies: + "@babel/runtime" "^7.1.2" + history "^4.9.0" + loose-envify "^1.3.1" + prop-types "^15.6.2" + react-router "5.2.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + +react-router@5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.2.0.tgz#424e75641ca8747fbf76e5ecca69781aa37ea293" + integrity sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw== + dependencies: + "@babel/runtime" "^7.1.2" + history "^4.9.0" + hoist-non-react-statics "^3.1.0" + loose-envify "^1.3.1" + mini-create-react-context "^0.4.0" + path-to-regexp "^1.7.0" + prop-types "^15.6.2" + react-is "^16.6.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + +react-router@^5.2.0: + version "5.3.3" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.3.3.tgz#8e3841f4089e728cf82a429d92cdcaa5e4a3a288" + integrity sha512-mzQGUvS3bM84TnbtMYR8ZjKnuPJ71IjSzR+DE6UkUqvN4czWIqEs17yLL8xkAycv4ev0AiN+IGrWu88vJs/p2w== + dependencies: + "@babel/runtime" "^7.12.13" + history "^4.9.0" + hoist-non-react-statics "^3.1.0" + loose-envify "^1.3.1" + mini-create-react-context "^0.4.0" + path-to-regexp "^1.7.0" + prop-types "^15.6.2" + react-is "^16.6.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + +react-select@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/react-select/-/react-select-4.0.2.tgz#4dcca9f38d6a41e01f2dc7673e244a325e3b4e0e" + integrity sha512-BiihrRpRIBBvNqofNZIBpo08Kw8DBHb/kgpIDW4bxgkttk50Sxf0alEIKobns3U7UJXk/CA4rsFUueQEg9Pm5A== + dependencies: + "@babel/runtime" "^7.4.4" + "@emotion/cache" "^11.0.0" + "@emotion/css" "^11.0.0" + "@emotion/react" "^11.1.1" + memoize-one "^5.0.0" + prop-types "^15.6.0" + react-input-autosize "^3.0.0" + react-transition-group "^4.3.0" + +react-side-effect@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-2.1.2.tgz#dc6345b9e8f9906dc2eeb68700b615e0b4fe752a" + integrity sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw== + +react-transition-group@^4.3.0: + version "4.4.5" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1" + integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g== + dependencies: + "@babel/runtime" "^7.5.5" + dom-helpers "^5.0.1" + loose-envify "^1.4.0" + prop-types "^15.6.2" + +react@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" + integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + readable-stream@~1.0.31: version "1.0.34" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" @@ -3730,17 +4347,27 @@ resolve-cwd@^3.0.0: dependencies: resolve-from "^5.0.0" +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + resolve-from@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== +resolve-pathname@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" + integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== + resolve.exports@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== -resolve@^1.20.0: +resolve@^1.19.0, resolve@^1.20.0: version "1.22.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== @@ -3783,6 +4410,14 @@ saxes@^5.0.1: dependencies: xmlchars "^2.2.0" +scheduler@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" + integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + semver@7.x, semver@^7.3.2: version "7.3.7" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" @@ -3818,6 +4453,11 @@ sha.js@^2.4.11: inherits "^2.0.1" safe-buffer "^5.0.1" +shallowequal@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" + integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -3869,6 +4509,11 @@ source-map-support@^0.5.6: buffer-from "^1.0.0" source-map "^0.6.0" +source-map@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== + source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -3901,7 +4546,7 @@ statuses@2.0.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== -strapi-typed@^1.0.12: +strapi-typed@^1.0.14: version "1.0.14" resolved "https://registry.yarnpkg.com/strapi-typed/-/strapi-typed-1.0.14.tgz#26132f1037357079a733ccd8620c9de5e3680f33" integrity sha512-z00rDFyMW9aJCZGpxV7UJ83RYZH6CTTd2SCNbAzcgGhctIdNW2G8hmLZwxrbrmhcoBFmad8H+RVPjUfx89r2lw== @@ -3979,6 +4624,27 @@ stubs@^3.0.0: resolved "https://registry.yarnpkg.com/stubs/-/stubs-3.0.0.tgz#e8d2ba1fa9c90570303c030b6900f7d5f89abe5b" integrity sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw== +styled-components@5.3.3: + version "5.3.3" + resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.3.3.tgz#312a3d9a549f4708f0fb0edc829eb34bde032743" + integrity sha512-++4iHwBM7ZN+x6DtPPWkCI4vdtwumQ+inA/DdAsqYd4SVgUKJie5vXyzotA00ttcFdQkCng7zc6grwlfIfw+lw== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/traverse" "^7.4.5" + "@emotion/is-prop-valid" "^0.8.8" + "@emotion/stylis" "^0.8.4" + "@emotion/unitless" "^0.7.4" + babel-plugin-styled-components ">= 1.12.0" + css-to-react-native "^3.0.0" + hoist-non-react-statics "^3.0.0" + shallowequal "^1.1.0" + supports-color "^5.5.0" + +stylis@4.0.13: + version "4.0.13" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.13.tgz#f5db332e376d13cc84ecfe5dace9a2a51d954c91" + integrity sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag== + subscriptions-transport-ws@0.9.19: version "0.9.19" resolved "https://registry.yarnpkg.com/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.19.tgz#10ca32f7e291d5ee8eb728b9c02e43c52606cdcf" @@ -4075,6 +4741,16 @@ through2@^2.0.1: readable-stream "~2.3.6" xtend "~4.0.1" +tiny-invariant@^1.0.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.2.0.tgz#a1141f86b672a9148c72e978a19a73b9b94a15a9" + integrity sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg== + +tiny-warning@^1.0.0, tiny-warning@^1.0.2, tiny-warning@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" + integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== + tmpl@1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" @@ -4169,6 +4845,11 @@ tslib@2.4.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== +tslib@^1.10.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + tslib@~2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" @@ -4291,6 +4972,11 @@ v8-to-istanbul@^8.1.0: convert-source-map "^1.6.0" source-map "^0.7.3" +value-equal@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" + integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== + value-or-promise@1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/value-or-promise/-/value-or-promise-1.0.10.tgz#5bf041f1e9a8e7043911875547636768a836e446" @@ -4349,6 +5035,11 @@ whatwg-encoding@^1.0.5: dependencies: iconv-lite "0.4.24" +whatwg-fetch@^3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c" + integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA== + whatwg-mimetype@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" @@ -4450,6 +5141,11 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yaml@^1.10.0: + version "1.10.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + yargs-parser@20.x, yargs-parser@^20.2.2: version "20.2.9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"