From 67cd66143e88dc28c8ceb293ea3a28e5da9b5c71 Mon Sep 17 00:00:00 2001 From: Ashu <11219262+ashutosh16@users.noreply.github.com> Date: Tue, 29 Oct 2024 13:58:39 -0700 Subject: [PATCH] chore: update docs to enable the ext (#23) Signed-off-by: ashutosh16 <11219262+ashutosh16@users.noreply.github.com> --- ui/gen/ephemeralAccessAPI.ts | 187 ++++++++++++ ui/package.json | 22 +- ui/src/component/access-details.tsx | 166 ----------- ui/src/component/access-panel.tsx | 97 ------- ...ils.scss => ephemeral-access-details.scss} | 4 + ui/src/component/ephemeral-access-details.tsx | 270 ++++++++++++++++++ ui/src/component/ephemeral-access-panel.tsx | 105 +++++++ ui/src/config/client.ts | 45 +-- ui/src/constant.ts | 6 +- ui/src/{access.tsx => ephemeral-access.tsx} | 18 +- ui/src/gen/ephemeralAccessAPI.ts | 150 ++++++++++ ui/src/gen/transformers/axiosInstance.ts | 29 ++ ui/src/gen/transformers/index.ts | 1 + ui/src/global.d.ts | 14 +- ui/src/index.tsx | 24 +- ui/src/models/type.ts | 1 + ui/src/tsconfig.json | 10 +- ui/src/utils/use-local-storage.ts | 18 -- ui/src/utils/utils.tsx | 55 ++-- ui/yarn.lock | 189 +++++++----- 20 files changed, 965 insertions(+), 446 deletions(-) create mode 100644 ui/gen/ephemeralAccessAPI.ts delete mode 100644 ui/src/component/access-details.tsx delete mode 100644 ui/src/component/access-panel.tsx rename ui/src/component/{access-details.scss => ephemeral-access-details.scss} (91%) create mode 100644 ui/src/component/ephemeral-access-details.tsx create mode 100644 ui/src/component/ephemeral-access-panel.tsx rename ui/src/{access.tsx => ephemeral-access.tsx} (61%) create mode 100644 ui/src/gen/ephemeralAccessAPI.ts create mode 100644 ui/src/gen/transformers/axiosInstance.ts create mode 100644 ui/src/gen/transformers/index.ts delete mode 100644 ui/src/utils/use-local-storage.ts diff --git a/ui/gen/ephemeralAccessAPI.ts b/ui/gen/ephemeralAccessAPI.ts new file mode 100644 index 0000000..7257101 --- /dev/null +++ b/ui/gen/ephemeralAccessAPI.ts @@ -0,0 +1,187 @@ +/** + * Generated by orval v7.1.1 🍺 + * Do not edit manually. + * Ephemeral Access API + * OpenAPI spec version: 0.0.1 + */ +import axios from 'axios' +import type { + AxiosRequestConfig, + AxiosResponse +} from 'axios' + +// https://stackoverflow.com/questions/49579094/typescript-conditional-types-filter-out-readonly-properties-pick-only-requir/49579497#49579497 +type IfEquals = (() => T extends X ? 1 : 2) extends < +T, +>() => T extends Y ? 1 : 2 +? A +: B; + +type WritableKeys = { +[P in keyof T]-?: IfEquals< + { [Q in P]: T[P] }, + { -readonly [Q in P]: T[P] }, + P +>; +}[keyof T]; + +type UnionToIntersection = + (U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never; +type DistributeReadOnlyOverUnions = T extends any ? NonReadonly : never; + +type Writable = Pick>; +type NonReadonly = [T] extends [UnionToIntersection] ? { + [P in keyof Writable]: T[P] extends object + ? NonReadonly> + : T[P]; +} : DistributeReadOnlyOverUnions; + +export type GetAccessrequestByNameParams = { +/** + * The namespace to use while searching for the access request. + */ +namespace?: string; +}; + +export type ListAccessrequestParams = { +/** + * Will search for all access requests for the given username. + */ +username?: string; +/** + * Will search for all access requests for the given application (format :). + */ +appName?: string; +}; + +export interface ListAccessRequestResponseBody { + /** A URL to the JSON Schema for this object. */ + readonly $schema?: string; + /** @nullable */ + items: AccessRequestResponseBody[] | null; +} + +export interface ErrorDetail { + /** Where the error occurred, e.g. 'body.items[3].tags' or 'path.thing-id' */ + location?: string; + /** Error message text */ + message?: string; + /** The value at the given location */ + value?: unknown; +} + +export interface ErrorModel { + /** A URL to the JSON Schema for this object. */ + readonly $schema?: string; + /** A human-readable explanation specific to this occurrence of the problem. */ + detail?: string; + /** + * Optional list of individual error details + * @nullable + */ + errors?: ErrorDetail[] | null; + /** A URI reference that identifies the specific occurrence of the problem. */ + instance?: string; + /** HTTP status code */ + status?: number; + /** A short, human-readable summary of the problem type. This value should not change between occurrences of the error. */ + title?: string; + /** A URI reference to human-readable documentation for the error. */ + type?: string; +} + +export interface CreateAccessRequestBody { + /** A URL to the JSON Schema for this object. */ + readonly $schema?: string; + /** The application to be associated with the access request (format :). */ + appName: string; + /** The user to be associated with the access request. */ + username: string; +} + +/** + * The current access request status. + */ +export type AccessRequestResponseBodyStatus = typeof AccessRequestResponseBodyStatus[keyof typeof AccessRequestResponseBodyStatus]; + + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const AccessRequestResponseBodyStatus = { + REQUESTED: 'REQUESTED', + GRANTED: 'GRANTED', + EXPIRED: 'EXPIRED', + DENIED: 'DENIED', +} as const; + +export interface AccessRequestResponseBody { + /** A URL to the JSON Schema for this object. */ + readonly $schema?: string; + /** The timestamp the access will expire (RFC3339 format). */ + expiresAt?: string; + /** A human readeable description with details about the access request. */ + message?: string; + /** The access request name. */ + name: string; + /** The access request namespace. */ + namespace: string; + /** The current permission description for the user. */ + permission: string; + /** The timestamp the access was requested (RFC3339 format). */ + requestedAt?: string; + /** The current role the user is associated with. */ + role?: string; + /** The current access request status. */ + status?: AccessRequestResponseBodyStatus; + /** The user associated with the access request. */ + username: string; +} + + + + + + /** + * Will retrieve a list of accessrequests respecting the search criteria provided as query params. + * @summary List AccessRequests + */ +export const listAccessrequest = >( + params?: ListAccessrequestParams, options?: AxiosRequestConfig + ): Promise => { + return axios.get( + `/accessrequests`,{ + ...options, + params: {...params, ...options?.params},} + ); + } + +/** + * Will create an access request for the given user and application. + * @summary Create AccessRequest + */ +export const createAccessrequest = >( + createAccessRequestBody: NonReadonly, options?: AxiosRequestConfig + ): Promise => { + return axios.post( + `/accessrequests`, + createAccessRequestBody,options + ); + } + +/** + * Will retrieve the accessrequest by name + * @summary Get AccessRequest + */ +export const getAccessrequestByName = >( + name: string, + params?: GetAccessrequestByNameParams, options?: AxiosRequestConfig + ): Promise => { + return axios.get( + `/accessrequests/${name}`,{ + ...options, + params: {...params, ...options?.params},} + ); + } + +export type ListAccessrequestResult = AxiosResponse +export type CreateAccessrequestResult = AxiosResponse +export type GetAccessrequestByNameResult = AxiosResponse diff --git a/ui/package.json b/ui/package.json index 53a9703..529c9ca 100644 --- a/ui/package.json +++ b/ui/package.json @@ -10,14 +10,15 @@ "@react-buddy/ide-toolbox": "^2.4.0", "@react-buddy/palette-antd": "^5.3.0", "antd": "^5.20.0", - "argo-ui": "git+https://github.com/argoproj/argo-ui.git", "classnames": "^2.5.1", "moment": "^2.29.4", - "react": "^16.9.3", - "react-dom": "^16.9.3", + "moment-timezone": "^0.5.33", + "react-moment": "^0.9.7", "react-router-dom": "^6.25.1", "react-hot-loader": "^3.1.3", - "react-moment": "^0.9.7" + "@tanstack/react-query": "4.36.1", + "@tanstack/react-query-devtools": "^5.59.0", + "axios": "1.6.2" }, "peerDependencies": { "moment": "^2.29.4", @@ -46,8 +47,8 @@ ] }, "devDependencies": { - "@types/react": "^17.0.44", - "@types/react-dom": "^17.0.9", + "@types/react": "^16.9.3", + "@types/react-dom": "^16.9.3", "@types/react-helmet": "^6.1.0", "@types/react-router-dom": "^5.1.8", "@types/styled-components": "^5.1.25", @@ -57,7 +58,6 @@ "portable-fetch": "^3.0.0", "prettier": "3.3.3", "raw-loader": "0.5.1", - "react-dom": "^17.0.2", "react-keyhooks": "^0.2.3", "rxjs": "^7.1.0", "sass": "1.34.1", @@ -68,5 +68,11 @@ "webpack": "^5.75.0", "webpack-bundle-analyzer": "^4.8.0", "webpack-cli": "^4.7.2" - } + }, + "resolutions": { + "@types/react": "^18.0.26", + "@types/react-dom": "^18.0.26", + "react-toastify": "9.0.8" + }, + "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" } diff --git a/ui/src/component/access-details.tsx b/ui/src/component/access-details.tsx deleted file mode 100644 index 1a8aa5e..0000000 --- a/ui/src/component/access-details.tsx +++ /dev/null @@ -1,166 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import { BUTTON_LABELS } from '../constant'; -import { getAccess, requestAccess } from '../config/client'; -import { UserInfo, Application, AccessRequest } from '../models/type'; -import { Spinner } from '../utils/utils'; -import './access-details.scss'; -import moment from 'moment/moment'; - -interface AccessDetailsomponentProps { - application: Application; - userInfo: UserInfo; -} - -const requestAccessHandler = async ( - application: Application, - userInfo: UserInfo, - setInitiated: React.Dispatch>, - setAccessRequest: React.Dispatch>, -) => { - try { - const response: AccessRequest = await requestAccess(application, userInfo.username); - if (response) { - localStorage.setItem(application.metadata.name, JSON.stringify(response)); - } - setAccessRequest(response); - setInitiated(true); - } catch (error) { - console.error('Error requesting access:', error); - setInitiated(false); - } -}; - -const AccessDetails: React.FC = ({ application, userInfo }) => { - const [accessRequest, setAccessRequest] = useState( - JSON.parse(localStorage.getItem(application?.metadata?.name)) || (null as AccessRequest) - ); - const [initiated, setInitiated] = useState(false); - useEffect(() => { - const interval = setInterval(async () => { - const response = await getAccess(application, userInfo.username); - - if (response && response?.items) { - setInitiated(true); - setAccessRequest(response?.items[0]); - } - if (accessRequest?.status === 'EXPIRED') { - localStorage.removeItem(application.metadata.name); - setAccessRequest({} as AccessRequest); - } - }, 5000); - - return () => clearInterval(interval); - }, []); - - const cancel = () => { - setAccessRequest({} as AccessRequest); - setInitiated(false); - }; - return ( -
- - - -
- -
-
- About Requesting Temporary Access -
-
- {window.GLOBAL_ARGOCD_ACCESS_EXT_MAIN_BANNER} - {window.GLOBAL_ARGOCD_ACCESS_EXT_MAIN_BANNER_ADDITIONAL_INFO_LINK && ( - - {' '} - Read more. - - )} -
-
-
- -
-
-

USER'S CURRENT PERMISSION

- -
-
USER NAME
-
{userInfo?.username?.toUpperCase()}
-
-
-
PERMISSION
-
- {accessRequest?.permission?.toUpperCase() || 'Read Only'} -
-
- {accessRequest?.expiresAt && ( -
-
-
REQUEST DATA
-
- {moment(accessRequest?.requestedAt).format('MMMM Do YYYY, h:mm:ss a')} -
-
-
-
ROLE
-
{accessRequest?.role?.toUpperCase()}
-
-
-
STATUS
-
{accessRequest?.status?.toUpperCase()}
-
-
-
MESSAGE
-
- {accessRequest?.status === 'PENDING' ? ( - - {accessRequest?.message} - - Click to create change request - - - ) : ( - accessRequest?.message - )} -
-
- {accessRequest?.status === 'ACTIVE' && accessRequest?.expiresAt && ( -
-
Access Expires:
-
- {moment(accessRequest?.expiresAt).format('MMMM Do YYYY, h:mm:ss a')} -
-
- )} -
- )} -
-
-
- ); -}; - -export default AccessDetails; diff --git a/ui/src/component/access-panel.tsx b/ui/src/component/access-panel.tsx deleted file mode 100644 index 2178e3c..0000000 --- a/ui/src/component/access-panel.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import moment from 'moment'; -import { AccessRequest, Application } from '../models/type'; -import { ARGO_GRAY6_COLOR } from '../shared/colors'; -import { HelpIcon } from 'argo-ui/src/components/help-icon/help-icon'; -import { AccessPanel } from '../utils/utils'; -import { TIME_FORMAT } from '../constant'; - -const DisplayAccessPermission: React.FC<{ application: Application }> = ({ application }) => { - const [accessRequest, setAccessRequest] = useState(null); - - useEffect(() => { - const checkPermission = () => { - const storedPermission = localStorage.getItem(application.metadata?.name); - if (storedPermission) { - const parsedPermission = JSON.parse(storedPermission); - const expiryTime = moment(parsedPermission.accessExpires, TIME_FORMAT); - const diffInSeconds = expiryTime.diff(moment(), 'seconds'); - if (diffInSeconds <= 0) { - localStorage.removeItem(application.metadata?.name); - setAccessRequest(null); - } else { - setAccessRequest(parsedPermission); - } - } else { - setAccessRequest(null); - } - }; - - const intervalId = setInterval(checkPermission, 1000); - return () => clearInterval(intervalId); - }, [application.metadata?.name]); - - return application?.metadata?.labels && - window?.GLOBAL_ARGOCD_ACCESS_EXT_LABEL_KEY && - application?.metadata?.labels[window?.GLOBAL_ARGOCD_ACCESS_EXT_LABEL_KEY] === - window?.GLOBAL_ARGOCD_ACCESS_EXT_LABEL_VALUE ? ( -
- -
-
( - - )} - style={{ - color: 'green', - marginRight: '5px', - position: 'relative', - top: '2px', - display: 'flex', - alignItems: 'center', - paddingTop: '10px', - fontSize: '12px', - fontFamily: 'inherit' - }} - > -
- -
-
- - {accessRequest?.expiresAt && ( -
- Expires:   - {moment(accessRequest.expiresAt, TIME_FORMAT).diff(moment(), 'seconds')} seconds -
- )} -
-
- ) : null; -}; - -export default DisplayAccessPermission; diff --git a/ui/src/component/access-details.scss b/ui/src/component/ephemeral-access-details.scss similarity index 91% rename from ui/src/component/access-details.scss rename to ui/src/component/ephemeral-access-details.scss index 10583d3..6622b81 100644 --- a/ui/src/component/access-details.scss +++ b/ui/src/component/ephemeral-access-details.scss @@ -32,6 +32,10 @@ font-family: 'Roboto', sans-serif; font-size: 14px; font-weight: 400; + margin-left: 8px; + a { + padding: 10px; + } } } } diff --git a/ui/src/component/ephemeral-access-details.tsx b/ui/src/component/ephemeral-access-details.tsx new file mode 100644 index 0000000..808bce0 --- /dev/null +++ b/ui/src/component/ephemeral-access-details.tsx @@ -0,0 +1,270 @@ +import React, { useEffect, useState, useCallback } from 'react'; +import { ToastContainer, toast } from 'react-toastify'; +import 'react-toastify/dist/ReactToastify.css'; + +import { BUTTON_LABELS } from '../constant'; +import { UserInfo, Application } from '../models/type'; +import { Spinner } from '../utils/utils'; +import './ephemeral-access-details.scss'; +import moment from 'moment/moment'; + +import { + AccessRequestResponseBody, + AccessRequestResponseBodyStatus, + createAccessrequest, + CreateAccessRequestBody, + listAccessrequest +} from '../gen/ephemeralAccessAPI'; +import { getHeaders } from '../config/client'; + +interface AccessDetailsComponentProps { + application: Application; + userInfo: UserInfo; +} + +const EphemeralAccessDetails: React.FC = ({ + application: application, + userInfo +}) => { + const [accessRequest, setAccessRequest] = useState(null); + const [enabled, setEnabled] = useState(accessRequest === null); + const applicationNamespace = application?.metadata?.namespace || ''; + const applicationName = application?.metadata?.name || ''; + const project = application?.spec?.project || ''; + const username = userInfo?.username; + const notify = (msg: string) => toast.warning('system message: ' + msg); + + const fetchAccess = useCallback(async (): Promise => { + try { + const { data } = await listAccessrequest({ + baseURL: '/extensions/ephemeral/', + headers: getHeaders({ applicationName, applicationNamespace, project, username }) + }); + const accessRequestData = data.items[0]; + if (data && data.items.length > 0) { + setAccessRequest(accessRequestData); + setEnabled(false); + localStorage.setItem( + application?.metadata?.name, + JSON.stringify( + data.items.find((item) => item.status === AccessRequestResponseBodyStatus.GRANTED) || + null + ) + ); + } else { + setEnabled(true); + localStorage.setItem(application?.metadata?.name, 'null'); + } + + if (accessRequest && accessRequest.status === AccessRequestResponseBodyStatus.GRANTED) { + setEnabled(false); + } + return accessRequestData; + } catch (error) { + setEnabled(true); + notify('Failed to connect to backend: ' + error.message); + } + return null; + }, []); + + const requestAccessHandler = useCallback(async (): Promise => { + try { + const { data } = await createAccessrequest( + { + roleName: window?.EPHEMERAL_ACCESS_VARS?.EPHEMERAL_ACCESS_DEFAULT_ROLE + }, + { + baseURL: '/extensions/ephemeral/', + headers: getHeaders({ applicationName, applicationNamespace, project, username }) + } + ); + + if ( + data.status === AccessRequestResponseBodyStatus.GRANTED || + data.status === AccessRequestResponseBodyStatus.DENIED + ) { + setEnabled(false); + } else { + const intervalId = setInterval(async () => { + const accessData = await fetchAccess(); + if ( + accessData?.status === AccessRequestResponseBodyStatus.GRANTED || + accessData?.status === AccessRequestResponseBodyStatus.DENIED + ) { + setEnabled(false); + clearInterval(intervalId); + } + }, 500); + } + } catch (error) { + setEnabled(true); + if (error.response.status === 409) { + notify('Permission request already exists'); + const accessData = await fetchAccess(); + if ( + accessData?.status === AccessRequestResponseBodyStatus.GRANTED || + accessData?.status === AccessRequestResponseBodyStatus.DENIED + ) { + setAccessRequest(accessData); + setEnabled(false); + } + } + if (error.response.status === 401) { + notify('Extension is not enabled'); + setEnabled(false); + } + + if (error.response.status === 502) { + notify('Error occurred while requesting permission'); + setEnabled(false); + } + return null; + } + }, [applicationName, applicationNamespace, project, username, fetchAccess]); + + useEffect(() => { + const fetchData = async () => { + const currentAccess = await fetchAccess(); + switch (currentAccess?.status) { + case AccessRequestResponseBodyStatus.GRANTED: + setEnabled(false); + break; + case AccessRequestResponseBodyStatus.DENIED: + notify('last request was denied: ' + accessRequest?.message + '. Please try again!'); + setEnabled(true); + setAccessRequest(null); + break; + case AccessRequestResponseBodyStatus.REQUESTED: + setEnabled(false); + break; + default: + setEnabled(true); + break; + } + }; + fetchData(); + }, []); + + const cancel = useCallback(() => { + setAccessRequest(null); + setEnabled(true); + }, []); + + return ( +
+ + + +
+ +
+
+ About Requesting Temporary Access +
+
+ {window?.EPHEMERAL_ACCESS_VARS?.EPHEMERAL_ACCESS_MAIN_BANNER} + {window?.EPHEMERAL_ACCESS_VARS?.EPHEMERAL_ACCESS_MAIN_BANNER_ADDITIONAL_INFO_LINK && ( + + Read More + + )} +
+
+
+
+
+

USER'S CURRENT PERMISSION

+ +
+
USER NAME
+
{userInfo?.username?.toUpperCase()}
+
+
+
PERMISSION
+
{accessRequest?.permission || 'Read Only'}
+
+ {accessRequest && ( +
+
+
REQUEST DATA
+
+ {moment(accessRequest?.requestedAt).format('MMMM Do YYYY, h:mm:ss a')} +
+
+
+
ROLE
+
{accessRequest?.role}
+
+
+
STATUS
+
{accessRequest?.status}
+
+ + {accessRequest?.expiresAt && ( +
+
EXPIRES
+
+ {moment(accessRequest?.expiresAt).format('MMMM Do YYYY, h:mm:ss a')} +
+
+ )} +
+
MESSAGE
+
+ {accessRequest?.status === AccessRequestResponseBodyStatus.REQUESTED ? ( + + {accessRequest?.message} + {window?.EPHEMERAL_ACCESS_VARS?.EPHEMERAL_ACCESS_CHANGE_REQUEST_URL && ( + + Click here to create + + )} + + ) : ( + accessRequest?.message + )} +
+
+
+ )} +
+
+ +
+ ); +}; + +export default EphemeralAccessDetails; diff --git a/ui/src/component/ephemeral-access-panel.tsx b/ui/src/component/ephemeral-access-panel.tsx new file mode 100644 index 0000000..1d529ac --- /dev/null +++ b/ui/src/component/ephemeral-access-panel.tsx @@ -0,0 +1,105 @@ +import React, { useEffect, useState, useCallback } from 'react'; +import moment from 'moment'; +import { Application } from '../models/type'; +import { ARGO_GRAY6_COLOR } from '../shared/colors'; +import { HelpIcon } from 'argo-ui/src/components/help-icon/help-icon'; +import { AccessPanel, EnableEphemeralAccess } from '../utils/utils'; +import { AccessRequestResponseBody } from '../gen/ephemeralAccessAPI'; +import { getDisplayTime } from '../utils/utils'; +const DisplayAccessPermission: React.FC<{ application: Application }> = ({ application }) => { + const [accessRequest, setAccessRequest] = useState(null); + + const getPermissions = useCallback(() => { + const accessPermission = JSON.parse(localStorage.getItem(application.metadata?.name)); + + if (accessPermission) { + const expiryTime = moment.parseZone(accessPermission.expiresAt); + setAccessRequest(accessPermission); + const diffInSeconds = expiryTime.diff(moment(), 'seconds'); + + if (diffInSeconds <= 0) { + // Access expired, remove from local storage and set to null + localStorage.removeItem(application.metadata?.name); + setAccessRequest(null); + } else { + setAccessRequest(accessPermission); + } + } + }, [application.metadata?.name]); + + const validatePermissions = () => { + const accessPermission = JSON.parse(localStorage.getItem(application.metadata?.name)); + if (accessPermission === null) { + localStorage.removeItem(application.metadata?.name); + setAccessRequest(null); + } + }; + + useEffect(() => { + const intervalId = setInterval(() => { + getPermissions(); + validatePermissions(); + }, 500); + + return () => clearInterval(intervalId); + }, [getPermissions]); + + + const handleLinkClick = useCallback(() => { + window.location.href = `/applications/argocd/${application.metadata.name}?view=tree&resource=&extension=ephemeral_access`; + }, []); + + return EnableEphemeralAccess(application) ? ( +
+ +
+
+
+ +
+
+ + {accessRequest?.expiresAt && ( +
+ Expires In:   + {getDisplayTime(accessRequest)} +
+ )} +
+
+ ) : null; +}; + +export default DisplayAccessPermission; diff --git a/ui/src/config/client.ts b/ui/src/config/client.ts index e4e7189..1afdb6a 100644 --- a/ui/src/config/client.ts +++ b/ui/src/config/client.ts @@ -1,42 +1,5 @@ -import { UserInfo, Application } from '../models/type'; +import { UserInfo } from '../models/type'; -export async function getAccess(application: Application, username: string) { - const applicationNamespace = application?.spec?.destination?.namespace || ''; - const applicationName = application?.metadata?.name || ''; - const project = application?.spec?.project || ''; - - const url = `/extensions/access/accessrequests`; - return fetch(url, { - headers: getHeaders({ applicationName, applicationNamespace, project, username }) - }) - .then((response) => { - return response.json(); - }) - .catch((err) => { - return {}; - }); -} - -export async function requestAccess(application: Application, username: string) { - const applicationNamespace = application?.spec?.destination?.namespace || ''; - const applicationName = application?.metadata?.name || ''; - const project = application?.spec?.project || ''; - const url = `/extensions/access/accessrequests`; - const argocdApplicationName = `${applicationNamespace}:${applicationName}`; - - try { - return await fetch(url, { - method: 'POST', - headers: getHeaders({ applicationName, applicationNamespace, project, username }), - body: JSON.stringify({ appName: argocdApplicationName, username: username }) - }).then((response) => { - return response.json(); - }); - } catch (err) { - console.error('Error updating Access:', err); - throw err; - } -} //Creates and returns the custom headers needed for the argocd extensions. export function getHeaders({ @@ -54,10 +17,8 @@ export function getHeaders({ return { 'cache-control': 'no-cache', 'Content-Type': 'application/json', - 'Argocd-Application-Name': `${argocdApplicationName}`, - 'Argocd-Project-Name': `${project}`, - 'Argocd-Username': `${username}`, - 'Argocd-User-Groups': 'dummy' + "Argocd-Application-Name": `${argocdApplicationName}`, + "Argocd-Project-Name": `${project}`, }; } diff --git a/ui/src/constant.ts b/ui/src/constant.ts index 43a2c19..c7f605d 100644 --- a/ui/src/constant.ts +++ b/ui/src/constant.ts @@ -4,7 +4,7 @@ export const BUTTON_LABELS = { CANCEL: "Cancel", }; -export const Access_READ_COLOR = '#18BE94'; -export const Access_WRITE_COLOR = '#DE303D'; +export const ACCESS_DEFAULT_COLOR = '#18BE94'; +export const ACCESS_PERMISSION_COLOR = '#f4c030'; -export const TIME_FORMAT = 'YYYY-MM-DD HH:MM:SSZ' +export const TIME_FORMAT = 'YYYY-MM-DDTHH:mm:ssZ' diff --git a/ui/src/access.tsx b/ui/src/ephemeral-access.tsx similarity index 61% rename from ui/src/access.tsx rename to ui/src/ephemeral-access.tsx index 5c55160..4f70e8e 100644 --- a/ui/src/access.tsx +++ b/ui/src/ephemeral-access.tsx @@ -1,7 +1,10 @@ import React, { useEffect, useState } from 'react'; -import AccessDetails from './component/access-details'; +import EphemeralAccessDetails from './component/ephemeral-access-details'; import { getUserInfo } from './config/client'; -import { UserInfo } from './models/type'; +import { Application, UserInfo } from './models/type'; +import { EnableEphemeralAccess } from './utils/utils'; + + export const RequestAccessBtn = () => { return ( @@ -13,13 +16,8 @@ export const RequestAccessBtn = () => { ); }; -export const ShowDeployBtn = (application: any) => { - return ( - application?.metadata?.labels && - window?.GLOBAL_ARGOCD_ACCESS_EXT_LABEL_KEY && - application?.metadata?.labels[window?.GLOBAL_ARGOCD_ACCESS_EXT_LABEL_KEY] === - window?.GLOBAL_ARGOCD_ACCESS_EXT_LABEL_VALUE - ); +export const ShowDeployBtn = (application: Application) => { + return EnableEphemeralAccess(application); }; interface RequestAccessBtnFlyoutProps { @@ -40,5 +38,5 @@ export const RequestAccessBtnFlyout = ({ application }: RequestAccessBtnFlyoutPr fetchUserInfo(); }, [application]); - return <>{userInfo && }; + return <>{userInfo && }; }; diff --git a/ui/src/gen/ephemeralAccessAPI.ts b/ui/src/gen/ephemeralAccessAPI.ts new file mode 100644 index 0000000..b51706b --- /dev/null +++ b/ui/src/gen/ephemeralAccessAPI.ts @@ -0,0 +1,150 @@ +/** + * Generated by orval v7.1.1 🍺 + * Do not edit manually. + * Ephemeral Access API + * OpenAPI spec version: 0.0.1 + */ +import axios from 'axios' +import type { + AxiosRequestConfig, + AxiosResponse +} from 'axios' + +// https://stackoverflow.com/questions/49579094/typescript-conditional-types-filter-out-readonly-properties-pick-only-requir/49579497#49579497 +type IfEquals = (() => T extends X ? 1 : 2) extends < +T, +>() => T extends Y ? 1 : 2 +? A +: B; + +type WritableKeys = { +[P in keyof T]-?: IfEquals< + { [Q in P]: T[P] }, + { -readonly [Q in P]: T[P] }, + P +>; +}[keyof T]; + +type UnionToIntersection = + (U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never; +type DistributeReadOnlyOverUnions = T extends any ? NonReadonly : never; + +type Writable = Pick>; +type NonReadonly = [T] extends [UnionToIntersection] ? { + [P in keyof Writable]: T[P] extends object + ? NonReadonly> + : T[P]; +} : DistributeReadOnlyOverUnions; + +export interface ListAccessRequestResponseBody { + /** A URL to the JSON Schema for this object. */ + readonly $schema?: string; + /** @nullable */ + items: AccessRequestResponseBody[] | null; +} + +export interface ErrorDetail { + /** Where the error occurred, e.g. 'body.items[3].tags' or 'path.thing-id' */ + location?: string; + /** Error message text */ + message?: string; + /** The value at the given location */ + value?: unknown; +} + +export interface ErrorModel { + /** A URL to the JSON Schema for this object. */ + readonly $schema?: string; + /** A human-readable explanation specific to this occurrence of the problem. */ + detail?: string; + /** + * Optional list of individual error details + * @nullable + */ + errors?: ErrorDetail[] | null; + /** A URI reference that identifies the specific occurrence of the problem. */ + instance?: string; + /** HTTP status code */ + status?: number; + /** A short, human-readable summary of the problem type. This value should not change between occurrences of the error. */ + title?: string; + /** A URI reference to human-readable documentation for the error. */ + type?: string; +} + +export interface CreateAccessRequestBody { + /** A URL to the JSON Schema for this object. */ + readonly $schema?: string; + /** The role template name to request. */ + roleName: string; +} + +/** + * The current access request status. + */ +export type AccessRequestResponseBodyStatus = typeof AccessRequestResponseBodyStatus[keyof typeof AccessRequestResponseBodyStatus]; + + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const AccessRequestResponseBodyStatus = { + REQUESTED: 'REQUESTED', + GRANTED: 'GRANTED', + EXPIRED: 'EXPIRED', + DENIED: 'DENIED', + INVALID: 'INVALID', +} as const; + +export interface AccessRequestResponseBody { + /** A URL to the JSON Schema for this object. */ + readonly $schema?: string; + /** The timestamp the access will expire (RFC3339 format). */ + expiresAt?: string; + /** A human readeable description with details about the access request. */ + message?: string; + /** The access request name. */ + name: string; + /** The access request namespace. */ + namespace: string; + /** The permission description of the role associated to this access request. */ + permission: string; + /** The timestamp the access was requested (RFC3339 format). */ + requestedAt?: string; + /** The role template associated to this access request. */ + role: string; + /** The current access request status. */ + status?: AccessRequestResponseBodyStatus; + /** The user associated with the access request. */ + username: string; +} + + + + + + /** + * Will retrieve an ordered list of access requests for the given context + * @summary List AccessRequests + */ +export const listAccessrequest = >( + options?: AxiosRequestConfig + ): Promise => { + return axios.get( + `/accessrequests`,options + ); + } + +/** + * Will create an access request for the given role and context + * @summary Create AccessRequest + */ +export const createAccessrequest = >( + createAccessRequestBody: NonReadonly, options?: AxiosRequestConfig + ): Promise => { + return axios.post( + `/accessrequests`, + createAccessRequestBody,options + ); + } + +export type ListAccessrequestResult = AxiosResponse +export type CreateAccessrequestResult = AxiosResponse diff --git a/ui/src/gen/transformers/axiosInstance.ts b/ui/src/gen/transformers/axiosInstance.ts new file mode 100644 index 0000000..2ce498b --- /dev/null +++ b/ui/src/gen/transformers/axiosInstance.ts @@ -0,0 +1,29 @@ +import Axios, { AxiosRequestConfig } from 'axios'; + +/** + * the axios instance that will be used to make the requests. + * its config can be modified at runtime. + */ +export const AXIOS_INSTANCE = Axios.create({ baseURL: '/extensions/ephemeral/' }); + +/** + * whenever we need to make a request, this function takes an axios config object + * and applies it to our shared axios instance. + * this lets us make changes to the shared instance, and have them applied + * whenever we make a request. + */ +export const injectAxios = (config: AxiosRequestConfig): Promise => { + const source = Axios.CancelToken.source(); + const promise = AXIOS_INSTANCE({ ...config, cancelToken: source.token }).then( + ({ data }) => data + ); + + // @ts-ignore + promise.cancel = () => { + source.cancel('Query was cancelled by React Query'); + }; + + return promise; +}; + +export default injectAxios; \ No newline at end of file diff --git a/ui/src/gen/transformers/index.ts b/ui/src/gen/transformers/index.ts new file mode 100644 index 0000000..78cd8d9 --- /dev/null +++ b/ui/src/gen/transformers/index.ts @@ -0,0 +1 @@ +export { AXIOS_INSTANCE } from './axiosInstance'; diff --git a/ui/src/global.d.ts b/ui/src/global.d.ts index 4a94306..bc5ea84 100644 --- a/ui/src/global.d.ts +++ b/ui/src/global.d.ts @@ -1,7 +1,11 @@ interface Window { - GLOBAL_ARGOCD_ACCESS_EXT_LABEL_KEY: string; - GLOBAL_ARGOCD_ACCESS_EXT_LABEL_VALUE: string; - GLOBAL_ARGOCD_ACCESS_EXT_MAIN_BANNER: string; - GLOBAL_ARGOCD_ACCESS_EXT_MAIN_BANNER_ADDITIONAL_INFO_LINK: string; - GLOBAL_ARGOCD_ACCESS_EXT_CHANGE_REQUEST_URL: string; + EPHEMERAL_ACCESS_VARS: { + EPHEMERAL_ACCESS_LABEL_KEY: string; + EPHEMERAL_ACCESS_LABEL_VALUE: string; + EPHEMERAL_ACCESS_MAIN_BANNER: string; + EPHEMERAL_ACCESS_MAIN_BANNER_ADDITIONAL_INFO_LINK: string; + EPHEMERAL_ACCESS_CHANGE_REQUEST_URL: string; + EPHEMERAL_ACCESS_DEFAULT_ROLE: string; + }; } + diff --git a/ui/src/index.tsx b/ui/src/index.tsx index 502e6ad..f8644fa 100644 --- a/ui/src/index.tsx +++ b/ui/src/index.tsx @@ -1,23 +1,21 @@ -import { RequestAccessBtnFlyout, RequestAccessBtn, ShowDeployBtn } from './access'; -import DisplayAccessPermission from './component/access-panel'; +import { RequestAccessBtnFlyout, RequestAccessBtn, ShowDeployBtn } from './ephemeral-access'; +import DisplayAccessPermission from './component/ephemeral-access-panel'; const PERMISSION_TITLE = "Ephemeral Access"; const PERMISSION_ID = "ephemeral_access"; const DISPLAY_PERMISSION_TITLE = "Display_Ephemeral Access"; const DISPLAY_PERMISSION_ID = "display_ephemeral_access"; +function initializeExtensions(window: any) { + window.extensionsAPI = window.extensionsAPI || {}; - - -((window: any) => { - window?.extensionsAPI?.registerStatusPanelExtension( + window.extensionsAPI.registerStatusPanelExtension( DisplayAccessPermission, DISPLAY_PERMISSION_TITLE, DISPLAY_PERMISSION_ID - )})(window); + ); -((window: any) => { - window?.extensionsAPI?.registerTopBarActionMenuExt( + window.extensionsAPI.registerTopBarActionMenuExt( RequestAccessBtn, PERMISSION_TITLE, PERMISSION_ID, @@ -25,4 +23,10 @@ const DISPLAY_PERMISSION_ID = "display_ephemeral_access"; ShowDeployBtn, '', true - )})(window); \ No newline at end of file + ); +} + +// Entry point +((window: any) => { + initializeExtensions(window); +})(window); \ No newline at end of file diff --git a/ui/src/models/type.ts b/ui/src/models/type.ts index 27ec262..290e4ea 100644 --- a/ui/src/models/type.ts +++ b/ui/src/models/type.ts @@ -26,6 +26,7 @@ export interface Application { metadata: { name: string; labels: any + namespace: string; }; } diff --git a/ui/src/tsconfig.json b/ui/src/tsconfig.json index 421584a..47e1361 100644 --- a/ui/src/tsconfig.json +++ b/ui/src/tsconfig.json @@ -1,18 +1,24 @@ { "compilerOptions": { + "module": "CommonJS", "outDir": "./dist", "sourceMap": true, "noImplicitAny": true, - "module": "esnext", "target": "es5", "jsx": "react", + "esModuleInterop": true, "moduleResolution": "node", "experimentalDecorators": true, "noUnusedLocals": true, "declaration": false, "allowSyntheticDefaultImports": true, "lib": ["es2017", "dom"], - "resolveJsonModule": true + "resolveJsonModule": true, + "baseUrl": ".", + "preserveSymlinks": false, + "paths": { + "@ui/*": ["./src/*"], + } }, "include": ["./**/*"], "exclude": ["node_modules"] diff --git a/ui/src/utils/use-local-storage.ts b/ui/src/utils/use-local-storage.ts deleted file mode 100644 index 3770334..0000000 --- a/ui/src/utils/use-local-storage.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { useEffect, useState } from 'react'; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export const useLocalStorage = (key: string, initialValue?: any) => { - const [storedValue, setStoredValue] = useState(() => { - try { - const item = window.localStorage.getItem(key); - return item ? JSON.parse(item) : initialValue; - } catch (_) { - return initialValue; - } - }); - - useEffect(() => { - window.localStorage.setItem(key, JSON.stringify(storedValue)); - }, [storedValue]); - return [storedValue, setStoredValue]; -}; diff --git a/ui/src/utils/utils.tsx b/ui/src/utils/utils.tsx index e9e332b..81848ed 100644 --- a/ui/src/utils/utils.tsx +++ b/ui/src/utils/utils.tsx @@ -1,6 +1,8 @@ import React from 'react'; -import { AccessRequest } from '../models/type'; -import { Access_READ_COLOR, Access_WRITE_COLOR } from '../constant'; +import Moment from 'react-moment'; +import { Application } from '../models/type'; +import { ACCESS_DEFAULT_COLOR, ACCESS_PERMISSION_COLOR } from '../constant'; +import { AccessRequestResponseBody } from '../gen/ephemeralAccessAPI'; export const Spinner = ({ show, style = {} }: { show: boolean; style?: React.CSSProperties }) => show ? ( @@ -10,21 +12,16 @@ export const Spinner = ({ show, style = {} }: { show: boolean; style?: React.CSS ) : null; export enum AccessRole { - Read = 'Read', - Write = 'Write' + DEFAULT_ACCESS = 'Read' } -export const AccessPanel = ({ - accessRequest -}: { - accessRequest: AccessRequest; -}) => { - let color = Access_READ_COLOR; +export const AccessPanel = ({ accessRequest }: { accessRequest: AccessRequestResponseBody }) => { + let color = ACCESS_DEFAULT_COLOR; let icon = 'fa-solid fa-lock'; - if (accessRequest && accessRequest?.permission === 'Write') { - color = Access_WRITE_COLOR; + if (accessRequest) { + color = ACCESS_PERMISSION_COLOR; icon = 'fa-solid fa-unlock'; } else { - color = Access_READ_COLOR; + color = ACCESS_DEFAULT_COLOR; icon = 'fa-solid fa-lock'; } @@ -42,10 +39,34 @@ export const AccessPanel = ({ ); }; -const getRoleTitle = (accessRequest: AccessRequest) => { - if (accessRequest && accessRequest.permission === 'Write') { - return AccessRole.Write; +const getRoleTitle = (accessRequest: AccessRequestResponseBody) => { + if (accessRequest === null) { + return AccessRole.DEFAULT_ACCESS; } else { - return AccessRole.Read; + return accessRequest.permission; } }; + +export const getDisplayTime = (accessRequest: AccessRequestResponseBody): any => { + return ( + + + {new Date(accessRequest.expiresAt)} + + + ); +}; + +export const EnableEphemeralAccess = (application: Application) => { + if (window?.EPHEMERAL_ACCESS_VARS === undefined || window?.EPHEMERAL_ACCESS_VARS?.EPHEMERAL_ACCESS_LABEL_KEY === undefined + || window?.EPHEMERAL_ACCESS_VARS?.EPHEMERAL_ACCESS_LABEL_VALUE === undefined) { + return true; + } + + return ( + application?.metadata?.labels && + window?.EPHEMERAL_ACCESS_VARS?.EPHEMERAL_ACCESS_LABEL_KEY && + application?.metadata?.labels[window?.EPHEMERAL_ACCESS_VARS?.EPHEMERAL_ACCESS_LABEL_KEY] === + window?.EPHEMERAL_ACCESS_VARS?.EPHEMERAL_ACCESS_LABEL_VALUE + ); +}; diff --git a/ui/yarn.lock b/ui/yarn.lock index b276644..ca74e18 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -389,6 +389,31 @@ resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.19.2.tgz#0c896535473291cb41f152c180bedd5680a3b273" integrity sha512-baiMx18+IMuD1yyvOGaHM9QrVUPGGG0jC+z+IPHnRJWUAUvaKuWKyE8gjDj2rzv3sz9zOGoRSPgeBVHRhZnBlA== +"@tanstack/query-core@4.36.1": + version "4.36.1" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/@tanstack/query-core/-/query-core-4.36.1.tgz#79f8c1a539d47c83104210be2388813a7af2e524" + integrity sha512-DJSilV5+ytBP1FbFcEJovv4rnnm/CokuVvrBEtW/Va9DvuJ3HksbXUJEpI0aV1KtuL4ZoO9AVE6PyNLzF7tLeA== + +"@tanstack/query-devtools@5.58.0": + version "5.58.0" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/@tanstack/query-devtools/-/query-devtools-5.58.0.tgz#5c68ce90562e154004de4372bc0a28fcd94cdf31" + integrity sha512-iFdQEFXaYYxqgrv63ots+65FGI+tNp5ZS5PdMU1DWisxk3fez5HG3FyVlbUva+RdYS5hSLbxZ9aw3yEs97GNTw== + +"@tanstack/react-query-devtools@^5.59.0": + version "5.59.16" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/@tanstack/react-query-devtools/-/react-query-devtools-5.59.16.tgz#f058e3ba146b97a4763b886074581d66cc1e5cf7" + integrity sha512-Dejo39QBXmDqXZ3vdrk7vHDvs7TvL573/AX2NveMBmRAufAPYuE3oWSKP/gGqkDfEqyr4CmldOj+v9cKskUchQ== + dependencies: + "@tanstack/query-devtools" "5.58.0" + +"@tanstack/react-query@4.36.1": + version "4.36.1" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/@tanstack/react-query/-/react-query-4.36.1.tgz#acb589fab4085060e2e78013164868c9c785e5d2" + integrity sha512-y7ySVHFyyQblPl3J3eQBWpXZkliroki3ARnBKsdJchlgt7yJLRDUcf4B8soufgiYt3pEQIkBWBx1N9/ZPIeUWw== + dependencies: + "@tanstack/query-core" "4.36.1" + use-sync-external-store "^1.2.0" + "@tippy.js/react@^3.1.1": version "3.1.1" resolved "https://registry.yarnpkg.com/@tippy.js/react/-/react-3.1.1.tgz#027e4595e55f31430741fe8e0d92aaddfbe47efd" @@ -432,12 +457,19 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.13.tgz#2af91918ee12d9d32914feb13f5326658461b451" integrity sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA== -"@types/react-dom@^17.0.9": - version "17.0.25" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.25.tgz#e0e5b3571e1069625b3a3da2b279379aa33a0cb5" - integrity sha512-urx7A7UxkZQmThYA4So0NelOVjx3V4rNFVJwp0WZlbIK5eM4rNJDiN3R/E9ix0MBh6kAEojk/9YL+Te6D9zHNA== +"@types/react-dom@^16.9.3": + version "16.9.24" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/@types/react-dom/-/react-dom-16.9.24.tgz#4d193d7d011267fca842e8a10a2d738f92ec5c30" + integrity sha512-Gcmq2JTDheyWn/1eteqyzzWKSqDjYU6KYsIvH7thb7CR5OYInAWOX+7WnKf6PaU/cbdOc4szJItcDEJO7UGmfA== dependencies: - "@types/react" "^17" + "@types/react" "^16" + +"@types/react-dom@^18.0.26": + version "18.3.1" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/@types/react-dom/-/react-dom-18.3.1.tgz#1e4654c08a9cdcfb6594c780ac59b55aad42fe07" + integrity sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ== + dependencies: + "@types/react" "*" "@types/react-helmet@^6.1.0": version "6.1.11" @@ -463,32 +495,14 @@ "@types/history" "^4.7.11" "@types/react" "*" -"@types/react@*": - version "18.3.11" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.11.tgz#9d530601ff843ee0d7030d4227ea4360236bd537" - integrity sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ== +"@types/react@*", "@types/react@^16", "@types/react@^16.9.3", "@types/react@^18.0.26": + version "18.3.12" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/@types/react/-/react-18.3.12.tgz#99419f182ccd69151813b7ee24b792fe08774f60" + integrity sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw== dependencies: "@types/prop-types" "*" csstype "^3.0.2" -"@types/react@^16.9.3": - version "16.14.62" - resolved "https://registry.yarnpkg.com/@types/react/-/react-16.14.62.tgz#449e4e81caaf132d0c2c390644e577702db1dd9e" - integrity sha512-BWf7hqninZav6nerxXj+NeZT/mTpDeG6Lk2zREHAy63CrnXoOGPGtNqTFYFN/sqpSaREDP5otVV88axIXmKfGA== - dependencies: - "@types/prop-types" "*" - "@types/scheduler" "^0.16" - csstype "^3.0.2" - -"@types/react@^17", "@types/react@^17.0.44": - version "17.0.83" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.83.tgz#b477c56387b74279281149dcf5ba2a1e2216d131" - integrity sha512-l0m4ArKJvmFtR4e8UmKrj1pB4tUgOhJITf+mADyF/p69Ts1YAR/E+G9XEM0mHXKVRa1dQNHseyyDNzeuAXfXQw== - dependencies: - "@types/prop-types" "*" - "@types/scheduler" "^0.16" - csstype "^3.0.2" - "@types/scheduler@^0.16": version "0.16.8" resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.8.tgz#ce5ace04cfeabe7ef87c0091e50752e36707deff" @@ -747,7 +761,7 @@ antd@^5.20.0: anymatch@~3.1.2: version "3.1.3" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== dependencies: normalize-path "^3.0.0" @@ -780,6 +794,20 @@ array-tree-filter@^2.1.0: resolved "https://registry.yarnpkg.com/array-tree-filter/-/array-tree-filter-2.1.0.tgz#873ac00fec83749f255ac8dd083814b4f6329190" integrity sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw== +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +axios@1.6.2: + version "1.6.2" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/axios/-/axios-1.6.2.tgz#de67d42c755b571d3e698df1b6504cde9b0ee9f2" + integrity sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A== + dependencies: + follow-redirects "^1.15.0" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + babel-helper-builder-react-jsx@^6.24.1: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz#39ff8313b75c8b65dceff1f31d383e0ff2a408a0" @@ -883,12 +911,12 @@ big.js@^5.2.2: binary-extensions@^2.0.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== braces@^3.0.3, braces@~3.0.2: version "3.0.3" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: fill-range "^7.1.1" @@ -923,7 +951,7 @@ chalk@^4.1.0: "chokidar@>=3.0.0 <4.0.0": version "3.6.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== dependencies: anymatch "~3.1.2" @@ -982,6 +1010,13 @@ colorette@^2.0.14: resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -1048,6 +1083,11 @@ deep-diff@^0.3.5: resolved "https://registry.yarnpkg.com/deep-diff/-/deep-diff-0.3.8.tgz#c01de63efb0eec9798801d40c7e0dae25b582c84" integrity sha512-yVn6RZmHiGnxRKR9sJb3iVV2XTF1Ghh2DiWRZ3dMnGc43yUdWWF/kX6lQyk3+P84iprfWKU/8zFTrlkvtFm1ug== +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + dom-scroll-into-view@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/dom-scroll-into-view/-/dom-scroll-into-view-1.0.1.tgz#32abb92f0d8feca6215162aef43e4b449ab8d99c" @@ -1240,6 +1280,20 @@ flat@^5.0.2: resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== +follow-redirects@^1.15.0: + version "1.15.9" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== + +form-data@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/form-data/-/form-data-4.0.1.tgz#ba1076daaaa5bfd7e99c1a6cb02aa0a5cff90d48" + integrity sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + foundation-sites@^6.4.3: version "6.9.0" resolved "https://registry.yarnpkg.com/foundation-sites/-/foundation-sites-6.9.0.tgz#ef4d51fa1c669cbdf61d080d8a328686ff85992a" @@ -1247,7 +1301,7 @@ foundation-sites@^6.4.3: fsevents@~2.3.2: version "2.3.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== function-bind@^1.1.2: @@ -1264,7 +1318,7 @@ get-tsconfig@^4.6.2: glob-parent@~5.1.2: version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" @@ -1369,7 +1423,7 @@ invariant@^2.2.4: is-binary-path@~2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== dependencies: binary-extensions "^2.0.0" @@ -1388,7 +1442,7 @@ is-extglob@^2.1.1: is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" @@ -1473,7 +1527,7 @@ kind-of@^6.0.2: klona@^2.0.4: version "2.0.6" - resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.6.tgz#85bffbf819c03b2f53270412420a4555ef882e22" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/klona/-/klona-2.0.6.tgz#85bffbf819c03b2f53270412420a4555ef882e22" integrity sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA== loader-runner@^4.2.0: @@ -1529,7 +1583,7 @@ merge-stream@^2.0.0: micromatch@^4.0.0: version "4.0.8" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: braces "^3.0.3" @@ -1540,9 +1594,9 @@ mime-db@1.52.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.27: +mime-types@^2.1.12, mime-types@^2.1.27: version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" @@ -1554,6 +1608,13 @@ min-document@^2.19.0: dependencies: dom-walk "^0.1.0" +moment-timezone@^0.5.33: + version "0.5.46" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/moment-timezone/-/moment-timezone-0.5.46.tgz#a21aa6392b3c6b3ed916cd5e95858a28d893704a" + integrity sha512-ZXm9b36esbe7OmdABqIWJuBBiLLwAjrN7CE+7sYdCCx82Nabt1wHDj8TVseS59QIlfFPbOoiBPm6ca9BioG4hw== + dependencies: + moment "^2.29.4" + moment@^2.29.4: version "2.30.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae" @@ -1584,7 +1645,7 @@ node-releases@^2.0.18: normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== object-assign@^4.0.1, object-assign@^4.1.1: @@ -1645,7 +1706,7 @@ picocolors@^1.0.0, picocolors@^1.1.0: picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== pkg-dir@^4.2.0: @@ -1692,6 +1753,11 @@ prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.6.1, prop-types@^15.6.2, object-assign "^4.1.1" react-is "^16.13.1" +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" @@ -2078,16 +2144,6 @@ react-deep-force-update@^2.1.1: resolved "https://registry.yarnpkg.com/react-deep-force-update/-/react-deep-force-update-2.1.3.tgz#740612322e617bcced38f61794a4af75dc3d98e7" integrity sha512-lqD4eHKVuB65RyO/hGbEST53E2/GPbcIPcFYyeW/p4vNngtH4G7jnKGlU6u1OqrFo0uNfIvwuBOg98IbLHlNEA== -react-dom@^16.9.3: - version "16.14.0" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.14.0.tgz#7ad838ec29a777fb3c75c3a190f661cf92ab8b89" - integrity sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - prop-types "^15.6.2" - scheduler "^0.19.1" - react-fast-compare@^3.1.1: version "3.2.2" resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49" @@ -2221,10 +2277,10 @@ react-side-effect@^2.1.0: resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-2.1.2.tgz#dc6345b9e8f9906dc2eeb68700b615e0b4fe752a" integrity sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw== -react-toastify@9.0.3: - version "9.0.3" - resolved "https://registry.yarnpkg.com/react-toastify/-/react-toastify-9.0.3.tgz#8e6d22651c85cb584c5ebd0b5e2c3bf0d7ec06ee" - integrity sha512-0QZJk0SqYBxouRBGCFU3ymvjlwimRRhVH7SzqGRiVrQ001KSoUNbGKx9Yq42aoPv18n45yJzEFG82zqv3HnASg== +react-toastify@9.0.3, react-toastify@9.0.8: + version "9.0.8" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/react-toastify/-/react-toastify-9.0.8.tgz#3876c89fc6211a29027b3075010b5ec39ebe4f7e" + integrity sha512-EwM+teWt49HSHx+67qI08yLAW1zAsBxCXLCsUfxHYv1W7/R3ZLhrqKalh7j+kjgPna1h5LQMSMwns4tB4ww2yQ== dependencies: clsx "^1.1.1" @@ -2252,7 +2308,7 @@ readable-stream@^2.0.1: readdirp@~3.6.0: version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== dependencies: picomatch "^2.2.1" @@ -2366,7 +2422,7 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: sass-loader@10.2.1: version "10.2.1" - resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-10.2.1.tgz#17e51df313f1a7a203889ce8ff91be362651276e" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/sass-loader/-/sass-loader-10.2.1.tgz#17e51df313f1a7a203889ce8ff91be362651276e" integrity sha512-RRvWl+3K2LSMezIsd008ErK4rk6CulIMSwrcc2aZvjymUgKo/vjXGp1rSWmfTUX7bblEOz8tst4wBwWtCGBqKA== dependencies: klona "^2.0.4" @@ -2377,19 +2433,11 @@ sass-loader@10.2.1: sass@1.34.1: version "1.34.1" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.34.1.tgz#30f45c606c483d47b634f1e7371e13ff773c96ef" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/sass/-/sass-1.34.1.tgz#30f45c606c483d47b634f1e7371e13ff773c96ef" integrity sha512-scLA7EIZM+MmYlej6sdVr0HRbZX5caX5ofDT9asWnUJj21oqgsC+1LuNfm0eg+vM0fCTZHhwImTiCU0sx9h9CQ== dependencies: chokidar ">=3.0.0 <4.0.0" -scheduler@^0.19.1: - version "0.19.1" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" - integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - schema-utils@^2.7.0: version "2.7.1" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7" @@ -2401,7 +2449,7 @@ schema-utils@^2.7.0: schema-utils@^3.0.0, schema-utils@^3.1.1, schema-utils@^3.2.0: version "3.3.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== dependencies: "@types/json-schema" "^7.0.8" @@ -2417,7 +2465,7 @@ scroll-into-view-if-needed@^3.1.0: semver@^7.3.2, semver@^7.3.4: version "7.6.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== serialize-javascript@^6.0.1: @@ -2655,6 +2703,11 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +use-sync-external-store@^1.2.0: + version "1.2.2" + resolved "https://registry.npmjs.intuit.com:443/artifactory/api/npm/npm-intuit/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz#c3b6390f3a30eba13200d2302dcdf1e7b57b2ef9" + integrity sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw== + util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"