From 1cda196bdf54be38188521952a6344ef91d32486 Mon Sep 17 00:00:00 2001 From: nikhagra Date: Mon, 26 Aug 2024 09:45:26 +0530 Subject: [PATCH 001/474] upcoming: [DI-20360] - Modified user preference logic --- packages/api-v4/src/cloudpulse/dashboards.ts | 15 ++- packages/api-v4/src/cloudpulse/services.ts | 6 +- packages/api-v4/src/cloudpulse/types.ts | 4 +- packages/manager/src/MainContent.tsx | 2 +- .../src/components/PrimaryNav/PrimaryNav.tsx | 2 +- .../Dashboard/CloudPulseDashboard.tsx | 6 +- .../Dashboard/CloudPulseDashboardLanding.tsx | 12 +- .../CloudPulse/Overview/GlobalFilters.tsx | 25 ++-- .../CloudPulse/Utils/FilterBuilder.ts | 30 ++++- .../CloudPulse/Utils/UserPreference.ts | 121 +++++++----------- .../CloudPulse/Widget/CloudPulseWidget.tsx | 72 +++++------ .../CloudPulseAggregateFunction.tsx | 25 +++- .../components/CloudPulseIntervalSelect.tsx | 29 +++-- .../CloudPulseDashboardFilterBuilder.tsx | 18 ++- .../shared/CloudPulseDashboardSelect.tsx | 22 ++-- .../shared/CloudPulseRegionSelect.tsx | 24 ++-- .../shared/CloudPulseResourcesSelect.tsx | 22 ++-- .../shared/CloudPulseTimeRangeSelect.tsx | 38 +++--- .../manager/src/queries/cloudpulse/metrics.ts | 8 +- packages/manager/src/request.tsx | 2 +- 20 files changed, 261 insertions(+), 222 deletions(-) diff --git a/packages/api-v4/src/cloudpulse/dashboards.ts b/packages/api-v4/src/cloudpulse/dashboards.ts index 32b9bbf3c31..29fa9e8dd45 100644 --- a/packages/api-v4/src/cloudpulse/dashboards.ts +++ b/packages/api-v4/src/cloudpulse/dashboards.ts @@ -1,7 +1,7 @@ import { ResourcePage } from 'src/types'; -import Request, { setMethod, setURL } from '../request'; +import Request, { setHeaders, setMethod, setURL } from '../request'; import { Dashboard } from './types'; -import { API_ROOT } from 'src/constants'; +// import { API_ROOT } from 'src/constants'; // Returns the list of all the dashboards available export const getDashboards = (serviceType: string) => @@ -16,6 +16,13 @@ export const getDashboards = (serviceType: string) => export const getDashboardById = (dashboardId: number) => Request( - setURL(`${API_ROOT}/monitor/dashboards/${encodeURIComponent(dashboardId)}`), - setMethod('GET') + setURL( + `https://blr-lhv95n.bangalore.corp.akamai.com:9000/v4beta/monitor/dashboards/${encodeURIComponent( + dashboardId + )}` + ), + setMethod('GET'), + setHeaders({ + Authorization: 'Bearer vagrant', + }) ); diff --git a/packages/api-v4/src/cloudpulse/services.ts b/packages/api-v4/src/cloudpulse/services.ts index 0ace1f4ceea..fb17cc506ca 100644 --- a/packages/api-v4/src/cloudpulse/services.ts +++ b/packages/api-v4/src/cloudpulse/services.ts @@ -22,12 +22,16 @@ export const getMetricDefinitionsByServiceType = (serviceType: string) => { export const getJWEToken = (data: JWETokenPayLoad, serviceType: string) => Request( setURL( - `${API_ROOT}/monitor/services/${encodeURIComponent(serviceType)}/token` + `${API_ROOT}/monitor/services/${encodeURIComponent( + serviceType + )}/token` ), setMethod('POST'), setData(data) ); + + // Returns the list of service types available export const getCloudPulseServiceTypes = () => Request( diff --git a/packages/api-v4/src/cloudpulse/types.ts b/packages/api-v4/src/cloudpulse/types.ts index 2c9c7f57662..e2979316945 100644 --- a/packages/api-v4/src/cloudpulse/types.ts +++ b/packages/api-v4/src/cloudpulse/types.ts @@ -44,8 +44,7 @@ export interface Filters { value: string; } -// Define the type for filter values -type FilterValue = +export type FilterValue = | number | string | string[] @@ -56,7 +55,6 @@ type FilterValue = type WidgetFilterValue = { [key: string]: AclpWidget }; export interface AclpConfig { - // we maintain only the filters selected in the preferences for latest selected dashboard [key: string]: FilterValue; widgets?: WidgetFilterValue; } diff --git a/packages/manager/src/MainContent.tsx b/packages/manager/src/MainContent.tsx index 3fed2fc35bd..346e08dee25 100644 --- a/packages/manager/src/MainContent.tsx +++ b/packages/manager/src/MainContent.tsx @@ -356,7 +356,7 @@ export const MainContent = () => { )} - {isACLPEnabled && ( + {!isACLPEnabled && ( { }, { display: 'Monitor', - hide: !isACLPEnabled, + hide: isACLPEnabled, href: '/monitor/cloudpulse', icon: , isBeta: flags.aclp?.beta, diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index ac019a321d3..b899580b761 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -12,7 +12,7 @@ import { useGetCloudPulseMetricDefinitionsByServiceType, } from 'src/queries/cloudpulse/services'; -import { getUserPreferenceObject } from '../Utils/UserPreference'; +import { useAclpPreference } from '../Utils/UserPreference'; import { createObjectCopy } from '../Utils/utils'; import { CloudPulseWidget } from '../Widget/CloudPulseWidget'; import { @@ -80,6 +80,8 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { savePref, } = props; + const { preferences } = useAclpPreference(); + const getJweTokenPayload = (): JWETokenPayLoad => { return { resource_ids: resourceList?.map((resource) => Number(resource.id)) ?? [], @@ -110,7 +112,7 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { }; const setPreferredWidgetPlan = (widgetObj: Widgets) => { - const widgetPreferences = getUserPreferenceObject().widgets; + const widgetPreferences = preferences.widgets; const pref = widgetPreferences?.[widgetObj.label]; if (pref) { Object.assign(widgetObj, { diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx index 89f5f6db2c9..55ca61b278b 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx @@ -2,7 +2,6 @@ import { Grid, Paper } from '@mui/material'; import * as React from 'react'; import CloudPulseIcon from 'src/assets/icons/entityIcons/monitor.svg'; -import { CircleProgress } from 'src/components/CircleProgress'; import { StyledPlaceholder } from 'src/features/StackScripts/StackScriptBase/StackScriptBase.styles'; import { GlobalFilters } from '../Overview/GlobalFilters'; @@ -12,7 +11,6 @@ import { getMetricsCallCustomFilters, } from '../Utils/FilterBuilder'; import { FILTER_CONFIG } from '../Utils/FilterConfig'; -import { useLoadUserPreferences } from '../Utils/UserPreference'; import { CloudPulseDashboard } from './CloudPulseDashboard'; import type { Dashboard, TimeDuration } from '@linode/api-v4'; @@ -23,7 +21,6 @@ export const CloudPulseDashboardLanding = () => { const [filterValue, setFilterValue] = React.useState<{ [key: string]: FilterValueType; }>({}); - const [timeDuration, setTimeDuration] = React.useState(); const [dashboard, setDashboard] = React.useState(); @@ -41,8 +38,8 @@ export const CloudPulseDashboardLanding = () => { const onDashboardChange = React.useCallback((dashboardObj: Dashboard) => { setDashboard(dashboardObj); setFilterValue({}); // clear the filter values on dashboard change - }, []); + }, []); const onTimeDurationChange = React.useCallback( (timeDurationObj: TimeDuration) => { setTimeDuration(timeDurationObj); @@ -50,8 +47,6 @@ export const CloudPulseDashboardLanding = () => { [] ); - const { isLoading } = useLoadUserPreferences(); - /** * Takes an error message as input and renders a placeholder with the error message * @param errorMessage {string} - Error message which will be displayed @@ -120,11 +115,6 @@ export const CloudPulseDashboardLanding = () => { /> ); }; - - if (isLoading) { - return ; - } - return ( diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index 0953eaa6303..993c100ec00 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -1,5 +1,5 @@ -import { Grid } from '@mui/material'; import { IconButton, Tooltip } from '@mui/material'; +import { Grid } from '@mui/material'; import { styled } from '@mui/material/styles'; import * as React from 'react'; @@ -9,10 +9,10 @@ import { Divider } from 'src/components/Divider'; import { CloudPulseDashboardFilterBuilder } from '../shared/CloudPulseDashboardFilterBuilder'; import { CloudPulseDashboardSelect } from '../shared/CloudPulseDashboardSelect'; import { CloudPulseTimeRangeSelect } from '../shared/CloudPulseTimeRangeSelect'; +import { useAclpPreference } from '../Utils/UserPreference'; import type { FilterValueType } from '../Dashboard/CloudPulseDashboardLanding'; import type { Dashboard, TimeDuration } from '@linode/api-v4'; -import type { WithStartAndEnd } from 'src/features/Longview/request.types'; export interface GlobalFilterProperties { handleAnyFilterChange(filterKey: string, filterValue: FilterValueType): void; @@ -20,25 +20,19 @@ export interface GlobalFilterProperties { handleTimeDurationChange(timeDuration: TimeDuration): void; } -export interface FiltersObject { - interval: string; - region: string; - resource: string[]; - serviceType?: string; - timeRange: WithStartAndEnd; -} - export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { const { handleAnyFilterChange, handleDashboardChange, handleTimeDurationChange, } = props; - + const { + preferences, + updateGlobalFilterPreference: updatePreferences, + } = useAclpPreference(); const [selectedDashboard, setSelectedDashboard] = React.useState< Dashboard | undefined >(); - const handleTimeRangeChange = React.useCallback( (timerDuration: TimeDuration) => { handleTimeDurationChange(timerDuration); @@ -77,7 +71,9 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { > @@ -85,6 +81,9 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { handleStatsChange={handleTimeRangeChange} hideLabel label="Select Time Range" + preferences={preferences} + savePreferences + updatePreferences={updatePreferences} /> { dashboard={selectedDashboard} emitFilterChange={emitFilterChange} isServiceAnalyticsIntegration={false} + preferences={preferences} + updatePreferences={updatePreferences} /> )} diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts index 57a6b6e7bbc..90ca69c1b71 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts @@ -12,7 +12,12 @@ import type { import type { CloudPulseTimeRangeSelectProps } from '../shared/CloudPulseTimeRangeSelect'; import type { CloudPulseMetricsAdditionalFilters } from '../Widget/CloudPulseWidget'; import type { CloudPulseServiceTypeFilters } from './models'; -import type { Dashboard, Filter, Filters, TimeDuration } from '@linode/api-v4'; +import type { + AclpConfig, + Dashboard, + Filter, + Filters, TimeDuration, +} from '@linode/api-v4'; interface CloudPulseFilterProperties { config: CloudPulseServiceTypeFilters; @@ -21,6 +26,8 @@ interface CloudPulseFilterProperties { [key: string]: FilterValueType; }; isServiceAnalyticsIntegration: boolean; + preferences: AclpConfig; + updatePreferences: (data: {}) => void; } interface CloudPulseMandatoryFilterCheckProps { @@ -45,12 +52,19 @@ export const getRegionProperties = ( handleRegionChange: (region: string | undefined) => void ): CloudPulseRegionSelectProps => { const { placeholder } = props.config.configuration; - const { dashboard, isServiceAnalyticsIntegration } = props; + const { + dashboard, + isServiceAnalyticsIntegration, + preferences, + updatePreferences, + } = props; return { handleRegionChange, placeholder, + preferences, savePreferences: !isServiceAnalyticsIntegration, selectedDashboard: dashboard, + updatePreferences, }; }; @@ -74,6 +88,8 @@ export const getResourcesProperties = ( dashboard, dependentFilters, isServiceAnalyticsIntegration, + preferences, + updatePreferences, } = props; return { disabled: checkIfWeNeedToDisableFilterByFilterKey( @@ -83,8 +99,10 @@ export const getResourcesProperties = ( ), handleResourcesSelection: handleResourceChange, placeholder, + preferences, resourceType: dashboard.service_type, savePreferences: !isServiceAnalyticsIntegration, + updatePreferences, xFilter: buildXFilter(config, dependentFilters ?? {}), }; }; @@ -150,11 +168,17 @@ export const getTimeDurationProperties = ( handleTimeRangeChange: (timeDuration: TimeDuration) => void ): CloudPulseTimeRangeSelectProps => { const { placeholder } = props.config.configuration; - const { isServiceAnalyticsIntegration } = props; + const { + isServiceAnalyticsIntegration, + preferences, + updatePreferences, + } = props; return { handleStatsChange: handleTimeRangeChange, placeholder, + preferences, savePreferences: !isServiceAnalyticsIntegration, + updatePreferences, }; }; diff --git a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts index 326dd5aebb2..98a64774c8a 100644 --- a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts +++ b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts @@ -1,86 +1,59 @@ +import { useRef } from 'react'; + import { useMutatePreferences, usePreferences, } from 'src/queries/profile/preferences'; -import { DASHBOARD_ID, TIME_DURATION } from './constants'; - -import type { AclpConfig, AclpWidget } from '@linode/api-v4'; - -let userPreference: AclpConfig; -let timerId: ReturnType; -let mutateFn: any; - -export const useLoadUserPreferences = () => { - const { data: preferences, isError, isLoading } = usePreferences(); - - const { mutate } = useMutatePreferences(); - - if (isLoading) { - return { isLoading }; - } - mutateFn = mutate; - - if (isError || !preferences) { - userPreference = {} as AclpConfig; - } else { - userPreference = preferences.aclpPreference ?? {}; - } - - return { isLoading }; -}; - -export const getUserPreferenceObject = () => { - return { ...userPreference }; -}; -const useUpdateUserPreference = (updatedData: AclpConfig) => { - if (mutateFn) { - mutateFn({ aclpPreference: updatedData }); - } -}; - -export const updateGlobalFilterPreference = (data: {}) => { - if (!userPreference) { - userPreference = {} as AclpConfig; - } - const keys = Object.keys(data); - - if (keys.includes(DASHBOARD_ID)) { - userPreference = { ...data, [TIME_DURATION]: userPreference.timeDuration }; - } else { - userPreference = { ...userPreference, ...data }; - } - - debounce(userPreference); -}; - -export const updateWidgetPreference = ( - label: string, - data: Partial -) => { - if (!userPreference) { - userPreference = {} as AclpConfig; - } - - if (!userPreference.widgets) { - userPreference.widgets = {}; - } +import { DASHBOARD_ID, TIME_DURATION } from './constants'; - userPreference.widgets[label] = { - ...userPreference.widgets[label], - label, - ...data, +import type { AclpWidget } from '@linode/api-v4'; + +export const useAclpPreference = () => { + const { data: preferences, isLoading } = usePreferences(); + + const { mutateAsync: updateFunction } = useMutatePreferences(); + + const preferenceRef = useRef({ ...(preferences?.aclpPreference ?? {}) }); + const updateGlobalFilterPreference = (data: {}) => { + let currentPreferences = { ...preferenceRef.current }; + const keys = Object.keys(data); + + if (keys.includes(DASHBOARD_ID)) { + currentPreferences = { + ...data, + [TIME_DURATION]: currentPreferences[TIME_DURATION], + }; + } else { + currentPreferences = { + ...currentPreferences, + ...data, + }; + } + preferenceRef.current = currentPreferences; + updateFunction({ aclpPreference: currentPreferences }); }; - debounce(userPreference); -}; + const updateWidgetPreference = (label: string, data: Partial) => { + const updatedPreferences = { ...preferenceRef.current }; -// to avoid frequent preference update calls within 500 ms interval -const debounce = (updatedData: AclpConfig) => { - if (timerId) { - clearTimeout(timerId); - } + if (!updatedPreferences.widgets) { + updatedPreferences.widgets = {}; + } - timerId = setTimeout(() => useUpdateUserPreference(updatedData), 500); + updatedPreferences.widgets[label] = { + ...updatedPreferences.widgets[label], + label, + ...data, + }; + preferenceRef.current = updatedPreferences; + updateFunction({ aclpPreference: updatedPreferences }); + }; + return { + isLoading, + preferences: preferenceRef.current, + updateGlobalFilterPreference, + updateWidgetPreference, + }; }; diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index a7172590950..f806985d9ab 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -14,10 +14,7 @@ import { import { AGGREGATE_FUNCTION, SIZE, TIME_GRANULARITY } from '../Utils/constants'; import { constructAdditionalRequestFilters } from '../Utils/FilterBuilder'; import { convertValueToUnit, formatToolTip } from '../Utils/unitConversion'; -import { - getUserPreferenceObject, - updateWidgetPreference, -} from '../Utils/UserPreference'; +import { useAclpPreference } from '../Utils/UserPreference'; import { convertStringToCamelCasesWithSpaces } from '../Utils/utils'; import { CloudPulseAggregateFunction } from './components/CloudPulseAggregateFunction'; import { CloudPulseIntervalSelect } from './components/CloudPulseIntervalSelect'; @@ -120,12 +117,14 @@ export interface LegendRow { } export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { + const { + preferences, + updateWidgetPreference: updatePreferences, + } = useAclpPreference(); const { data: profile } = useProfile(); - const timezone = profile?.timezone ?? DateTime.local().zoneName; const [widget, setWidget] = React.useState({ ...props.widget }); - const { additionalFilters, ariaLabel, @@ -138,6 +137,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { serviceType, timeStamp, unit, + widget: widgetProp, } = props; const flags = useFlags(); @@ -148,7 +148,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { */ const handleZoomToggle = React.useCallback((zoomInValue: boolean) => { if (savePref) { - updateWidgetPreference(widget.label, { + updatePreferences(widget.label, { [SIZE]: zoomInValue ? 12 : 6, }); } @@ -168,20 +168,19 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { const handleAggregateFunctionChange = React.useCallback( (aggregateValue: string) => { // To avoid updation if user again selected the currently selected value from drop down. - if (aggregateValue !== widget.aggregate_function) { - if (savePref) { - updateWidgetPreference(widget.label, { - [AGGREGATE_FUNCTION]: aggregateValue, - }); - } - - setWidget((currentWidget: Widgets) => { - return { - ...currentWidget, - aggregate_function: aggregateValue, - }; + + if (savePref) { + updatePreferences(widget.label, { + [AGGREGATE_FUNCTION]: aggregateValue, }); } + + setWidget((currentWidget: Widgets) => { + return { + ...currentWidget, + aggregate_function: aggregateValue, + }; + }); }, [] ); @@ -192,33 +191,27 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { */ const handleIntervalChange = React.useCallback( (intervalValue: TimeGranularity) => { - if ( - !widget.time_granularity || - intervalValue.unit !== widget.time_granularity.unit || - intervalValue.value !== widget.time_granularity.value - ) { - if (savePref) { - updateWidgetPreference(widget.label, { - [TIME_GRANULARITY]: { ...intervalValue }, - }); - } - - setWidget((currentWidget: Widgets) => { - return { - ...currentWidget, - time_granularity: { ...intervalValue }, - }; + if (savePref) { + updatePreferences(widget.label, { + [TIME_GRANULARITY]: { ...intervalValue }, }); } + + setWidget((currentWidget: Widgets) => { + return { + ...currentWidget, + time_granularity: { ...intervalValue }, + }; + }); }, [] ); // Update the widget preference if already not present in the preferences React.useEffect(() => { if (savePref) { - const widgets = getUserPreferenceObject()?.widgets; + const widgets = preferences.widgets; if (!widgets || !widgets[widget.label]) { - updateWidgetPreference(widget.label, { + updatePreferences(widget.label, { [AGGREGATE_FUNCTION]: widget.aggregate_function, [SIZE]: widget.size, [TIME_GRANULARITY]: widget.time_granularity, @@ -282,6 +275,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { today = generatedData.today; currentUnit = generatedData.unit; } + return ( @@ -310,7 +304,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { > {availableMetrics?.scrape_interval && ( @@ -322,7 +316,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { availableAggregateFunctions={ availableMetrics!.available_aggregate_functions } - defaultAggregateFunction={widget?.aggregate_function} + defaultAggregateFunction={widgetProp?.aggregate_function} onAggregateFuncChange={handleAggregateFunctionChange} /> )} diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx index 0c4836abfac..bc38cedf805 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx @@ -21,8 +21,14 @@ export interface AggregateFunctionProperties { export const CloudPulseAggregateFunction = React.memo( (props: AggregateFunctionProperties) => { + const { + availableAggregateFunctions, + defaultAggregateFunction, + onAggregateFuncChange, + } = props; + // Convert list of availableAggregateFunc into a proper response structure accepted by Autocomplete component - const availableAggregateFunc = props.availableAggregateFunctions?.map( + const availableAggregateFunc = availableAggregateFunctions?.map( (aggrFunc) => { return { label: aggrFunc, @@ -30,11 +36,15 @@ export const CloudPulseAggregateFunction = React.memo( }; } ); - - const defaultAggregateFunc = + const defaultValue = availableAggregateFunc.find( - (obj) => obj.label === props.defaultAggregateFunction - ) || props.availableAggregateFunctions[0]; + (obj) => obj.label === defaultAggregateFunction + ) || availableAggregateFunctions[0]; + + const [ + selectedAggregateFunction, + setSelectedAggregateFunction, + ] = React.useState(defaultValue); return ( { - props.onAggregateFuncChange(selectedAggregateFunc.label); + setSelectedAggregateFunction(selectedAggregateFunc); + onAggregateFuncChange(selectedAggregateFunc.label); }} textFieldProps={{ hideLabel: true, }} - defaultValue={defaultAggregateFunc} disableClearable fullWidth={false} label="Select an Aggregate Function" noMarginTop={true} options={availableAggregateFunc} sx={{ width: '100%' }} + value={selectedAggregateFunction} /> ); } diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx index fe0bfed6a9d..eb375e74932 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx @@ -78,7 +78,8 @@ export const getIntervalIndex = (scrapeIntervalValue: number) => { export const CloudPulseIntervalSelect = React.memo( (props: IntervalSelectProperties) => { - const scrapeIntervalValue = getInSeconds(props.scrape_interval); + const { default_interval, onIntervalChange, scrape_interval } = props; + const scrapeIntervalValue = getInSeconds(scrape_interval); const firstIntervalIndex = getIntervalIndex(scrapeIntervalValue); @@ -91,22 +92,25 @@ export const CloudPulseIntervalSelect = React.memo( all_interval_options.length ); - let default_interval = - props.default_interval?.unit === 'Auto' + let default_value = + default_interval?.unit === 'Auto' ? autoIntervalOption : available_interval_options.find( (obj) => - obj.value === props.default_interval?.value && - obj.unit === props.default_interval?.unit + obj.value === default_interval?.value && + obj.unit === default_interval?.unit ); - if (!default_interval) { - default_interval = autoIntervalOption; - props.onIntervalChange({ - unit: default_interval.unit, - value: default_interval.value, + if (!default_value) { + default_value = autoIntervalOption; + onIntervalChange({ + unit: default_value.unit, + value: default_value.value, }); } + const [selectedInterval, setSelectedInterval] = React.useState( + default_value + ); return ( { - props.onIntervalChange({ + setSelectedInterval(selectedInterval); + onIntervalChange({ unit: selectedInterval?.unit, value: selectedInterval?.value, }); @@ -122,13 +127,13 @@ export const CloudPulseIntervalSelect = React.memo( textFieldProps={{ hideLabel: true, }} - defaultValue={{ ...default_interval }} disableClearable fullWidth={false} label="Select an Interval" noMarginTop={true} options={[autoIntervalOption, ...available_interval_options]} sx={{ width: { xs: '100%' } }} + value={{ ...selectedInterval }} /> ); } diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index a0e1cd76801..876575a59e7 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -25,7 +25,7 @@ import { FILTER_CONFIG } from '../Utils/FilterConfig'; import type { FilterValueType } from '../Dashboard/CloudPulseDashboardLanding'; import type { CloudPulseServiceTypeFilters } from '../Utils/models'; import type { CloudPulseResources } from './CloudPulseResourcesSelect'; -import type { Dashboard } from '@linode/api-v4'; +import type { AclpConfig, Dashboard } from '@linode/api-v4'; export interface CloudPulseDashboardFilterBuilderProps { /** @@ -43,6 +43,8 @@ export interface CloudPulseDashboardFilterBuilderProps { * this will handle the restrictions, if the parent of the component is going to be integrated in service analytics page */ isServiceAnalyticsIntegration: boolean; + preferences: AclpConfig; + updatePreferences: (data: {}) => void; } export const CloudPulseDashboardFilterBuilder = React.memo( @@ -51,6 +53,8 @@ export const CloudPulseDashboardFilterBuilder = React.memo( dashboard, emitFilterChange, isServiceAnalyticsIntegration, + preferences, + updatePreferences, } = props; const [, setDependentFilters] = React.useState<{ @@ -123,7 +127,13 @@ export const CloudPulseDashboardFilterBuilder = React.memo( (config: CloudPulseServiceTypeFilters) => { if (config.configuration.filterKey === REGION) { return getRegionProperties( - { config, dashboard, isServiceAnalyticsIntegration }, + { + config, + dashboard, + isServiceAnalyticsIntegration, + preferences, + updatePreferences, + }, handleRegionChange ); } else if (config.configuration.filterKey === RESOURCE_ID) { @@ -133,6 +143,8 @@ export const CloudPulseDashboardFilterBuilder = React.memo( dashboard, dependentFilters: dependentFilterReference.current, isServiceAnalyticsIntegration, + preferences, + updatePreferences, }, handleResourceChange ); @@ -154,6 +166,8 @@ export const CloudPulseDashboardFilterBuilder = React.memo( handleResourceChange, handleCustomSelectChange, isServiceAnalyticsIntegration, + preferences, + updatePreferences, ] ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index 6b62eba2ea2..fe908ac2b12 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -7,23 +7,23 @@ import { useCloudPulseDashboardsQuery } from 'src/queries/cloudpulse/dashboards' import { useCloudPulseServiceTypes } from 'src/queries/cloudpulse/services'; import { DASHBOARD_ID } from '../Utils/constants'; -import { - getUserPreferenceObject, - updateGlobalFilterPreference, -} from '../Utils/UserPreference'; import { formattedServiceTypes, getAllDashboards } from '../Utils/utils'; import type { Dashboard } from '@linode/api-v4'; export interface CloudPulseDashboardSelectProps { + defaultValue: number | undefined; handleDashboardChange: ( dashboard: Dashboard | undefined, isDefault?: boolean ) => void; + updatePreferences: (data: {}) => void; } export const CloudPulseDashboardSelect = React.memo( (props: CloudPulseDashboardSelectProps) => { + const { defaultValue, handleDashboardChange, updatePreferences } = props; + const { data: serviceTypesList, error: serviceTypesError, @@ -71,16 +71,16 @@ export const CloudPulseDashboardSelect = React.memo( React.useEffect(() => { // only call this code when the component is rendered initially if (dashboardsList.length > 0 && selectedDashboard === undefined) { - const dashboardId = getUserPreferenceObject()?.dashboardId; + // const dashboardId = preferences.dashboardId; - if (dashboardId) { + if (defaultValue) { const dashboard = dashboardsList.find( - (obj: Dashboard) => obj.id === dashboardId + (obj: Dashboard) => obj.id === defaultValue ); setSelectedDashboard(dashboard); - props.handleDashboardChange(dashboard, true); + handleDashboardChange(dashboard, true); } else { - props.handleDashboardChange(undefined, true); + handleDashboardChange(undefined, true); } } // eslint-disable-next-line react-hooks/exhaustive-deps @@ -88,11 +88,11 @@ export const CloudPulseDashboardSelect = React.memo( return ( { - updateGlobalFilterPreference({ + updatePreferences({ [DASHBOARD_ID]: dashboard?.id, }); setSelectedDashboard(dashboard); - props.handleDashboardChange(dashboard); + handleDashboardChange(dashboard); }} renderGroup={(params) => ( diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index c2f9095f8b6..7710adad464 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -4,31 +4,39 @@ import { RegionSelect } from 'src/components/RegionSelect/RegionSelect'; import { useRegionsQuery } from 'src/queries/regions/regions'; import { REGION, RESOURCES } from '../Utils/constants'; -import { - getUserPreferenceObject, - updateGlobalFilterPreference, -} from '../Utils/UserPreference'; -import type { Dashboard } from '@linode/api-v4'; +import type { AclpConfig, Dashboard } from '@linode/api-v4'; export interface CloudPulseRegionSelectProps { handleRegionChange: (region: string | undefined) => void; placeholder?: string; + preferences: AclpConfig; savePreferences?: boolean; selectedDashboard: Dashboard | undefined; + updatePreferences: (data: {}) => void; } export const CloudPulseRegionSelect = React.memo( (props: CloudPulseRegionSelectProps) => { + // const { + // preferences, + // updateGlobalFilterPreference: updatePreferences, + // } = useAclpPreference(); const { data: regions } = useRegionsQuery(); - const { handleRegionChange, placeholder, selectedDashboard } = props; + const { + handleRegionChange, + placeholder, + preferences, + selectedDashboard, + updatePreferences, + } = props; const [selectedRegion, setSelectedRegion] = React.useState(); // Once the data is loaded, set the state variable with value stored in preferences React.useEffect(() => { - const defaultRegion = getUserPreferenceObject()?.region; + const defaultRegion = preferences.region; if (regions) { if (defaultRegion) { @@ -46,7 +54,7 @@ export const CloudPulseRegionSelect = React.memo( return ( { - updateGlobalFilterPreference({ + updatePreferences({ [REGION]: region?.id, [RESOURCES]: undefined, }); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index 3245d9c211f..5b42d9a1418 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -5,12 +5,8 @@ import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; import { useResourcesQuery } from 'src/queries/cloudpulse/resources'; import { RESOURCES } from '../Utils/constants'; -import { - getUserPreferenceObject, - updateGlobalFilterPreference, -} from '../Utils/UserPreference'; -import type { Filter } from '@linode/api-v4'; +import type { AclpConfig, Filter } from '@linode/api-v4'; export interface CloudPulseResources { id: string; @@ -22,9 +18,11 @@ export interface CloudPulseResourcesSelectProps { disabled?: boolean; handleResourcesSelection: (resources: CloudPulseResources[]) => void; placeholder?: string; + preferences: AclpConfig; region?: string; resourceType: string | undefined; savePreferences?: boolean; + updatePreferences: (data: {}) => void; xFilter?: Filter; } @@ -34,8 +32,10 @@ export const CloudPulseResourcesSelect = React.memo( disabled, handleResourcesSelection, placeholder, + preferences, region, resourceType, + updatePreferences, xFilter, } = props; @@ -56,12 +56,12 @@ export const CloudPulseResourcesSelect = React.memo( // Once the data is loaded, set the state variable with value stored in preferences React.useEffect(() => { - const saveResources = getUserPreferenceObject()?.resources; - const defaultResources = Array.isArray(saveResources) - ? Array.of(saveResources).map((resourceId) => String(resourceId)) - : undefined; + const defaultValue = preferences.resources; if (resources) { - if (defaultResources) { + if (defaultValue && Array.isArray(defaultValue)) { + const defaultResources = defaultValue.map((resource) => + String(resource) + ); const resource = getResourcesList().filter((resource) => defaultResources.includes(String(resource.id)) ); @@ -81,7 +81,7 @@ export const CloudPulseResourcesSelect = React.memo( return ( { - updateGlobalFilterPreference({ + updatePreferences({ [RESOURCES]: resourceSelections.map((resource: { id: string }) => String(resource.id) ), diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx index cb1eff771e2..5a93c5d6682 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx @@ -3,12 +3,8 @@ import * as React from 'react'; import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; import { TIME_DURATION } from '../Utils/constants'; -import { - getUserPreferenceObject, - updateGlobalFilterPreference, -} from '../Utils/UserPreference'; -import type { TimeDuration } from '@linode/api-v4'; +import type { AclpConfig, TimeDuration } from '@linode/api-v4'; import type { BaseSelectProps, Item, @@ -21,7 +17,9 @@ export interface CloudPulseTimeRangeSelectProps > { handleStatsChange?: (timeDuration: TimeDuration) => void; placeholder?: string; + preferences?: AclpConfig; savePreferences?: boolean; + updatePreferences?: (data: {}) => void; } const PAST_7_DAYS = 'Past 7 Days'; @@ -38,13 +36,19 @@ export type Labels = export const CloudPulseTimeRangeSelect = React.memo( (props: CloudPulseTimeRangeSelectProps) => { - const { handleStatsChange, placeholder } = props; + const { + handleStatsChange, + placeholder, + preferences, + savePreferences, + updatePreferences, + } = props; const options = generateSelectOptions(); - const getDefaultValue = React.useCallback((): Item => { - const defaultValue = getUserPreferenceObject().timeDuration; + const getDefaultValue = React.useCallback((): Item => { + const defaultValue = preferences?.timeDuration; return options.find((o) => o.label === defaultValue) || options[0]; - }, [options]); + }, []); const [selectedTimeRange, setSelectedTimeRange] = React.useState< Item >(getDefaultValue()); @@ -55,19 +59,21 @@ export const CloudPulseTimeRangeSelect = React.memo( if (handleStatsChange) { handleStatsChange(getTimeDurationFromTimeRange(item.value)); } - setSelectedTimeRange(item); }, [handleStatsChange, getDefaultValue]); const handleChange = (item: Item) => { - updateGlobalFilterPreference({ - [TIME_DURATION]: item.value, - }); + if (savePreferences && updatePreferences) { + updatePreferences({ + [TIME_DURATION]: item.value, + }); + } + + setSelectedTimeRange(item); if (handleStatsChange) { handleStatsChange(getTimeDurationFromTimeRange(item.value)); } }; - return ( ) => { @@ -165,11 +171,11 @@ const getTimeDurationFromTimeRange = (label: string): TimeDuration => { } if (label === PAST_7_DAYS) { - return { unit: 'day', value: 7 }; + return { unit: 'days', value: 7 }; } if (label === PAST_30_DAYS) { - return { unit: 'day', value: 30 }; + return { unit: 'days', value: 30 }; } return { unit: 'min', value: 30 }; diff --git a/packages/manager/src/queries/cloudpulse/metrics.ts b/packages/manager/src/queries/cloudpulse/metrics.ts index de200c3c040..77c8f978014 100644 --- a/packages/manager/src/queries/cloudpulse/metrics.ts +++ b/packages/manager/src/queries/cloudpulse/metrics.ts @@ -71,15 +71,17 @@ export const fetchCloudPulseMetrics = ( const config: AxiosRequestConfig = { data: requestData, headers: { - 'Authentication-Type': 'jwe', + 'Authentication-type': 'jwe', Authorization: `Bearer ${token}`, }, method: 'POST', - url: `${readApiEndpoint}${encodeURIComponent(serviceType!)}/metrics`, + url: `https://metrics-query.aclp.linode.com/v1/monitor/services/${encodeURIComponent( + serviceType! + )}/metrics`, }; return axiosInstance .request(config) .then((response) => response.data) - .catch((error) => Promise.reject(error.response.data.errors)); + .catch((error) => Promise.reject(error.response?.data?.errors)); }; diff --git a/packages/manager/src/request.tsx b/packages/manager/src/request.tsx index ad5ae5e60e2..2c1cbcea37e 100644 --- a/packages/manager/src/request.tsx +++ b/packages/manager/src/request.tsx @@ -38,7 +38,7 @@ export const handleError = ( * this will blow out redux state and the componentDidUpdate in the * AuthenticationWrapper.tsx will be responsible for redirecting to Login */ - store.dispatch(handleLogout()); + // store.dispatch(handleLogout()); } const config = error.response?.config; From f54ca49fbf9943318afd4c6575ad36497e126411 Mon Sep 17 00:00:00 2001 From: nikhagra Date: Tue, 27 Aug 2024 21:27:15 +0530 Subject: [PATCH 002/474] upcoming: [DI-20360] - Modified user preference logic --- packages/api-v4/src/cloudpulse/dashboards.ts | 8 ++------ packages/manager/src/MainContent.tsx | 2 +- packages/manager/src/components/PrimaryNav/PrimaryNav.tsx | 2 +- .../CloudPulse/shared/CloudPulseDashboardSelect.tsx | 2 -- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/packages/api-v4/src/cloudpulse/dashboards.ts b/packages/api-v4/src/cloudpulse/dashboards.ts index 29fa9e8dd45..e5d2f790dea 100644 --- a/packages/api-v4/src/cloudpulse/dashboards.ts +++ b/packages/api-v4/src/cloudpulse/dashboards.ts @@ -1,7 +1,7 @@ import { ResourcePage } from 'src/types'; import Request, { setHeaders, setMethod, setURL } from '../request'; import { Dashboard } from './types'; -// import { API_ROOT } from 'src/constants'; +import { API_ROOT } from 'src/constants'; // Returns the list of all the dashboards available export const getDashboards = (serviceType: string) => @@ -16,11 +16,7 @@ export const getDashboards = (serviceType: string) => export const getDashboardById = (dashboardId: number) => Request( - setURL( - `https://blr-lhv95n.bangalore.corp.akamai.com:9000/v4beta/monitor/dashboards/${encodeURIComponent( - dashboardId - )}` - ), + setURL(`${API_ROOT}/monitor/dashboards/${encodeURIComponent(dashboardId)}`), setMethod('GET'), setHeaders({ Authorization: 'Bearer vagrant', diff --git a/packages/manager/src/MainContent.tsx b/packages/manager/src/MainContent.tsx index 346e08dee25..3fed2fc35bd 100644 --- a/packages/manager/src/MainContent.tsx +++ b/packages/manager/src/MainContent.tsx @@ -356,7 +356,7 @@ export const MainContent = () => { )} - {!isACLPEnabled && ( + {isACLPEnabled && ( { }, { display: 'Monitor', - hide: isACLPEnabled, + hide: !isACLPEnabled, href: '/monitor/cloudpulse', icon: , isBeta: flags.aclp?.beta, diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index fe908ac2b12..5c72f8b8a97 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -71,8 +71,6 @@ export const CloudPulseDashboardSelect = React.memo( React.useEffect(() => { // only call this code when the component is rendered initially if (dashboardsList.length > 0 && selectedDashboard === undefined) { - // const dashboardId = preferences.dashboardId; - if (defaultValue) { const dashboard = dashboardsList.find( (obj: Dashboard) => obj.id === defaultValue From 109646351f36fdba62ace2b5df51482de4dfed55 Mon Sep 17 00:00:00 2001 From: nikhagra Date: Thu, 29 Aug 2024 18:44:54 +0530 Subject: [PATCH 003/474] upcoming: [DI-20360] - Removed useEffect from widget component --- .../Dashboard/CloudPulseDashboard.tsx | 18 +++++++++++++++--- .../CloudPulse/Overview/GlobalFilters.tsx | 6 +++--- .../CloudPulse/Utils/UserPreference.ts | 15 +++++++++++++++ .../CloudPulse/Widget/CloudPulseWidget.tsx | 14 -------------- .../shared/CloudPulseTimeRangeSelect.tsx | 3 ++- 5 files changed, 35 insertions(+), 21 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index b899580b761..5277f9c3cf0 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -116,9 +116,21 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { const pref = widgetPreferences?.[widgetObj.label]; if (pref) { Object.assign(widgetObj, { - aggregate_function: pref.aggregateFunction, - size: pref.size, - time_granularity: { ...pref.timeGranularity }, + aggregate_function: + pref.aggregateFunction ?? widgetObj.aggregate_function, + size: pref.size ?? widgetObj.size, + time_granularity: { + ...(pref.timeGranularity ?? widgetObj.time_granularity), + }, + }); + } else { + Object.assign(widgetObj, { + ...widgetObj, + time_granularity: { + label: 'Auto', + unit: 'Auto', + value: -1, + }, }); } }; diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index 993c100ec00..1d246c857d8 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -37,7 +37,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { (timerDuration: TimeDuration) => { handleTimeDurationChange(timerDuration); }, - [handleTimeDurationChange] + [] ); const onDashboardChange = React.useCallback( @@ -45,14 +45,14 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { setSelectedDashboard(dashboard); handleDashboardChange(dashboard); }, - [handleDashboardChange] + [] ); const emitFilterChange = React.useCallback( (filterKey: string, value: FilterValueType) => { handleAnyFilterChange(filterKey, value); }, - [handleAnyFilterChange] + [] ); const handleGlobalRefresh = React.useCallback(() => {}, []); diff --git a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts index 98a64774c8a..82dab96481d 100644 --- a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts +++ b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts @@ -10,12 +10,22 @@ import { DASHBOARD_ID, TIME_DURATION } from './constants'; import type { AclpWidget } from '@linode/api-v4'; +/** + * + * This hook is used in CloudPulseDashboardLanding, GlobalFilters & CloudPulseWidget component + */ + export const useAclpPreference = () => { const { data: preferences, isLoading } = usePreferences(); const { mutateAsync: updateFunction } = useMutatePreferences(); const preferenceRef = useRef({ ...(preferences?.aclpPreference ?? {}) }); + + /** + * + * @param data AclpConfig data to be updated in preferences + */ const updateGlobalFilterPreference = (data: {}) => { let currentPreferences = { ...preferenceRef.current }; const keys = Object.keys(data); @@ -35,6 +45,11 @@ export const useAclpPreference = () => { updateFunction({ aclpPreference: currentPreferences }); }; + /** + * + * @param label label of the widget that should be updated + * @param data AclpWidget data for the label that is to be updated in preference + */ const updateWidgetPreference = (label: string, data: Partial) => { const updatedPreferences = { ...preferenceRef.current }; diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index f806985d9ab..207f9c6c204 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -139,7 +139,6 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { unit, widget: widgetProp, } = props; - const flags = useFlags(); /** @@ -206,19 +205,6 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { }, [] ); - // Update the widget preference if already not present in the preferences - React.useEffect(() => { - if (savePref) { - const widgets = preferences.widgets; - if (!widgets || !widgets[widget.label]) { - updatePreferences(widget.label, { - [AGGREGATE_FUNCTION]: widget.aggregate_function, - [SIZE]: widget.size, - [TIME_GRANULARITY]: widget.time_granularity, - }); - } - } - }, []); /** * diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx index 5a93c5d6682..d3018af2b20 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx @@ -93,7 +93,8 @@ export const CloudPulseTimeRangeSelect = React.memo( value={selectedTimeRange} /> ); - } + }, + () => true ); /** From 6e9f89977bb533af31a69be899079393cf6d1178 Mon Sep 17 00:00:00 2001 From: nikhagra Date: Thu, 29 Aug 2024 19:13:09 +0530 Subject: [PATCH 004/474] upcoming: [DI-20360] - Updated request.tsx file --- packages/manager/src/request.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/request.tsx b/packages/manager/src/request.tsx index 2c1cbcea37e..ad5ae5e60e2 100644 --- a/packages/manager/src/request.tsx +++ b/packages/manager/src/request.tsx @@ -38,7 +38,7 @@ export const handleError = ( * this will blow out redux state and the componentDidUpdate in the * AuthenticationWrapper.tsx will be responsible for redirecting to Login */ - // store.dispatch(handleLogout()); + store.dispatch(handleLogout()); } const config = error.response?.config; From a7ce52f5ab76b6ecac38fbe61d5ea87906138dd4 Mon Sep 17 00:00:00 2001 From: nikhagra Date: Thu, 29 Aug 2024 19:40:42 +0530 Subject: [PATCH 005/474] upcoming: [DI-20360] - remove sensitive information --- packages/api-v4/src/cloudpulse/dashboards.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/api-v4/src/cloudpulse/dashboards.ts b/packages/api-v4/src/cloudpulse/dashboards.ts index e5d2f790dea..32b9bbf3c31 100644 --- a/packages/api-v4/src/cloudpulse/dashboards.ts +++ b/packages/api-v4/src/cloudpulse/dashboards.ts @@ -1,5 +1,5 @@ import { ResourcePage } from 'src/types'; -import Request, { setHeaders, setMethod, setURL } from '../request'; +import Request, { setMethod, setURL } from '../request'; import { Dashboard } from './types'; import { API_ROOT } from 'src/constants'; @@ -17,8 +17,5 @@ export const getDashboards = (serviceType: string) => export const getDashboardById = (dashboardId: number) => Request( setURL(`${API_ROOT}/monitor/dashboards/${encodeURIComponent(dashboardId)}`), - setMethod('GET'), - setHeaders({ - Authorization: 'Bearer vagrant', - }) + setMethod('GET') ); From 12fcb4bd9683e17b468455c14e357117f349c6b2 Mon Sep 17 00:00:00 2001 From: nikhagra Date: Mon, 2 Sep 2024 16:45:24 +0530 Subject: [PATCH 006/474] upcoming: [DI-20360] - Update preference logic to avoid extra re-renderings --- .../CloudPulse/Overview/GlobalFilters.tsx | 4 ++- .../CloudPulse/Utils/FilterBuilder.ts | 9 ++++-- .../CloudPulseDashboardFilterBuilder.tsx | 4 +-- .../shared/CloudPulseDashboardSelect.tsx | 29 +++++++++++++----- .../shared/CloudPulseRegionSelect.tsx | 29 ++++++++++-------- .../shared/CloudPulseResourcesSelect.tsx | 30 +++++++++++-------- .../shared/CloudPulseTimeRangeSelect.tsx | 8 +++-- 7 files changed, 70 insertions(+), 43 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index 1d246c857d8..47552500ccb 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -26,6 +26,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { handleDashboardChange, handleTimeDurationChange, } = props; + const { preferences, updateGlobalFilterPreference: updatePreferences, @@ -73,15 +74,16 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts index 90ca69c1b71..47083b26814 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts @@ -26,8 +26,8 @@ interface CloudPulseFilterProperties { [key: string]: FilterValueType; }; isServiceAnalyticsIntegration: boolean; - preferences: AclpConfig; - updatePreferences: (data: {}) => void; + preferences?: AclpConfig; + updatePreferences?: (data: {}) => void; } interface CloudPulseMandatoryFilterCheckProps { @@ -173,10 +173,13 @@ export const getTimeDurationProperties = ( preferences, updatePreferences, } = props; + + const timeDuration = preferences?.timeDuration; return { + defaultValue: + timeDuration !== undefined ? (timeDuration as string) : undefined, handleStatsChange: handleTimeRangeChange, placeholder, - preferences, savePreferences: !isServiceAnalyticsIntegration, updatePreferences, }; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index 876575a59e7..87dc2a85077 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -43,8 +43,8 @@ export interface CloudPulseDashboardFilterBuilderProps { * this will handle the restrictions, if the parent of the component is going to be integrated in service analytics page */ isServiceAnalyticsIntegration: boolean; - preferences: AclpConfig; - updatePreferences: (data: {}) => void; + preferences?: AclpConfig; + updatePreferences?: (data: {}) => void; } export const CloudPulseDashboardFilterBuilder = React.memo( diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index 5c72f8b8a97..3a711843f4d 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -12,17 +12,23 @@ import { formattedServiceTypes, getAllDashboards } from '../Utils/utils'; import type { Dashboard } from '@linode/api-v4'; export interface CloudPulseDashboardSelectProps { - defaultValue: number | undefined; + defaultValue?: number; handleDashboardChange: ( dashboard: Dashboard | undefined, isDefault?: boolean ) => void; - updatePreferences: (data: {}) => void; + savePreferences?: boolean; + updatePreferences?: (data: {}) => void; } export const CloudPulseDashboardSelect = React.memo( (props: CloudPulseDashboardSelectProps) => { - const { defaultValue, handleDashboardChange, updatePreferences } = props; + const { + defaultValue, + handleDashboardChange, + savePreferences, + updatePreferences, + } = props; const { data: serviceTypesList, @@ -70,7 +76,11 @@ export const CloudPulseDashboardSelect = React.memo( // Once the data is loaded, set the state variable with value stored in preferences React.useEffect(() => { // only call this code when the component is rendered initially - if (dashboardsList.length > 0 && selectedDashboard === undefined) { + if ( + savePreferences && + dashboardsList.length > 0 && + selectedDashboard === undefined + ) { if (defaultValue) { const dashboard = dashboardsList.find( (obj: Dashboard) => obj.id === defaultValue @@ -86,9 +96,11 @@ export const CloudPulseDashboardSelect = React.memo( return ( { - updatePreferences({ - [DASHBOARD_ID]: dashboard?.id, - }); + if (savePreferences && updatePreferences) { + updatePreferences({ + [DASHBOARD_ID]: dashboard?.id, + }); + } setSelectedDashboard(dashboard); handleDashboardChange(dashboard); }} @@ -121,5 +133,6 @@ export const CloudPulseDashboardSelect = React.memo( value={selectedDashboard ?? null} // Undefined is not allowed for uncontrolled component /> ); - } + }, + () => true ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index 7710adad464..aa04ccf1da7 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -10,24 +10,21 @@ import type { AclpConfig, Dashboard } from '@linode/api-v4'; export interface CloudPulseRegionSelectProps { handleRegionChange: (region: string | undefined) => void; placeholder?: string; - preferences: AclpConfig; + preferences?: AclpConfig; savePreferences?: boolean; selectedDashboard: Dashboard | undefined; - updatePreferences: (data: {}) => void; + updatePreferences?: (data: {}) => void; } export const CloudPulseRegionSelect = React.memo( (props: CloudPulseRegionSelectProps) => { - // const { - // preferences, - // updateGlobalFilterPreference: updatePreferences, - // } = useAclpPreference(); const { data: regions } = useRegionsQuery(); const { handleRegionChange, placeholder, preferences, + savePreferences, selectedDashboard, updatePreferences, } = props; @@ -36,9 +33,9 @@ export const CloudPulseRegionSelect = React.memo( // Once the data is loaded, set the state variable with value stored in preferences React.useEffect(() => { - const defaultRegion = preferences.region; + const defaultRegion = preferences?.region; - if (regions) { + if (regions && savePreferences) { if (defaultRegion) { const region = regions.find((obj) => obj.id === defaultRegion)?.id; handleRegionChange(region); @@ -54,10 +51,12 @@ export const CloudPulseRegionSelect = React.memo( return ( { - updatePreferences({ - [REGION]: region?.id, - [RESOURCES]: undefined, - }); + if (savePreferences && updatePreferences) { + updatePreferences({ + [REGION]: region?.id, + [RESOURCES]: undefined, + }); + } setSelectedRegion(region?.id); handleRegionChange(region?.id); }} @@ -75,5 +74,9 @@ export const CloudPulseRegionSelect = React.memo( value={selectedRegion} /> ); - } + }, + ( + oldProps: CloudPulseRegionSelectProps, + newProps: CloudPulseRegionSelectProps + ) => oldProps.selectedDashboard?.id === newProps.selectedDashboard?.id ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index 5b42d9a1418..15f30a2970b 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -18,11 +18,11 @@ export interface CloudPulseResourcesSelectProps { disabled?: boolean; handleResourcesSelection: (resources: CloudPulseResources[]) => void; placeholder?: string; - preferences: AclpConfig; + preferences?: AclpConfig; region?: string; resourceType: string | undefined; savePreferences?: boolean; - updatePreferences: (data: {}) => void; + updatePreferences?: (data: {}) => void; xFilter?: Filter; } @@ -35,6 +35,7 @@ export const CloudPulseResourcesSelect = React.memo( preferences, region, resourceType, + savePreferences, updatePreferences, xFilter, } = props; @@ -48,7 +49,7 @@ export const CloudPulseResourcesSelect = React.memo( const [selectedResources, setSelectedResources] = React.useState< CloudPulseResources[] - >([]); + >(); const getResourcesList = (): CloudPulseResources[] => { return resources && resources.length > 0 ? resources : []; @@ -56,8 +57,8 @@ export const CloudPulseResourcesSelect = React.memo( // Once the data is loaded, set the state variable with value stored in preferences React.useEffect(() => { - const defaultValue = preferences.resources; - if (resources) { + const defaultValue = preferences?.resources; + if (resources && savePreferences && !selectedResources) { if (defaultValue && Array.isArray(defaultValue)) { const defaultResources = defaultValue.map((resource) => String(resource) @@ -72,20 +73,23 @@ export const CloudPulseResourcesSelect = React.memo( setSelectedResources([]); handleResourcesSelection([]); } - } else { + } else if (selectedResources) { + handleResourcesSelection([]); setSelectedResources([]); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [resources, region, resourceType, xFilter]); + }, [resources]); return ( { - updatePreferences({ - [RESOURCES]: resourceSelections.map((resource: { id: string }) => - String(resource.id) - ), - }); + if (savePreferences && updatePreferences) { + updatePreferences({ + [RESOURCES]: resourceSelections.map((resource: { id: string }) => + String(resource.id) + ), + }); + } setSelectedResources(resourceSelections); handleResourcesSelection(resourceSelections); }} @@ -108,7 +112,7 @@ export const CloudPulseResourcesSelect = React.memo( multiple options={getResourcesList()} placeholder={placeholder ? placeholder : 'Select Resources'} - value={selectedResources} + value={selectedResources ?? []} /> ); }, diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx index d3018af2b20..f92cf807e8a 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx @@ -15,9 +15,9 @@ export interface CloudPulseTimeRangeSelectProps BaseSelectProps, false>, 'defaultValue' | 'onChange' > { + defaultValue?: string; handleStatsChange?: (timeDuration: TimeDuration) => void; placeholder?: string; - preferences?: AclpConfig; savePreferences?: boolean; updatePreferences?: (data: {}) => void; } @@ -37,16 +37,18 @@ export type Labels = export const CloudPulseTimeRangeSelect = React.memo( (props: CloudPulseTimeRangeSelectProps) => { const { + defaultValue, handleStatsChange, placeholder, - preferences, savePreferences, updatePreferences, } = props; const options = generateSelectOptions(); const getDefaultValue = React.useCallback((): Item => { - const defaultValue = preferences?.timeDuration; + if (!savePreferences) { + return options[0]; + } return options.find((o) => o.label === defaultValue) || options[0]; }, []); const [selectedTimeRange, setSelectedTimeRange] = React.useState< From 7d14f4618b4fea6263bc8aa471b7fc018362cbed Mon Sep 17 00:00:00 2001 From: nikhagra Date: Mon, 2 Sep 2024 17:32:53 +0530 Subject: [PATCH 007/474] upcoming: [DI-20360] - Updated preference logic in custom select --- .../CloudPulse/Utils/FilterBuilder.ts | 13 +++++-- .../shared/CloudPulseCustomSelect.tsx | 10 ++++++ .../shared/CloudPulseCustomSelectUtils.ts | 35 +++++++++++-------- .../CloudPulseDashboardFilterBuilder.tsx | 2 ++ 4 files changed, 44 insertions(+), 16 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts index 47083b26814..c3244ec9423 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts @@ -16,7 +16,8 @@ import type { AclpConfig, Dashboard, Filter, - Filters, TimeDuration, + Filters, + TimeDuration, } from '@linode/api-v4'; interface CloudPulseFilterProperties { @@ -127,7 +128,13 @@ export const getCustomSelectProperties = ( options, placeholder, } = props.config.configuration; - const { dashboard, dependentFilters, isServiceAnalyticsIntegration } = props; + const { + dashboard, + dependentFilters, + isServiceAnalyticsIntegration, + preferences, + updatePreferences, + } = props; return { apiResponseIdField: apiIdField, apiResponseLabelField: apiLabelField, @@ -148,10 +155,12 @@ export const getCustomSelectProperties = ( maxSelections, options, placeholder, + preferences, savePreferences: !isServiceAnalyticsIntegration, type: options ? CloudPulseSelectTypes.static : CloudPulseSelectTypes.dynamic, + updatePreferences, }; }; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index f43f0c8c74f..cf5782e9c1e 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -14,6 +14,7 @@ import type { CloudPulseServiceTypeFiltersOptions, QueryFunctionAndKey, } from '../Utils/models'; +import type { AclpConfig } from '@linode/api-v4'; /** * These are the properties requires for CloudPulseCustomSelect Components @@ -86,6 +87,8 @@ export interface CloudPulseCustomSelectProps { */ placeholder?: string; + preferences?: AclpConfig; + /** * This property controls whether to save the preferences or not */ @@ -95,6 +98,8 @@ export interface CloudPulseCustomSelectProps { * The cloud pulse select types, it can be static or dynamic depending on the use case */ type: CloudPulseSelectTypes; + + updatePreferences?: (data: {}) => void; } export enum CloudPulseSelectTypes { @@ -116,8 +121,10 @@ export const CloudPulseCustomSelect = React.memo( maxSelections, options, placeholder, + preferences, savePreferences, type, + updatePreferences, } = props; const [selectedResource, setResource] = React.useState< @@ -146,6 +153,7 @@ export const CloudPulseCustomSelect = React.memo( handleSelectionChange, isMultiSelect: isMultiSelect ?? false, options: options ?? [], + preferences, savePreferences: savePreferences ?? false, }) ); @@ -165,6 +173,8 @@ export const CloudPulseCustomSelect = React.memo( filterKey, handleSelectionChange, maxSelections, + savePreferences, + updatePreferences, value, }); setResource( diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts index 4bd030e8627..b99baebecf2 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts @@ -1,10 +1,6 @@ -import { - getUserPreferenceObject, - updateGlobalFilterPreference, -} from '../Utils/UserPreference'; - import type { FilterValueType } from '../Dashboard/CloudPulseDashboardLanding'; import type { CloudPulseServiceTypeFiltersOptions } from '../Utils/models'; +import type { AclpConfig } from '@linode/api-v4'; /** * The interface for selecting the default value from the user preferences @@ -29,10 +25,13 @@ interface CloudPulseCustomSelectDefaultValueProps { */ options: CloudPulseServiceTypeFiltersOptions[]; + preferences?: AclpConfig; + /** * Indicates whether we need to save preferences or not */ - savePreferences: boolean; + savePreferences?: boolean; + updatePreferences?: (data: {}) => void; } /** @@ -57,6 +56,11 @@ interface CloudPulseCustomSelectionChangeProps { */ maxSelections?: number; + preferences?: AclpConfig; + savePreferences?: boolean; + + updatePreferences?: (data: {}) => void; + /** * The listed options in the custom select component */ @@ -81,12 +85,11 @@ export const getInitialDefaultSelections = ( handleSelectionChange, isMultiSelect, options, + preferences, savePreferences, } = defaultSelectionProps; - const defaultValue = savePreferences - ? getUserPreferenceObject()[filterKey] - : undefined; + const defaultValue = savePreferences ? preferences?.[filterKey] : undefined; if (!options || options.length === 0) { return isMultiSelect ? [] : undefined; } @@ -138,6 +141,8 @@ export const handleCustomSelectionChange = ( filterKey, handleSelectionChange, maxSelections, + savePreferences, + updatePreferences, } = selectionChangeProps; let { value } = selectionChangeProps; @@ -156,14 +161,16 @@ export const handleCustomSelectionChange = ( handleSelectionChange(filterKey, result); // update the preferences - updateGlobalFilterPreference({ - [filterKey]: result, - }); + if (savePreferences && updatePreferences) { + updatePreferences({ + [filterKey]: result, + }); + } // update the clear selections in the preference - if (clearSelections) { + if (clearSelections && savePreferences && updatePreferences) { clearSelections.forEach((selection) => - updateGlobalFilterPreference({ [selection]: undefined }) + updatePreferences({ [selection]: undefined }) ); } diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index 87dc2a85077..43f82c1c6bf 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -155,6 +155,8 @@ export const CloudPulseDashboardFilterBuilder = React.memo( dashboard, dependentFilters: dependentFilterReference.current, isServiceAnalyticsIntegration, + preferences, + updatePreferences, }, handleCustomSelectChange ); From a32940da528999f95bd14b2eb25920eafa6b398f Mon Sep 17 00:00:00 2001 From: nikhagra Date: Mon, 2 Sep 2024 18:39:22 +0530 Subject: [PATCH 008/474] upcoming: [DI-20360] - Metrics api hardcoded url removed --- packages/manager/src/queries/cloudpulse/metrics.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/manager/src/queries/cloudpulse/metrics.ts b/packages/manager/src/queries/cloudpulse/metrics.ts index df983c5a7b9..be599a9e32b 100644 --- a/packages/manager/src/queries/cloudpulse/metrics.ts +++ b/packages/manager/src/queries/cloudpulse/metrics.ts @@ -84,9 +84,7 @@ export const fetchCloudPulseMetrics = ( Authorization: `Bearer ${token}`, }, method: 'POST', - url: `https://metrics-query.aclp.linode.com/v1/monitor/services/${encodeURIComponent( - serviceType! - )}/metrics`, + url: `${readApiEndpoint}${encodeURIComponent(serviceType!)}/metrics`, }; return axiosInstance From 0545491d21d0ec7dfa388d3114e76f06dc46f23f Mon Sep 17 00:00:00 2001 From: nikhagra Date: Tue, 3 Sep 2024 18:22:33 +0530 Subject: [PATCH 009/474] upcoming: [DI-20360] - Updated jsdocs & removed un-used variable --- .../Dashboard/CloudPulseDashboard.tsx | 5 +++++ .../CloudPulse/Widget/CloudPulseWidget.tsx | 5 +---- .../shared/CloudPulseCustomSelect.tsx | 7 +++++++ .../shared/CloudPulseCustomSelectUtils.ts | 19 +++++++++++++++++++ .../CloudPulseDashboardFilterBuilder.tsx | 9 +++++++++ 5 files changed, 41 insertions(+), 4 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index 5277f9c3cf0..7750a1d2592 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -111,9 +111,14 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { return graphProp; }; + /** + * + * @param widgetObj Widget configuration received from metrics-definition api + */ const setPreferredWidgetPlan = (widgetObj: Widgets) => { const widgetPreferences = preferences.widgets; const pref = widgetPreferences?.[widgetObj.label]; + // if preference is present then update the widget properties present in preference if (pref) { Object.assign(widgetObj, { aggregate_function: diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 207f9c6c204..bbbae9a44c3 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -117,10 +117,7 @@ export interface LegendRow { } export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { - const { - preferences, - updateWidgetPreference: updatePreferences, - } = useAclpPreference(); + const { updateWidgetPreference: updatePreferences } = useAclpPreference(); const { data: profile } = useProfile(); const timezone = profile?.timezone ?? DateTime.local().zoneName; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index cf5782e9c1e..761b825af91 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -87,6 +87,9 @@ export interface CloudPulseCustomSelectProps { */ placeholder?: string; + /** + * Last selected values from user preferences + */ preferences?: AclpConfig; /** @@ -99,6 +102,10 @@ export interface CloudPulseCustomSelectProps { */ type: CloudPulseSelectTypes; + /** + * Function to update the user preference + * @param data Data to be updated in the preferences + */ updatePreferences?: (data: {}) => void; } diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts index b99baebecf2..783fb8b4bd6 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts @@ -25,12 +25,20 @@ interface CloudPulseCustomSelectDefaultValueProps { */ options: CloudPulseServiceTypeFiltersOptions[]; + /** + * Last selected values from user preference + */ preferences?: AclpConfig; /** * Indicates whether we need to save preferences or not */ savePreferences?: boolean; + + /** + * Function to update the user preference + * @param data Data to be updated in the preferences + */ updatePreferences?: (data: {}) => void; } @@ -56,9 +64,20 @@ interface CloudPulseCustomSelectionChangeProps { */ maxSelections?: number; + /** + * Last selected values from user preference + */ preferences?: AclpConfig; + + /** + * boolean variable to check whether preferences should be saved or not + */ savePreferences?: boolean; + /** + * Function to update the user preference + * @param data Data to be updated in the preferences + */ updatePreferences?: (data: {}) => void; /** diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index 43f82c1c6bf..503f5df3323 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -43,7 +43,16 @@ export interface CloudPulseDashboardFilterBuilderProps { * this will handle the restrictions, if the parent of the component is going to be integrated in service analytics page */ isServiceAnalyticsIntegration: boolean; + + /** + * Last selected values from user preferences + */ preferences?: AclpConfig; + + /** + * Function to update the user preference + * @param data Data to be updated in the preferences + */ updatePreferences?: (data: {}) => void; } From 33938a5184a022a463e1034fd917f992ff082f2c Mon Sep 17 00:00:00 2001 From: nikhagra Date: Tue, 3 Sep 2024 19:12:08 +0530 Subject: [PATCH 010/474] upcoming: [DI-20360] - Test cases updated --- packages/api-v4/src/cloudpulse/services.ts | 6 +-- .../CloudPulse/Utils/UserPreference.ts | 1 - .../CloudPulseCustomSelectUtils.test.ts | 40 ++++++++----------- .../shared/CloudPulseDashboardSelect.test.tsx | 14 +++---- .../shared/CloudPulseResourcesSelect.test.tsx | 8 +--- 5 files changed, 26 insertions(+), 43 deletions(-) diff --git a/packages/api-v4/src/cloudpulse/services.ts b/packages/api-v4/src/cloudpulse/services.ts index fb17cc506ca..0ace1f4ceea 100644 --- a/packages/api-v4/src/cloudpulse/services.ts +++ b/packages/api-v4/src/cloudpulse/services.ts @@ -22,16 +22,12 @@ export const getMetricDefinitionsByServiceType = (serviceType: string) => { export const getJWEToken = (data: JWETokenPayLoad, serviceType: string) => Request( setURL( - `${API_ROOT}/monitor/services/${encodeURIComponent( - serviceType - )}/token` + `${API_ROOT}/monitor/services/${encodeURIComponent(serviceType)}/token` ), setMethod('POST'), setData(data) ); - - // Returns the list of service types available export const getCloudPulseServiceTypes = () => Request( diff --git a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts index 82dab96481d..3bbd327e95b 100644 --- a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts +++ b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts @@ -5,7 +5,6 @@ import { usePreferences, } from 'src/queries/profile/preferences'; - import { DASHBOARD_ID, TIME_DURATION } from './constants'; import type { AclpWidget } from '@linode/api-v4'; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.test.ts b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.test.ts index 0c1bc3e1844..3a18762e49e 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.test.ts +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.test.ts @@ -5,20 +5,6 @@ import { import type { CloudPulseServiceTypeFiltersOptions } from '../Utils/models'; -const queryMocks = vi.hoisted(() => ({ - getUserPreferenceObject: vi.fn().mockReturnValue({ - test: '1', - }), -})); - -vi.mock('../Utils/UserPreference', async () => { - const actual = await vi.importActual('../Utils/UserPreference'); - return { - ...actual, - getUserPreferenceObject: queryMocks.getUserPreferenceObject, - }; -}); - it('test handleCustomSelectionChange method for single selection', () => { const selectedValue: CloudPulseServiceTypeFiltersOptions = { id: '1', @@ -73,22 +59,27 @@ it('test getInitialDefaultSelections method for single selection', () => { handleSelectionChange, isMultiSelect: false, options, + preferences: { + test: '1', + }, savePreferences: true, + updatePreferences: (_: {}) => {}, }); expect(Array.isArray(result)).toBe(false); expect(result).toEqual(options[0]); expect(handleSelectionChange).toBeCalledTimes(1); - queryMocks.getUserPreferenceObject.mockReturnValue({ - test: '2', - }); result = getInitialDefaultSelections({ filterKey: 'test', handleSelectionChange, isMultiSelect: false, options, + preferences: { + test: '2', + }, savePreferences: true, + updatePreferences: (_: {}) => {}, }); expect(result).toEqual(undefined); expect(handleSelectionChange).toBeCalledTimes(2); @@ -97,10 +88,6 @@ it('test getInitialDefaultSelections method for single selection', () => { it('test getInitialDefaultSelections method for multi selection', () => { const handleSelectionChange = vi.fn(); - queryMocks.getUserPreferenceObject.mockReturnValue({ - test: '1', - }); - const options: CloudPulseServiceTypeFiltersOptions[] = [ { id: '1', @@ -113,22 +100,27 @@ it('test getInitialDefaultSelections method for multi selection', () => { handleSelectionChange, isMultiSelect: true, options, + preferences: { + test: '1', + }, savePreferences: true, + updatePreferences: (_: {}) => {}, }); expect(Array.isArray(result)).toBe(true); expect(result).toEqual(options); expect(handleSelectionChange).toBeCalledTimes(1); - queryMocks.getUserPreferenceObject.mockReturnValue({ - test: '2', - }); result = getInitialDefaultSelections({ filterKey: 'test', handleSelectionChange, isMultiSelect: false, options, + preferences: { + test: '2', + }, savePreferences: true, + updatePreferences: (_: {}) => {}, }); expect(result).toEqual(undefined); expect(handleSelectionChange).toBeCalledTimes(2); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx index 1ff706d78d5..300c184dfe7 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx @@ -5,12 +5,9 @@ import { dashboardFactory } from 'src/factories'; import * as utils from 'src/features/CloudPulse/Utils/utils'; import { renderWithTheme } from 'src/utilities/testHelpers'; -import { DASHBOARD_ID } from '../Utils/constants'; -import * as preferences from '../Utils/UserPreference'; import { CloudPulseDashboardSelect } from './CloudPulseDashboardSelect'; import type { CloudPulseDashboardSelectProps } from './CloudPulseDashboardSelect'; -import type { AclpConfig } from '@linode/api-v4'; const dashboardLabel = 'Factory Dashboard-1'; const props: CloudPulseDashboardSelectProps = { @@ -89,10 +86,13 @@ describe('CloudPulse Dashboard select', () => { ); }), it('Should select the default value from preferences', () => { - const mockFunction = vi.spyOn(preferences, 'getUserPreferenceObject'); - mockFunction.mockReturnValue({ [DASHBOARD_ID]: 1 } as AclpConfig); - - renderWithTheme(); + renderWithTheme( + + ); expect(screen.getByRole('combobox')).toHaveAttribute( 'value', diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx index 1567a0681d2..6a256900de6 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx @@ -5,11 +5,8 @@ import { linodeFactory } from 'src/factories'; import { renderWithTheme } from 'src/utilities/testHelpers'; import { RESOURCES } from '../Utils/constants'; -import * as preferences from '../Utils/UserPreference'; import { CloudPulseResourcesSelect } from './CloudPulseResourcesSelect'; -import type { AclpConfig } from '@linode/api-v4'; - const queryMocks = vi.hoisted(() => ({ useResourcesQuery: vi.fn().mockReturnValue({}), })); @@ -174,15 +171,14 @@ describe('CloudPulseResourcesSelect component tests', () => { isLoading: false, status: 'success', }); - vi.spyOn(preferences, 'getUserPreferenceObject').mockReturnValue({ - [RESOURCES]: ['12'], - } as AclpConfig); renderWithTheme( ); From c27988537bf6b44e31c466a424c6ac95138625ef Mon Sep 17 00:00:00 2001 From: nikhagra Date: Tue, 3 Sep 2024 19:24:45 +0530 Subject: [PATCH 011/474] upcoming: [DI-20360] - added changeset --- .../.changeset/pr-10853-upcoming-features-1725371578425.md | 5 +++++ .../.changeset/pr-10853-upcoming-features-1725371660855.md | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 packages/api-v4/.changeset/pr-10853-upcoming-features-1725371578425.md create mode 100644 packages/manager/.changeset/pr-10853-upcoming-features-1725371660855.md diff --git a/packages/api-v4/.changeset/pr-10853-upcoming-features-1725371578425.md b/packages/api-v4/.changeset/pr-10853-upcoming-features-1725371578425.md new file mode 100644 index 00000000000..96feffe8820 --- /dev/null +++ b/packages/api-v4/.changeset/pr-10853-upcoming-features-1725371578425.md @@ -0,0 +1,5 @@ +--- +"@linode/api-v4": Upcoming Features +--- + +Add export to FilterValue interface ([#10853](https://github.com/linode/manager/pull/10853)) diff --git a/packages/manager/.changeset/pr-10853-upcoming-features-1725371660855.md b/packages/manager/.changeset/pr-10853-upcoming-features-1725371660855.md new file mode 100644 index 00000000000..90e7665b557 --- /dev/null +++ b/packages/manager/.changeset/pr-10853-upcoming-features-1725371660855.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Upcoming Features +--- + +add useAclpPreference hook in UserPreference.ts, update CloudPulseWidget.ts, CloudPulseDashboard & GlobalFilters to use useAclpPreference and pass preference values to child component ([#10853](https://github.com/linode/manager/pull/10853)) From 21496fb86157dca26e8170a2d252173b75189b50 Mon Sep 17 00:00:00 2001 From: nikhagra Date: Tue, 3 Sep 2024 22:14:19 +0530 Subject: [PATCH 012/474] upcoming: [DI-20360] - Removed unused variable --- .../features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx index f92cf807e8a..11b2ea67db0 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx @@ -4,7 +4,7 @@ import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; import { TIME_DURATION } from '../Utils/constants'; -import type { AclpConfig, TimeDuration } from '@linode/api-v4'; +import type { TimeDuration } from '@linode/api-v4'; import type { BaseSelectProps, Item, From a4d7132b43620400cc821d2fa3d60cfffa505dcf Mon Sep 17 00:00:00 2001 From: agorthi Date: Thu, 5 Sep 2024 17:36:32 +0530 Subject: [PATCH 013/474] upcoming:[DI-20585]- added aclp e2e test cases --- .../core/cloudpulse/dashboard-filters.spec.ts | 56 +++ .../cloudpulse/widget-verification.spec.ts | 109 ++++++ .../cypress/support/constants/aggregation.ts | 11 + .../cypress/support/constants/granularity.ts | 13 + .../manager/cypress/support/constants/time.ts | 5 + .../cypress/support/constants/timerange.ts | 13 + .../cypress/support/constants/widgets.ts | 6 + .../intercepts/cloudpulseAPIHandler.ts | 12 + .../cypress/support/ui/autocomplete.ts | 28 ++ .../manager/cypress/support/ui/cloudpulse.ts | 26 ++ packages/manager/cypress/support/ui/index.ts | 2 + .../cypress/support/util/cloudpulse.ts | 357 ++++++++++++++++++ 12 files changed, 638 insertions(+) create mode 100644 packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts create mode 100644 packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts create mode 100644 packages/manager/cypress/support/constants/aggregation.ts create mode 100644 packages/manager/cypress/support/constants/granularity.ts create mode 100644 packages/manager/cypress/support/constants/time.ts create mode 100644 packages/manager/cypress/support/constants/timerange.ts create mode 100644 packages/manager/cypress/support/constants/widgets.ts create mode 100644 packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts create mode 100644 packages/manager/cypress/support/ui/cloudpulse.ts create mode 100644 packages/manager/cypress/support/util/cloudpulse.ts diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts new file mode 100644 index 00000000000..1b177cd63cf --- /dev/null +++ b/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts @@ -0,0 +1,56 @@ +import { + navigateToCloudpulse, + selectServiceName, + selectRegion, + selectTimeRange, + selectAndVerifyServiceName, + assertSelections, + visitCloudPulseWithFeatureFlagsDisabled, + dashboardName, + actualRelativeTimeDuration, + region, + resource, + verifyZerothPage, +} from 'support/util/cloudpulse'; + +/** + * This test suite focuses on the standard operations and verifications for the Cloudpulse dashboard. + * + * The tests include verifying the visibility and functionality of the Cloud View when the feature flag is disabled, + * clearing and resetting dashboard preferences, and ensuring that specific selections such as dashboard name, + * time range, region, and resources are correctly applied and verified. + * + * Each test case checks the correctness and persistence of these configurations to ensure that the + * dashboard behaves as expected under various conditions. + */ + +describe('Standard Dashboard Filter Application and Configuration Tests', () => { + beforeEach(() => { + navigateToCloudpulse(); + }); + + it('should verify cloudpulse availability when feature flag is set to false', () => { + visitCloudPulseWithFeatureFlagsDisabled(); + }); + + it('should clear the preferences of the dashboard', () => { + verifyZerothPage(dashboardName); + }); + it('should set and verify dashboard name', () => { + selectServiceName(dashboardName); + assertSelections(dashboardName); + }); + it('should set and verify time range', () => { + selectTimeRange(actualRelativeTimeDuration); + assertSelections(actualRelativeTimeDuration); + }); + + it('should set and verify region', () => { + selectRegion(region); + assertSelections(region); + }); + + it('should set and verify resource', () => { + selectAndVerifyServiceName(resource); + }); +}); diff --git a/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts new file mode 100644 index 00000000000..3e0291428f2 --- /dev/null +++ b/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts @@ -0,0 +1,109 @@ +import { + navigateToCloudpulse, + selectTimeRange, + cloudpulseTestData, + validateWidgetTitle, + setGranularity, + setAggregation, + verifyGranularity, + verifyAggregation, + verifyZoomInOut, + applyGlobalRefresh, +} from 'support/util/cloudpulse'; +import { timeUnit } from 'support/constants/time'; +import { interceptMetricsRequests } from 'support/intercepts/cloudpulseAPIHandler'; +import { timeRange } from 'support/constants/timerange'; +export const actualRelativeTimeDuration = timeRange.Last30Minutes; + +/** + * This test ensures that widget titles are displayed correctly on the dashboard. + * This test suite is dedicated to verifying the functionality and display of widgets on the Cloudpulse dashboard. + * It includes: + * Validating that widgets are correctly loaded and displayed. + * Ensuring that widget titles and data match the expected values. + * Verifying that widget settings, such as granularity and aggregation, are applied correctly. + * Testing widget interactions, including zooming and filtering, to ensure proper behavior. + * Each test ensures that widgets on the dashboard operate correctly and display accurate information. + */ + +describe('Dashboard Widget Verification Tests', () => { + beforeEach(() => { + navigateToCloudpulse(); + selectTimeRange(actualRelativeTimeDuration); + }); + + it(`should verify the title of the widget`, () => { + cloudpulseTestData.forEach((testData) => { + validateWidgetTitle(testData.title); + }); + }); + it(`should set available granularity of the all the widget`, () => { + cloudpulseTestData.forEach((testData) => { + setGranularity(testData.title, testData.expectedGranularity); + }); + }); + it(`should set available aggregation of the all the widget`, () => { + cloudpulseTestData.forEach((testData) => { + setAggregation(testData.title, testData.expectedAggregation); + }); + }); + it(`should verify available granularity of the widget`, () => { + cloudpulseTestData.forEach((testData) => { + verifyGranularity(testData.title, testData.expectedGranularityArray); + }); + }); + + it(`should verify available aggregation of the widget`, () => { + cloudpulseTestData.forEach((testData) => { + verifyAggregation(testData.title, testData.expectedAggregationArray); + }); + }); + it(`should zoom in and out of the all the widget`, () => { + cloudpulseTestData.forEach((testData) => { + verifyZoomInOut(testData.title); + }); + }); + it('should apply global refresh button and verify network calls', () => { + applyGlobalRefresh(); + + interceptMetricsRequests().then((xhrArray) => { + xhrArray.forEach((xhr) => { + const { body: requestPayload } = xhr.request; + const metric = requestPayload.metric; + const metricData = cloudpulseTestData.find( + (data) => data.name === metric + ); + + if (!metricData) { + throw new Error(`Unknown metric: ${metric}`); + } + + const granularity = requestPayload['time_granularity']; + const currentGranularity = granularity + ? granularity.value + granularity.unit + : ''; + + const durationUnit = requestPayload.relative_time_duration.unit.toLowerCase(); + const durationValue = requestPayload.relative_time_duration.value; + const currentRelativeTimeDuration = + durationUnit in timeUnit + ? 'Last' + + durationValue + + timeUnit[durationUnit as keyof typeof timeUnit] + : ''; + + // Assertions + expect(requestPayload.aggregate_function).to.equal( + metricData.expectedAggregation + ); + expect(currentRelativeTimeDuration).to.containIgnoreSpaces( + actualRelativeTimeDuration + ); + expect(currentGranularity).to.containIgnoreSpaces( + metricData.expectedGranularity + ); + expect(requestPayload.metric).to.containIgnoreSpaces(metricData.name); + }); + }); + }); +}); diff --git a/packages/manager/cypress/support/constants/aggregation.ts b/packages/manager/cypress/support/constants/aggregation.ts new file mode 100644 index 00000000000..e637de39ceb --- /dev/null +++ b/packages/manager/cypress/support/constants/aggregation.ts @@ -0,0 +1,11 @@ +export enum aggregation { + Avg = 'avg', + Max = 'max', + Min = 'min', + Sum = 'sum', +} + +export const aggregationConfig = { + all: [aggregation.Avg, aggregation.Max, aggregation.Min, aggregation.Sum], + basic: [aggregation.Avg, aggregation.Max, aggregation.Min], +}; diff --git a/packages/manager/cypress/support/constants/granularity.ts b/packages/manager/cypress/support/constants/granularity.ts new file mode 100644 index 00000000000..72e8253c027 --- /dev/null +++ b/packages/manager/cypress/support/constants/granularity.ts @@ -0,0 +1,13 @@ +export enum granularity { + Auto = 'Auto', + Day1 = '1 min', + Hr1 = '5 min', + Min1 = '1 hr', + Min5 = '1 day', +} + +export enum timeUnit { + Day = 'day', + Hr = 'hr', + Min = 'min', +} diff --git a/packages/manager/cypress/support/constants/time.ts b/packages/manager/cypress/support/constants/time.ts new file mode 100644 index 00000000000..c91032898b7 --- /dev/null +++ b/packages/manager/cypress/support/constants/time.ts @@ -0,0 +1,5 @@ +export enum timeUnit { + day = 'Days', + hr = 'Hours', + min = 'Minutes', +} diff --git a/packages/manager/cypress/support/constants/timerange.ts b/packages/manager/cypress/support/constants/timerange.ts new file mode 100644 index 00000000000..88520ccb87a --- /dev/null +++ b/packages/manager/cypress/support/constants/timerange.ts @@ -0,0 +1,13 @@ +export enum timeRange { + Last7Days = 'Last 7 Days', + Last12Hours = 'Last 12 Hours', + Last24Hours = 'Last 24 Hours', + Last30Days = 'Last 30 Days', + Last30Minutes = 'Last 30 Minutes', +} + +export enum timeUnit { + Day = 'day', + Hr = 'hr', + Min = 'min', +} diff --git a/packages/manager/cypress/support/constants/widgets.ts b/packages/manager/cypress/support/constants/widgets.ts new file mode 100644 index 00000000000..5e193af9bff --- /dev/null +++ b/packages/manager/cypress/support/constants/widgets.ts @@ -0,0 +1,6 @@ +export const widgets = { + system_cpu_utilization_percent: 'CPU Utilization', + system_disk_OPS_total: 'Disk I/O', + system_memory_usage_by_resource: 'Memory Usage', + system_network_io_by_resource: 'Network Traffic', +}; diff --git a/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts b/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts new file mode 100644 index 00000000000..fafc355950c --- /dev/null +++ b/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts @@ -0,0 +1,12 @@ +/** + * Intercepts request to metrics requests for a cloud pulse. + * + * @returns Cypress chainable. + */ +export const interceptMetricsRequests = () => { + cy.intercept({ + method: 'POST', + url: '**/monitor/services/linode/metrics', + }).as('getMetrics'); + return cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']); +}; diff --git a/packages/manager/cypress/support/ui/autocomplete.ts b/packages/manager/cypress/support/ui/autocomplete.ts index 86356ab3d88..fcb4ef31c14 100644 --- a/packages/manager/cypress/support/ui/autocomplete.ts +++ b/packages/manager/cypress/support/ui/autocomplete.ts @@ -13,6 +13,34 @@ export const autocomplete = { find: (): Cypress.Chainable => { return cy.get('[data-qa-autocomplete] input'); }, + /** + * Finds an autocomplete input element by its placeholder text. + * This method is useful for locating input fields within autocomplete components + * when the placeholder text is known. + * + * @param {string} title - The placeholder text of the input element. + * @param {SelectorMatcherOptions} [options] - Optional additional options for selecting elements. + * @returns {Cypress.Chainable} - A Cypress chainable object that represents the located element. + */ + findByPlaceholderCustom: ( + title: string, + options?: SelectorMatcherOptions + ): Cypress.Chainable => { + return cy.get("[data-qa-autocomplete] input[placeholder='" + title + "']"); + }, + + /** + * Finds an autocomplete element by its title attribute. + * This method is used to locate elements with a specific title attribute within + * autocomplete components, useful for when you need to interact with elements + * identified by their title. + * + * @param {string} title - The value of the title attribute for the autocomplete element. + * @returns {Cypress.Chainable} - A Cypress chainable object that represents the located element. + */ + findByTitleCustom: (title: string): Cypress.Chainable => { + return cy.get('[data-qa-autocomplete="' + title + '"]'); + }, }; /** diff --git a/packages/manager/cypress/support/ui/cloudpulse.ts b/packages/manager/cypress/support/ui/cloudpulse.ts new file mode 100644 index 00000000000..02f6e3115eb --- /dev/null +++ b/packages/manager/cypress/support/ui/cloudpulse.ts @@ -0,0 +1,26 @@ +/** + * cloudpulse RefreshIcon,Zoom Button UI element. + */ +export const cloudpulse = { + /** + * Finds a refresh button within the UI and returns the corresponding Cypress chainable object. + * This method is useful for locating and interacting with the refresh button in the user interface. + * + * @returns {Cypress.Chainable} - A Cypress chainable object representing the refresh button. + */ + findRefreshIcon: (): Cypress.Chainable => { + return cy.get('[data-qa-refresh-button="true"]'); + }, + + /** + * Generates a selector for a zoom button within a button group based on its title. + * This method helps in locating specific zoom buttons by their title attribute within a group of buttons. + * + * @param {string} buttonTitle - The title of the zoom button to find. + * + * @returns {string} - A string representing the CSS selector for the zoom button. + */ + findZoomButtonByTitle: (buttonTitle: string): string => { + return `[data-qa-zoomer="${buttonTitle}"]`; + }, +}; diff --git a/packages/manager/cypress/support/ui/index.ts b/packages/manager/cypress/support/ui/index.ts index 26d8b89ac17..8eff88aa598 100644 --- a/packages/manager/cypress/support/ui/index.ts +++ b/packages/manager/cypress/support/ui/index.ts @@ -3,6 +3,7 @@ import * as actionMenu from './action-menu'; import * as autocomplete from './autocomplete'; import * as breadcrumb from './breadcrumb'; import * as buttons from './buttons'; +import { cloudpulse } from './cloudpulse'; import * as dialog from './dialog'; import * as drawer from './drawer'; import * as entityHeader from './entity-header'; @@ -38,4 +39,5 @@ export const ui = { ...toggle, ...tooltip, ...userMenu, + ...cloudpulse, }; diff --git a/packages/manager/cypress/support/util/cloudpulse.ts b/packages/manager/cypress/support/util/cloudpulse.ts new file mode 100644 index 00000000000..cc2d37fe92d --- /dev/null +++ b/packages/manager/cypress/support/util/cloudpulse.ts @@ -0,0 +1,357 @@ +/* eslint-disable cypress/unsafe-to-chain-command */ +import 'cypress-wait-until'; +import { aggregation, aggregationConfig } from 'support/constants/aggregation'; +import { granularity } from 'support/constants/granularity'; +import { timeRange } from 'support/constants/timerange'; +import { + mockAppendFeatureFlags, + mockGetFeatureFlagClientstream, +} from 'support/intercepts/feature-flags'; +import { ui } from 'support/ui'; +import { makeFeatureFlagData } from 'support/util/feature-flags'; + +export const dashboardName = 'Linode Service I/O Statistics'; +export const region = 'US, Chicago, IL (us-ord)'; +export const actualRelativeTimeDuration = timeRange.Last24Hours; +export const resource = 'test1'; + +/** + * This class provides utility functions for interacting with the Cloudpulse dashboard + * in a Cypress test suite. It includes methods for: + * - Navigating to the Cloudpulse page + * - Selecting and verifying dashboard options (service names, regions, time ranges) + * - Managing feature flags + * - Setting and validating widget configurations (granularity, aggregation) + * - Performing actions like zooming in and out on widgets + * These utilities ensure efficient and consistent test execution and validation. + */ +export const cloudpulseTestData = [ + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.all, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_disk_OPS_total', + title: 'Disk I/O', + }, + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.all, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_network_io_by_resource', + title: 'Network Traffic', + }, + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.all, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_memory_usage_by_resource', + title: 'Memory Usage', + }, + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.basic, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_cpu_utilization_percent', + title: 'CPU Utilization', + }, +]; + +/** + * Navigates to the Cloudpulse dashboard and waits for the page to load. + */ +export const navigateToCloudpulse = () => { + mockAppendFeatureFlags({ aclp: makeFeatureFlagData(true) }).as( + 'getFeatureFlags' + ); + mockGetFeatureFlagClientstream().as('getClientStream'); + + cy.visitWithLogin('/monitor/cloudpulse', { + onLoad: (contentWindow: Window) => { + if (contentWindow.document.readyState !== 'complete') { + throw new Error('Page did not load completely'); + } + }, + timeout: 500, + }); + + cy.wait(['@getFeatureFlags', '@getClientStream']); + cy.url().should('include', '/monitor/cloudpulse'); + waitForPageToLoad(); +}; + +/** + * Waits for the Cloudpulse page to fully load and checks that key elements are visible. + */ +export const waitForPageToLoad = () => { + cy.get('[data-testid="circle-progress"]').should('not.exist'); + + const keyElementsSelectors = ['[data-testid="textfield-input"]']; + keyElementsSelectors.forEach((selector) => { + cy.get(selector).should('be.visible'); + }); +}; + +/** + * Visits the Linodes page when the Cloudpulse feature flag is disabled, + * and verifies that the Monitor tab is not present. + */ +export const visitCloudPulseWithFeatureFlagsDisabled = () => { + cy.visitWithLogin('/linodes'); + mockAppendFeatureFlags({ aclp: makeFeatureFlagData(false) }).as( + 'getFeatureFlags' + ); + mockGetFeatureFlagClientstream().as('getClientStream'); + + cy.findByLabelText('Monitor').should('not.exist'); +}; + +/** + * Selects a service name from the dashboard dropdown. + * @param {string} serviceName - The name of the service to select. + */ +export const selectServiceName = (serviceName: string) => { + ui.autocomplete + .findByTitleCustom('Select Dashboard') + .findByTitle('Open') + .click(); + ui.autocompletePopper.findByTitle(serviceName).should('be.visible').click(); +}; + +/** + * Selects a region from the region dropdown. + * @param {string} region - The name of the region to select. + */ +export const selectRegion = (region: string) => { + // ui.regionSelect.find().click(); + // ui.autocompletePopper.findByTitle(region); + ui.regionSelect.find().click().type(`${region}{enter}`); +}; + +/** + * Selects a time range from the time range dropdown. + * @param {string} timeRange - The time range to select. + */ +export const selectTimeRange = (timeRange: string) => { + ui.autocomplete + .findByTitleCustom('Select Time Duration') + .findByTitle('Open') + .click(); + ui.autocompletePopper.findByTitle(timeRange).should('be.visible').click(); +}; + +/** + * Selects a resource name from the resources dropdown and verifies the selection. + * @param {string} service - The name of the service to select. + */ +export const selectAndVerifyServiceName = (service: string) => { + const resourceInput = ui.autocomplete.findByTitleCustom('Select Resources'); + resourceInput.findByTitle('Open').click(); + resourceInput.click().type(`${service}{enter}`); + //resourceInput.findByTitle('Close').click(); +}; + +/** + * Asserts that the selected options match the expected values. + * @param {string} expectedOptions - The expected options to verify. + */ +export const assertSelections = (expectedOptions: string) => { + expect(cy.get(`[value*='${expectedOptions}']`), expectedOptions); +}; + +/** + * Applies a global refresh action on the dashboard. + */ +export const applyGlobalRefresh = () => { + ui.cloudpulse.findRefreshIcon().click(); +}; +/** + * Clears the dashboard's preferences and verifies the zeroth page. + * @param {string} serviceName - The name of the service to verify. + */ +export const verifyZerothPage = (serviceName: string) => { + ui.autocomplete + .findByTitleCustom('Select Dashboard') + .findByTitle('Open') + .click(); + ui.autocompletePopper.findByTitle(serviceName).should('be.visible').click(); + ui.autocomplete + .findByTitleCustom('Select Dashboard') + .findByTitle('Clear') + .click(); +}; + +/** + * Validates that the widget title matches the expected title. + * @param {string} widgetName - The name of the widget to verify. + */ +export const validateWidgetTitle = (widgetName: string) => { + const widgetSelector = `[data-qa-widget="${widgetName}"]`; + cy.get(widgetSelector) + .find('h1') + .invoke('text') + .then((actualTitle) => { + expect(actualTitle.trim()).to.equal(widgetName); + }); +}; + +/** + * Sets the granularity of a widget. + * @param {string} widgetName - The name of the widget to set granularity for. + * @param {string} granularity - The granularity to select. + */ +export const setGranularity = (widgetName: string, granularity: string) => { + cy.log('widgetName***', widgetName); + const widgetSelector = `[data-qa-widget="${widgetName}"]`; + cy.get(widgetSelector) + .first() + .should('be.visible') + .within(() => { + ui.autocomplete + .findByTitleCustom('Select an Interval') + .findByTitle('Open') + .click(); + ui.autocompletePopper + .findByTitle(granularity) + .should('be.visible') + .click(); + assertSelections(granularity); + }); +}; + +/** + * Sets the aggregation function of a widget. + * @param {string} widgetName - The name of the widget to set aggregation for. + * @param {string} aggregation - The aggregation function to select. + */ +export const setAggregation = (widgetName: string, aggregation: string) => { + const widgetSelector = `[data-qa-widget="${widgetName}"]`; + cy.get(widgetSelector) + .first() + .should('be.visible') + .within(() => { + ui.autocomplete + .findByTitleCustom('Select an Aggregate Function') + .findByTitle('Open') + .click(); + ui.autocompletePopper + .findByTitle(aggregation) + .should('be.visible') + .click(); + assertSelections(aggregation); + }); +}; + +/** + * Verifies that the granularity options available for a widget match the expected options. + * @param {string} widgetName - The name of the widget to verify. + * @param {string[]} expectedGranularityOptions - The expected granularity options. + */ + +export const verifyGranularity = ( + widgetName: string, + expectedGranularityOptions: string[] +) => { + const widgetSelector = `[data-qa-widget="${widgetName}"]`; + cy.get(widgetSelector) + .first() + .scrollIntoView() + .should('be.visible') + .within(() => { + ui.autocomplete + .findByTitleCustom('Select an Interval') + .findByTitle('Open') + .click(); + expectedGranularityOptions.forEach((option) => { + ui.autocompletePopper + .findByTitle(option) + .should('be.visible') + .then(() => { + cy.log(`${option} is visible`); + }); + }); + ui.autocomplete + .findByTitleCustom('Select an Interval') + .findByTitle('Close') + .click(); + }); +}; + +/** + * Verifies that the aggregation options available for a widget match the expected options. + * @param {string} widgetName - The name of the widget to verify. + * @param {string[]} expectedAggregationOptions - The expected aggregation options. + */ + +export const verifyAggregation = ( + widgetName: string, + expectedAggregationOptions: string[] +) => { + const widgetSelector = `[data-qa-widget="${widgetName}"]`; + cy.get(widgetSelector) + .first() + .scrollIntoView() + .should('be.visible') + .within(() => { + ui.autocomplete + .findByTitleCustom('Select an Aggregate Function') + .findByTitle('Open') + .click(); + expectedAggregationOptions.forEach((option) => { + ui.autocompletePopper + .findByTitle(option) + .should('be.visible') + .then(() => { + cy.log(`${option} is visible`); + }); + }); + ui.autocomplete + .findByTitleCustom('Select an Aggregate Function') + .findByTitle('Close') + .click(); + }); +}; + +/** + * Verifies that zoom in and zoom out actions are available and performs them on a widget. + * @param {string} widgetName - The name of the widget to zoom in or out. + */ +export const verifyZoomInOut = (widgetName: string) => { + const widgetSelector = `[data-qa-widget="${widgetName}"]`; + const zoomInSelector = ui.cloudpulse.findZoomButtonByTitle('zoom-in'); + const zoomOutSelector = ui.cloudpulse.findZoomButtonByTitle('zoom-out'); + + cy.get(widgetSelector).each(($widget) => { + cy.wrap($widget).then(($el) => { + const zoomInAvailable = $el.find(zoomInSelector).length > 0; + const zoomOutAvailable = $el.find(zoomOutSelector).length > 0; + + if (zoomInAvailable) { + // eslint-disable-next-line cypress/unsafe-to-chain-command + cy.wrap($el) + .find(zoomInSelector) + .should('be.visible') + .click({ timeout: 5000 }) + .then(() => { + cy.log('Zoomed In on widget:', $el); + }); + } else if (zoomOutAvailable) { + cy.wrap($el) + .find(zoomOutSelector) + .should('be.visible') + .click({ timeout: 5000 }) + .then(() => { + cy.log('Zoomed Out on widget:', $el); + }); + } else { + cy.log( + 'Neither ZoomInMapIcon nor ZoomOutMapIcon found for widget:', + $el + ); + } + }); + }); +}; From 2b87944bf581eebd61003c3c673c92486be3ea53 Mon Sep 17 00:00:00 2001 From: agorthi Date: Thu, 5 Sep 2024 17:58:24 +0530 Subject: [PATCH 014/474] upcoming:[DI-20585]- added aclp e2e test cases --- .../manager/src/components/Autocomplete/Autocomplete.tsx | 2 +- packages/manager/src/components/LineGraph/LineGraph.tsx | 1 + .../src/features/CloudPulse/Overview/GlobalFilters.tsx | 1 + .../src/features/CloudPulse/Widget/CloudPulseWidget.tsx | 5 ++++- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/components/Autocomplete/Autocomplete.tsx b/packages/manager/src/components/Autocomplete/Autocomplete.tsx index e8644fbce4d..cf0bab2f76b 100644 --- a/packages/manager/src/components/Autocomplete/Autocomplete.tsx +++ b/packages/manager/src/components/Autocomplete/Autocomplete.tsx @@ -159,7 +159,7 @@ export const Autocomplete = < ChipProps={{ deleteIcon: }} PopperComponent={CustomPopper} clearOnBlur={clearOnBlur} - data-qa-autocomplete + data-qa-autocomplete={label} defaultValue={defaultValue} disableCloseOnSelect={multiple} disablePortal={disablePortal} diff --git a/packages/manager/src/components/LineGraph/LineGraph.tsx b/packages/manager/src/components/LineGraph/LineGraph.tsx index fa631573b07..28374ec83fd 100644 --- a/packages/manager/src/components/LineGraph/LineGraph.tsx +++ b/packages/manager/src/components/LineGraph/LineGraph.tsx @@ -383,6 +383,7 @@ export const LineGraph = (props: LineGraphProps) => { width: isLegendsFullSize ? '100%' : '85%', }} // this sx is added because styled table forcing the legends to be 85% width & 600px max width aria-label={`Controls for ${ariaLabel || 'Stats and metrics'}`} + data-qa-table-id={ariaLabel} noBorder > diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index 248e1fcfa33..bfda993d257 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -98,6 +98,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { sx={{ marginBlockEnd: 'auto', }} + data-qa-refresh-button disabled={!selectedDashboard} onClick={() => handleGlobalRefresh(selectedDashboard)} size="small" diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 06847a0573e..7d413ef5988 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -289,7 +289,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { const metricsApiCallError = error?.[0]?.reason; return ( - + { padding={1} > Date: Thu, 5 Sep 2024 18:03:12 +0530 Subject: [PATCH 015/474] upcoming:[DI-20585]- added missing message constants file --- packages/manager/cypress/support/constants/messages.ts | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 packages/manager/cypress/support/constants/messages.ts diff --git a/packages/manager/cypress/support/constants/messages.ts b/packages/manager/cypress/support/constants/messages.ts new file mode 100644 index 00000000000..fbcf2b5fa8f --- /dev/null +++ b/packages/manager/cypress/support/constants/messages.ts @@ -0,0 +1,6 @@ +export const expectedText = { + aclpMessage: 'Akamai Cloud Pulse', + noResult: 'No results', + nooption: 'You have no options to choose from', + selectDashboardMessage: 'Select Dashboard and filters to visualize metrics.', +}; From 1bc1a73e38d895560583ef5373032277f166198e Mon Sep 17 00:00:00 2001 From: agorthi Date: Thu, 5 Sep 2024 18:34:35 +0530 Subject: [PATCH 016/474] upcoming:[DI-20585]- added cloudpulse tsx file under ui/util files --- packages/manager/cypress/support/ui/index.ts | 2 +- packages/manager/cypress/support/util/cloudpulse.ts | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/manager/cypress/support/ui/index.ts b/packages/manager/cypress/support/ui/index.ts index 8eff88aa598..ac2c4fb61d6 100644 --- a/packages/manager/cypress/support/ui/index.ts +++ b/packages/manager/cypress/support/ui/index.ts @@ -3,7 +3,7 @@ import * as actionMenu from './action-menu'; import * as autocomplete from './autocomplete'; import * as breadcrumb from './breadcrumb'; import * as buttons from './buttons'; -import { cloudpulse } from './cloudpulse'; +import * as cloudpulse from './cloudpulse'; import * as dialog from './dialog'; import * as drawer from './drawer'; import * as entityHeader from './entity-header'; diff --git a/packages/manager/cypress/support/util/cloudpulse.ts b/packages/manager/cypress/support/util/cloudpulse.ts index cc2d37fe92d..23fadc47dd1 100644 --- a/packages/manager/cypress/support/util/cloudpulse.ts +++ b/packages/manager/cypress/support/util/cloudpulse.ts @@ -126,8 +126,6 @@ export const selectServiceName = (serviceName: string) => { * @param {string} region - The name of the region to select. */ export const selectRegion = (region: string) => { - // ui.regionSelect.find().click(); - // ui.autocompletePopper.findByTitle(region); ui.regionSelect.find().click().type(`${region}{enter}`); }; @@ -151,7 +149,7 @@ export const selectAndVerifyServiceName = (service: string) => { const resourceInput = ui.autocomplete.findByTitleCustom('Select Resources'); resourceInput.findByTitle('Open').click(); resourceInput.click().type(`${service}{enter}`); - //resourceInput.findByTitle('Close').click(); + // resourceInput.findByTitle('Close').click(); }; /** From 12c87433fd48855f8861092ef11cb1acba674106 Mon Sep 17 00:00:00 2001 From: agorthi Date: Thu, 5 Sep 2024 19:03:04 +0530 Subject: [PATCH 017/474] upcoming:[DI-20585]- added findByPlaceholderCustom for selectServiceName --- packages/manager/cypress/support/util/cloudpulse.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/manager/cypress/support/util/cloudpulse.ts b/packages/manager/cypress/support/util/cloudpulse.ts index 23fadc47dd1..19224fd94cb 100644 --- a/packages/manager/cypress/support/util/cloudpulse.ts +++ b/packages/manager/cypress/support/util/cloudpulse.ts @@ -118,7 +118,11 @@ export const selectServiceName = (serviceName: string) => { .findByTitleCustom('Select Dashboard') .findByTitle('Open') .click(); - ui.autocompletePopper.findByTitle(serviceName).should('be.visible').click(); + ui.autocomplete + .findByPlaceholderCustom('Select Dashboard') + .type(`${serviceName}{enter}`); + + // ui.autocompletePopper.findByTitle(serviceName).should('be.visible').click(); }; /** From a4c2fab60140b0d46434eaab59107d3c75d672c7 Mon Sep 17 00:00:00 2001 From: agorthi Date: Fri, 6 Sep 2024 16:56:23 +0530 Subject: [PATCH 018/474] upcoming:[DI-20585]- Added code review comments --- .../core/cloudpulse/dashboard-filters.spec.ts | 15 +- .../cloudpulse/widget-verification.spec.ts | 50 ++- .../cypress/support/constants/granularity.ts | 7 +- .../intercepts/cloudpulseAPIHandler.ts | 322 ++++++++++++++++++ .../cypress/support/util/cloudpulse.ts | 242 ++++++++----- .../cypress/support/util/widgetFactory.ts | 21 ++ .../cypress/support/util/widgetService.ts | 73 ++++ 7 files changed, 599 insertions(+), 131 deletions(-) create mode 100644 packages/manager/cypress/support/util/widgetFactory.ts create mode 100644 packages/manager/cypress/support/util/widgetService.ts diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts index 1b177cd63cf..f10b0757152 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts @@ -1,18 +1,17 @@ import { - navigateToCloudpulse, selectServiceName, selectRegion, selectTimeRange, - selectAndVerifyServiceName, + selectAndVerifyResource, assertSelections, visitCloudPulseWithFeatureFlagsDisabled, dashboardName, actualRelativeTimeDuration, region, resource, - verifyZerothPage, + resetDashboardAndVerifyPage, + initializeMockUserData, } from 'support/util/cloudpulse'; - /** * This test suite focuses on the standard operations and verifications for the Cloudpulse dashboard. * @@ -26,7 +25,7 @@ import { describe('Standard Dashboard Filter Application and Configuration Tests', () => { beforeEach(() => { - navigateToCloudpulse(); + initializeMockUserData(); }); it('should verify cloudpulse availability when feature flag is set to false', () => { @@ -34,7 +33,7 @@ describe('Standard Dashboard Filter Application and Configuration Tests', () => }); it('should clear the preferences of the dashboard', () => { - verifyZerothPage(dashboardName); + resetDashboardAndVerifyPage(dashboardName); }); it('should set and verify dashboard name', () => { selectServiceName(dashboardName); @@ -51,6 +50,6 @@ describe('Standard Dashboard Filter Application and Configuration Tests', () => }); it('should set and verify resource', () => { - selectAndVerifyServiceName(resource); + selectAndVerifyResource(resource); }); -}); + }); diff --git a/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts index 3e0291428f2..64526d67553 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts @@ -1,20 +1,21 @@ import { - navigateToCloudpulse, selectTimeRange, - cloudpulseTestData, validateWidgetTitle, setGranularity, setAggregation, verifyGranularity, verifyAggregation, - verifyZoomInOut, - applyGlobalRefresh, + checkZoomActions, + performGlobalRefresh, + initializeMockUserData, } from 'support/util/cloudpulse'; import { timeUnit } from 'support/constants/time'; -import { interceptMetricsRequests } from 'support/intercepts/cloudpulseAPIHandler'; +import { interceptMetricsRequests} from 'support/intercepts/cloudpulseAPIHandler'; import { timeRange } from 'support/constants/timerange'; export const actualRelativeTimeDuration = timeRange.Last30Minutes; +import { widgetDetails } from 'support/util/widgetService'; +const linodeWidgets = widgetDetails.linode; /** * This test ensures that widget titles are displayed correctly on the dashboard. * This test suite is dedicated to verifying the functionality and display of widgets on the Cloudpulse dashboard. @@ -25,64 +26,58 @@ export const actualRelativeTimeDuration = timeRange.Last30Minutes; * Testing widget interactions, including zooming and filtering, to ensure proper behavior. * Each test ensures that widgets on the dashboard operate correctly and display accurate information. */ - describe('Dashboard Widget Verification Tests', () => { beforeEach(() => { - navigateToCloudpulse(); + initializeMockUserData(); selectTimeRange(actualRelativeTimeDuration); }); - - it(`should verify the title of the widget`, () => { - cloudpulseTestData.forEach((testData) => { - validateWidgetTitle(testData.title); + it(`should set available granularity of the all the widget`, () => { + linodeWidgets.forEach((testData) => { + setGranularity(testData.title, testData.expectedGranularity); }); }); - it(`should set available granularity of the all the widget`, () => { - cloudpulseTestData.forEach((testData) => { - setGranularity(testData.title, testData.expectedGranularity); + it(`should verify the title of the widget`, () => { + linodeWidgets.forEach((testData) => { + validateWidgetTitle(testData.title); }); }); it(`should set available aggregation of the all the widget`, () => { - cloudpulseTestData.forEach((testData) => { + linodeWidgets.forEach((testData) => { setAggregation(testData.title, testData.expectedAggregation); }); }); it(`should verify available granularity of the widget`, () => { - cloudpulseTestData.forEach((testData) => { + linodeWidgets.forEach((testData) => { verifyGranularity(testData.title, testData.expectedGranularityArray); }); }); it(`should verify available aggregation of the widget`, () => { - cloudpulseTestData.forEach((testData) => { + linodeWidgets.forEach((testData) => { verifyAggregation(testData.title, testData.expectedAggregationArray); }); }); it(`should zoom in and out of the all the widget`, () => { - cloudpulseTestData.forEach((testData) => { - verifyZoomInOut(testData.title); + linodeWidgets.forEach((testData) => { + checkZoomActions(testData.title); }); }); it('should apply global refresh button and verify network calls', () => { - applyGlobalRefresh(); - + performGlobalRefresh(); interceptMetricsRequests().then((xhrArray) => { xhrArray.forEach((xhr) => { const { body: requestPayload } = xhr.request; const metric = requestPayload.metric; - const metricData = cloudpulseTestData.find( + const metricData = linodeWidgets.find( (data) => data.name === metric ); - - if (!metricData) { + if (!metricData) { throw new Error(`Unknown metric: ${metric}`); } - const granularity = requestPayload['time_granularity']; const currentGranularity = granularity ? granularity.value + granularity.unit : ''; - const durationUnit = requestPayload.relative_time_duration.unit.toLowerCase(); const durationValue = requestPayload.relative_time_duration.value; const currentRelativeTimeDuration = @@ -91,8 +86,6 @@ describe('Dashboard Widget Verification Tests', () => { durationValue + timeUnit[durationUnit as keyof typeof timeUnit] : ''; - - // Assertions expect(requestPayload.aggregate_function).to.equal( metricData.expectedAggregation ); @@ -107,3 +100,4 @@ describe('Dashboard Widget Verification Tests', () => { }); }); }); + diff --git a/packages/manager/cypress/support/constants/granularity.ts b/packages/manager/cypress/support/constants/granularity.ts index 72e8253c027..89ee2164ce9 100644 --- a/packages/manager/cypress/support/constants/granularity.ts +++ b/packages/manager/cypress/support/constants/granularity.ts @@ -1,9 +1,8 @@ export enum granularity { Auto = 'Auto', - Day1 = '1 min', - Hr1 = '5 min', - Min1 = '1 hr', - Min5 = '1 day', + Day1 = '1 day', + Hr1 = '1 hr', + Min5 = '5 min', } export enum timeUnit { diff --git a/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts b/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts index fafc355950c..5a5a9d6f8e9 100644 --- a/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts +++ b/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts @@ -3,6 +3,319 @@ * * @returns Cypress chainable. */ + +import { apiMatcher } from 'support/util/intercepts'; +const dashboardMetricsData = { + data: [ + { + available_aggregate_functions: ['min', 'max', 'avg'], + dimensions: [ + { + dim_label: 'cpu', + label: 'CPU name', + values: null, + }, + { + dim_label: 'state', + label: 'State of CPU', + values: [ + 'user', + 'system', + 'idle', + 'interrupt', + 'nice', + 'softirq', + 'steal', + 'wait', + ], + }, + { + dim_label: 'LINODE_ID', + label: 'Linode ID', + values: null, + }, + ], + label: 'CPU utilization', + metric: 'system_cpu_utilization_percent', + metric_type: 'gauge', + scrape_interval: '2m', + unit: 'percent', + }, + { + available_aggregate_functions: ['min', 'max', 'avg', 'sum'], + dimensions: [ + { + dim_label: 'state', + label: 'State of memory', + values: [ + 'used', + 'free', + 'buffered', + 'cached', + 'slab_reclaimable', + 'slab_unreclaimable', + ], + }, + { + dim_label: 'LINODE_ID', + label: 'Linode ID', + values: null, + }, + ], + label: 'Memory Usage', + metric: 'system_memory_usage_by_resource', + metric_type: 'gauge', + scrape_interval: '30s', + unit: 'byte', + }, + { + available_aggregate_functions: ['min', 'max', 'avg', 'sum'], + dimensions: [ + { + dim_label: 'device', + label: 'Device name', + values: ['lo', 'eth0'], + }, + { + dim_label: 'direction', + label: 'Direction of network transfer', + values: ['transmit', 'receive'], + }, + { + dim_label: 'LINODE_ID', + label: 'Linode ID', + values: null, + }, + ], + label: 'Network Traffic', + metric: 'system_network_io_by_resource', + metric_type: 'counter', + scrape_interval: '30s', + unit: 'byte', + }, + { + available_aggregate_functions: ['min', 'max', 'avg', 'sum'], + dimensions: [ + { + dim_label: 'device', + label: 'Device name', + values: ['loop0', 'sda', 'sdb'], + }, + { + dim_label: 'direction', + label: 'Operation direction', + values: ['read', 'write'], + }, + { + dim_label: 'LINODE_ID', + label: 'Linode ID', + values: null, + }, + ], + label: 'Disk I/O', + metric: 'system_disk_OPS_total', + metric_type: 'counter', + scrape_interval: '30s', + unit: 'ops_per_second', + }, + ], +}; + +const dashboardData = { + data: [ + { + created: '2024-09-06T08:09:43.641Z', + id: 1, + label: 'Linode Dashboard', + service_type: 'linode', + time_duration: { + unit: 'min', + value: 30, + }, + updated: '2024-09-06T08:09:43.641Z', + widgets: [], + }, + { + created: '2024-09-06T08:09:43.641Z', + id: 2, + label: 'DBaaS Dashboard', + service_type: 'dbaas', + time_duration: { + unit: 'min', + value: 30, + }, + updated: '2024-09-06T08:09:43.641Z', + widgets: [], + }, + ], +}; +const resourceData = { + data: [ + { + alerts: { + cpu: 180, + io: 10000, + network_in: 10, + network_out: 10, + transfer_quota: 80, + }, + backups: { + available: false, + enabled: false, + last_successful: null, + schedule: { + day: null, + window: null, + }, + }, + capabilities: [], + created: '2024-04-24T12:11:28', + disk_encryption: 'disabled', + group: '', + has_user_data: false, + host_uuid: '2c9c27e421a9e088d8e49029a3596aa3a789ed74', + hypervisor: 'kvm', + id: 57667285, + image: 'linode/debian11', + ipv4: ['172.234.222.69'], + ipv6: '2600:3c06::f03c:94ff:fe6a:684c/128', + label: 'test1', + lke_cluster_id: null, + placement_group: null, + region: 'us-ord', + site_type: 'core', + specs: { + disk: 81920, + gpus: 0, + memory: 4096, + transfer: 4000, + vcpus: 2, + }, + status: 'running', + tags: [], + type: 'g6-standard-2', + updated: '2024-09-04T09:17:42', + watchdog_enabled: true, + }, + { + alerts: { + cpu: 180, + io: 10000, + network_in: 10, + network_out: 10, + transfer_quota: 80, + }, + backups: { + available: false, + enabled: false, + last_successful: null, + schedule: { + day: null, + window: null, + }, + }, + capabilities: [], + created: '2024-04-24T12:12:27', + disk_encryption: 'disabled', + group: '', + has_user_data: false, + host_uuid: '062252cf2ef2739a167ea31f3518086ca7f20a65', + hypervisor: 'kvm', + id: 57667325, + image: 'linode/debian11', + ipv4: ['172.234.222.72'], + ipv6: '2600:3c06::f03c:94ff:fe6a:6894/128', + label: 'linode2', + lke_cluster_id: null, + placement_group: null, + region: 'us-ord', + site_type: 'core', + specs: { + disk: 81920, + gpus: 0, + memory: 4096, + transfer: 4000, + vcpus: 2, + }, + status: 'running', + tags: [], + type: 'g6-standard-2', + updated: '2024-05-05T10:40:10', + watchdog_enabled: true, + }, + { + alerts: { + cpu: 180, + io: 10000, + network_in: 10, + network_out: 10, + transfer_quota: 80, + }, + backups: { + available: false, + enabled: false, + last_successful: null, + schedule: { + day: null, + window: null, + }, + }, + capabilities: [], + created: '2024-04-24T12:13:21', + disk_encryption: 'disabled', + group: '', + has_user_data: false, + host_uuid: 'd939a55bfaed7afa7301c722948a5f99fd800c00', + hypervisor: 'kvm', + id: 57667355, + image: 'linode/debian11', + ipv4: ['172.234.222.73'], + ipv6: '2600:3c06::f03c:94ff:fe6a:40db/128', + label: 'Cloudpulse-demo-ananth', + lke_cluster_id: null, + placement_group: null, + region: 'us-ord', + site_type: 'core', + specs: { + disk: 81920, + gpus: 0, + memory: 4096, + transfer: 4000, + vcpus: 2, + }, + status: 'running', + tags: [], + type: 'g6-standard-2', + updated: '2024-04-30T04:37:18', + watchdog_enabled: true, + }, + ], + page: 1, + pages: 1, + results: 3, +}; + +export const interceptGetMetricDefinitions = (): Cypress.Chainable => { + return cy.intercept( + 'GET', + apiMatcher('**/monitor/services/linode/metric-definitions'), + dashboardMetricsData + ); +}; +export const interceptGetDashBoards = (): Cypress.Chainable => { + return cy.intercept( + 'GET', + apiMatcher('**/monitor/services/linode/dashboards'), + dashboardData + ); +}; +export const interceptGetResources = (): Cypress.Chainable => { + return cy.intercept( + 'GET', + apiMatcher('**/linode/instances/?page_size=500'), + resourceData + ); +}; export const interceptMetricsRequests = () => { cy.intercept({ method: 'POST', @@ -10,3 +323,12 @@ export const interceptMetricsRequests = () => { }).as('getMetrics'); return cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']); }; +export const interceptMetricAPI = ( + mockResponse: any +): Cypress.Chainable => { + return cy.intercept( + 'POST', + '**/monitor/services/linode/metrics', + mockResponse + ); +}; diff --git a/packages/manager/cypress/support/util/cloudpulse.ts b/packages/manager/cypress/support/util/cloudpulse.ts index 19224fd94cb..3d28b1b76f4 100644 --- a/packages/manager/cypress/support/util/cloudpulse.ts +++ b/packages/manager/cypress/support/util/cloudpulse.ts @@ -1,20 +1,28 @@ /* eslint-disable cypress/unsafe-to-chain-command */ -import 'cypress-wait-until'; -import { aggregation, aggregationConfig } from 'support/constants/aggregation'; +import { accountFactory, profileFactory } from '@src/factories'; +import { accountUserFactory } from '@src/factories/accountUsers'; import { granularity } from 'support/constants/granularity'; import { timeRange } from 'support/constants/timerange'; +import { mockGetAccount, mockGetUser } from 'support/intercepts/account'; +import { + interceptGetDashBoards, + interceptGetMetricDefinitions, + interceptGetResources, + interceptMetricAPI, +} from 'support/intercepts/cloudpulseAPIHandler'; import { mockAppendFeatureFlags, mockGetFeatureFlagClientstream, } from 'support/intercepts/feature-flags'; +import { mockGetProfile } from 'support/intercepts/profile'; import { ui } from 'support/ui'; import { makeFeatureFlagData } from 'support/util/feature-flags'; -export const dashboardName = 'Linode Service I/O Statistics'; +import type { Flags } from 'src/featureFlags'; +export const dashboardName = 'Linode Dashboard'; export const region = 'US, Chicago, IL (us-ord)'; export const actualRelativeTimeDuration = timeRange.Last24Hours; export const resource = 'test1'; - /** * This class provides utility functions for interacting with the Cloudpulse dashboard * in a Cypress test suite. It includes methods for: @@ -25,74 +33,89 @@ export const resource = 'test1'; * - Performing actions like zooming in and out on widgets * These utilities ensure efficient and consistent test execution and validation. */ -export const cloudpulseTestData = [ - { - expectedAggregation: aggregation.Max, - expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hr1, - expectedGranularityArray: Object.values(granularity), - name: 'system_disk_OPS_total', - title: 'Disk I/O', - }, - { - expectedAggregation: aggregation.Max, - expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hr1, - expectedGranularityArray: Object.values(granularity), - name: 'system_network_io_by_resource', - title: 'Network Traffic', - }, - { - expectedAggregation: aggregation.Max, - expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hr1, - expectedGranularityArray: Object.values(granularity), - name: 'system_memory_usage_by_resource', - title: 'Memory Usage', - }, - { - expectedAggregation: aggregation.Max, - expectedAggregationArray: aggregationConfig.basic, - expectedGranularity: granularity.Hr1, - expectedGranularityArray: Object.values(granularity), - name: 'system_cpu_utilization_percent', - title: 'CPU Utilization', - }, -]; + interface MetricResponse { + data: { + result: Array<{ + metric: Record; + values: [number, string][]; + }>; + resultType: string; + }; + isPartial: boolean; + stats: { + executionTimeMsec: number; + seriesFetched: string; + }; + status: string; +} /** - * Navigates to the Cloudpulse dashboard and waits for the page to load. + * Generates a mock metric response based on the specified time range and granularity. + * + * This function: + * 1. Determines the time interval based on the granularity (e.g., 5 minutes, 1 hour, 1 day). + * 2. Calculates the time range in seconds based on the specified time range (e.g., last 12 hours, last 30 days). + * 3. Creates a series of random metric values for the given time range at the specified interval. + * 4. Returns a mock response object containing the generated metric data. + * + * @param {string} time - The time range for the metric data (e.g., "Last12Hours"). + * @param {string} granularityData - The granularity of the metric data (e.g., "Min5"). + * @returns {MetricResponse} - The generated mock metric response. */ -export const navigateToCloudpulse = () => { - mockAppendFeatureFlags({ aclp: makeFeatureFlagData(true) }).as( - 'getFeatureFlags' - ); - mockGetFeatureFlagClientstream().as('getClientStream'); +export const createMetricResponse = ( + time: string, + granularityData: string +): MetricResponse => { + const currentTime = Math.floor(Date.now() / 1000); - cy.visitWithLogin('/monitor/cloudpulse', { - onLoad: (contentWindow: Window) => { - if (contentWindow.document.readyState !== 'complete') { - throw new Error('Page did not load completely'); - } - }, - timeout: 500, - }); + const intervals: Record = { + [granularity.Auto]: 3600, + [granularity.Day1]: 86400, + [granularity.Hr1]: 3600, + [granularity.Min5]: 5 * 60, + }; - cy.wait(['@getFeatureFlags', '@getClientStream']); - cy.url().should('include', '/monitor/cloudpulse'); - waitForPageToLoad(); -}; + const timeRanges: Record = { + [timeRange.Last7Days]: 7 * 24 * 3600, + [timeRange.Last12Hours]: 12 * 3600, + [timeRange.Last24Hours]: 24 * 3600, + [timeRange.Last30Days]: 30 * 24 * 3600, + [timeRange.Last30Minutes]: 30 * 60, + }; -/** - * Waits for the Cloudpulse page to fully load and checks that key elements are visible. - */ -export const waitForPageToLoad = () => { - cy.get('[data-testid="circle-progress"]').should('not.exist'); + const interval = + intervals[granularityData] || + (() => { + throw new Error(`Unsupported granularity: ${granularityData}`); + })(); + const timeRangeInSeconds = + timeRanges[time] || + (() => { + throw new Error(`Unsupported time range: ${time}`); + })(); + const startTime = currentTime - timeRangeInSeconds; - const keyElementsSelectors = ['[data-testid="textfield-input"]']; - keyElementsSelectors.forEach((selector) => { - cy.get(selector).should('be.visible'); - }); + const values: [number, string][] = Array.from( + { length: Math.ceil(timeRangeInSeconds / interval) + 1 }, + (_, i) => { + const timestamp = startTime + i * interval; + const value = (Math.random() * 100).toFixed(2); + return [timestamp, value]; + } + ); + + return { + data: { + result: [{ metric: {}, values }], + resultType: 'matrix', + }, + isPartial: false, + stats: { + executionTimeMsec: 53, + seriesFetched: '6', + }, + status: 'success', + }; }; /** @@ -105,7 +128,6 @@ export const visitCloudPulseWithFeatureFlagsDisabled = () => { 'getFeatureFlags' ); mockGetFeatureFlagClientstream().as('getClientStream'); - cy.findByLabelText('Monitor').should('not.exist'); }; @@ -118,13 +140,8 @@ export const selectServiceName = (serviceName: string) => { .findByTitleCustom('Select Dashboard') .findByTitle('Open') .click(); - ui.autocomplete - .findByPlaceholderCustom('Select Dashboard') - .type(`${serviceName}{enter}`); - - // ui.autocompletePopper.findByTitle(serviceName).should('be.visible').click(); + ui.autocomplete .findByPlaceholderCustom('Select Dashboard').type(`${serviceName}{enter}`); }; - /** * Selects a region from the region dropdown. * @param {string} region - The name of the region to select. @@ -132,7 +149,6 @@ export const selectServiceName = (serviceName: string) => { export const selectRegion = (region: string) => { ui.regionSelect.find().click().type(`${region}{enter}`); }; - /** * Selects a time range from the time range dropdown. * @param {string} timeRange - The time range to select. @@ -144,18 +160,15 @@ export const selectTimeRange = (timeRange: string) => { .click(); ui.autocompletePopper.findByTitle(timeRange).should('be.visible').click(); }; - /** * Selects a resource name from the resources dropdown and verifies the selection. * @param {string} service - The name of the service to select. */ -export const selectAndVerifyServiceName = (service: string) => { +export const selectAndVerifyResource = (service: string) => { const resourceInput = ui.autocomplete.findByTitleCustom('Select Resources'); resourceInput.findByTitle('Open').click(); resourceInput.click().type(`${service}{enter}`); - // resourceInput.findByTitle('Close').click(); }; - /** * Asserts that the selected options match the expected values. * @param {string} expectedOptions - The expected options to verify. @@ -163,40 +176,48 @@ export const selectAndVerifyServiceName = (service: string) => { export const assertSelections = (expectedOptions: string) => { expect(cy.get(`[value*='${expectedOptions}']`), expectedOptions); }; - /** * Applies a global refresh action on the dashboard. */ -export const applyGlobalRefresh = () => { +export const performGlobalRefresh = () => { ui.cloudpulse.findRefreshIcon().click(); }; /** * Clears the dashboard's preferences and verifies the zeroth page. * @param {string} serviceName - The name of the service to verify. */ -export const verifyZerothPage = (serviceName: string) => { +export const resetDashboardAndVerifyPage = (serviceName: string) => { ui.autocomplete .findByTitleCustom('Select Dashboard') .findByTitle('Open') .click(); - ui.autocompletePopper.findByTitle(serviceName).should('be.visible').click(); + ui.autocomplete .findByPlaceholderCustom('Select Dashboard').type(`${serviceName}{enter}`); ui.autocomplete .findByTitleCustom('Select Dashboard') .findByTitle('Clear') .click(); }; - /** * Validates that the widget title matches the expected title. - * @param {string} widgetName - The name of the widget to verify. + * + * This function locates a widget on the page using its `data-qa-widget` attribute, + * finds the `h1` element within the widget, and checks that its text content matches + * the expected widget name. It also returns the actual text content of the `h1` element. + * + * @param {string} widgetName - The expected name of the widget to verify. This is used to + * construct the selector and to check the title of the widget. + * + * @returns {Cypress.Chainable} A Cypress chainable object that resolves to the + * text content of the `h1` element within the widget. */ export const validateWidgetTitle = (widgetName: string) => { const widgetSelector = `[data-qa-widget="${widgetName}"]`; - cy.get(widgetSelector) + return cy + .get(widgetSelector) .find('h1') .invoke('text') - .then((actualTitle) => { - expect(actualTitle.trim()).to.equal(widgetName); + .then((text) => { + expect(text.trim()).to.equal(widgetName); }); }; @@ -223,7 +244,6 @@ export const setGranularity = (widgetName: string, granularity: string) => { assertSelections(granularity); }); }; - /** * Sets the aggregation function of a widget. * @param {string} widgetName - The name of the widget to set aggregation for. @@ -246,13 +266,11 @@ export const setAggregation = (widgetName: string, aggregation: string) => { assertSelections(aggregation); }); }; - /** * Verifies that the granularity options available for a widget match the expected options. * @param {string} widgetName - The name of the widget to verify. * @param {string[]} expectedGranularityOptions - The expected granularity options. */ - export const verifyGranularity = ( widgetName: string, expectedGranularityOptions: string[] @@ -321,7 +339,7 @@ export const verifyAggregation = ( * Verifies that zoom in and zoom out actions are available and performs them on a widget. * @param {string} widgetName - The name of the widget to zoom in or out. */ -export const verifyZoomInOut = (widgetName: string) => { +export const checkZoomActions = (widgetName: string) => { const widgetSelector = `[data-qa-widget="${widgetName}"]`; const zoomInSelector = ui.cloudpulse.findZoomButtonByTitle('zoom-in'); const zoomOutSelector = ui.cloudpulse.findZoomButtonByTitle('zoom-out'); @@ -332,7 +350,6 @@ export const verifyZoomInOut = (widgetName: string) => { const zoomOutAvailable = $el.find(zoomOutSelector).length > 0; if (zoomInAvailable) { - // eslint-disable-next-line cypress/unsafe-to-chain-command cy.wrap($el) .find(zoomInSelector) .should('be.visible') @@ -357,3 +374,46 @@ export const verifyZoomInOut = (widgetName: string) => { }); }); }; + +const mockParentProfile = profileFactory.build({ + user_type: 'parent', + username: 'mock-user@linode.com', +}); + +const mockParentUser = accountUserFactory.build({ + user_type: 'default', + username: mockParentProfile.email, +}); +const mockParentAccount = accountFactory.build({ + company: 'Parent Company', +}); +/** + * Sets up mock data and intercepts for user-related tests. + * + * This function: + * 1. Mocks responses for user profile, account, and user data APIs. + * 2. Configures feature flags for testing. + * 3. Mocks the feature flag client stream. + * 4. Visits the specified page with a logged-in user. + * 5. Sets up intercepts for various API calls and aliases them for testing. + * + * This ensures a controlled environment for testing user-related functionality. + */ +export const initializeMockUserData = () => { + mockGetProfile(mockParentProfile); + mockGetAccount(mockParentAccount); + mockGetUser(mockParentUser); + mockAppendFeatureFlags({ + aclp: makeFeatureFlagData({ beta: true, enabled: true }), + }); + mockGetFeatureFlagClientstream(); + cy.visitWithLogin('monitor/cloudpulse'); + interceptGetMetricDefinitions().as('dashboardMetricsData'); + interceptGetDashBoards().as('dashboard'); + interceptGetResources().as('resourceData'); + const responsePayload = createMetricResponse( + actualRelativeTimeDuration, + granularity.Min5 + ); + interceptMetricAPI(responsePayload).as('metricAPI'); +}; diff --git a/packages/manager/cypress/support/util/widgetFactory.ts b/packages/manager/cypress/support/util/widgetFactory.ts new file mode 100644 index 00000000000..3dc6e2f9672 --- /dev/null +++ b/packages/manager/cypress/support/util/widgetFactory.ts @@ -0,0 +1,21 @@ +import type { aggregation } from 'support/constants/aggregation'; +import type { granularity } from 'support/constants/granularity'; + +// Factory function to create widget constants +export function createWidget( + name: string, + title: string, + expectedAggregation: aggregation, + expectedGranularity: granularity, + expectedGranularityArray: string[], + expectedAggregationyArray: string[] +) { + return { + expectedAggregation, + expectedAggregationyArray, + expectedGranularity, + expectedGranularityArray, + name, + title, + }; +} diff --git a/packages/manager/cypress/support/util/widgetService.ts b/packages/manager/cypress/support/util/widgetService.ts new file mode 100644 index 00000000000..cb5fa140881 --- /dev/null +++ b/packages/manager/cypress/support/util/widgetService.ts @@ -0,0 +1,73 @@ +import { aggregation, aggregationConfig } from 'support/constants/aggregation'; +import { granularity } from 'support/constants/granularity'; + +export const widgetDetails = { + dbaas: [ + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.all, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_disk_OPS_total', + title: 'Disk I/O', + }, + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.all, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_network_io_by_resource', + title: 'Network Traffic', + }, + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.all, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_memory_usage_by_resource', + title: 'Memory Usage', + }, + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.basic, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_cpu_utilization_percent', + title: 'CPU Utilization', + }, + ], + linode: [ + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.all, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_disk_OPS_total', + title: 'Disk I/O', + }, + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.all, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_network_io_by_resource', + title: 'Network Traffic', + }, + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.all, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_memory_usage_by_resource', + title: 'Memory Usage', + }, + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.basic, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_cpu_utilization_percent', + title: 'CPU Utilization', + }, + ], +}; From 96e5341f1df548befe3328963379a8a93e76a825 Mon Sep 17 00:00:00 2001 From: agorthi Date: Mon, 9 Sep 2024 13:01:53 +0530 Subject: [PATCH 019/474] upcoming:[DI-20585]- Added code review comments --- .../core/cloudpulse/dashboard-filters.spec.ts | 54 ++- .../cloudpulse/widget-verification.spec.ts | 91 ++--- .../cypress/support/constants/aggregation.ts | 11 - .../cypress/support/constants/granularity.ts | 12 - .../cypress/support/constants/messages.ts | 6 - .../manager/cypress/support/constants/time.ts | 5 - .../cypress/support/constants/timerange.ts | 13 - .../support/constants/widget-mockdata.ts | 132 +++++++ .../support/constants/widget-service.ts | 89 +++++ .../cypress/support/constants/widgets.ts | 6 - .../intercepts/cloudpulseAPIHandler.ts | 339 ++---------------- .../cypress/support/util/cloudpulse.ts | 182 ++-------- .../cypress/support/util/widgetFactory.ts | 21 -- .../cypress/support/util/widgetService.ts | 73 ---- .../manager/src/factories/widgetFactory.ts | 104 ++++++ 15 files changed, 489 insertions(+), 649 deletions(-) delete mode 100644 packages/manager/cypress/support/constants/aggregation.ts delete mode 100644 packages/manager/cypress/support/constants/granularity.ts delete mode 100644 packages/manager/cypress/support/constants/messages.ts delete mode 100644 packages/manager/cypress/support/constants/time.ts delete mode 100644 packages/manager/cypress/support/constants/timerange.ts create mode 100644 packages/manager/cypress/support/constants/widget-mockdata.ts create mode 100644 packages/manager/cypress/support/constants/widget-service.ts delete mode 100644 packages/manager/cypress/support/constants/widgets.ts delete mode 100644 packages/manager/cypress/support/util/widgetFactory.ts delete mode 100644 packages/manager/cypress/support/util/widgetService.ts create mode 100644 packages/manager/src/factories/widgetFactory.ts diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts index f10b0757152..368e293ecf5 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts @@ -4,14 +4,30 @@ import { selectTimeRange, selectAndVerifyResource, assertSelections, - visitCloudPulseWithFeatureFlagsDisabled, dashboardName, actualRelativeTimeDuration, region, resource, resetDashboardAndVerifyPage, - initializeMockUserData, } from 'support/util/cloudpulse'; +import { + mockAppendFeatureFlags, + mockGetFeatureFlagClientstream, +} from 'support/intercepts/feature-flags'; +import { granularity } from 'support/constants/widget-service'; +import { + interceptCreateMetrics, + interceptGetDashboards, + interceptGetMetricDefinitions, +} from 'support/intercepts/cloudpulseAPIHandler'; +import { makeFeatureFlagData } from 'support/util/feature-flags'; +import type { Flags } from 'src/featureFlags'; +import {createMetricResponse} from '@src/factories/widgetFactory' +import { mockGetLinodes} from 'support/intercepts/linodes'; +import { + kubeLinodeFactory, + linodeFactory, +} from 'src/factories'; /** * This test suite focuses on the standard operations and verifications for the Cloudpulse dashboard. * @@ -22,14 +38,42 @@ import { * Each test case checks the correctness and persistence of these configurations to ensure that the * dashboard behaves as expected under various conditions. */ +const mockKubeLinode = kubeLinodeFactory.build(); +const mockLinode = linodeFactory.build({ + label: "test1", + id: mockKubeLinode.instance_id ?? undefined, +}); describe('Standard Dashboard Filter Application and Configuration Tests', () => { beforeEach(() => { - initializeMockUserData(); + mockAppendFeatureFlags({ + aclp: makeFeatureFlagData({ beta: true, enabled: true }), + }); + mockGetFeatureFlagClientstream(); + cy.visitWithLogin('monitor/cloudpulse'); + interceptGetMetricDefinitions().as('dashboardMetricsData'); + interceptGetDashboards().as('dashboard'); + mockGetLinodes([mockLinode]).as('getLinodes'); + const responsePayload = createMetricResponse(actualRelativeTimeDuration,granularity.Min5); + interceptCreateMetrics(responsePayload).as('metricAPI'); }); - it('should verify cloudpulse availability when feature flag is set to false', () => { - visitCloudPulseWithFeatureFlagsDisabled(); + + it.only('should verify cloudpulse availability when feature flag is set to false', () => { + mockAppendFeatureFlags({ + aclp: makeFeatureFlagData({ beta: true, enabled: false }), + }); + mockGetFeatureFlagClientstream(); + cy.visitWithLogin('/linodes'); + cy.get('[data-testid="menu-item-Monitor"]').should('be.visible').invoke('attr', 'href').then((href) => { + cy.log("url ******",href) + cy.request({ + url: href, + failOnStatusCode: false + }).then((response) => { + expect(response.status).to.be.equal(404); + }); + }); }); it('should clear the preferences of the dashboard', () => { diff --git a/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts index 64526d67553..0bab3c0d603 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts @@ -6,14 +6,24 @@ import { verifyGranularity, verifyAggregation, checkZoomActions, - performGlobalRefresh, - initializeMockUserData, } from 'support/util/cloudpulse'; -import { timeUnit } from 'support/constants/time'; +import { + mockAppendFeatureFlags, + mockGetFeatureFlagClientstream, +} from 'support/intercepts/feature-flags'; import { interceptMetricsRequests} from 'support/intercepts/cloudpulseAPIHandler'; -import { timeRange } from 'support/constants/timerange'; +import { ui } from 'support/ui'; export const actualRelativeTimeDuration = timeRange.Last30Minutes; -import { widgetDetails } from 'support/util/widgetService'; +import { timeRange, widgetDetails,timeUnit,granularity } from 'support/constants/widget-service'; +import { + interceptCreateMetrics, + interceptGetDashboards, + interceptGetMetricDefinitions, +} from 'support/intercepts/cloudpulseAPIHandler'; +import { makeFeatureFlagData } from 'support/util/feature-flags'; +import {createMetricResponse} from '@src/factories/widgetFactory' +import type { Flags } from 'src/featureFlags'; + const linodeWidgets = widgetDetails.linode; /** @@ -26,9 +36,18 @@ const linodeWidgets = widgetDetails.linode; * Testing widget interactions, including zooming and filtering, to ensure proper behavior. * Each test ensures that widgets on the dashboard operate correctly and display accurate information. */ + describe('Dashboard Widget Verification Tests', () => { beforeEach(() => { - initializeMockUserData(); + cy.visitWithLogin('monitor/cloudpulse'); + mockAppendFeatureFlags({ + aclp: makeFeatureFlagData({ beta: true, enabled: true }), + }); + mockGetFeatureFlagClientstream(); + interceptGetMetricDefinitions().as('dashboardMetricsData'); + interceptGetDashboards().as('dashboard'); + const responsePayload = createMetricResponse(actualRelativeTimeDuration,granularity.Min5); + interceptCreateMetrics(responsePayload).as('metricAPI'); selectTimeRange(actualRelativeTimeDuration); }); it(`should set available granularity of the all the widget`, () => { @@ -62,42 +81,34 @@ describe('Dashboard Widget Verification Tests', () => { checkZoomActions(testData.title); }); }); - it('should apply global refresh button and verify network calls', () => { - performGlobalRefresh(); - interceptMetricsRequests().then((xhrArray) => { - xhrArray.forEach((xhr) => { - const { body: requestPayload } = xhr.request; - const metric = requestPayload.metric; - const metricData = linodeWidgets.find( - (data) => data.name === metric - ); + +it('should apply global refresh button and verify network calls', () => { + ui.cloudpulse.findRefreshIcon().click(); + interceptMetricsRequests(); + cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']).then((interceptions) => { + const interceptionsArray = Array.isArray(interceptions) ? interceptions : [interceptions]; + + interceptionsArray.forEach((interception) => { + const { body: requestPayload } = interception.request; + const metric = requestPayload.metric; + const metricData = linodeWidgets.find((data) => data.name === metric); + if (!metricData) { - throw new Error(`Unknown metric: ${metric}`); - } - const granularity = requestPayload['time_granularity']; - const currentGranularity = granularity - ? granularity.value + granularity.unit - : ''; - const durationUnit = requestPayload.relative_time_duration.unit.toLowerCase(); - const durationValue = requestPayload.relative_time_duration.value; - const currentRelativeTimeDuration = - durationUnit in timeUnit - ? 'Last' + - durationValue + - timeUnit[durationUnit as keyof typeof timeUnit] - : ''; - expect(requestPayload.aggregate_function).to.equal( - metricData.expectedAggregation - ); - expect(currentRelativeTimeDuration).to.containIgnoreSpaces( - actualRelativeTimeDuration - ); - expect(currentGranularity).to.containIgnoreSpaces( - metricData.expectedGranularity - ); - expect(requestPayload.metric).to.containIgnoreSpaces(metricData.name); - }); + throw new Error(`Unknown metric: ${metric}`); + } + const granularity = requestPayload['time_granularity']; + const currentGranularity = granularity ? `${granularity.value} ${granularity.unit}` : ''; + const durationUnit = requestPayload.relative_time_duration.unit.toLowerCase(); + const durationValue = requestPayload.relative_time_duration.value; + const currentRelativeTimeDuration = durationUnit in timeUnit ? 'Last' + durationValue + timeUnit[durationUnit as keyof typeof timeUnit] : ''; + expect(requestPayload.aggregate_function).to.equal(metricData.expectedAggregation); + expect(currentRelativeTimeDuration).to.containIgnoreSpaces(actualRelativeTimeDuration); + expect(requestPayload.metric).to.equal(metricData.name); + expect(currentGranularity).to.equal(metricData.expectedGranularity); }); }); }); +}); + + diff --git a/packages/manager/cypress/support/constants/aggregation.ts b/packages/manager/cypress/support/constants/aggregation.ts deleted file mode 100644 index e637de39ceb..00000000000 --- a/packages/manager/cypress/support/constants/aggregation.ts +++ /dev/null @@ -1,11 +0,0 @@ -export enum aggregation { - Avg = 'avg', - Max = 'max', - Min = 'min', - Sum = 'sum', -} - -export const aggregationConfig = { - all: [aggregation.Avg, aggregation.Max, aggregation.Min, aggregation.Sum], - basic: [aggregation.Avg, aggregation.Max, aggregation.Min], -}; diff --git a/packages/manager/cypress/support/constants/granularity.ts b/packages/manager/cypress/support/constants/granularity.ts deleted file mode 100644 index 89ee2164ce9..00000000000 --- a/packages/manager/cypress/support/constants/granularity.ts +++ /dev/null @@ -1,12 +0,0 @@ -export enum granularity { - Auto = 'Auto', - Day1 = '1 day', - Hr1 = '1 hr', - Min5 = '5 min', -} - -export enum timeUnit { - Day = 'day', - Hr = 'hr', - Min = 'min', -} diff --git a/packages/manager/cypress/support/constants/messages.ts b/packages/manager/cypress/support/constants/messages.ts deleted file mode 100644 index fbcf2b5fa8f..00000000000 --- a/packages/manager/cypress/support/constants/messages.ts +++ /dev/null @@ -1,6 +0,0 @@ -export const expectedText = { - aclpMessage: 'Akamai Cloud Pulse', - noResult: 'No results', - nooption: 'You have no options to choose from', - selectDashboardMessage: 'Select Dashboard and filters to visualize metrics.', -}; diff --git a/packages/manager/cypress/support/constants/time.ts b/packages/manager/cypress/support/constants/time.ts deleted file mode 100644 index c91032898b7..00000000000 --- a/packages/manager/cypress/support/constants/time.ts +++ /dev/null @@ -1,5 +0,0 @@ -export enum timeUnit { - day = 'Days', - hr = 'Hours', - min = 'Minutes', -} diff --git a/packages/manager/cypress/support/constants/timerange.ts b/packages/manager/cypress/support/constants/timerange.ts deleted file mode 100644 index 88520ccb87a..00000000000 --- a/packages/manager/cypress/support/constants/timerange.ts +++ /dev/null @@ -1,13 +0,0 @@ -export enum timeRange { - Last7Days = 'Last 7 Days', - Last12Hours = 'Last 12 Hours', - Last24Hours = 'Last 24 Hours', - Last30Days = 'Last 30 Days', - Last30Minutes = 'Last 30 Minutes', -} - -export enum timeUnit { - Day = 'day', - Hr = 'hr', - Min = 'min', -} diff --git a/packages/manager/cypress/support/constants/widget-mockdata.ts b/packages/manager/cypress/support/constants/widget-mockdata.ts new file mode 100644 index 00000000000..39056b864b1 --- /dev/null +++ b/packages/manager/cypress/support/constants/widget-mockdata.ts @@ -0,0 +1,132 @@ +export const dashboardMetricsData = { + data: [ + { + available_aggregate_functions: ['min', 'max', 'avg'], + dimensions: [ + { + dim_label: 'cpu', + label: 'CPU name', + values: null, + }, + { + dim_label: 'state', + label: 'State of CPU', + values: [ + 'user', + 'system', + 'idle', + 'interrupt', + 'nice', + 'softirq', + 'steal', + 'wait', + ], + }, + { + dim_label: 'LINODE_ID', + label: 'Linode ID', + values: null, + }, + ], + label: 'CPU utilization', + metric: 'system_cpu_utilization_percent', + metric_type: 'gauge', + scrape_interval: '2m', + unit: 'percent', + }, + { + available_aggregate_functions: ['min', 'max', 'avg', 'sum'], + dimensions: [ + { + dim_label: 'state', + label: 'State of memory', + values: [ + 'used', + 'free', + 'buffered', + 'cached', + 'slab_reclaimable', + 'slab_unreclaimable', + ], + }, + { + dim_label: 'LINODE_ID', + label: 'Linode ID', + values: null, + }, + ], + label: 'Memory Usage', + metric: 'system_memory_usage_by_resource', + metric_type: 'gauge', + scrape_interval: '30s', + unit: 'byte', + }, + { + available_aggregate_functions: ['min', 'max', 'avg', 'sum'], + dimensions: [ + { + dim_label: 'device', + label: 'Device name', + values: ['lo', 'eth0'], + }, + { + dim_label: 'direction', + label: 'Direction of network transfer', + values: ['transmit', 'receive'], + }, + { + dim_label: 'LINODE_ID', + label: 'Linode ID', + values: null, + }, + ], + label: 'Network Traffic', + metric: 'system_network_io_by_resource', + metric_type: 'counter', + scrape_interval: '30s', + unit: 'byte', + }, + { + available_aggregate_functions: ['min', 'max', 'avg', 'sum'], + dimensions: [ + { + dim_label: 'device', + label: 'Device name', + values: ['loop0', 'sda', 'sdb'], + }, + { + dim_label: 'direction', + label: 'Operation direction', + values: ['read', 'write'], + }, + { + dim_label: 'LINODE_ID', + label: 'Linode ID', + values: null, + }, + ], + label: 'Disk I/O', + metric: 'system_disk_OPS_total', + metric_type: 'counter', + scrape_interval: '30s', + unit: 'ops_per_second', + }, + ], +}; + +export const dashboardDefinitions = { + data: [ + { + created: '2024-09-06T08:09:43.641Z', + id: 1, + label: 'Linode Dashboard', + service_type: 'linode', + time_duration: { + unit: 'min', + value: 30, + }, + updated: '2024-09-06T08:09:43.641Z', + widgets: [], + }, + ], +}; diff --git a/packages/manager/cypress/support/constants/widget-service.ts b/packages/manager/cypress/support/constants/widget-service.ts new file mode 100644 index 00000000000..f3ddc9eeed8 --- /dev/null +++ b/packages/manager/cypress/support/constants/widget-service.ts @@ -0,0 +1,89 @@ +/** + * Defines the granularity levels used for specifying time intervals in data aggregation or reporting. + * Each property represents a different granularity level. + */ +export const granularity = { + Auto: 'Auto', + Day1: '1 day', + Hr1: '1 hr', + Min5: '5 min', +} as const; + +/** + * Defines various aggregation types that can be applied to data. + * Each property represents a different type of aggregation operation. + */ +export const aggregation = { + Avg: 'avg', + Max: 'max', + Min: 'min', + Sum: 'sum', +} as const; + +// Define a constant object named `timeRange` to represent various time periods. +// This object maps time range identifiers to their descriptive strings. +export const timeRange = { + Last7Days: 'Last 7 Days', + Last12Hours: 'Last 12 Hours', + Last24Hours: 'Last 24 Hours', + Last30Days: 'Last 30 Days', + Last30Minutes: 'Last 30 Minutes', +} as const; + +// Define a constant object named `timeUnit` which serves as a mapping +// between time unit identifiers and their full descriptive names. +// This object provides a convenient way to reference standard time units. +export const timeUnit = { + day: 'Days', + hr: 'Hours', + min: 'Minutes', +} as const; +/** + * Configuration object defining predefined sets of aggregation types. + * These sets can be used to specify acceptable aggregation operations for different contexts. + */ + +export const aggregationConfig = { + all: [aggregation.Avg, aggregation.Max, aggregation.Min, aggregation.Sum], + basic: [aggregation.Avg, aggregation.Max, aggregation.Min], +}; +/** + * Configuration object for widget details. + * Each widget configuration includes expected aggregation types, granularity levels, and other relevant properties. + */ +export const widgetDetails = { + linode: [ + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.all, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_disk_OPS_total', + title: 'Disk I/O', + }, + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.all, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_network_io_by_resource', + title: 'Network Traffic', + }, + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.all, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_memory_usage_by_resource', + title: 'Memory Usage', + }, + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.basic, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_cpu_utilization_percent', + title: 'CPU Utilization', + }, + ], +}; diff --git a/packages/manager/cypress/support/constants/widgets.ts b/packages/manager/cypress/support/constants/widgets.ts deleted file mode 100644 index 5e193af9bff..00000000000 --- a/packages/manager/cypress/support/constants/widgets.ts +++ /dev/null @@ -1,6 +0,0 @@ -export const widgets = { - system_cpu_utilization_percent: 'CPU Utilization', - system_disk_OPS_total: 'Disk I/O', - system_memory_usage_by_resource: 'Memory Usage', - system_network_io_by_resource: 'Network Traffic', -}; diff --git a/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts b/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts index 5a5a9d6f8e9..2865aa43998 100644 --- a/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts +++ b/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts @@ -3,297 +3,20 @@ * * @returns Cypress chainable. */ - +import { + dashboardDefinitions, + dashboardMetricsData, +} from 'support/constants/widget-mockdata'; import { apiMatcher } from 'support/util/intercepts'; -const dashboardMetricsData = { - data: [ - { - available_aggregate_functions: ['min', 'max', 'avg'], - dimensions: [ - { - dim_label: 'cpu', - label: 'CPU name', - values: null, - }, - { - dim_label: 'state', - label: 'State of CPU', - values: [ - 'user', - 'system', - 'idle', - 'interrupt', - 'nice', - 'softirq', - 'steal', - 'wait', - ], - }, - { - dim_label: 'LINODE_ID', - label: 'Linode ID', - values: null, - }, - ], - label: 'CPU utilization', - metric: 'system_cpu_utilization_percent', - metric_type: 'gauge', - scrape_interval: '2m', - unit: 'percent', - }, - { - available_aggregate_functions: ['min', 'max', 'avg', 'sum'], - dimensions: [ - { - dim_label: 'state', - label: 'State of memory', - values: [ - 'used', - 'free', - 'buffered', - 'cached', - 'slab_reclaimable', - 'slab_unreclaimable', - ], - }, - { - dim_label: 'LINODE_ID', - label: 'Linode ID', - values: null, - }, - ], - label: 'Memory Usage', - metric: 'system_memory_usage_by_resource', - metric_type: 'gauge', - scrape_interval: '30s', - unit: 'byte', - }, - { - available_aggregate_functions: ['min', 'max', 'avg', 'sum'], - dimensions: [ - { - dim_label: 'device', - label: 'Device name', - values: ['lo', 'eth0'], - }, - { - dim_label: 'direction', - label: 'Direction of network transfer', - values: ['transmit', 'receive'], - }, - { - dim_label: 'LINODE_ID', - label: 'Linode ID', - values: null, - }, - ], - label: 'Network Traffic', - metric: 'system_network_io_by_resource', - metric_type: 'counter', - scrape_interval: '30s', - unit: 'byte', - }, - { - available_aggregate_functions: ['min', 'max', 'avg', 'sum'], - dimensions: [ - { - dim_label: 'device', - label: 'Device name', - values: ['loop0', 'sda', 'sdb'], - }, - { - dim_label: 'direction', - label: 'Operation direction', - values: ['read', 'write'], - }, - { - dim_label: 'LINODE_ID', - label: 'Linode ID', - values: null, - }, - ], - label: 'Disk I/O', - metric: 'system_disk_OPS_total', - metric_type: 'counter', - scrape_interval: '30s', - unit: 'ops_per_second', - }, - ], -}; -const dashboardData = { - data: [ - { - created: '2024-09-06T08:09:43.641Z', - id: 1, - label: 'Linode Dashboard', - service_type: 'linode', - time_duration: { - unit: 'min', - value: 30, - }, - updated: '2024-09-06T08:09:43.641Z', - widgets: [], - }, - { - created: '2024-09-06T08:09:43.641Z', - id: 2, - label: 'DBaaS Dashboard', - service_type: 'dbaas', - time_duration: { - unit: 'min', - value: 30, - }, - updated: '2024-09-06T08:09:43.641Z', - widgets: [], - }, - ], -}; -const resourceData = { - data: [ - { - alerts: { - cpu: 180, - io: 10000, - network_in: 10, - network_out: 10, - transfer_quota: 80, - }, - backups: { - available: false, - enabled: false, - last_successful: null, - schedule: { - day: null, - window: null, - }, - }, - capabilities: [], - created: '2024-04-24T12:11:28', - disk_encryption: 'disabled', - group: '', - has_user_data: false, - host_uuid: '2c9c27e421a9e088d8e49029a3596aa3a789ed74', - hypervisor: 'kvm', - id: 57667285, - image: 'linode/debian11', - ipv4: ['172.234.222.69'], - ipv6: '2600:3c06::f03c:94ff:fe6a:684c/128', - label: 'test1', - lke_cluster_id: null, - placement_group: null, - region: 'us-ord', - site_type: 'core', - specs: { - disk: 81920, - gpus: 0, - memory: 4096, - transfer: 4000, - vcpus: 2, - }, - status: 'running', - tags: [], - type: 'g6-standard-2', - updated: '2024-09-04T09:17:42', - watchdog_enabled: true, - }, - { - alerts: { - cpu: 180, - io: 10000, - network_in: 10, - network_out: 10, - transfer_quota: 80, - }, - backups: { - available: false, - enabled: false, - last_successful: null, - schedule: { - day: null, - window: null, - }, - }, - capabilities: [], - created: '2024-04-24T12:12:27', - disk_encryption: 'disabled', - group: '', - has_user_data: false, - host_uuid: '062252cf2ef2739a167ea31f3518086ca7f20a65', - hypervisor: 'kvm', - id: 57667325, - image: 'linode/debian11', - ipv4: ['172.234.222.72'], - ipv6: '2600:3c06::f03c:94ff:fe6a:6894/128', - label: 'linode2', - lke_cluster_id: null, - placement_group: null, - region: 'us-ord', - site_type: 'core', - specs: { - disk: 81920, - gpus: 0, - memory: 4096, - transfer: 4000, - vcpus: 2, - }, - status: 'running', - tags: [], - type: 'g6-standard-2', - updated: '2024-05-05T10:40:10', - watchdog_enabled: true, - }, - { - alerts: { - cpu: 180, - io: 10000, - network_in: 10, - network_out: 10, - transfer_quota: 80, - }, - backups: { - available: false, - enabled: false, - last_successful: null, - schedule: { - day: null, - window: null, - }, - }, - capabilities: [], - created: '2024-04-24T12:13:21', - disk_encryption: 'disabled', - group: '', - has_user_data: false, - host_uuid: 'd939a55bfaed7afa7301c722948a5f99fd800c00', - hypervisor: 'kvm', - id: 57667355, - image: 'linode/debian11', - ipv4: ['172.234.222.73'], - ipv6: '2600:3c06::f03c:94ff:fe6a:40db/128', - label: 'Cloudpulse-demo-ananth', - lke_cluster_id: null, - placement_group: null, - region: 'us-ord', - site_type: 'core', - specs: { - disk: 81920, - gpus: 0, - memory: 4096, - transfer: 4000, - vcpus: 2, - }, - status: 'running', - tags: [], - type: 'g6-standard-2', - updated: '2024-04-30T04:37:18', - watchdog_enabled: true, - }, - ], - page: 1, - pages: 1, - results: 3, -}; +/** + * Intercepts HTTP GET requests for metric definitions. + * + * This function mocks the API response for requests to the endpoint + * `dashboardMetricsData`. + * + * @returns {Cypress.Chainable} The chainable Cypress object. + */ export const interceptGetMetricDefinitions = (): Cypress.Chainable => { return cy.intercept( @@ -302,28 +25,44 @@ export const interceptGetMetricDefinitions = (): Cypress.Chainable => { dashboardMetricsData ); }; -export const interceptGetDashBoards = (): Cypress.Chainable => { +/** + * Intercepts HTTP GET requests for dashboard definitions. + * + * This function mocks the API response for requests to the endpoint + * `dashboardDefinitions`. + * + * @returns {Cypress.Chainable} The chainable Cypress object. + */ + +export const interceptGetDashboards = (): Cypress.Chainable => { return cy.intercept( 'GET', apiMatcher('**/monitor/services/linode/dashboards'), - dashboardData - ); -}; -export const interceptGetResources = (): Cypress.Chainable => { - return cy.intercept( - 'GET', - apiMatcher('**/linode/instances/?page_size=500'), - resourceData + dashboardDefinitions ); }; +/** + * Sets up an intercept for POST requests to the metrics endpoint. + * + * and assign an alias of 'getMetrics' to the intercepted request. + * + * @returns {void} + */ export const interceptMetricsRequests = () => { cy.intercept({ method: 'POST', url: '**/monitor/services/linode/metrics', }).as('getMetrics'); - return cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']); }; -export const interceptMetricAPI = ( +/** + * Intercepts POST requests to the metrics endpoint with a custom mock response. + * + * This function allows you to specify a mock response for POST requests + * + * @param {any} mockResponse - The mock response to return for the intercepted request. + * @returns {Cypress.Chainable} The chainable Cypress object. + */ +export const interceptCreateMetrics = ( mockResponse: any ): Cypress.Chainable => { return cy.intercept( diff --git a/packages/manager/cypress/support/util/cloudpulse.ts b/packages/manager/cypress/support/util/cloudpulse.ts index 3d28b1b76f4..6cafce2834f 100644 --- a/packages/manager/cypress/support/util/cloudpulse.ts +++ b/packages/manager/cypress/support/util/cloudpulse.ts @@ -1,24 +1,7 @@ /* eslint-disable cypress/unsafe-to-chain-command */ -import { accountFactory, profileFactory } from '@src/factories'; -import { accountUserFactory } from '@src/factories/accountUsers'; -import { granularity } from 'support/constants/granularity'; -import { timeRange } from 'support/constants/timerange'; -import { mockGetAccount, mockGetUser } from 'support/intercepts/account'; -import { - interceptGetDashBoards, - interceptGetMetricDefinitions, - interceptGetResources, - interceptMetricAPI, -} from 'support/intercepts/cloudpulseAPIHandler'; -import { - mockAppendFeatureFlags, - mockGetFeatureFlagClientstream, -} from 'support/intercepts/feature-flags'; -import { mockGetProfile } from 'support/intercepts/profile'; +import { timeRange } from 'support/constants/widget-service'; import { ui } from 'support/ui'; -import { makeFeatureFlagData } from 'support/util/feature-flags'; -import type { Flags } from 'src/featureFlags'; export const dashboardName = 'Linode Dashboard'; export const region = 'US, Chicago, IL (us-ord)'; export const actualRelativeTimeDuration = timeRange.Last24Hours; @@ -34,103 +17,6 @@ export const resource = 'test1'; * These utilities ensure efficient and consistent test execution and validation. */ - interface MetricResponse { - data: { - result: Array<{ - metric: Record; - values: [number, string][]; - }>; - resultType: string; - }; - isPartial: boolean; - stats: { - executionTimeMsec: number; - seriesFetched: string; - }; - status: string; -} -/** - * Generates a mock metric response based on the specified time range and granularity. - * - * This function: - * 1. Determines the time interval based on the granularity (e.g., 5 minutes, 1 hour, 1 day). - * 2. Calculates the time range in seconds based on the specified time range (e.g., last 12 hours, last 30 days). - * 3. Creates a series of random metric values for the given time range at the specified interval. - * 4. Returns a mock response object containing the generated metric data. - * - * @param {string} time - The time range for the metric data (e.g., "Last12Hours"). - * @param {string} granularityData - The granularity of the metric data (e.g., "Min5"). - * @returns {MetricResponse} - The generated mock metric response. - */ -export const createMetricResponse = ( - time: string, - granularityData: string -): MetricResponse => { - const currentTime = Math.floor(Date.now() / 1000); - - const intervals: Record = { - [granularity.Auto]: 3600, - [granularity.Day1]: 86400, - [granularity.Hr1]: 3600, - [granularity.Min5]: 5 * 60, - }; - - const timeRanges: Record = { - [timeRange.Last7Days]: 7 * 24 * 3600, - [timeRange.Last12Hours]: 12 * 3600, - [timeRange.Last24Hours]: 24 * 3600, - [timeRange.Last30Days]: 30 * 24 * 3600, - [timeRange.Last30Minutes]: 30 * 60, - }; - - const interval = - intervals[granularityData] || - (() => { - throw new Error(`Unsupported granularity: ${granularityData}`); - })(); - const timeRangeInSeconds = - timeRanges[time] || - (() => { - throw new Error(`Unsupported time range: ${time}`); - })(); - const startTime = currentTime - timeRangeInSeconds; - - const values: [number, string][] = Array.from( - { length: Math.ceil(timeRangeInSeconds / interval) + 1 }, - (_, i) => { - const timestamp = startTime + i * interval; - const value = (Math.random() * 100).toFixed(2); - return [timestamp, value]; - } - ); - - return { - data: { - result: [{ metric: {}, values }], - resultType: 'matrix', - }, - isPartial: false, - stats: { - executionTimeMsec: 53, - seriesFetched: '6', - }, - status: 'success', - }; -}; - -/** - * Visits the Linodes page when the Cloudpulse feature flag is disabled, - * and verifies that the Monitor tab is not present. - */ -export const visitCloudPulseWithFeatureFlagsDisabled = () => { - cy.visitWithLogin('/linodes'); - mockAppendFeatureFlags({ aclp: makeFeatureFlagData(false) }).as( - 'getFeatureFlags' - ); - mockGetFeatureFlagClientstream().as('getClientStream'); - cy.findByLabelText('Monitor').should('not.exist'); -}; - /** * Selects a service name from the dashboard dropdown. * @param {string} serviceName - The name of the service to select. @@ -139,9 +25,14 @@ export const selectServiceName = (serviceName: string) => { ui.autocomplete .findByTitleCustom('Select Dashboard') .findByTitle('Open') + .should('be.visible') .click(); - ui.autocomplete .findByPlaceholderCustom('Select Dashboard').type(`${serviceName}{enter}`); + ui.autocomplete + .findByPlaceholderCustom('Select Dashboard') + .type(`${serviceName}{enter}`); + cy.findByDisplayValue(serviceName).should('have.value', serviceName); }; + /** * Selects a region from the region dropdown. * @param {string} region - The name of the region to select. @@ -159,22 +50,27 @@ export const selectTimeRange = (timeRange: string) => { .findByTitle('Open') .click(); ui.autocompletePopper.findByTitle(timeRange).should('be.visible').click(); + cy.findByDisplayValue(timeRange).should('have.value', timeRange); }; /** * Selects a resource name from the resources dropdown and verifies the selection. * @param {string} service - The name of the service to select. */ -export const selectAndVerifyResource = (service: string) => { +export const selectAndVerifyResource = (service: string) => { const resourceInput = ui.autocomplete.findByTitleCustom('Select Resources'); resourceInput.findByTitle('Open').click(); resourceInput.click().type(`${service}{enter}`); + // Commenting out the line because resourceInput.findByTitle('closure') does not work + // resourceInput.findByTitle('Close').click(); + cy.get('[title="Close"]').click(); }; /** * Asserts that the selected options match the expected values. * @param {string} expectedOptions - The expected options to verify. */ export const assertSelections = (expectedOptions: string) => { - expect(cy.get(`[value*='${expectedOptions}']`), expectedOptions); + cy.get(`[value*='${expectedOptions}']`).should('be.visible'); + cy.get(`[value*='${expectedOptions}']`).should('have.value', expectedOptions); }; /** * Applies a global refresh action on the dashboard. @@ -191,7 +87,9 @@ export const resetDashboardAndVerifyPage = (serviceName: string) => { .findByTitleCustom('Select Dashboard') .findByTitle('Open') .click(); - ui.autocomplete .findByPlaceholderCustom('Select Dashboard').type(`${serviceName}{enter}`); + ui.autocomplete + .findByPlaceholderCustom('Select Dashboard') + .type(`${serviceName}{enter}`); ui.autocomplete .findByTitleCustom('Select Dashboard') .findByTitle('Clear') @@ -219,6 +117,7 @@ export const validateWidgetTitle = (widgetName: string) => { .then((text) => { expect(text.trim()).to.equal(widgetName); }); + cy.findByDisplayValue(widgetName).should('have.value', widgetName); }; /** @@ -375,45 +274,14 @@ export const checkZoomActions = (widgetName: string) => { }); }; -const mockParentProfile = profileFactory.build({ - user_type: 'parent', - username: 'mock-user@linode.com', -}); - -const mockParentUser = accountUserFactory.build({ - user_type: 'default', - username: mockParentProfile.email, -}); -const mockParentAccount = accountFactory.build({ - company: 'Parent Company', -}); /** * Sets up mock data and intercepts for user-related tests. - * + * * This function: - * 1. Mocks responses for user profile, account, and user data APIs. - * 2. Configures feature flags for testing. - * 3. Mocks the feature flag client stream. - * 4. Visits the specified page with a logged-in user. - * 5. Sets up intercepts for various API calls and aliases them for testing. - * - * This ensures a controlled environment for testing user-related functionality. + * 1. Configures feature flags for testing. + * 2 Mocks the feature flag client stream. + * 3. Visits the specified page with a logged-in user. + * 4. Sets up intercepts for various API calls and aliases them for testing. + * + * */ -export const initializeMockUserData = () => { - mockGetProfile(mockParentProfile); - mockGetAccount(mockParentAccount); - mockGetUser(mockParentUser); - mockAppendFeatureFlags({ - aclp: makeFeatureFlagData({ beta: true, enabled: true }), - }); - mockGetFeatureFlagClientstream(); - cy.visitWithLogin('monitor/cloudpulse'); - interceptGetMetricDefinitions().as('dashboardMetricsData'); - interceptGetDashBoards().as('dashboard'); - interceptGetResources().as('resourceData'); - const responsePayload = createMetricResponse( - actualRelativeTimeDuration, - granularity.Min5 - ); - interceptMetricAPI(responsePayload).as('metricAPI'); -}; diff --git a/packages/manager/cypress/support/util/widgetFactory.ts b/packages/manager/cypress/support/util/widgetFactory.ts deleted file mode 100644 index 3dc6e2f9672..00000000000 --- a/packages/manager/cypress/support/util/widgetFactory.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { aggregation } from 'support/constants/aggregation'; -import type { granularity } from 'support/constants/granularity'; - -// Factory function to create widget constants -export function createWidget( - name: string, - title: string, - expectedAggregation: aggregation, - expectedGranularity: granularity, - expectedGranularityArray: string[], - expectedAggregationyArray: string[] -) { - return { - expectedAggregation, - expectedAggregationyArray, - expectedGranularity, - expectedGranularityArray, - name, - title, - }; -} diff --git a/packages/manager/cypress/support/util/widgetService.ts b/packages/manager/cypress/support/util/widgetService.ts deleted file mode 100644 index cb5fa140881..00000000000 --- a/packages/manager/cypress/support/util/widgetService.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { aggregation, aggregationConfig } from 'support/constants/aggregation'; -import { granularity } from 'support/constants/granularity'; - -export const widgetDetails = { - dbaas: [ - { - expectedAggregation: aggregation.Max, - expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hr1, - expectedGranularityArray: Object.values(granularity), - name: 'system_disk_OPS_total', - title: 'Disk I/O', - }, - { - expectedAggregation: aggregation.Max, - expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hr1, - expectedGranularityArray: Object.values(granularity), - name: 'system_network_io_by_resource', - title: 'Network Traffic', - }, - { - expectedAggregation: aggregation.Max, - expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hr1, - expectedGranularityArray: Object.values(granularity), - name: 'system_memory_usage_by_resource', - title: 'Memory Usage', - }, - { - expectedAggregation: aggregation.Max, - expectedAggregationArray: aggregationConfig.basic, - expectedGranularity: granularity.Hr1, - expectedGranularityArray: Object.values(granularity), - name: 'system_cpu_utilization_percent', - title: 'CPU Utilization', - }, - ], - linode: [ - { - expectedAggregation: aggregation.Max, - expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hr1, - expectedGranularityArray: Object.values(granularity), - name: 'system_disk_OPS_total', - title: 'Disk I/O', - }, - { - expectedAggregation: aggregation.Max, - expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hr1, - expectedGranularityArray: Object.values(granularity), - name: 'system_network_io_by_resource', - title: 'Network Traffic', - }, - { - expectedAggregation: aggregation.Max, - expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hr1, - expectedGranularityArray: Object.values(granularity), - name: 'system_memory_usage_by_resource', - title: 'Memory Usage', - }, - { - expectedAggregation: aggregation.Max, - expectedAggregationArray: aggregationConfig.basic, - expectedGranularity: granularity.Hr1, - expectedGranularityArray: Object.values(granularity), - name: 'system_cpu_utilization_percent', - title: 'CPU Utilization', - }, - ], -}; diff --git a/packages/manager/src/factories/widgetFactory.ts b/packages/manager/src/factories/widgetFactory.ts new file mode 100644 index 00000000000..dab641ea40c --- /dev/null +++ b/packages/manager/src/factories/widgetFactory.ts @@ -0,0 +1,104 @@ +import { + granularity, + timeRange, +} from '../../cypress/support/constants/widget-service'; +export function createWidget( + name: string, + title: string, + expectedAggregation: string, + expectedGranularity: string, + expectedGranularityArray: string[], + expectedAggregationyArray: string[] +) { + return { + expectedAggregation, + expectedAggregationyArray, + expectedGranularity, + expectedGranularityArray, + name, + title, + }; +} +interface MetricResponse { + data: { + result: Array<{ + metric: Record; + values: [number, string][]; + }>; + resultType: string; + }; + isPartial: boolean; + stats: { + executionTimeMsec: number; + seriesFetched: string; + }; + status: string; +} +/** + * Generates a mock metric response based on the specified time range and granularity. + * + * This function: + * 1. Determines the time interval based on the granularity (e.g., 5 minutes, 1 hour, 1 day). + * 2. Calculates the time range in seconds based on the specified time range (e.g., last 12 hours, last 30 days). + * 3. Creates a series of random metric values for the given time range at the specified interval. + * 4. Returns a mock response object containing the generated metric data. + * + * @param {string} time - The time range for the metric data (e.g., "Last12Hours"). + * @param {string} granularityData - The granularity of the metric data (e.g., "Min5"). + * @returns {MetricResponse} - The generated mock metric response. + */ +export const createMetricResponse = ( + time: string, + granularityData: string +): MetricResponse => { + const currentTime = Math.floor(Date.now() / 1000); + + const intervals: Record = { + [granularity.Auto]: 3600, + [granularity.Day1]: 86400, + [granularity.Hr1]: 3600, + [granularity.Min5]: 5 * 60, + }; + + const timeRanges: Record = { + [timeRange.Last7Days]: 7 * 24 * 3600, + [timeRange.Last12Hours]: 12 * 3600, + [timeRange.Last24Hours]: 24 * 3600, + [timeRange.Last30Days]: 30 * 24 * 3600, + [timeRange.Last30Minutes]: 30 * 60, + }; + + const interval = + intervals[granularityData] || + (() => { + throw new Error(`Unsupported granularity: ${granularityData}`); + })(); + const timeRangeInSeconds = + timeRanges[time] || + (() => { + throw new Error(`Unsupported time range: ${time}`); + })(); + const startTime = currentTime - timeRangeInSeconds; + + const values: [number, string][] = Array.from( + { length: Math.ceil(timeRangeInSeconds / interval) + 1 }, + (_, i) => { + const timestamp = startTime + i * interval; + const value = (Math.random() * 100).toFixed(2); + return [timestamp, value]; + } + ); + + return { + data: { + result: [{ metric: {}, values }], + resultType: 'matrix', + }, + isPartial: false, + stats: { + executionTimeMsec: 53, + seriesFetched: '6', + }, + status: 'success', + }; +}; From 308c2679a96ad02392849f5b642591268746f117 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 9 Sep 2024 15:39:37 +0530 Subject: [PATCH 020/474] upcoming: [DI-20585] - Fix validation for feature flag test case --- .../core/cloudpulse/dashboard-filters.spec.ts | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts index 368e293ecf5..4f46aba7e8f 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts @@ -22,12 +22,19 @@ import { } from 'support/intercepts/cloudpulseAPIHandler'; import { makeFeatureFlagData } from 'support/util/feature-flags'; import type { Flags } from 'src/featureFlags'; -import {createMetricResponse} from '@src/factories/widgetFactory' -import { mockGetLinodes} from 'support/intercepts/linodes'; +import { createMetricResponse } from '@src/factories/widgetFactory' +import { mockGetLinodes } from 'support/intercepts/linodes'; import { + accountFactory, kubeLinodeFactory, linodeFactory, } from 'src/factories'; + +import { + mockGetAccount, + mockCancelAccount, + mockCancelAccountError, +} from 'support/intercepts/account'; /** * This test suite focuses on the standard operations and verifications for the Cloudpulse dashboard. * @@ -54,26 +61,20 @@ describe('Standard Dashboard Filter Application and Configuration Tests', () => interceptGetMetricDefinitions().as('dashboardMetricsData'); interceptGetDashboards().as('dashboard'); mockGetLinodes([mockLinode]).as('getLinodes'); - const responsePayload = createMetricResponse(actualRelativeTimeDuration,granularity.Min5); + const responsePayload = createMetricResponse(actualRelativeTimeDuration, granularity.Min5); interceptCreateMetrics(responsePayload).as('metricAPI'); + const mockAccount = accountFactory.build(); + mockGetAccount(mockAccount).as('getAccount'); // this enables the account to have capability for Akamai Cloud Pulse }); - + it.only('should verify cloudpulse availability when feature flag is set to false', () => { mockAppendFeatureFlags({ aclp: makeFeatureFlagData({ beta: true, enabled: false }), }); mockGetFeatureFlagClientstream(); - cy.visitWithLogin('/linodes'); - cy.get('[data-testid="menu-item-Monitor"]').should('be.visible').invoke('attr', 'href').then((href) => { - cy.log("url ******",href) - cy.request({ - url: href, - failOnStatusCode: false - }).then((response) => { - expect(response.status).to.be.equal(404); - }); - }); + cy.visitWithLogin('monitor/cloudpulse'); // since we disabled the flag here, we should have not found + cy.findByText('Not Found').should('be.visible'); // not found }); it('should clear the preferences of the dashboard', () => { @@ -96,4 +97,4 @@ describe('Standard Dashboard Filter Application and Configuration Tests', () => it('should set and verify resource', () => { selectAndVerifyResource(resource); }); - }); +}); From bf0797465553d8a840eab8e45c6854b36a44ec4a Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 9 Sep 2024 15:49:34 +0530 Subject: [PATCH 021/474] upcoming: [DI-20585] - Enable services call through mock --- .../core/cloudpulse/dashboard-filters.spec.ts | 8 +++++--- .../support/constants/widget-mockdata.ts | 4 ++++ .../support/intercepts/cloudpulseAPIHandler.ts | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts index 4f46aba7e8f..2367c418a74 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts @@ -16,6 +16,7 @@ import { } from 'support/intercepts/feature-flags'; import { granularity } from 'support/constants/widget-service'; import { + interceptCloudPulseServices, interceptCreateMetrics, interceptGetDashboards, interceptGetMetricDefinitions, @@ -60,6 +61,7 @@ describe('Standard Dashboard Filter Application and Configuration Tests', () => cy.visitWithLogin('monitor/cloudpulse'); interceptGetMetricDefinitions().as('dashboardMetricsData'); interceptGetDashboards().as('dashboard'); + interceptCloudPulseServices().as('services'); mockGetLinodes([mockLinode]).as('getLinodes'); const responsePayload = createMetricResponse(actualRelativeTimeDuration, granularity.Min5); interceptCreateMetrics(responsePayload).as('metricAPI'); @@ -68,7 +70,7 @@ describe('Standard Dashboard Filter Application and Configuration Tests', () => }); - it.only('should verify cloudpulse availability when feature flag is set to false', () => { + it('should verify cloudpulse availability when feature flag is set to false', () => { mockAppendFeatureFlags({ aclp: makeFeatureFlagData({ beta: true, enabled: false }), }); @@ -77,10 +79,10 @@ describe('Standard Dashboard Filter Application and Configuration Tests', () => cy.findByText('Not Found').should('be.visible'); // not found }); - it('should clear the preferences of the dashboard', () => { + it.only('should clear the preferences of the dashboard', () => { resetDashboardAndVerifyPage(dashboardName); }); - it('should set and verify dashboard name', () => { + it.only('should set and verify dashboard name', () => { selectServiceName(dashboardName); assertSelections(dashboardName); }); diff --git a/packages/manager/cypress/support/constants/widget-mockdata.ts b/packages/manager/cypress/support/constants/widget-mockdata.ts index 39056b864b1..2d8a1a2f59c 100644 --- a/packages/manager/cypress/support/constants/widget-mockdata.ts +++ b/packages/manager/cypress/support/constants/widget-mockdata.ts @@ -130,3 +130,7 @@ export const dashboardDefinitions = { }, ], }; + +export const cloudPulseServices = { + data: [{ service_type: 'linode' }], +}; diff --git a/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts b/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts index 2865aa43998..5de24935b9a 100644 --- a/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts +++ b/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts @@ -4,6 +4,7 @@ * @returns Cypress chainable. */ import { + cloudPulseServices, dashboardDefinitions, dashboardMetricsData, } from 'support/constants/widget-mockdata'; @@ -25,6 +26,23 @@ export const interceptGetMetricDefinitions = (): Cypress.Chainable => { dashboardMetricsData ); }; + +/** + * Intercepts HTTP GET requests for metric definitions. + * + * This function mocks the API response for requests to the endpoint + * `dashboardMetricsData`. + * + * @returns {Cypress.Chainable} The chainable Cypress object. + */ + +export const interceptCloudPulseServices = (): Cypress.Chainable => { + return cy.intercept( + 'GET', + apiMatcher('**/monitor/services'), + cloudPulseServices + ); +}; /** * Intercepts HTTP GET requests for dashboard definitions. * From 40be33a077a4daaeefd621fcbbe0371756868d69 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 9 Sep 2024 16:02:05 +0530 Subject: [PATCH 022/474] upcoming: [DI-20585] - Flow update for widget tests --- .../core/cloudpulse/dashboard-filters.spec.ts | 4 +- .../cloudpulse/widget-verification.spec.ts | 65 ++++++++++--------- 2 files changed, 37 insertions(+), 32 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts index 2367c418a74..c15df648383 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts @@ -79,10 +79,10 @@ describe('Standard Dashboard Filter Application and Configuration Tests', () => cy.findByText('Not Found').should('be.visible'); // not found }); - it.only('should clear the preferences of the dashboard', () => { + it('should clear the preferences of the dashboard', () => { resetDashboardAndVerifyPage(dashboardName); }); - it.only('should set and verify dashboard name', () => { + it('should set and verify dashboard name', () => { selectServiceName(dashboardName); assertSelections(dashboardName); }); diff --git a/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts index 0bab3c0d603..ee53dee5453 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts @@ -11,18 +11,20 @@ import { mockAppendFeatureFlags, mockGetFeatureFlagClientstream, } from 'support/intercepts/feature-flags'; -import { interceptMetricsRequests} from 'support/intercepts/cloudpulseAPIHandler'; +import { interceptCloudPulseServices, interceptMetricsRequests } from 'support/intercepts/cloudpulseAPIHandler'; import { ui } from 'support/ui'; export const actualRelativeTimeDuration = timeRange.Last30Minutes; -import { timeRange, widgetDetails,timeUnit,granularity } from 'support/constants/widget-service'; +import { timeRange, widgetDetails, timeUnit, granularity } from 'support/constants/widget-service'; import { interceptCreateMetrics, interceptGetDashboards, interceptGetMetricDefinitions, } from 'support/intercepts/cloudpulseAPIHandler'; import { makeFeatureFlagData } from 'support/util/feature-flags'; -import {createMetricResponse} from '@src/factories/widgetFactory' +import { createMetricResponse } from '@src/factories/widgetFactory' import type { Flags } from 'src/featureFlags'; +import { accountFactory } from 'src/factories'; +import { mockGetAccount } from 'support/intercepts/account'; const linodeWidgets = widgetDetails.linode; @@ -39,20 +41,23 @@ const linodeWidgets = widgetDetails.linode; describe('Dashboard Widget Verification Tests', () => { beforeEach(() => { - cy.visitWithLogin('monitor/cloudpulse'); mockAppendFeatureFlags({ aclp: makeFeatureFlagData({ beta: true, enabled: true }), }); mockGetFeatureFlagClientstream(); interceptGetMetricDefinitions().as('dashboardMetricsData'); interceptGetDashboards().as('dashboard'); - const responsePayload = createMetricResponse(actualRelativeTimeDuration,granularity.Min5); + interceptCloudPulseServices().as('services'); + const mockAccount = accountFactory.build(); + mockGetAccount(mockAccount).as('getAccount'); // this enables the account to have capability for Akamai Cloud Pulse + cy.visitWithLogin('monitor/cloudpulse'); + const responsePayload = createMetricResponse(actualRelativeTimeDuration, granularity.Min5); interceptCreateMetrics(responsePayload).as('metricAPI'); selectTimeRange(actualRelativeTimeDuration); }); it(`should set available granularity of the all the widget`, () => { linodeWidgets.forEach((testData) => { - setGranularity(testData.title, testData.expectedGranularity); + setGranularity(testData.title, testData.expectedGranularity); }); }); it(`should verify the title of the widget`, () => { @@ -82,33 +87,33 @@ describe('Dashboard Widget Verification Tests', () => { }); }); -it('should apply global refresh button and verify network calls', () => { - ui.cloudpulse.findRefreshIcon().click(); - interceptMetricsRequests(); - cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']).then((interceptions) => { - const interceptionsArray = Array.isArray(interceptions) ? interceptions : [interceptions]; + it('should apply global refresh button and verify network calls', () => { + ui.cloudpulse.findRefreshIcon().click(); + interceptMetricsRequests(); + cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']).then((interceptions) => { + const interceptionsArray = Array.isArray(interceptions) ? interceptions : [interceptions]; + + interceptionsArray.forEach((interception) => { + const { body: requestPayload } = interception.request; + const metric = requestPayload.metric; + const metricData = linodeWidgets.find((data) => data.name === metric); - interceptionsArray.forEach((interception) => { - const { body: requestPayload } = interception.request; - const metric = requestPayload.metric; - const metricData = linodeWidgets.find((data) => data.name === metric); - - if (!metricData) { - throw new Error(`Unknown metric: ${metric}`); - } - const granularity = requestPayload['time_granularity']; - const currentGranularity = granularity ? `${granularity.value} ${granularity.unit}` : ''; - const durationUnit = requestPayload.relative_time_duration.unit.toLowerCase(); - const durationValue = requestPayload.relative_time_duration.value; - const currentRelativeTimeDuration = durationUnit in timeUnit ? 'Last' + durationValue + timeUnit[durationUnit as keyof typeof timeUnit] : ''; - expect(requestPayload.aggregate_function).to.equal(metricData.expectedAggregation); - expect(currentRelativeTimeDuration).to.containIgnoreSpaces(actualRelativeTimeDuration); - expect(requestPayload.metric).to.equal(metricData.name); - expect(currentGranularity).to.equal(metricData.expectedGranularity); + if (!metricData) { + throw new Error(`Unknown metric: ${metric}`); + } + const granularity = requestPayload['time_granularity']; + const currentGranularity = granularity ? `${granularity.value} ${granularity.unit}` : ''; + const durationUnit = requestPayload.relative_time_duration.unit.toLowerCase(); + const durationValue = requestPayload.relative_time_duration.value; + const currentRelativeTimeDuration = durationUnit in timeUnit ? 'Last' + durationValue + timeUnit[durationUnit as keyof typeof timeUnit] : ''; + expect(requestPayload.aggregate_function).to.equal(metricData.expectedAggregation); + expect(currentRelativeTimeDuration).to.containIgnoreSpaces(actualRelativeTimeDuration); + expect(requestPayload.metric).to.equal(metricData.name); + expect(currentGranularity).to.equal(metricData.expectedGranularity); + }); }); }); -}); }); - + From d0885dc2b6c6891e998ab8ff69b58c357bcd4701 Mon Sep 17 00:00:00 2001 From: agorthi Date: Mon, 9 Sep 2024 18:08:41 +0530 Subject: [PATCH 023/474] upcoming:[DI-20585]- Added code review comments and fixing few mocking issues --- .../core/cloudpulse/dashboard-filters.spec.ts | 7 +-- .../cloudpulse/widget-verification.spec.ts | 25 ++++++--- .../support/constants/widget-mockdata.ts | 51 +++++++++++++++++++ .../intercepts/cloudpulseAPIHandler.ts | 17 +++++++ .../cypress/support/util/cloudpulse.ts | 23 ++++----- .../src/components/LineGraph/LineGraph.tsx | 1 - .../manager/src/factories/widgetFactory.ts | 21 ++------ .../CloudPulse/Widget/CloudPulseWidget.tsx | 2 +- 8 files changed, 104 insertions(+), 43 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts index c15df648383..f17f9fcf69a 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts @@ -33,9 +33,10 @@ import { import { mockGetAccount, - mockCancelAccount, - mockCancelAccountError, } from 'support/intercepts/account'; +import { + timeRange, +} from 'support/constants/widget-service'; /** * This test suite focuses on the standard operations and verifications for the Cloudpulse dashboard. * @@ -87,7 +88,7 @@ describe('Standard Dashboard Filter Application and Configuration Tests', () => assertSelections(dashboardName); }); it('should set and verify time range', () => { - selectTimeRange(actualRelativeTimeDuration); + selectTimeRange(actualRelativeTimeDuration, Object.values(timeRange)); assertSelections(actualRelativeTimeDuration); }); diff --git a/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts index ee53dee5453..4c6e18baccc 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts @@ -6,12 +6,14 @@ import { verifyGranularity, verifyAggregation, checkZoomActions, + selectAndVerifyResource, + resource, } from 'support/util/cloudpulse'; import { mockAppendFeatureFlags, mockGetFeatureFlagClientstream, } from 'support/intercepts/feature-flags'; -import { interceptCloudPulseServices, interceptMetricsRequests } from 'support/intercepts/cloudpulseAPIHandler'; +import { interceptCloudPulseServices, interceptMetricsRequests ,mockJWSToken,mockLinodeDashboardServicesResponse} from 'support/intercepts/cloudpulseAPIHandler'; import { ui } from 'support/ui'; export const actualRelativeTimeDuration = timeRange.Last30Minutes; import { timeRange, widgetDetails, timeUnit, granularity } from 'support/constants/widget-service'; @@ -23,11 +25,11 @@ import { import { makeFeatureFlagData } from 'support/util/feature-flags'; import { createMetricResponse } from '@src/factories/widgetFactory' import type { Flags } from 'src/featureFlags'; -import { accountFactory } from 'src/factories'; +import { accountFactory ,kubeLinodeFactory,linodeFactory} from 'src/factories'; import { mockGetAccount } from 'support/intercepts/account'; +import { mockGetLinodes } from 'support/intercepts/linodes'; - -const linodeWidgets = widgetDetails.linode; + const linodeWidgets = widgetDetails.linode; /** * This test ensures that widget titles are displayed correctly on the dashboard. * This test suite is dedicated to verifying the functionality and display of widgets on the Cloudpulse dashboard. @@ -38,24 +40,33 @@ const linodeWidgets = widgetDetails.linode; * Testing widget interactions, including zooming and filtering, to ensure proper behavior. * Each test ensures that widgets on the dashboard operate correctly and display accurate information. */ +const mockKubeLinode = kubeLinodeFactory.build(); + +const mockLinode = linodeFactory.build({ + label:"test1", + id: mockKubeLinode.instance_id ?? undefined, +}); describe('Dashboard Widget Verification Tests', () => { beforeEach(() => { mockAppendFeatureFlags({ aclp: makeFeatureFlagData({ beta: true, enabled: true }), }); + mockGetFeatureFlagClientstream(); + mockGetLinodes([mockLinode]).as('getLinodes'); interceptGetMetricDefinitions().as('dashboardMetricsData'); interceptGetDashboards().as('dashboard'); interceptCloudPulseServices().as('services'); + mockLinodeDashboardServicesResponse(); + mockJWSToken(); const mockAccount = accountFactory.build(); mockGetAccount(mockAccount).as('getAccount'); // this enables the account to have capability for Akamai Cloud Pulse cy.visitWithLogin('monitor/cloudpulse'); const responsePayload = createMetricResponse(actualRelativeTimeDuration, granularity.Min5); interceptCreateMetrics(responsePayload).as('metricAPI'); - selectTimeRange(actualRelativeTimeDuration); - }); - it(`should set available granularity of the all the widget`, () => { + }); + it.only(`should set available granularity of the all the widget`, () => { linodeWidgets.forEach((testData) => { setGranularity(testData.title, testData.expectedGranularity); }); diff --git a/packages/manager/cypress/support/constants/widget-mockdata.ts b/packages/manager/cypress/support/constants/widget-mockdata.ts index 2d8a1a2f59c..b48e4df3b61 100644 --- a/packages/manager/cypress/support/constants/widget-mockdata.ts +++ b/packages/manager/cypress/support/constants/widget-mockdata.ts @@ -134,3 +134,54 @@ export const dashboardDefinitions = { export const cloudPulseServices = { data: [{ service_type: 'linode' }], }; + +export const linodeMetricsDashboard = { + created: '2024-04-29T17:09:29', + id: '1', + label: 'Linode Service I/O Statistics', + service_type: 'linode', + type: 'standard', + updated: null, + widgets: [ + { + aggregate_function: 'avg', + chart_type: 'area', + color: 'blue', + label: 'CPU utilization', + metric: 'system_cpu_utilization_percent', + size: 12, + unit: '%', + y_label: 'system_cpu_utilization_ratio', + }, + { + aggregate_function: 'avg', + chart_type: 'area', + color: 'red', + label: 'Memory Usage', + metric: 'system_memory_usage_by_resource', + size: 12, + unit: 'Bytes', + y_label: 'system_memory_usage_bytes', + }, + { + aggregate_function: 'avg', + chart_type: 'area', + color: 'green', + label: 'Network Traffic', + metric: 'system_network_io_by_resource', + size: 6, + unit: 'Bytes', + y_label: 'system_network_io_bytes_total', + }, + { + aggregate_function: 'avg', + chart_type: 'area', + color: 'yellow', + label: 'Disk I/O', + metric: 'system_disk_OPS_total', + size: 6, + unit: 'OPS', + y_label: 'system_disk_operations_total', + }, + ], +}; diff --git a/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts b/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts index 5de24935b9a..0e45c9d4b16 100644 --- a/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts +++ b/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts @@ -7,6 +7,7 @@ import { cloudPulseServices, dashboardDefinitions, dashboardMetricsData, + linodeMetricsDashboard, } from 'support/constants/widget-mockdata'; import { apiMatcher } from 'support/util/intercepts'; @@ -89,3 +90,19 @@ export const interceptCreateMetrics = ( mockResponse ); }; + +export const mockLinodeDashboardServicesResponse = (): Cypress.Chainable => { + return cy.intercept( + 'GET', + apiMatcher('**/monitor/dashboards/1'), + linodeMetricsDashboard + ); +}; +const JWSToken = { + token: 'eyJhbGciOiAiZGlyIiwgImVuYyI6ICJBMTI4Q0JDLUhTMjU2IiwgImtpZCI6ID', +}; +export const mockJWSToken = (): Cypress.Chainable => { + return cy.intercept('POST', apiMatcher('**/monitor/services/linode/token'), { + JWSToken, + }); +}; diff --git a/packages/manager/cypress/support/util/cloudpulse.ts b/packages/manager/cypress/support/util/cloudpulse.ts index 6cafce2834f..c97adcf3ab0 100644 --- a/packages/manager/cypress/support/util/cloudpulse.ts +++ b/packages/manager/cypress/support/util/cloudpulse.ts @@ -43,12 +43,17 @@ export const selectRegion = (region: string) => { /** * Selects a time range from the time range dropdown. * @param {string} timeRange - The time range to select. + * @param {Array} timeSegments - An array of time segment values (e.g., ["2024-01-01", "2024-01-02"]). + */ -export const selectTimeRange = (timeRange: string) => { +export const selectTimeRange = (timeRange: string, timeSegments: string[]) => { ui.autocomplete .findByTitleCustom('Select Time Duration') .findByTitle('Open') .click(); + timeSegments.forEach((option) => { + ui.autocompletePopper.findByTitle(option).should('be.visible'); + }); ui.autocompletePopper.findByTitle(timeRange).should('be.visible').click(); cy.findByDisplayValue(timeRange).should('have.value', timeRange); }; @@ -116,8 +121,8 @@ export const validateWidgetTitle = (widgetName: string) => { .invoke('text') .then((text) => { expect(text.trim()).to.equal(widgetName); + cy.findByDisplayValue(widgetName).should('have.value', widgetName); }); - cy.findByDisplayValue(widgetName).should('have.value', widgetName); }; /** @@ -141,6 +146,7 @@ export const setGranularity = (widgetName: string, granularity: string) => { .should('be.visible') .click(); assertSelections(granularity); + cy.findByDisplayValue(granularity).should('have.value', granularity); }); }; /** @@ -163,6 +169,7 @@ export const setAggregation = (widgetName: string, aggregation: string) => { .should('be.visible') .click(); assertSelections(aggregation); + cy.findByDisplayValue(aggregation).should('have.value', aggregation); }); }; /** @@ -273,15 +280,3 @@ export const checkZoomActions = (widgetName: string) => { }); }); }; - -/** - * Sets up mock data and intercepts for user-related tests. - * - * This function: - * 1. Configures feature flags for testing. - * 2 Mocks the feature flag client stream. - * 3. Visits the specified page with a logged-in user. - * 4. Sets up intercepts for various API calls and aliases them for testing. - * - * - */ diff --git a/packages/manager/src/components/LineGraph/LineGraph.tsx b/packages/manager/src/components/LineGraph/LineGraph.tsx index 28374ec83fd..fa631573b07 100644 --- a/packages/manager/src/components/LineGraph/LineGraph.tsx +++ b/packages/manager/src/components/LineGraph/LineGraph.tsx @@ -383,7 +383,6 @@ export const LineGraph = (props: LineGraphProps) => { width: isLegendsFullSize ? '100%' : '85%', }} // this sx is added because styled table forcing the legends to be 85% width & 600px max width aria-label={`Controls for ${ariaLabel || 'Stats and metrics'}`} - data-qa-table-id={ariaLabel} noBorder > diff --git a/packages/manager/src/factories/widgetFactory.ts b/packages/manager/src/factories/widgetFactory.ts index dab641ea40c..9d041103c52 100644 --- a/packages/manager/src/factories/widgetFactory.ts +++ b/packages/manager/src/factories/widgetFactory.ts @@ -2,6 +2,8 @@ import { granularity, timeRange, } from '../../cypress/support/constants/widget-service'; + +import type { AvailableMetrics } from '@linode/api-v4'; export function createWidget( name: string, title: string, @@ -19,21 +21,6 @@ export function createWidget( title, }; } -interface MetricResponse { - data: { - result: Array<{ - metric: Record; - values: [number, string][]; - }>; - resultType: string; - }; - isPartial: boolean; - stats: { - executionTimeMsec: number; - seriesFetched: string; - }; - status: string; -} /** * Generates a mock metric response based on the specified time range and granularity. * @@ -45,12 +32,12 @@ interface MetricResponse { * * @param {string} time - The time range for the metric data (e.g., "Last12Hours"). * @param {string} granularityData - The granularity of the metric data (e.g., "Min5"). - * @returns {MetricResponse} - The generated mock metric response. + * @returns {AvailableMetrics} - The generated mock metric response. */ export const createMetricResponse = ( time: string, granularityData: string -): MetricResponse => { +): AvailableMetrics => { const currentTime = Math.floor(Date.now() / 1000); const intervals: Record = { diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 7d413ef5988..1ce96dde92e 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -299,7 +299,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { padding={1} > Date: Mon, 9 Sep 2024 17:31:42 +0530 Subject: [PATCH 024/474] upcoming: [DI-20360] - Optimized user preferences to avoid passing update function as props --- .../CloudPulse/Overview/GlobalFilters.tsx | 46 ++++++++---- .../CloudPulse/Utils/FilterBuilder.ts | 40 +++++------ .../CloudPulse/Utils/UserPreference.ts | 10 ++- .../CloudPulse/Widget/CloudPulseWidget.tsx | 9 +-- .../shared/CloudPulseCustomSelect.tsx | 15 ++-- .../shared/CloudPulseCustomSelectUtils.ts | 54 +++++++------- .../CloudPulseDashboardFilterBuilder.tsx | 70 +++++++++++++------ .../shared/CloudPulseDashboardSelect.tsx | 22 ++---- .../shared/CloudPulseRegionSelect.tsx | 14 +--- .../shared/CloudPulseResourcesSelect.tsx | 18 ++--- .../shared/CloudPulseTimeRangeSelect.tsx | 28 ++++---- 11 files changed, 166 insertions(+), 160 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index e6891f01c9c..33ce50a894c 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -1,5 +1,5 @@ -import { IconButton } from '@mui/material'; import { Grid } from '@mui/material'; +import { IconButton } from '@mui/material'; import { styled } from '@mui/material/styles'; import * as React from 'react'; @@ -10,6 +10,7 @@ import { CloudPulseDashboardFilterBuilder } from '../shared/CloudPulseDashboardF import { CloudPulseDashboardSelect } from '../shared/CloudPulseDashboardSelect'; import { CloudPulseTimeRangeSelect } from '../shared/CloudPulseTimeRangeSelect'; import { REFRESH } from '../Utils/constants'; +import { DASHBOARD_ID, TIME_DURATION } from '../Utils/constants'; import { useAclpPreference } from '../Utils/UserPreference'; import type { FilterValueType } from '../Dashboard/CloudPulseDashboardLanding'; @@ -35,14 +36,26 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { Dashboard | undefined >(); const handleTimeRangeChange = React.useCallback( - (timerDuration: TimeDuration) => { + ( + timerDuration: TimeDuration, + timeDurationValue: string = 'Auto', + savePref: boolean = false + ) => { + if (savePref) { + updatePreferences({ [TIME_DURATION]: timeDurationValue }); + } handleTimeDurationChange(timerDuration); }, [] ); const onDashboardChange = React.useCallback( - (dashboard: Dashboard | undefined) => { + (dashboard: Dashboard | undefined, savePref: boolean = false) => { + if (savePref) { + updatePreferences({ + [DASHBOARD_ID]: dashboard?.id, + }); + } setSelectedDashboard(dashboard); handleDashboardChange(dashboard); }, @@ -50,20 +63,26 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { ); const emitFilterChange = React.useCallback( - (filterKey: string, value: FilterValueType) => { + ( + filterKey: string, + value: FilterValueType, + savePref: boolean = false, + updatedPreferenceData: {} = {} + ) => { + if (savePref) { + updatePreferences(updatedPreferenceData); + } handleAnyFilterChange(filterKey, value); }, [] ); - const handleGlobalRefresh = React.useCallback( - (dashboardObj?: Dashboard) => { - if (!dashboardObj) { - return; - } - handleAnyFilterChange(REFRESH, Date.now()); - },[] - ); + const handleGlobalRefresh = React.useCallback((dashboardObj?: Dashboard) => { + if (!dashboardObj) { + return; + } + handleAnyFilterChange(REFRESH, Date.now()); + }, []); return ( @@ -82,7 +101,6 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { defaultValue={preferences?.dashboardId} handleDashboardChange={onDashboardChange} savePreferences={true} - updatePreferences={updatePreferences} /> @@ -92,7 +110,6 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { hideLabel label="Select Time Range" savePreferences - updatePreferences={updatePreferences} /> { emitFilterChange={emitFilterChange} isServiceAnalyticsIntegration={false} preferences={preferences} - updatePreferences={updatePreferences} /> )} diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts index c3244ec9423..3da8496ad59 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts @@ -28,7 +28,6 @@ interface CloudPulseFilterProperties { }; isServiceAnalyticsIntegration: boolean; preferences?: AclpConfig; - updatePreferences?: (data: {}) => void; } interface CloudPulseMandatoryFilterCheckProps { @@ -50,22 +49,16 @@ interface CloudPulseMandatoryFilterCheckProps { */ export const getRegionProperties = ( props: CloudPulseFilterProperties, - handleRegionChange: (region: string | undefined) => void + handleRegionChange: (region: string | undefined, savePref?: boolean) => void ): CloudPulseRegionSelectProps => { const { placeholder } = props.config.configuration; - const { - dashboard, - isServiceAnalyticsIntegration, - preferences, - updatePreferences, - } = props; + const { dashboard, isServiceAnalyticsIntegration, preferences } = props; return { handleRegionChange, placeholder, preferences, savePreferences: !isServiceAnalyticsIntegration, selectedDashboard: dashboard, - updatePreferences, }; }; @@ -81,7 +74,10 @@ export const getRegionProperties = ( */ export const getResourcesProperties = ( props: CloudPulseFilterProperties, - handleResourceChange: (resourceId: CloudPulseResources[]) => void + handleResourceChange: ( + resourceId: CloudPulseResources[], + savePref?: boolean + ) => void ): CloudPulseResourcesSelectProps => { const { filterKey, placeholder } = props.config.configuration; const { @@ -90,7 +86,6 @@ export const getResourcesProperties = ( dependentFilters, isServiceAnalyticsIntegration, preferences, - updatePreferences, } = props; return { disabled: checkIfWeNeedToDisableFilterByFilterKey( @@ -103,7 +98,6 @@ export const getResourcesProperties = ( preferences, resourceType: dashboard.service_type, savePreferences: !isServiceAnalyticsIntegration, - updatePreferences, xFilter: buildXFilter(config, dependentFilters ?? {}), }; }; @@ -115,7 +109,12 @@ export const getResourcesProperties = ( */ export const getCustomSelectProperties = ( props: CloudPulseFilterProperties, - handleCustomSelectChange: (filterKey: string, value: FilterValueType) => void + handleCustomSelectChange: ( + filterKey: string, + value: FilterValueType, + savePref?: boolean, + updatedPreferenceData?: {} + ) => void ): CloudPulseCustomSelectProps => { const { apiIdField, @@ -133,7 +132,6 @@ export const getCustomSelectProperties = ( dependentFilters, isServiceAnalyticsIntegration, preferences, - updatePreferences, } = props; return { apiResponseIdField: apiIdField, @@ -160,7 +158,6 @@ export const getCustomSelectProperties = ( type: options ? CloudPulseSelectTypes.static : CloudPulseSelectTypes.dynamic, - updatePreferences, }; }; @@ -174,14 +171,14 @@ export const getCustomSelectProperties = ( */ export const getTimeDurationProperties = ( props: CloudPulseFilterProperties, - handleTimeRangeChange: (timeDuration: TimeDuration) => void + handleTimeRangeChange: ( + timeDuration: TimeDuration, + timeDurationValue?: string, + savePref?: boolean + ) => void ): CloudPulseTimeRangeSelectProps => { const { placeholder } = props.config.configuration; - const { - isServiceAnalyticsIntegration, - preferences, - updatePreferences, - } = props; + const { isServiceAnalyticsIntegration, preferences } = props; const timeDuration = preferences?.timeDuration; return { @@ -190,7 +187,6 @@ export const getTimeDurationProperties = ( handleStatsChange: handleTimeRangeChange, placeholder, savePreferences: !isServiceAnalyticsIntegration, - updatePreferences, }; }; diff --git a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts index 3bbd327e95b..a68a113241b 100644 --- a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts +++ b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts @@ -19,14 +19,14 @@ export const useAclpPreference = () => { const { mutateAsync: updateFunction } = useMutatePreferences(); - const preferenceRef = useRef({ ...(preferences?.aclpPreference ?? {}) }); + // const preferenceRef = useRef({ ...(preferences?.aclpPreference ?? {}) }); /** * * @param data AclpConfig data to be updated in preferences */ const updateGlobalFilterPreference = (data: {}) => { - let currentPreferences = { ...preferenceRef.current }; + let currentPreferences = { ...(preferences?.aclpPreference ?? {}) }; const keys = Object.keys(data); if (keys.includes(DASHBOARD_ID)) { @@ -40,7 +40,6 @@ export const useAclpPreference = () => { ...data, }; } - preferenceRef.current = currentPreferences; updateFunction({ aclpPreference: currentPreferences }); }; @@ -50,7 +49,7 @@ export const useAclpPreference = () => { * @param data AclpWidget data for the label that is to be updated in preference */ const updateWidgetPreference = (label: string, data: Partial) => { - const updatedPreferences = { ...preferenceRef.current }; + const updatedPreferences = { ...(preferences?.aclpPreference ?? {}) }; if (!updatedPreferences.widgets) { updatedPreferences.widgets = {}; @@ -61,12 +60,11 @@ export const useAclpPreference = () => { label, ...data, }; - preferenceRef.current = updatedPreferences; updateFunction({ aclpPreference: updatedPreferences }); }; return { isLoading, - preferences: preferenceRef.current, + preferences: preferences?.aclpPreference ?? {}, updateGlobalFilterPreference, updateWidgetPreference, }; diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 5305d24fb72..1eb37c711b4 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -205,13 +205,6 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { [] ); - /** - * - * @param value number value for the tool tip - * @param unit string unit for the tool tip - * @returns formatted string using @value & @unit - */ - const { data: metricsList, error, @@ -265,7 +258,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { const metricsApiCallError = error?.[0]?.reason; return ( - + void; + handleSelectionChange: ( + filterKey: string, + value: FilterValueType, + savePref?: boolean, + updatedPreferenceData?: {} + ) => void; /** * If true, multiselect is allowed, otherwise false */ @@ -101,12 +106,6 @@ export interface CloudPulseCustomSelectProps { * The cloud pulse select types, it can be static or dynamic depending on the use case */ type: CloudPulseSelectTypes; - - /** - * Function to update the user preference - * @param data Data to be updated in the preferences - */ - updatePreferences?: (data: {}) => void; } export enum CloudPulseSelectTypes { @@ -131,7 +130,6 @@ export const CloudPulseCustomSelect = React.memo( preferences, savePreferences, type, - updatePreferences, } = props; const [selectedResource, setResource] = React.useState< @@ -181,7 +179,6 @@ export const CloudPulseCustomSelect = React.memo( handleSelectionChange, maxSelections, savePreferences, - updatePreferences, value, }); setResource( diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts index 783fb8b4bd6..aa1fd3b8396 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts @@ -13,7 +13,12 @@ interface CloudPulseCustomSelectDefaultValueProps { /** * The callback for the selection changes happening in the custom select component */ - handleSelectionChange: (filterKey: string, value: FilterValueType) => void; + handleSelectionChange: ( + filterKey: string, + value: FilterValueType, + savePref?: boolean, + updatedPreferenceData?: {} + ) => void; /** * Indicates whether we need multiselect for the component or not @@ -34,12 +39,6 @@ interface CloudPulseCustomSelectDefaultValueProps { * Indicates whether we need to save preferences or not */ savePreferences?: boolean; - - /** - * Function to update the user preference - * @param data Data to be updated in the preferences - */ - updatePreferences?: (data: {}) => void; } /** @@ -57,7 +56,12 @@ interface CloudPulseCustomSelectionChangeProps { /** * The callback for the selection changes happening in the custom select component */ - handleSelectionChange: (filterKey: string, value: FilterValueType) => void; + handleSelectionChange: ( + filterKey: string, + value: FilterValueType, + savePref?: boolean, + updatedPreferenceData?: {} + ) => void; /** * The maximum number of selections that needs to be allowed @@ -74,12 +78,6 @@ interface CloudPulseCustomSelectionChangeProps { */ savePreferences?: boolean; - /** - * Function to update the user preference - * @param data Data to be updated in the preferences - */ - updatePreferences?: (data: {}) => void; - /** * The listed options in the custom select component */ @@ -161,7 +159,6 @@ export const handleCustomSelectionChange = ( handleSelectionChange, maxSelections, savePreferences, - updatePreferences, } = selectionChangeProps; let { value } = selectionChangeProps; @@ -176,22 +173,29 @@ export const handleCustomSelectionChange = ( : String(value.id) : undefined; - // publish the selection change - handleSelectionChange(filterKey, result); + let updatedPreferenceData: AclpConfig = {}; // update the preferences - if (savePreferences && updatePreferences) { - updatePreferences({ - [filterKey]: result, - }); + if (savePreferences) { + updatedPreferenceData = { [filterKey]: result }; } // update the clear selections in the preference - if (clearSelections && savePreferences && updatePreferences) { - clearSelections.forEach((selection) => - updatePreferences({ [selection]: undefined }) + if (clearSelections && savePreferences) { + clearSelections.forEach( + (selection) => + (updatedPreferenceData = { + ...updatedPreferenceData, + [selection]: undefined, + }) ); } - + // publish the selection change + handleSelectionChange( + filterKey, + result, + savePreferences, + updatedPreferenceData + ); return value; }; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index 503f5df3323..089f69fe418 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -14,6 +14,7 @@ import { REGION, RELATIVE_TIME_DURATION, RESOURCE_ID, + RESOURCES, } from '../Utils/constants'; import { getCustomSelectProperties, @@ -37,7 +38,12 @@ export interface CloudPulseDashboardFilterBuilderProps { /** * all the selection changes in the filter goes through this method */ - emitFilterChange: (filterKey: string, value: FilterValueType) => void; + emitFilterChange: ( + filterKey: string, + value: FilterValueType, + savePref?: boolean, + updatePreferenceData?: {} + ) => void; /** * this will handle the restrictions, if the parent of the component is going to be integrated in service analytics page @@ -48,12 +54,6 @@ export interface CloudPulseDashboardFilterBuilderProps { * Last selected values from user preferences */ preferences?: AclpConfig; - - /** - * Function to update the user preference - * @param data Data to be updated in the preferences - */ - updatePreferences?: (data: {}) => void; } export const CloudPulseDashboardFilterBuilder = React.memo( @@ -63,7 +63,6 @@ export const CloudPulseDashboardFilterBuilder = React.memo( emitFilterChange, isServiceAnalyticsIntegration, preferences, - updatePreferences, } = props; const [, setDependentFilters] = React.useState<{ @@ -101,33 +100,68 @@ export const CloudPulseDashboardFilterBuilder = React.memo( ); const emitFilterChangeByFilterKey = React.useCallback( - (filterKey: string, filterValue: FilterValueType) => { - emitFilterChange(filterKey, filterValue); + ( + filterKey: string, + filterValue: FilterValueType, + savePref: boolean = false, + updatedPreferenceData: {} = {} + ) => { + emitFilterChange( + filterKey, + filterValue, + savePref, + updatedPreferenceData + ); checkAndUpdateDependentFilters(filterKey, filterValue); }, [emitFilterChange, checkAndUpdateDependentFilters] ); const handleResourceChange = React.useCallback( - (resourceId: CloudPulseResources[]) => { + (resourceId: CloudPulseResources[], savePref: boolean = false) => { emitFilterChangeByFilterKey( RESOURCE_ID, - resourceId.map((resource) => resource.id) + resourceId.map((resource) => resource.id), + savePref, + { + [RESOURCES]: resourceId.map((resource: { id: string }) => + String(resource.id) + ), + } ); }, [emitFilterChangeByFilterKey] ); const handleRegionChange = React.useCallback( - (region: string | undefined) => { - emitFilterChangeByFilterKey(REGION, region); + (region: string | undefined, savePref: boolean = false) => { + const updatedPreferenceData = { + [REGION]: region, + [RESOURCES]: undefined, + }; + emitFilterChangeByFilterKey( + REGION, + region, + savePref, + updatedPreferenceData + ); }, [emitFilterChangeByFilterKey] ); const handleCustomSelectChange = React.useCallback( - (filterKey: string, value: FilterValueType) => { - emitFilterChangeByFilterKey(filterKey, value); + ( + filterKey: string, + value: FilterValueType, + savePref: boolean = false, + updatedPreferenceData: {} = {} + ) => { + emitFilterChangeByFilterKey( + filterKey, + value, + savePref, + updatedPreferenceData + ); }, [emitFilterChangeByFilterKey] ); @@ -141,7 +175,6 @@ export const CloudPulseDashboardFilterBuilder = React.memo( dashboard, isServiceAnalyticsIntegration, preferences, - updatePreferences, }, handleRegionChange ); @@ -153,7 +186,6 @@ export const CloudPulseDashboardFilterBuilder = React.memo( dependentFilters: dependentFilterReference.current, isServiceAnalyticsIntegration, preferences, - updatePreferences, }, handleResourceChange ); @@ -165,7 +197,6 @@ export const CloudPulseDashboardFilterBuilder = React.memo( dependentFilters: dependentFilterReference.current, isServiceAnalyticsIntegration, preferences, - updatePreferences, }, handleCustomSelectChange ); @@ -178,7 +209,6 @@ export const CloudPulseDashboardFilterBuilder = React.memo( handleCustomSelectChange, isServiceAnalyticsIntegration, preferences, - updatePreferences, ] ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index d6eac0e351b..f0cf89aebae 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -6,7 +6,6 @@ import { Typography } from 'src/components/Typography'; import { useCloudPulseDashboardsQuery } from 'src/queries/cloudpulse/dashboards'; import { useCloudPulseServiceTypes } from 'src/queries/cloudpulse/services'; -import { DASHBOARD_ID } from '../Utils/constants'; import { formattedServiceTypes, getAllDashboards } from '../Utils/utils'; import type { Dashboard } from '@linode/api-v4'; @@ -15,20 +14,14 @@ export interface CloudPulseDashboardSelectProps { defaultValue?: number; handleDashboardChange: ( dashboard: Dashboard | undefined, - isDefault?: boolean + savePref?: boolean ) => void; savePreferences?: boolean; - updatePreferences?: (data: {}) => void; } export const CloudPulseDashboardSelect = React.memo( (props: CloudPulseDashboardSelectProps) => { - const { - defaultValue, - handleDashboardChange, - savePreferences, - updatePreferences, - } = props; + const { defaultValue, handleDashboardChange, savePreferences } = props; const { data: serviceTypesList, @@ -86,9 +79,9 @@ export const CloudPulseDashboardSelect = React.memo( (obj: Dashboard) => obj.id === defaultValue ); setSelectedDashboard(dashboard); - handleDashboardChange(dashboard, true); + handleDashboardChange(dashboard); } else { - handleDashboardChange(undefined, true); + handleDashboardChange(undefined); } } // eslint-disable-next-line react-hooks/exhaustive-deps @@ -96,13 +89,8 @@ export const CloudPulseDashboardSelect = React.memo( return ( { - if (savePreferences && updatePreferences) { - updatePreferences({ - [DASHBOARD_ID]: dashboard?.id, - }); - } setSelectedDashboard(dashboard); - handleDashboardChange(dashboard); + handleDashboardChange(dashboard, savePreferences); }} renderGroup={(params) => ( diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index aa04ccf1da7..b7ba7b9cbb6 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -3,17 +3,14 @@ import * as React from 'react'; import { RegionSelect } from 'src/components/RegionSelect/RegionSelect'; import { useRegionsQuery } from 'src/queries/regions/regions'; -import { REGION, RESOURCES } from '../Utils/constants'; - import type { AclpConfig, Dashboard } from '@linode/api-v4'; export interface CloudPulseRegionSelectProps { - handleRegionChange: (region: string | undefined) => void; + handleRegionChange: (region: string | undefined, savePref?: boolean) => void; placeholder?: string; preferences?: AclpConfig; savePreferences?: boolean; selectedDashboard: Dashboard | undefined; - updatePreferences?: (data: {}) => void; } export const CloudPulseRegionSelect = React.memo( @@ -26,7 +23,6 @@ export const CloudPulseRegionSelect = React.memo( preferences, savePreferences, selectedDashboard, - updatePreferences, } = props; const [selectedRegion, setSelectedRegion] = React.useState(); @@ -51,14 +47,8 @@ export const CloudPulseRegionSelect = React.memo( return ( { - if (savePreferences && updatePreferences) { - updatePreferences({ - [REGION]: region?.id, - [RESOURCES]: undefined, - }); - } setSelectedRegion(region?.id); - handleRegionChange(region?.id); + handleRegionChange(region?.id, savePreferences); }} textFieldProps={{ hideLabel: true, diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index e8823f12af2..e5c5e315a35 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -5,8 +5,6 @@ import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; import { useResourcesQuery } from 'src/queries/cloudpulse/resources'; import { themes } from 'src/utilities/theme'; -import { RESOURCES } from '../Utils/constants'; - import type { AclpConfig, Filter } from '@linode/api-v4'; export interface CloudPulseResources { @@ -17,13 +15,15 @@ export interface CloudPulseResources { export interface CloudPulseResourcesSelectProps { disabled?: boolean; - handleResourcesSelection: (resources: CloudPulseResources[]) => void; + handleResourcesSelection: ( + resources: CloudPulseResources[], + savePref?: boolean + ) => void; placeholder?: string; preferences?: AclpConfig; region?: string; resourceType: string | undefined; savePreferences?: boolean; - updatePreferences?: (data: {}) => void; xFilter?: Filter; } @@ -37,7 +37,6 @@ export const CloudPulseResourcesSelect = React.memo( region, resourceType, savePreferences, - updatePreferences, xFilter, } = props; @@ -84,15 +83,8 @@ export const CloudPulseResourcesSelect = React.memo( return ( { - if (savePreferences && updatePreferences) { - updatePreferences({ - [RESOURCES]: resourceSelections.map((resource: { id: string }) => - String(resource.id) - ), - }); - } setSelectedResources(resourceSelections); - handleResourcesSelection(resourceSelections); + handleResourcesSelection(resourceSelections, savePreferences); }} textFieldProps={{ InputProps: { diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx index b61d887a76c..4ea18f3a131 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx @@ -2,8 +2,6 @@ import * as React from 'react'; import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; -import { TIME_DURATION } from '../Utils/constants'; - import type { TimeDuration } from '@linode/api-v4'; import type { BaseSelectProps, @@ -16,10 +14,13 @@ export interface CloudPulseTimeRangeSelectProps 'defaultValue' | 'onChange' > { defaultValue?: string; - handleStatsChange?: (timeDuration: TimeDuration) => void; + handleStatsChange?: ( + timeDuration: TimeDuration, + timeDurationValue?: string, + savePref?: boolean + ) => void; placeholder?: string; savePreferences?: boolean; - updatePreferences?: (data: {}) => void; } const PAST_7_DAYS = 'Last 7 Days'; @@ -41,7 +42,6 @@ export const CloudPulseTimeRangeSelect = React.memo( handleStatsChange, placeholder, savePreferences, - updatePreferences, } = props; const options = generateSelectOptions(); @@ -59,22 +59,24 @@ export const CloudPulseTimeRangeSelect = React.memo( const item = getDefaultValue(); if (handleStatsChange) { - handleStatsChange(getTimeDurationFromTimeRange(item.value)); + handleStatsChange( + getTimeDurationFromTimeRange(item.value), + item.value, + false + ); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // need to execute only once, during mounting of this component const handleChange = (item: Item) => { - if (savePreferences && updatePreferences) { - updatePreferences({ - [TIME_DURATION]: item.value, - }); - } - setSelectedTimeRange(item); if (handleStatsChange) { - handleStatsChange(getTimeDurationFromTimeRange(item.value)); + handleStatsChange( + getTimeDurationFromTimeRange(item.value), + item.value, + savePreferences + ); } setSelectedTimeRange(item); // update the state variable to retain latest selections }; From 4f9adadfbc8727dcabbd2ca6b9856acb6327f18f Mon Sep 17 00:00:00 2001 From: nikhagra Date: Mon, 9 Sep 2024 19:26:13 +0530 Subject: [PATCH 025/474] upcoming: [DI-20360] - Eslint errors resolve --- .../CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx | 1 - .../manager/src/features/CloudPulse/Utils/UserPreference.ts | 2 -- .../CloudPulse/shared/CloudPulseCustomSelectUtils.test.ts | 4 ---- 3 files changed, 7 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx index 8c1654e9060..f43ea8daed8 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx @@ -38,7 +38,6 @@ export const CloudPulseDashboardLanding = () => { const onDashboardChange = React.useCallback((dashboardObj: Dashboard) => { setDashboard(dashboardObj); setFilterValue({}); // clear the filter values on dashboard change - }, []); const onTimeDurationChange = React.useCallback( (timeDurationObj: TimeDuration) => { diff --git a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts index a68a113241b..f5763a2647b 100644 --- a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts +++ b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts @@ -1,5 +1,3 @@ -import { useRef } from 'react'; - import { useMutatePreferences, usePreferences, diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.test.ts b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.test.ts index 3a18762e49e..afe36ed2778 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.test.ts +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.test.ts @@ -63,7 +63,6 @@ it('test getInitialDefaultSelections method for single selection', () => { test: '1', }, savePreferences: true, - updatePreferences: (_: {}) => {}, }); expect(Array.isArray(result)).toBe(false); @@ -79,7 +78,6 @@ it('test getInitialDefaultSelections method for single selection', () => { test: '2', }, savePreferences: true, - updatePreferences: (_: {}) => {}, }); expect(result).toEqual(undefined); expect(handleSelectionChange).toBeCalledTimes(2); @@ -104,7 +102,6 @@ it('test getInitialDefaultSelections method for multi selection', () => { test: '1', }, savePreferences: true, - updatePreferences: (_: {}) => {}, }); expect(Array.isArray(result)).toBe(true); @@ -120,7 +117,6 @@ it('test getInitialDefaultSelections method for multi selection', () => { test: '2', }, savePreferences: true, - updatePreferences: (_: {}) => {}, }); expect(result).toEqual(undefined); expect(handleSelectionChange).toBeCalledTimes(2); From 77dc1fcf2f787df893b875b58f8e5fe5b0112f76 Mon Sep 17 00:00:00 2001 From: agorthi Date: Mon, 9 Sep 2024 20:49:54 +0530 Subject: [PATCH 026/474] upcoming:[DI-20585]- Added code review comments and fixing few mocking issues --- .../cloudpulse/widget-verification.spec.ts | 22 +++++++--- .../support/constants/widget-mockdata.ts | 21 ++-------- .../intercepts/cloudpulseAPIHandler.ts | 4 +- .../cypress/support/util/cloudpulse.ts | 41 +++++++++++++++---- 4 files changed, 57 insertions(+), 31 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts index 4c6e18baccc..504707623e3 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts @@ -8,6 +8,11 @@ import { checkZoomActions, selectAndVerifyResource, resource, + resetDashboardAndVerifyPage, + selectServiceName, + dashboardName, + region, + selectRegion } from 'support/util/cloudpulse'; import { mockAppendFeatureFlags, @@ -65,8 +70,14 @@ describe('Dashboard Widget Verification Tests', () => { cy.visitWithLogin('monitor/cloudpulse'); const responsePayload = createMetricResponse(actualRelativeTimeDuration, granularity.Min5); interceptCreateMetrics(responsePayload).as('metricAPI'); + resetDashboardAndVerifyPage(dashboardName); + selectServiceName(dashboardName); + selectTimeRange(actualRelativeTimeDuration, Object.values(timeRange)); + selectRegion(region); + selectAndVerifyResource(resource); + }); - it.only(`should set available granularity of the all the widget`, () => { + it(`should set available granularity of the all the widget`, () => { linodeWidgets.forEach((testData) => { setGranularity(testData.title, testData.expectedGranularity); }); @@ -92,11 +103,12 @@ describe('Dashboard Widget Verification Tests', () => { verifyAggregation(testData.title, testData.expectedAggregationArray); }); }); - it(`should zoom in and out of the all the widget`, () => { + it.only(`should zoom in and out of the all the widget`, () => { linodeWidgets.forEach((testData) => { - checkZoomActions(testData.title); - }); + checkZoomActions(testData.title); }); + }); + }); it('should apply global refresh button and verify network calls', () => { ui.cloudpulse.findRefreshIcon().click(); @@ -125,6 +137,6 @@ describe('Dashboard Widget Verification Tests', () => { }); }); -}); + diff --git a/packages/manager/cypress/support/constants/widget-mockdata.ts b/packages/manager/cypress/support/constants/widget-mockdata.ts index b48e4df3b61..7c48e632df0 100644 --- a/packages/manager/cypress/support/constants/widget-mockdata.ts +++ b/packages/manager/cypress/support/constants/widget-mockdata.ts @@ -114,22 +114,6 @@ export const dashboardMetricsData = { ], }; -export const dashboardDefinitions = { - data: [ - { - created: '2024-09-06T08:09:43.641Z', - id: 1, - label: 'Linode Dashboard', - service_type: 'linode', - time_duration: { - unit: 'min', - value: 30, - }, - updated: '2024-09-06T08:09:43.641Z', - widgets: [], - }, - ], -}; export const cloudPulseServices = { data: [{ service_type: 'linode' }], @@ -138,7 +122,7 @@ export const cloudPulseServices = { export const linodeMetricsDashboard = { created: '2024-04-29T17:09:29', id: '1', - label: 'Linode Service I/O Statistics', + label: 'Linode Dashboard', service_type: 'linode', type: 'standard', updated: null, @@ -185,3 +169,6 @@ export const linodeMetricsDashboard = { }, ], }; +export const dashboardDefinitions = { + data: [linodeMetricsDashboard], +}; diff --git a/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts b/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts index 0e45c9d4b16..0c97ce6f1fc 100644 --- a/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts +++ b/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts @@ -102,7 +102,7 @@ const JWSToken = { token: 'eyJhbGciOiAiZGlyIiwgImVuYyI6ICJBMTI4Q0JDLUhTMjU2IiwgImtpZCI6ID', }; export const mockJWSToken = (): Cypress.Chainable => { - return cy.intercept('POST', apiMatcher('**/monitor/services/linode/token'), { + return cy.intercept('POST', apiMatcher('**/monitor/services/linode/token'), JWSToken, - }); + ); }; diff --git a/packages/manager/cypress/support/util/cloudpulse.ts b/packages/manager/cypress/support/util/cloudpulse.ts index c97adcf3ab0..9e43e646f9c 100644 --- a/packages/manager/cypress/support/util/cloudpulse.ts +++ b/packages/manager/cypress/support/util/cloudpulse.ts @@ -94,6 +94,7 @@ export const resetDashboardAndVerifyPage = (serviceName: string) => { .click(); ui.autocomplete .findByPlaceholderCustom('Select Dashboard') + .clear() .type(`${serviceName}{enter}`); ui.autocomplete .findByTitleCustom('Select Dashboard') @@ -114,14 +115,12 @@ export const resetDashboardAndVerifyPage = (serviceName: string) => { * text content of the `h1` element within the widget. */ export const validateWidgetTitle = (widgetName: string) => { - const widgetSelector = `[data-qa-widget="${widgetName}"]`; + const widgetSelector = `h1[data-qa-widget-header="${widgetName}"]`; return cy .get(widgetSelector) - .find('h1') .invoke('text') .then((text) => { expect(text.trim()).to.equal(widgetName); - cy.findByDisplayValue(widgetName).should('have.value', widgetName); }); }; @@ -145,8 +144,7 @@ export const setGranularity = (widgetName: string, granularity: string) => { .findByTitle(granularity) .should('be.visible') .click(); - assertSelections(granularity); - cy.findByDisplayValue(granularity).should('have.value', granularity); + // assertSelections(granularity); }); }; /** @@ -169,7 +167,6 @@ export const setAggregation = (widgetName: string, aggregation: string) => { .should('be.visible') .click(); assertSelections(aggregation); - cy.findByDisplayValue(aggregation).should('have.value', aggregation); }); }; /** @@ -245,7 +242,37 @@ export const verifyAggregation = ( * Verifies that zoom in and zoom out actions are available and performs them on a widget. * @param {string} widgetName - The name of the widget to zoom in or out. */ + export const checkZoomActions = (widgetName: string) => { + const widgetSelector = `[data-qa-widget="${widgetName}"]`; + //const zoomInSelector = 'svg[data-testid="zoom-in"]'; + // const zoomOutSelector = 'svg[data-testid="zoom-out"]'; + const zoomInSelector = ui.cloudpulse.findZoomButtonByTitle('zoom-in'); + const zoomOutSelector = ui.cloudpulse.findZoomButtonByTitle('zoom-out'); +cy.get(widgetSelector).each(($widget) => { + cy.wrap($widget).then(($el) => { + const zoomInElement = $el.find(zoomInSelector); + const zoomOutElement = $el.find(zoomOutSelector); + if (zoomOutElement.length > 0) { + cy.wrap(zoomOutElement) + .should('be.visible') + .click({ timeout: 5000 }) + .then(() => { + cy.log('Zoomed Out on widget:', $el); + }); + } else if (zoomInElement.length > 0) { + cy.wrap(zoomInElement) + .should('be.visible') + .click({ timeout: 5000 }) + .then(() => { + cy.log('Zoomed In on widget:', $el); + }); + } + }); + }); +}; + +/* export const checkZoomActions1 = (widgetName: string) => { const widgetSelector = `[data-qa-widget="${widgetName}"]`; const zoomInSelector = ui.cloudpulse.findZoomButtonByTitle('zoom-in'); const zoomOutSelector = ui.cloudpulse.findZoomButtonByTitle('zoom-out'); @@ -279,4 +306,4 @@ export const checkZoomActions = (widgetName: string) => { } }); }); -}; +};*/ From 56ce544be42b2107252e9a71d1c3b49c813865c8 Mon Sep 17 00:00:00 2001 From: agorthi Date: Mon, 9 Sep 2024 21:58:56 +0530 Subject: [PATCH 027/474] upcoming:[DI-20585]- Added code review comments and fixing few mocking issues --- .../core/cloudpulse/dashboard-filters.spec.ts | 3 +- .../cloudpulse/widget-verification.spec.ts | 137 +++++++++++-- .../cypress/support/util/cloudpulse.ts | 185 +----------------- 3 files changed, 119 insertions(+), 206 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts index f17f9fcf69a..4a4fcf06516 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts @@ -37,6 +37,7 @@ import { import { timeRange, } from 'support/constants/widget-service'; +import { ui } from 'support/ui'; /** * This test suite focuses on the standard operations and verifications for the Cloudpulse dashboard. * @@ -93,7 +94,7 @@ describe('Standard Dashboard Filter Application and Configuration Tests', () => }); it('should set and verify region', () => { - selectRegion(region); + ui.regionSelect.find().click().type(`${region}{enter}`); assertSelections(region); }); diff --git a/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts index 504707623e3..11d2d75847d 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts @@ -1,18 +1,12 @@ import { selectTimeRange, - validateWidgetTitle, - setGranularity, - setAggregation, - verifyGranularity, - verifyAggregation, - checkZoomActions, selectAndVerifyResource, resource, - resetDashboardAndVerifyPage, selectServiceName, dashboardName, region, - selectRegion + assertSelections, + resetDashboardAndVerifyPage } from 'support/util/cloudpulse'; import { mockAppendFeatureFlags, @@ -71,41 +65,141 @@ describe('Dashboard Widget Verification Tests', () => { const responsePayload = createMetricResponse(actualRelativeTimeDuration, granularity.Min5); interceptCreateMetrics(responsePayload).as('metricAPI'); resetDashboardAndVerifyPage(dashboardName); - selectServiceName(dashboardName); + selectServiceName(dashboardName); selectTimeRange(actualRelativeTimeDuration, Object.values(timeRange)); - selectRegion(region); - selectAndVerifyResource(resource); + ui.regionSelect.find().click().type(`${region}{enter}`); + selectAndVerifyResource(resource); }); + it(`should set available granularity of the all the widget`, () => { linodeWidgets.forEach((testData) => { - setGranularity(testData.title, testData.expectedGranularity); + const widgetSelector = `[data-qa-widget="${testData.title}"]`; + cy.get(widgetSelector) + .first() + .should('be.visible') + .within(() => { + ui.autocomplete + .findByTitleCustom('Select an Interval') + .findByTitle('Open') + .click(); + ui.autocompletePopper + .findByTitle(testData.expectedGranularity) + .should('be.visible') + .click(); + assertSelections(testData.expectedGranularity); + }); }); + }); it(`should verify the title of the widget`, () => { linodeWidgets.forEach((testData) => { - validateWidgetTitle(testData.title); + const widgetSelector = `[data-qa-widget-header="${testData.title}"]`; + cy.get(widgetSelector).invoke('text').then((text) => { + expect(text.trim()).to.equal(testData.title); }); }); + it(`should set available aggregation of the all the widget`, () => { linodeWidgets.forEach((testData) => { - setAggregation(testData.title, testData.expectedAggregation); - }); + const widgetSelector = `[data-qa-widget="${testData.title}"]`; + cy.get(widgetSelector) + .first() + .should('be.visible') + .within(() => { + ui.autocomplete + .findByTitleCustom('Select an Aggregate Function') + .findByTitle('Open') + .click(); + ui.autocompletePopper + .findByTitle(testData.expectedAggregation) + .should('be.visible') + .click(); + assertSelections(testData.expectedAggregation); + }); + }); }); it(`should verify available granularity of the widget`, () => { linodeWidgets.forEach((testData) => { - verifyGranularity(testData.title, testData.expectedGranularityArray); + const widgetSelector = `[data-qa-widget="${testData.title}"]`; + cy.get(widgetSelector) + .first() + .scrollIntoView() + .should('be.visible') + .within(() => { + ui.autocomplete + .findByTitleCustom('Select an Interval') + .findByTitle('Open') + .click(); + testData.expectedGranularityArray.forEach((option) => { + ui.autocompletePopper + .findByTitle(option) + .should('be.visible') + .then(() => { + cy.log(`${option} is visible`); + }); + }); + ui.autocomplete + .findByTitleCustom('Select an Interval') + .findByTitle('Close') + .click(); }); }); +}); it(`should verify available aggregation of the widget`, () => { linodeWidgets.forEach((testData) => { - verifyAggregation(testData.title, testData.expectedAggregationArray); + const widgetSelector = `[data-qa-widget="${testData.title}"]`; + cy.get(widgetSelector) + .first() + .scrollIntoView() + .should('be.visible') + .within(() => { + ui.autocomplete + .findByTitleCustom('Select an Aggregate Function') + .findByTitle('Open') + .click(); + testData.expectedAggregationArray.forEach((option) => { + ui.autocompletePopper + .findByTitle(option) + .should('be.visible') + .then(() => { + cy.log(`${option} is visible`); + }); + }); + ui.autocomplete + .findByTitleCustom('Select an Aggregate Function') + .findByTitle('Close') + .click(); + }); }); }); - it.only(`should zoom in and out of the all the widget`, () => { + it(`should zoom in and out of the all the widget`, () => { linodeWidgets.forEach((testData) => { - checkZoomActions(testData.title); + const widgetSelector = `[data-qa-widget="${testData.title}"]`; + //const zoomInSelector = 'svg[data-testid="zoom-in"]'; + // const zoomOutSelector = 'svg[data-testid="zoom-out"]'; + const zoomInSelector = ui.cloudpulse.findZoomButtonByTitle('zoom-in'); + const zoomOutSelector = ui.cloudpulse.findZoomButtonByTitle('zoom-out'); + cy.get(widgetSelector).each(($widget) => { + cy.wrap($widget).then(($el) => { + const zoomInElement = $el.find(zoomInSelector); + const zoomOutElement = $el.find(zoomOutSelector); + if (zoomOutElement.length > 0) { + cy.wrap(zoomOutElement) + .should('be.visible') + .click({ timeout: 5000 }) + .then(() => { + cy.log('Zoomed Out on widget:', $el); + }); + } else if (zoomInElement.length > 0) { + cy.wrap(zoomInElement) + .should('be.visible') + .click({ timeout: 5000 }) + .then(() => { + cy.log('Zoomed In on widget:', $el); + }); + } }); }); }); @@ -136,7 +230,8 @@ describe('Dashboard Widget Verification Tests', () => { }); }); }); - - +}); +}); +}); diff --git a/packages/manager/cypress/support/util/cloudpulse.ts b/packages/manager/cypress/support/util/cloudpulse.ts index 9e43e646f9c..bf9cbeee219 100644 --- a/packages/manager/cypress/support/util/cloudpulse.ts +++ b/packages/manager/cypress/support/util/cloudpulse.ts @@ -32,14 +32,6 @@ export const selectServiceName = (serviceName: string) => { .type(`${serviceName}{enter}`); cy.findByDisplayValue(serviceName).should('have.value', serviceName); }; - -/** - * Selects a region from the region dropdown. - * @param {string} region - The name of the region to select. - */ -export const selectRegion = (region: string) => { - ui.regionSelect.find().click().type(`${region}{enter}`); -}; /** * Selects a time range from the time range dropdown. * @param {string} timeRange - The time range to select. @@ -77,12 +69,7 @@ export const assertSelections = (expectedOptions: string) => { cy.get(`[value*='${expectedOptions}']`).should('be.visible'); cy.get(`[value*='${expectedOptions}']`).should('have.value', expectedOptions); }; -/** - * Applies a global refresh action on the dashboard. - */ -export const performGlobalRefresh = () => { - ui.cloudpulse.findRefreshIcon().click(); -}; + /** * Clears the dashboard's preferences and verifies the zeroth page. * @param {string} serviceName - The name of the service to verify. @@ -101,176 +88,6 @@ export const resetDashboardAndVerifyPage = (serviceName: string) => { .findByTitle('Clear') .click(); }; -/** - * Validates that the widget title matches the expected title. - * - * This function locates a widget on the page using its `data-qa-widget` attribute, - * finds the `h1` element within the widget, and checks that its text content matches - * the expected widget name. It also returns the actual text content of the `h1` element. - * - * @param {string} widgetName - The expected name of the widget to verify. This is used to - * construct the selector and to check the title of the widget. - * - * @returns {Cypress.Chainable} A Cypress chainable object that resolves to the - * text content of the `h1` element within the widget. - */ -export const validateWidgetTitle = (widgetName: string) => { - const widgetSelector = `h1[data-qa-widget-header="${widgetName}"]`; - return cy - .get(widgetSelector) - .invoke('text') - .then((text) => { - expect(text.trim()).to.equal(widgetName); - }); -}; - -/** - * Sets the granularity of a widget. - * @param {string} widgetName - The name of the widget to set granularity for. - * @param {string} granularity - The granularity to select. - */ -export const setGranularity = (widgetName: string, granularity: string) => { - cy.log('widgetName***', widgetName); - const widgetSelector = `[data-qa-widget="${widgetName}"]`; - cy.get(widgetSelector) - .first() - .should('be.visible') - .within(() => { - ui.autocomplete - .findByTitleCustom('Select an Interval') - .findByTitle('Open') - .click(); - ui.autocompletePopper - .findByTitle(granularity) - .should('be.visible') - .click(); - // assertSelections(granularity); - }); -}; -/** - * Sets the aggregation function of a widget. - * @param {string} widgetName - The name of the widget to set aggregation for. - * @param {string} aggregation - The aggregation function to select. - */ -export const setAggregation = (widgetName: string, aggregation: string) => { - const widgetSelector = `[data-qa-widget="${widgetName}"]`; - cy.get(widgetSelector) - .first() - .should('be.visible') - .within(() => { - ui.autocomplete - .findByTitleCustom('Select an Aggregate Function') - .findByTitle('Open') - .click(); - ui.autocompletePopper - .findByTitle(aggregation) - .should('be.visible') - .click(); - assertSelections(aggregation); - }); -}; -/** - * Verifies that the granularity options available for a widget match the expected options. - * @param {string} widgetName - The name of the widget to verify. - * @param {string[]} expectedGranularityOptions - The expected granularity options. - */ -export const verifyGranularity = ( - widgetName: string, - expectedGranularityOptions: string[] -) => { - const widgetSelector = `[data-qa-widget="${widgetName}"]`; - cy.get(widgetSelector) - .first() - .scrollIntoView() - .should('be.visible') - .within(() => { - ui.autocomplete - .findByTitleCustom('Select an Interval') - .findByTitle('Open') - .click(); - expectedGranularityOptions.forEach((option) => { - ui.autocompletePopper - .findByTitle(option) - .should('be.visible') - .then(() => { - cy.log(`${option} is visible`); - }); - }); - ui.autocomplete - .findByTitleCustom('Select an Interval') - .findByTitle('Close') - .click(); - }); -}; - -/** - * Verifies that the aggregation options available for a widget match the expected options. - * @param {string} widgetName - The name of the widget to verify. - * @param {string[]} expectedAggregationOptions - The expected aggregation options. - */ - -export const verifyAggregation = ( - widgetName: string, - expectedAggregationOptions: string[] -) => { - const widgetSelector = `[data-qa-widget="${widgetName}"]`; - cy.get(widgetSelector) - .first() - .scrollIntoView() - .should('be.visible') - .within(() => { - ui.autocomplete - .findByTitleCustom('Select an Aggregate Function') - .findByTitle('Open') - .click(); - expectedAggregationOptions.forEach((option) => { - ui.autocompletePopper - .findByTitle(option) - .should('be.visible') - .then(() => { - cy.log(`${option} is visible`); - }); - }); - ui.autocomplete - .findByTitleCustom('Select an Aggregate Function') - .findByTitle('Close') - .click(); - }); -}; - -/** - * Verifies that zoom in and zoom out actions are available and performs them on a widget. - * @param {string} widgetName - The name of the widget to zoom in or out. - */ - -export const checkZoomActions = (widgetName: string) => { - const widgetSelector = `[data-qa-widget="${widgetName}"]`; - //const zoomInSelector = 'svg[data-testid="zoom-in"]'; - // const zoomOutSelector = 'svg[data-testid="zoom-out"]'; - const zoomInSelector = ui.cloudpulse.findZoomButtonByTitle('zoom-in'); - const zoomOutSelector = ui.cloudpulse.findZoomButtonByTitle('zoom-out'); -cy.get(widgetSelector).each(($widget) => { - cy.wrap($widget).then(($el) => { - const zoomInElement = $el.find(zoomInSelector); - const zoomOutElement = $el.find(zoomOutSelector); - if (zoomOutElement.length > 0) { - cy.wrap(zoomOutElement) - .should('be.visible') - .click({ timeout: 5000 }) - .then(() => { - cy.log('Zoomed Out on widget:', $el); - }); - } else if (zoomInElement.length > 0) { - cy.wrap(zoomInElement) - .should('be.visible') - .click({ timeout: 5000 }) - .then(() => { - cy.log('Zoomed In on widget:', $el); - }); - } - }); - }); -}; /* export const checkZoomActions1 = (widgetName: string) => { const widgetSelector = `[data-qa-widget="${widgetName}"]`; From 4997149e0137f79f9a64af1129712c2453aab2c1 Mon Sep 17 00:00:00 2001 From: agorthi Date: Tue, 10 Sep 2024 11:53:53 +0530 Subject: [PATCH 028/474] upcoming:[DI-20585]- Added code factories to mock the data --- .../core/cloudpulse/dashboard-filters.spec.ts | 40 ++-- .../cloudpulse/widget-verification.spec.ts | 40 +++- .../support/constants/widget-mockdata.ts | 174 ------------------ .../intercepts/cloudpulseAPIHandler.ts | 49 ++--- .../cypress/support/util/cloudpulse.ts | 5 +- packages/manager/src/factories/dashboards.ts | 102 +++++++++- .../factories/{widgetFactory.ts => widget.ts} | 18 +- 7 files changed, 184 insertions(+), 244 deletions(-) delete mode 100644 packages/manager/cypress/support/constants/widget-mockdata.ts rename packages/manager/src/factories/{widgetFactory.ts => widget.ts} (86%) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts index 4a4fcf06516..a91b030f124 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts @@ -1,6 +1,5 @@ import { selectServiceName, - selectRegion, selectTimeRange, selectAndVerifyResource, assertSelections, @@ -23,14 +22,8 @@ import { } from 'support/intercepts/cloudpulseAPIHandler'; import { makeFeatureFlagData } from 'support/util/feature-flags'; import type { Flags } from 'src/featureFlags'; -import { createMetricResponse } from '@src/factories/widgetFactory' +import { createMetricResponse } from '@src/factories/widget'; import { mockGetLinodes } from 'support/intercepts/linodes'; -import { - accountFactory, - kubeLinodeFactory, - linodeFactory, -} from 'src/factories'; - import { mockGetAccount, } from 'support/intercepts/account'; @@ -38,6 +31,7 @@ import { timeRange, } from 'support/constants/widget-service'; import { ui } from 'support/ui'; +import { accountFactory ,dashboardFactory,kubeLinodeFactory,linodeFactory,metricDefinitionsFactory} from 'src/factories'; /** * This test suite focuses on the standard operations and verifications for the Cloudpulse dashboard. * @@ -49,21 +43,40 @@ import { ui } from 'support/ui'; * dashboard behaves as expected under various conditions. */ const mockKubeLinode = kubeLinodeFactory.build(); - const mockLinode = linodeFactory.build({ label: "test1", id: mockKubeLinode.instance_id ?? undefined, }); +const widgetLabels = [ + 'CPU utilization', + 'Memory Usage', + 'Network Traffic', + 'Disk I/O', +]; +const metricsLabels = [ + 'system_cpu_utilization_percent', + 'system_memory_usage_by_resource', + 'system_network_io_by_resource', + 'system_disk_operations_total', +]; +const y_labels = [ + 'system_cpu_utilization_ratio', + 'system_memory_usage_bytes', + 'system_network_io_bytes_total', + 'system_disk_operations_total', +]; +const dashboard = dashboardFactory(dashboardName,widgetLabels,metricsLabels,y_labels).build(); +const metricDefinitions = metricDefinitionsFactory(widgetLabels,metricsLabels).build(); describe('Standard Dashboard Filter Application and Configuration Tests', () => { beforeEach(() => { mockAppendFeatureFlags({ aclp: makeFeatureFlagData({ beta: true, enabled: true }), - }); + }).as('getFeatureFlags'); mockGetFeatureFlagClientstream(); cy.visitWithLogin('monitor/cloudpulse'); - interceptGetMetricDefinitions().as('dashboardMetricsData'); - interceptGetDashboards().as('dashboard'); - interceptCloudPulseServices().as('services'); + interceptGetMetricDefinitions(metricDefinitions); + interceptGetDashboards(dashboard).as('dashboard'); + interceptCloudPulseServices('linode').as('services'); mockGetLinodes([mockLinode]).as('getLinodes'); const responsePayload = createMetricResponse(actualRelativeTimeDuration, granularity.Min5); interceptCreateMetrics(responsePayload).as('metricAPI'); @@ -82,6 +95,7 @@ describe('Standard Dashboard Filter Application and Configuration Tests', () => }); it('should clear the preferences of the dashboard', () => { + cy.log("dashboardName****",dashboardName) resetDashboardAndVerifyPage(dashboardName); }); it('should set and verify dashboard name', () => { diff --git a/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts index 11d2d75847d..ae634df17b4 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts @@ -22,9 +22,9 @@ import { interceptGetMetricDefinitions, } from 'support/intercepts/cloudpulseAPIHandler'; import { makeFeatureFlagData } from 'support/util/feature-flags'; -import { createMetricResponse } from '@src/factories/widgetFactory' +import { createMetricResponse } from '@src/factories/widget' import type { Flags } from 'src/featureFlags'; -import { accountFactory ,kubeLinodeFactory,linodeFactory} from 'src/factories'; +import { accountFactory ,dashboardFactory,kubeLinodeFactory,linodeFactory,metricDefinitionsFactory} from 'src/factories'; import { mockGetAccount } from 'support/intercepts/account'; import { mockGetLinodes } from 'support/intercepts/linodes'; @@ -45,19 +45,39 @@ const mockLinode = linodeFactory.build({ label:"test1", id: mockKubeLinode.instance_id ?? undefined, }); +const widgetLabels = [ + 'CPU utilization', + 'Memory Usage', + 'Network Traffic', + 'Disk I/O', +]; +const metricsLabels = [ + 'system_cpu_utilization_percent', + 'system_memory_usage_by_resource', + 'system_network_io_by_resource', + 'system_disk_operations_total', +]; +const y_labels = [ + 'system_cpu_utilization_ratio', + 'system_memory_usage_bytes', + 'system_network_io_bytes_total', + 'system_disk_operations_total', +]; +const dashboard = dashboardFactory(dashboardName,widgetLabels,metricsLabels,y_labels).build(); +const metricDefinitions = metricDefinitionsFactory(widgetLabels,metricsLabels).build(); describe('Dashboard Widget Verification Tests', () => { beforeEach(() => { mockAppendFeatureFlags({ aclp: makeFeatureFlagData({ beta: true, enabled: true }), - }); - - mockGetFeatureFlagClientstream(); + }).as('getFeatureFlags'); + mockGetFeatureFlagClientstream().as('getClientStream'); + mockGetFeatureFlagClientstream(); mockGetLinodes([mockLinode]).as('getLinodes'); - interceptGetMetricDefinitions().as('dashboardMetricsData'); - interceptGetDashboards().as('dashboard'); - interceptCloudPulseServices().as('services'); - mockLinodeDashboardServicesResponse(); + interceptGetMetricDefinitions(metricDefinitions); + interceptGetDashboards(dashboard).as('dashboard'); + interceptCloudPulseServices('linode').as('services'); + mockLinodeDashboardServicesResponse(dashboard); mockJWSToken(); const mockAccount = accountFactory.build(); mockGetAccount(mockAccount).as('getAccount'); // this enables the account to have capability for Akamai Cloud Pulse @@ -96,7 +116,7 @@ describe('Dashboard Widget Verification Tests', () => { linodeWidgets.forEach((testData) => { const widgetSelector = `[data-qa-widget-header="${testData.title}"]`; cy.get(widgetSelector).invoke('text').then((text) => { - expect(text.trim()).to.equal(testData.title); + expect(text.trim()).to.containIgnoreCase(testData.title); }); }); diff --git a/packages/manager/cypress/support/constants/widget-mockdata.ts b/packages/manager/cypress/support/constants/widget-mockdata.ts deleted file mode 100644 index 7c48e632df0..00000000000 --- a/packages/manager/cypress/support/constants/widget-mockdata.ts +++ /dev/null @@ -1,174 +0,0 @@ -export const dashboardMetricsData = { - data: [ - { - available_aggregate_functions: ['min', 'max', 'avg'], - dimensions: [ - { - dim_label: 'cpu', - label: 'CPU name', - values: null, - }, - { - dim_label: 'state', - label: 'State of CPU', - values: [ - 'user', - 'system', - 'idle', - 'interrupt', - 'nice', - 'softirq', - 'steal', - 'wait', - ], - }, - { - dim_label: 'LINODE_ID', - label: 'Linode ID', - values: null, - }, - ], - label: 'CPU utilization', - metric: 'system_cpu_utilization_percent', - metric_type: 'gauge', - scrape_interval: '2m', - unit: 'percent', - }, - { - available_aggregate_functions: ['min', 'max', 'avg', 'sum'], - dimensions: [ - { - dim_label: 'state', - label: 'State of memory', - values: [ - 'used', - 'free', - 'buffered', - 'cached', - 'slab_reclaimable', - 'slab_unreclaimable', - ], - }, - { - dim_label: 'LINODE_ID', - label: 'Linode ID', - values: null, - }, - ], - label: 'Memory Usage', - metric: 'system_memory_usage_by_resource', - metric_type: 'gauge', - scrape_interval: '30s', - unit: 'byte', - }, - { - available_aggregate_functions: ['min', 'max', 'avg', 'sum'], - dimensions: [ - { - dim_label: 'device', - label: 'Device name', - values: ['lo', 'eth0'], - }, - { - dim_label: 'direction', - label: 'Direction of network transfer', - values: ['transmit', 'receive'], - }, - { - dim_label: 'LINODE_ID', - label: 'Linode ID', - values: null, - }, - ], - label: 'Network Traffic', - metric: 'system_network_io_by_resource', - metric_type: 'counter', - scrape_interval: '30s', - unit: 'byte', - }, - { - available_aggregate_functions: ['min', 'max', 'avg', 'sum'], - dimensions: [ - { - dim_label: 'device', - label: 'Device name', - values: ['loop0', 'sda', 'sdb'], - }, - { - dim_label: 'direction', - label: 'Operation direction', - values: ['read', 'write'], - }, - { - dim_label: 'LINODE_ID', - label: 'Linode ID', - values: null, - }, - ], - label: 'Disk I/O', - metric: 'system_disk_OPS_total', - metric_type: 'counter', - scrape_interval: '30s', - unit: 'ops_per_second', - }, - ], -}; - - -export const cloudPulseServices = { - data: [{ service_type: 'linode' }], -}; - -export const linodeMetricsDashboard = { - created: '2024-04-29T17:09:29', - id: '1', - label: 'Linode Dashboard', - service_type: 'linode', - type: 'standard', - updated: null, - widgets: [ - { - aggregate_function: 'avg', - chart_type: 'area', - color: 'blue', - label: 'CPU utilization', - metric: 'system_cpu_utilization_percent', - size: 12, - unit: '%', - y_label: 'system_cpu_utilization_ratio', - }, - { - aggregate_function: 'avg', - chart_type: 'area', - color: 'red', - label: 'Memory Usage', - metric: 'system_memory_usage_by_resource', - size: 12, - unit: 'Bytes', - y_label: 'system_memory_usage_bytes', - }, - { - aggregate_function: 'avg', - chart_type: 'area', - color: 'green', - label: 'Network Traffic', - metric: 'system_network_io_by_resource', - size: 6, - unit: 'Bytes', - y_label: 'system_network_io_bytes_total', - }, - { - aggregate_function: 'avg', - chart_type: 'area', - color: 'yellow', - label: 'Disk I/O', - metric: 'system_disk_OPS_total', - size: 6, - unit: 'OPS', - y_label: 'system_disk_operations_total', - }, - ], -}; -export const dashboardDefinitions = { - data: [linodeMetricsDashboard], -}; diff --git a/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts b/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts index 0c97ce6f1fc..2034333873f 100644 --- a/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts +++ b/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts @@ -3,14 +3,11 @@ * * @returns Cypress chainable. */ -import { - cloudPulseServices, - dashboardDefinitions, - dashboardMetricsData, - linodeMetricsDashboard, -} from 'support/constants/widget-mockdata'; + import { apiMatcher } from 'support/util/intercepts'; +import type { Dashboard, MetricDefinitions } from '@linode/api-v4'; + /** * Intercepts HTTP GET requests for metric definitions. * @@ -20,11 +17,13 @@ import { apiMatcher } from 'support/util/intercepts'; * @returns {Cypress.Chainable} The chainable Cypress object. */ -export const interceptGetMetricDefinitions = (): Cypress.Chainable => { +export const interceptGetMetricDefinitions = ( + metricDefinitions: MetricDefinitions +): Cypress.Chainable => { return cy.intercept( 'GET', apiMatcher('**/monitor/services/linode/metric-definitions'), - dashboardMetricsData + metricDefinitions ); }; @@ -37,12 +36,12 @@ export const interceptGetMetricDefinitions = (): Cypress.Chainable => { * @returns {Cypress.Chainable} The chainable Cypress object. */ -export const interceptCloudPulseServices = (): Cypress.Chainable => { - return cy.intercept( - 'GET', - apiMatcher('**/monitor/services'), - cloudPulseServices - ); +export const interceptCloudPulseServices = ( + service_type: string +): Cypress.Chainable => { + return cy.intercept('GET', apiMatcher('**/monitor/services'), { + data: [{ service_type }], + }); }; /** * Intercepts HTTP GET requests for dashboard definitions. @@ -53,11 +52,13 @@ export const interceptCloudPulseServices = (): Cypress.Chainable => { * @returns {Cypress.Chainable} The chainable Cypress object. */ -export const interceptGetDashboards = (): Cypress.Chainable => { +export const interceptGetDashboards = ( + dashboard: Dashboard +): Cypress.Chainable => { return cy.intercept( 'GET', apiMatcher('**/monitor/services/linode/dashboards'), - dashboardDefinitions + { data: [dashboard] } ); }; /** @@ -91,18 +92,18 @@ export const interceptCreateMetrics = ( ); }; -export const mockLinodeDashboardServicesResponse = (): Cypress.Chainable => { - return cy.intercept( - 'GET', - apiMatcher('**/monitor/dashboards/1'), - linodeMetricsDashboard - ); +export const mockLinodeDashboardServicesResponse = ( + dashboard: Dashboard +): Cypress.Chainable => { + return cy.intercept('GET', apiMatcher('**/monitor/dashboards/1'), dashboard); }; const JWSToken = { token: 'eyJhbGciOiAiZGlyIiwgImVuYyI6ICJBMTI4Q0JDLUhTMjU2IiwgImtpZCI6ID', }; export const mockJWSToken = (): Cypress.Chainable => { - return cy.intercept('POST', apiMatcher('**/monitor/services/linode/token'), - JWSToken, + return cy.intercept( + 'POST', + apiMatcher('**/monitor/services/linode/token'), + JWSToken ); }; diff --git a/packages/manager/cypress/support/util/cloudpulse.ts b/packages/manager/cypress/support/util/cloudpulse.ts index bf9cbeee219..71e445db2b1 100644 --- a/packages/manager/cypress/support/util/cloudpulse.ts +++ b/packages/manager/cypress/support/util/cloudpulse.ts @@ -1,4 +1,3 @@ -/* eslint-disable cypress/unsafe-to-chain-command */ import { timeRange } from 'support/constants/widget-service'; import { ui } from 'support/ui'; @@ -32,6 +31,7 @@ export const selectServiceName = (serviceName: string) => { .type(`${serviceName}{enter}`); cy.findByDisplayValue(serviceName).should('have.value', serviceName); }; + /** * Selects a time range from the time range dropdown. * @param {string} timeRange - The time range to select. @@ -87,6 +87,9 @@ export const resetDashboardAndVerifyPage = (serviceName: string) => { .findByTitleCustom('Select Dashboard') .findByTitle('Clear') .click(); + ui.autocomplete + .findByPlaceholderCustom('Select Dashboard') + .should('have.value', ''); // Ensure the input field is cleared }; /* export const checkZoomActions1 = (widgetName: string) => { diff --git a/packages/manager/src/factories/dashboards.ts b/packages/manager/src/factories/dashboards.ts index e4a1117bad1..091efbf5018 100644 --- a/packages/manager/src/factories/dashboards.ts +++ b/packages/manager/src/factories/dashboards.ts @@ -1,16 +1,108 @@ import Factory from 'src/factories/factoryProxy'; -import type { Dashboard } from '@linode/api-v4'; +import type { + AvailableMetrics, + Dashboard, + MetricDefinitions, + Widgets, +} from '@linode/api-v4'; -export const dashboardFactory = Factory.Sync.makeFactory({ +const units = ['%', '%', 'Bytes', 'OPS']; +const color = ['blue', 'red', 'green', 'yellow']; +const chart_type = ['area', 'area', 'area', 'line']; +const scrape_interval = ['2m', '30s', '30s', '30s']; +const units_interval = ['percent', 'byte', 'byte', 'ops_per_second']; + +/* export const dashboardFactory1 = Factory.Sync.makeFactory({ created: new Date().toISOString(), id: Factory.each((i) => i), - label: Factory.each((i) => `Factory Dashboard-${i}`), + label: 'Linode Dashboard', service_type: 'linode', time_duration: { unit: 'min', value: 30, }, updated: new Date().toISOString(), - widgets: [], -}); + widgets: Factory.each(() => widgetFactory.buildList(4)), // Create a list of 1 widgets +});*/ +export const dashboardFactory = ( + dashboardLabel: string, + widgetLabels: string[], + metricsLabels: string[], + y_labels: string[] +) => { + return Factory.Sync.makeFactory({ + created: new Date().toISOString(), + id: Factory.each((i) => i), + label: dashboardLabel, // Use the passed argument here + service_type: 'linode', + time_duration: { + unit: 'min', + value: 30, + }, + updated: new Date().toISOString(), + widgets: Factory.each(() => + widgetFactory(widgetLabels, metricsLabels, y_labels).buildList( + widgetLabels.length + ) + ), + }); +}; + +export const widgetFactory = ( + widgetLabels: string[], + metricsLabels: string[], + y_labels: string[] +) => { + return Factory.Sync.makeFactory({ + aggregate_function: 'avg', + chart_type: Factory.each((i) => chart_type[i % chart_type.length]), + color: Factory.each((i) => color[i % color.length]), + filters: [], + group_by: 'region', + label: Factory.each((i) => widgetLabels[i % widgetLabels.length]), + metric: Factory.each((i) => metricsLabels[i % metricsLabels.length]), + namespace_id: Factory.each((i) => i % 10), + region_id: Factory.each((i) => i % 5), + resource_id: Factory.each((i) => [`resource-${i}`]), + service_type: 'default', + serviceType: 'default', + size: 12, + time_duration: { + unit: 'min', + value: 30, + }, + time_granularity: { + unit: 'hour', + value: 1, + }, + unit: Factory.each((i) => units[i % units.length]), + y_label: Factory.each((i) => y_labels[i % y_labels.length]), + }); +}; +export const metricDefinitionsFactory = ( + widgetLabels: string[], + metricsLabels: string[] +) => { + return Factory.Sync.makeFactory({ + data: Factory.each(() => [ + dashboardMetricFactory(widgetLabels, metricsLabels).build(), // Pass widgetLabels and metricsLabels + ]), + }); +}; +const dashboardMetricFactory = ( + widgetLabels: string[], + metricsLabels: string[] +) => { + return Factory.Sync.makeFactory({ + available_aggregate_functions: ['min', 'max', 'avg', 'sum'], + dimensions: [], + label: Factory.each((i) => widgetLabels[i % widgetLabels.length]), + metric: Factory.each((i) => metricsLabels[i % metricsLabels.length]), + metric_type: 'gauge', + scrape_interval: Factory.each( + (i) => scrape_interval[i % scrape_interval.length] + ), + unit: Factory.each((i) => units_interval[i % units_interval.length]), + }); +}; diff --git a/packages/manager/src/factories/widgetFactory.ts b/packages/manager/src/factories/widget.ts similarity index 86% rename from packages/manager/src/factories/widgetFactory.ts rename to packages/manager/src/factories/widget.ts index 9d041103c52..69517e57b67 100644 --- a/packages/manager/src/factories/widgetFactory.ts +++ b/packages/manager/src/factories/widget.ts @@ -4,23 +4,7 @@ import { } from '../../cypress/support/constants/widget-service'; import type { AvailableMetrics } from '@linode/api-v4'; -export function createWidget( - name: string, - title: string, - expectedAggregation: string, - expectedGranularity: string, - expectedGranularityArray: string[], - expectedAggregationyArray: string[] -) { - return { - expectedAggregation, - expectedAggregationyArray, - expectedGranularity, - expectedGranularityArray, - name, - title, - }; -} + /** * Generates a mock metric response based on the specified time range and granularity. * From 22f758d9649ad0161c1fdca889ea1f3dc1bd4158 Mon Sep 17 00:00:00 2001 From: agorthi Date: Tue, 10 Sep 2024 12:59:50 +0530 Subject: [PATCH 029/474] upcoming:[DI-20585]- Added code review comments --- .../core/cloudpulse/dashboard-filters.spec.ts | 25 ++++++++++++------- .../cypress/support/util/cloudpulse.ts | 18 +++---------- packages/manager/src/factories/dashboards.ts | 2 +- 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts index a91b030f124..bccac6f5522 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts @@ -3,10 +3,6 @@ import { selectTimeRange, selectAndVerifyResource, assertSelections, - dashboardName, - actualRelativeTimeDuration, - region, - resource, resetDashboardAndVerifyPage, } from 'support/util/cloudpulse'; import { @@ -19,6 +15,8 @@ import { interceptCreateMetrics, interceptGetDashboards, interceptGetMetricDefinitions, + mockJWSToken, + mockLinodeDashboardServicesResponse, } from 'support/intercepts/cloudpulseAPIHandler'; import { makeFeatureFlagData } from 'support/util/feature-flags'; import type { Flags } from 'src/featureFlags'; @@ -42,11 +40,20 @@ import { accountFactory ,dashboardFactory,kubeLinodeFactory,linodeFactory,metric * Each test case checks the correctness and persistence of these configurations to ensure that the * dashboard behaves as expected under various conditions. */ + + + + const dashboardName = 'ananth'; + const region = 'US, Chicago, IL (us-ord)'; + const actualRelativeTimeDuration = timeRange.Last24Hours; +const resource = 'test1'; const mockKubeLinode = kubeLinodeFactory.build(); const mockLinode = linodeFactory.build({ - label: "test1", + label: resource, id: mockKubeLinode.instance_id ?? undefined, }); +const mockAccount = accountFactory.build(); + const widgetLabels = [ 'CPU utilization', 'Memory Usage', @@ -69,19 +76,20 @@ const dashboard = dashboardFactory(dashboardName,widgetLabels,metricsLabels,y_la const metricDefinitions = metricDefinitionsFactory(widgetLabels,metricsLabels).build(); describe('Standard Dashboard Filter Application and Configuration Tests', () => { beforeEach(() => { + cy.visitWithLogin('monitor/cloudpulse'); mockAppendFeatureFlags({ aclp: makeFeatureFlagData({ beta: true, enabled: true }), }).as('getFeatureFlags'); + mockGetAccount(mockAccount).as('getAccount'); // this enables the account to have capability for Akamai Cloud Pulse mockGetFeatureFlagClientstream(); - cy.visitWithLogin('monitor/cloudpulse'); interceptGetMetricDefinitions(metricDefinitions); interceptGetDashboards(dashboard).as('dashboard'); interceptCloudPulseServices('linode').as('services'); mockGetLinodes([mockLinode]).as('getLinodes'); const responsePayload = createMetricResponse(actualRelativeTimeDuration, granularity.Min5); interceptCreateMetrics(responsePayload).as('metricAPI'); - const mockAccount = accountFactory.build(); - mockGetAccount(mockAccount).as('getAccount'); // this enables the account to have capability for Akamai Cloud Pulse + mockJWSToken(); + mockLinodeDashboardServicesResponse(dashboard); }); @@ -95,7 +103,6 @@ describe('Standard Dashboard Filter Application and Configuration Tests', () => }); it('should clear the preferences of the dashboard', () => { - cy.log("dashboardName****",dashboardName) resetDashboardAndVerifyPage(dashboardName); }); it('should set and verify dashboard name', () => { diff --git a/packages/manager/cypress/support/util/cloudpulse.ts b/packages/manager/cypress/support/util/cloudpulse.ts index 71e445db2b1..45f08a09f8e 100644 --- a/packages/manager/cypress/support/util/cloudpulse.ts +++ b/packages/manager/cypress/support/util/cloudpulse.ts @@ -1,10 +1,4 @@ -import { timeRange } from 'support/constants/widget-service'; -import { ui } from 'support/ui'; -export const dashboardName = 'Linode Dashboard'; -export const region = 'US, Chicago, IL (us-ord)'; -export const actualRelativeTimeDuration = timeRange.Last24Hours; -export const resource = 'test1'; /** * This class provides utility functions for interacting with the Cloudpulse dashboard * in a Cypress test suite. It includes methods for: @@ -20,6 +14,9 @@ export const resource = 'test1'; * Selects a service name from the dashboard dropdown. * @param {string} serviceName - The name of the service to select. */ +import { ui } from 'support/ui'; + + export const selectServiceName = (serviceName: string) => { ui.autocomplete .findByTitleCustom('Select Dashboard') @@ -75,14 +72,7 @@ export const assertSelections = (expectedOptions: string) => { * @param {string} serviceName - The name of the service to verify. */ export const resetDashboardAndVerifyPage = (serviceName: string) => { - ui.autocomplete - .findByTitleCustom('Select Dashboard') - .findByTitle('Open') - .click(); - ui.autocomplete - .findByPlaceholderCustom('Select Dashboard') - .clear() - .type(`${serviceName}{enter}`); + ui.autocomplete .findByTitleCustom('Select Dashboard') .findByTitle('Clear') diff --git a/packages/manager/src/factories/dashboards.ts b/packages/manager/src/factories/dashboards.ts index 091efbf5018..6d0a536e041 100644 --- a/packages/manager/src/factories/dashboards.ts +++ b/packages/manager/src/factories/dashboards.ts @@ -34,7 +34,7 @@ export const dashboardFactory = ( return Factory.Sync.makeFactory({ created: new Date().toISOString(), id: Factory.each((i) => i), - label: dashboardLabel, // Use the passed argument here + label: dashboardLabel, service_type: 'linode', time_duration: { unit: 'min', From 0822966673091e760664b6db468f2e4177f08b5c Mon Sep 17 00:00:00 2001 From: agorthi Date: Tue, 10 Sep 2024 17:18:16 +0530 Subject: [PATCH 030/474] upcoming:[DI-20585]- Added code review comments --- .../core/cloudpulse/dashboard-filters.spec.ts | 55 ++-- .../cloudpulse/widget-verification.spec.ts | 256 ++++++++---------- .../support/constants/widget-service.ts | 28 +- .../cypress/support/util/cloudpulse.ts | 20 +- packages/manager/src/factories/dashboards.ts | 18 +- 5 files changed, 175 insertions(+), 202 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts index bccac6f5522..f83670fb6a7 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts @@ -9,7 +9,6 @@ import { mockAppendFeatureFlags, mockGetFeatureFlagClientstream, } from 'support/intercepts/feature-flags'; -import { granularity } from 'support/constants/widget-service'; import { interceptCloudPulseServices, interceptCreateMetrics, @@ -25,11 +24,9 @@ import { mockGetLinodes } from 'support/intercepts/linodes'; import { mockGetAccount, } from 'support/intercepts/account'; -import { - timeRange, -} from 'support/constants/widget-service'; import { ui } from 'support/ui'; import { accountFactory ,dashboardFactory,kubeLinodeFactory,linodeFactory,metricDefinitionsFactory} from 'src/factories'; +import { timeRange, widgetDetails, granularity } from 'support/constants/widget-service'; /** * This test suite focuses on the standard operations and verifications for the Cloudpulse dashboard. * @@ -43,7 +40,7 @@ import { accountFactory ,dashboardFactory,kubeLinodeFactory,linodeFactory,metric - const dashboardName = 'ananth'; + const dashboardName = 'Linode Dashboard'; const region = 'US, Chicago, IL (us-ord)'; const actualRelativeTimeDuration = timeRange.Last24Hours; const resource = 'test1'; @@ -54,26 +51,17 @@ const mockLinode = linodeFactory.build({ }); const mockAccount = accountFactory.build(); -const widgetLabels = [ - 'CPU utilization', - 'Memory Usage', - 'Network Traffic', - 'Disk I/O', -]; -const metricsLabels = [ - 'system_cpu_utilization_percent', - 'system_memory_usage_by_resource', - 'system_network_io_by_resource', - 'system_disk_operations_total', -]; const y_labels = [ 'system_cpu_utilization_ratio', 'system_memory_usage_bytes', 'system_network_io_bytes_total', 'system_disk_operations_total', ]; -const dashboard = dashboardFactory(dashboardName,widgetLabels,metricsLabels,y_labels).build(); -const metricDefinitions = metricDefinitionsFactory(widgetLabels,metricsLabels).build(); +const linodeWidgets = widgetDetails.linode; +const widgetLabels: string[] = linodeWidgets.map(widget => widget.title); +const metricsLabels: string[] = linodeWidgets.map(widget => widget.name); +const dashboard = dashboardFactory(dashboardName, widgetLabels, metricsLabels, y_labels).build(); +const metricDefinitions = metricDefinitionsFactory(widgetLabels, metricsLabels).build(); describe('Standard Dashboard Filter Application and Configuration Tests', () => { beforeEach(() => { cy.visitWithLogin('monitor/cloudpulse'); @@ -102,24 +90,15 @@ describe('Standard Dashboard Filter Application and Configuration Tests', () => cy.findByText('Not Found').should('be.visible'); // not found }); - it('should clear the preferences of the dashboard', () => { - resetDashboardAndVerifyPage(dashboardName); - }); - it('should set and verify dashboard name', () => { - selectServiceName(dashboardName); - assertSelections(dashboardName); - }); - it('should set and verify time range', () => { - selectTimeRange(actualRelativeTimeDuration, Object.values(timeRange)); - assertSelections(actualRelativeTimeDuration); - }); - - it('should set and verify region', () => { - ui.regionSelect.find().click().type(`${region}{enter}`); - assertSelections(region); - }); - - it('should set and verify resource', () => { - selectAndVerifyResource(resource); + it('Check the Linode Dashboard for the required global filter.', () => { + resetDashboardAndVerifyPage(dashboardName); + selectServiceName(dashboardName); + assertSelections(dashboardName); + selectTimeRange(actualRelativeTimeDuration, Object.values(timeRange)); + assertSelections(actualRelativeTimeDuration); + ui.regionSelect.find().click().type(`${region}{enter}`); + assertSelections(region); + selectAndVerifyResource(resource); }); }); + diff --git a/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts index ae634df17b4..4de2c9fce41 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts @@ -1,34 +1,36 @@ import { selectTimeRange, - selectAndVerifyResource, - resource, selectServiceName, - dashboardName, - region, + selectAndVerifyResource, assertSelections, - resetDashboardAndVerifyPage + resetDashboardAndVerifyPage, } from 'support/util/cloudpulse'; import { mockAppendFeatureFlags, mockGetFeatureFlagClientstream, } from 'support/intercepts/feature-flags'; -import { interceptCloudPulseServices, interceptMetricsRequests ,mockJWSToken,mockLinodeDashboardServicesResponse} from 'support/intercepts/cloudpulseAPIHandler'; +import { + interceptCloudPulseServices, + interceptMetricsRequests, + mockJWSToken, + mockLinodeDashboardServicesResponse, +} from 'support/intercepts/cloudpulseAPIHandler'; import { ui } from 'support/ui'; -export const actualRelativeTimeDuration = timeRange.Last30Minutes; -import { timeRange, widgetDetails, timeUnit, granularity } from 'support/constants/widget-service'; +import { timeRange, widgetDetails, granularity } from 'support/constants/widget-service'; import { interceptCreateMetrics, interceptGetDashboards, interceptGetMetricDefinitions, } from 'support/intercepts/cloudpulseAPIHandler'; import { makeFeatureFlagData } from 'support/util/feature-flags'; -import { createMetricResponse } from '@src/factories/widget' +import { createMetricResponse } from '@src/factories/widget'; import type { Flags } from 'src/featureFlags'; -import { accountFactory ,dashboardFactory,kubeLinodeFactory,linodeFactory,metricDefinitionsFactory} from 'src/factories'; +import { accountFactory, dashboardFactory, kubeLinodeFactory, linodeFactory, metricDefinitionsFactory } from 'src/factories'; import { mockGetAccount } from 'support/intercepts/account'; import { mockGetLinodes } from 'support/intercepts/linodes'; - const linodeWidgets = widgetDetails.linode; + + /** * This test ensures that widget titles are displayed correctly on the dashboard. * This test suite is dedicated to verifying the functionality and display of widgets on the Cloudpulse dashboard. @@ -39,88 +41,85 @@ import { mockGetLinodes } from 'support/intercepts/linodes'; * Testing widget interactions, including zooming and filtering, to ensure proper behavior. * Each test ensures that widgets on the dashboard operate correctly and display accurate information. */ -const mockKubeLinode = kubeLinodeFactory.build(); +export const dashboardName = 'Linode Dashboard'; +export const region = 'US, Chicago, IL (us-ord)'; +export const actualRelativeTimeDuration = timeRange.Last24Hours; +export const resource = 'test1'; +const mockKubeLinode = kubeLinodeFactory.build(); const mockLinode = linodeFactory.build({ - label:"test1", + label: resource, id: mockKubeLinode.instance_id ?? undefined, }); -const widgetLabels = [ - 'CPU utilization', - 'Memory Usage', - 'Network Traffic', - 'Disk I/O', -]; -const metricsLabels = [ - 'system_cpu_utilization_percent', - 'system_memory_usage_by_resource', - 'system_network_io_by_resource', - 'system_disk_operations_total', -]; +const mockAccount = accountFactory.build(); + const y_labels = [ 'system_cpu_utilization_ratio', 'system_memory_usage_bytes', 'system_network_io_bytes_total', 'system_disk_operations_total', ]; +const linodeWidgets = widgetDetails.linode; +const widgetLabels: string[] = linodeWidgets.map(widget => widget.title); +const metricsLabels: string[] = linodeWidgets.map(widget => widget.name); + +const dashboard = dashboardFactory(dashboardName, widgetLabels, metricsLabels, y_labels).build(); +const metricDefinitions = metricDefinitionsFactory(widgetLabels, metricsLabels).build(); -const dashboard = dashboardFactory(dashboardName,widgetLabels,metricsLabels,y_labels).build(); -const metricDefinitions = metricDefinitionsFactory(widgetLabels,metricsLabels).build(); describe('Dashboard Widget Verification Tests', () => { beforeEach(() => { + cy.visitWithLogin('monitor/cloudpulse'); + mockAppendFeatureFlags({ aclp: makeFeatureFlagData({ beta: true, enabled: true }), }).as('getFeatureFlags'); + mockGetAccount(mockAccount).as('getAccount'); // Enables the account to have capability for Akamai Cloud Pulse mockGetFeatureFlagClientstream().as('getClientStream'); - mockGetFeatureFlagClientstream(); mockGetLinodes([mockLinode]).as('getLinodes'); interceptGetMetricDefinitions(metricDefinitions); interceptGetDashboards(dashboard).as('dashboard'); interceptCloudPulseServices('linode').as('services'); mockLinodeDashboardServicesResponse(dashboard); mockJWSToken(); - const mockAccount = accountFactory.build(); - mockGetAccount(mockAccount).as('getAccount'); // this enables the account to have capability for Akamai Cloud Pulse - cy.visitWithLogin('monitor/cloudpulse'); const responsePayload = createMetricResponse(actualRelativeTimeDuration, granularity.Min5); interceptCreateMetrics(responsePayload).as('metricAPI'); - resetDashboardAndVerifyPage(dashboardName); - selectServiceName(dashboardName); - selectTimeRange(actualRelativeTimeDuration, Object.values(timeRange)); - ui.regionSelect.find().click().type(`${region}{enter}`); - selectAndVerifyResource(resource); + resetDashboardAndVerifyPage(dashboardName); + selectServiceName(dashboardName); + selectTimeRange(actualRelativeTimeDuration, Object.values(timeRange)); + ui.regionSelect.find().click().type(`${region}{enter}`); + selectAndVerifyResource(resource); + }); - }); - - it(`should set available granularity of the all the widget`, () => { + it('should set available granularity of all the widgets', () => { linodeWidgets.forEach((testData) => { - const widgetSelector = `[data-qa-widget="${testData.title}"]`; - cy.get(widgetSelector) - .first() - .should('be.visible') - .within(() => { - ui.autocomplete - .findByTitleCustom('Select an Interval') - .findByTitle('Open') - .click(); - ui.autocompletePopper - .findByTitle(testData.expectedGranularity) + const widgetSelector = `[data-qa-widget="${testData.title}"]`; + cy.get(widgetSelector) + .first() .should('be.visible') - .click(); - assertSelections(testData.expectedGranularity); - + .within(() => { + ui.autocomplete + .findByTitleCustom('Select an Interval') + .findByTitle('Open') + .click(); + ui.autocompletePopper + .findByTitle(testData.expectedGranularity) + .should('be.visible') + .click(); + assertSelections(testData.expectedGranularity); + }); }); }); - }); - it(`should verify the title of the widget`, () => { + + it('should verify the title of the widget', () => { linodeWidgets.forEach((testData) => { const widgetSelector = `[data-qa-widget-header="${testData.title}"]`; cy.get(widgetSelector).invoke('text').then((text) => { - expect(text.trim()).to.containIgnoreCase(testData.title); + expect(text.trim()).to.equal(testData.title); + }); }); }); - it(`should set available aggregation of the all the widget`, () => { + it('should set available aggregation of all the widgets', () => { linodeWidgets.forEach((testData) => { const widgetSelector = `[data-qa-widget="${testData.title}"]`; cy.get(widgetSelector) @@ -135,77 +134,77 @@ describe('Dashboard Widget Verification Tests', () => { .findByTitle(testData.expectedAggregation) .should('be.visible') .click(); - assertSelections(testData.expectedAggregation); + assertSelections(testData.expectedAggregation); }); + }); }); - }); - it(`should verify available granularity of the widget`, () => { + + it('should verify available granularity of the widget', () => { linodeWidgets.forEach((testData) => { const widgetSelector = `[data-qa-widget="${testData.title}"]`; - cy.get(widgetSelector) - .first() - .scrollIntoView() + cy.get(widgetSelector) + .first() + .scrollIntoView() .should('be.visible') - .within(() => { - ui.autocomplete - .findByTitleCustom('Select an Interval') - .findByTitle('Open') - .click(); - testData.expectedGranularityArray.forEach((option) => { - ui.autocompletePopper - .findByTitle(option) - .should('be.visible') - .then(() => { - cy.log(`${option} is visible`); + .within(() => { + ui.autocomplete.findByTitleCustom('Select an Interval') + .findByTitle('Open') + .click(); + testData.expectedGranularityArray.forEach((option) => { + ui.autocompletePopper + .findByTitle(option) + .should('be.visible') + .then(() => { + cy.log(`${option} is visible`); + }); }); - }); - ui.autocomplete - .findByTitleCustom('Select an Interval') - .findByTitle('Close') - .click(); + ui.autocomplete + .findByTitleCustom('Select an Interval') + .findByTitle('Close') + .click(); + }); }); }); -}); - it(`should verify available aggregation of the widget`, () => { + it('should verify available aggregation of the widget', () => { linodeWidgets.forEach((testData) => { const widgetSelector = `[data-qa-widget="${testData.title}"]`; - cy.get(widgetSelector) - .first() - .scrollIntoView() - .should('be.visible') - .within(() => { - ui.autocomplete - .findByTitleCustom('Select an Aggregate Function') - .findByTitle('Open') - .click(); - testData.expectedAggregationArray.forEach((option) => { - ui.autocompletePopper - .findByTitle(option) - .should('be.visible') - .then(() => { - cy.log(`${option} is visible`); + cy.get(widgetSelector) + .first() + .scrollIntoView() + .should('be.visible') + .within(() => { + ui.autocomplete + .findByTitleCustom('Select an Aggregate Function') + .findByTitle('Open') + .click(); + testData.expectedAggregationArray.forEach((option) => { + ui.autocompletePopper + .findByTitle(option) + .should('be.visible') + .then(() => { + cy.log(`${option} is visible`); + }); }); - }); - ui.autocomplete - .findByTitleCustom('Select an Aggregate Function') - .findByTitle('Close') - .click(); - }); + ui.autocomplete + .findByTitleCustom('Select an Aggregate Function') + .findByTitle('Close') + .click(); + }); }); }); - it(`should zoom in and out of the all the widget`, () => { + + it('should zoom in and out of all the widgets', () => { linodeWidgets.forEach((testData) => { const widgetSelector = `[data-qa-widget="${testData.title}"]`; - //const zoomInSelector = 'svg[data-testid="zoom-in"]'; - // const zoomOutSelector = 'svg[data-testid="zoom-out"]'; - const zoomInSelector = ui.cloudpulse.findZoomButtonByTitle('zoom-in'); + const zoomInSelector = ui.cloudpulse.findZoomButtonByTitle('zoom-in'); const zoomOutSelector = ui.cloudpulse.findZoomButtonByTitle('zoom-out'); - cy.get(widgetSelector).each(($widget) => { + cy.get(widgetSelector).each(($widget) => { cy.wrap($widget).then(($el) => { const zoomInElement = $el.find(zoomInSelector); const zoomOutElement = $el.find(zoomOutSelector); - if (zoomOutElement.length > 0) { + + if (zoomOutElement.length > 0) { cy.wrap(zoomOutElement) .should('be.visible') .click({ timeout: 5000 }) @@ -220,38 +219,23 @@ describe('Dashboard Widget Verification Tests', () => { cy.log('Zoomed In on widget:', $el); }); } - }); + }); }); }); + }); it('should apply global refresh button and verify network calls', () => { - ui.cloudpulse.findRefreshIcon().click(); - interceptMetricsRequests(); - cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']).then((interceptions) => { - const interceptionsArray = Array.isArray(interceptions) ? interceptions : [interceptions]; - - interceptionsArray.forEach((interception) => { - const { body: requestPayload } = interception.request; - const metric = requestPayload.metric; - const metricData = linodeWidgets.find((data) => data.name === metric); - - if (!metricData) { - throw new Error(`Unknown metric: ${metric}`); - } - const granularity = requestPayload['time_granularity']; - const currentGranularity = granularity ? `${granularity.value} ${granularity.unit}` : ''; - const durationUnit = requestPayload.relative_time_duration.unit.toLowerCase(); - const durationValue = requestPayload.relative_time_duration.value; - const currentRelativeTimeDuration = durationUnit in timeUnit ? 'Last' + durationValue + timeUnit[durationUnit as keyof typeof timeUnit] : ''; - expect(requestPayload.aggregate_function).to.equal(metricData.expectedAggregation); - expect(currentRelativeTimeDuration).to.containIgnoreSpaces(actualRelativeTimeDuration); - expect(requestPayload.metric).to.equal(metricData.name); - expect(currentGranularity).to.equal(metricData.expectedGranularity); - }); + ui.cloudpulse.findRefreshIcon() + .should('be.visible') // Check if the refresh icon is visible + .click(); // Click the refresh icon + // check for specific UI elements that should be updated or appear after the refresh + // For example, check if widgets have updated data or if new data is visible + linodeWidgets.forEach((widget) => { + const widgetSelector = `[data-qa-widget="${widget.title}"]`; + cy.get(widgetSelector) + .should('be.visible') + .and('contain.text', widget.title); // Adjust based on what you expect after refresh }); + }); }); -}); -}); - - diff --git a/packages/manager/cypress/support/constants/widget-service.ts b/packages/manager/cypress/support/constants/widget-service.ts index f3ddc9eeed8..556ee10a8c1 100644 --- a/packages/manager/cypress/support/constants/widget-service.ts +++ b/packages/manager/cypress/support/constants/widget-service.ts @@ -7,7 +7,7 @@ export const granularity = { Day1: '1 day', Hr1: '1 hr', Min5: '5 min', -} as const; +}; /** * Defines various aggregation types that can be applied to data. @@ -18,7 +18,7 @@ export const aggregation = { Max: 'max', Min: 'min', Sum: 'sum', -} as const; +}; // Define a constant object named `timeRange` to represent various time periods. // This object maps time range identifiers to their descriptive strings. @@ -28,7 +28,7 @@ export const timeRange = { Last24Hours: 'Last 24 Hours', Last30Days: 'Last 30 Days', Last30Minutes: 'Last 30 Minutes', -} as const; +}; // Define a constant object named `timeUnit` which serves as a mapping // between time unit identifiers and their full descriptive names. @@ -37,7 +37,7 @@ export const timeUnit = { day: 'Days', hr: 'Hours', min: 'Minutes', -} as const; +} ; /** * Configuration object defining predefined sets of aggregation types. * These sets can be used to specify acceptable aggregation operations for different contexts. @@ -55,35 +55,35 @@ export const widgetDetails = { linode: [ { expectedAggregation: aggregation.Max, - expectedAggregationArray: aggregationConfig.all, + expectedAggregationArray: aggregationConfig.basic, expectedGranularity: granularity.Hr1, expectedGranularityArray: Object.values(granularity), - name: 'system_disk_OPS_total', - title: 'Disk I/O', + name: 'system_cpu_utilization_percent', + title: 'CPU Utilization', }, { expectedAggregation: aggregation.Max, expectedAggregationArray: aggregationConfig.all, expectedGranularity: granularity.Hr1, expectedGranularityArray: Object.values(granularity), - name: 'system_network_io_by_resource', - title: 'Network Traffic', + name: 'system_memory_usage_by_resource', + title: 'Memory Usage', }, { expectedAggregation: aggregation.Max, expectedAggregationArray: aggregationConfig.all, expectedGranularity: granularity.Hr1, expectedGranularityArray: Object.values(granularity), - name: 'system_memory_usage_by_resource', - title: 'Memory Usage', + name: 'system_network_io_by_resource', + title: 'Network Traffic', }, { expectedAggregation: aggregation.Max, - expectedAggregationArray: aggregationConfig.basic, + expectedAggregationArray: aggregationConfig.all, expectedGranularity: granularity.Hr1, expectedGranularityArray: Object.values(granularity), - name: 'system_cpu_utilization_percent', - title: 'CPU Utilization', + name: 'system_disk_OPS_total', + title: 'Disk I/O', }, ], }; diff --git a/packages/manager/cypress/support/util/cloudpulse.ts b/packages/manager/cypress/support/util/cloudpulse.ts index 45f08a09f8e..df354c8a209 100644 --- a/packages/manager/cypress/support/util/cloudpulse.ts +++ b/packages/manager/cypress/support/util/cloudpulse.ts @@ -1,4 +1,3 @@ - /** * This class provides utility functions for interacting with the Cloudpulse dashboard * in a Cypress test suite. It includes methods for: @@ -16,7 +15,6 @@ */ import { ui } from 'support/ui'; - export const selectServiceName = (serviceName: string) => { ui.autocomplete .findByTitleCustom('Select Dashboard') @@ -72,14 +70,18 @@ export const assertSelections = (expectedOptions: string) => { * @param {string} serviceName - The name of the service to verify. */ export const resetDashboardAndVerifyPage = (serviceName: string) => { - ui.autocomplete - .findByTitleCustom('Select Dashboard') - .findByTitle('Clear') - .click(); - ui.autocomplete - .findByPlaceholderCustom('Select Dashboard') - .should('have.value', ''); // Ensure the input field is cleared + .findByTitleCustom('Select Dashboard') // Custom method to locate the dropdown + .findByTitle('Clear') // Custom method to locate the "Clear" button + .then(($clearButton) => { + if ($clearButton.is(':visible')) { + // If the "Clear" button is visible, click it + cy.wrap($clearButton).click(); + } else { + // If the "Clear" button is not visible, do nothing + cy.log('Clear button is not visible, no action taken'); + } + }); }; /* export const checkZoomActions1 = (widgetName: string) => { diff --git a/packages/manager/src/factories/dashboards.ts b/packages/manager/src/factories/dashboards.ts index 6d0a536e041..8ce9a7a38f0 100644 --- a/packages/manager/src/factories/dashboards.ts +++ b/packages/manager/src/factories/dashboards.ts @@ -85,11 +85,18 @@ export const metricDefinitionsFactory = ( metricsLabels: string[] ) => { return Factory.Sync.makeFactory({ - data: Factory.each(() => [ - dashboardMetricFactory(widgetLabels, metricsLabels).build(), // Pass widgetLabels and metricsLabels - ]), + data: Factory.each(() => { + // Create the list of metrics definitions by iterating over widgetLabels + return widgetLabels.map((_, index) => { + return dashboardMetricFactory(widgetLabels, metricsLabels).build({ + label: widgetLabels[index % widgetLabels.length], + metric: metricsLabels[index % metricsLabels.length] + }); + }); + }), }); }; + const dashboardMetricFactory = ( widgetLabels: string[], metricsLabels: string[] @@ -97,8 +104,8 @@ const dashboardMetricFactory = ( return Factory.Sync.makeFactory({ available_aggregate_functions: ['min', 'max', 'avg', 'sum'], dimensions: [], - label: Factory.each((i) => widgetLabels[i % widgetLabels.length]), - metric: Factory.each((i) => metricsLabels[i % metricsLabels.length]), + label: Factory.each((i) => widgetLabels[i % widgetLabels.length]), // This might be overridden + metric: Factory.each((i) => metricsLabels[i % metricsLabels.length]), // This might be overridden metric_type: 'gauge', scrape_interval: Factory.each( (i) => scrape_interval[i % scrape_interval.length] @@ -106,3 +113,4 @@ const dashboardMetricFactory = ( unit: Factory.each((i) => units_interval[i % units_interval.length]), }); }; + From 78887f763169962ea0f225818fe8a58a11d1151e Mon Sep 17 00:00:00 2001 From: nikhagra Date: Tue, 10 Sep 2024 19:37:15 +0530 Subject: [PATCH 031/474] upcoming: [DI-20360] - Merge conflicts resolved --- .../manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 1eb37c711b4..c992f283468 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -258,7 +258,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { const metricsApiCallError = error?.[0]?.reason; return ( - + Date: Wed, 11 Sep 2024 11:20:55 +0530 Subject: [PATCH 032/474] upcoming:[DI-20585]- Added code review comments --- .../core/cloudpulse/dashboard-filters.spec.ts | 104 --------------- ....ts => linode-widget-verification.spec.ts} | 104 +++++++++------ .../support/constants/widget-service.ts | 36 ++++- .../cypress/support/util/cloudpulse.ts | 70 +++------- packages/manager/src/factories/dashboards.ts | 123 +++++++++++++++++- .../CloudPulse/Widget/components/Zoomer.tsx | 2 + 6 files changed, 234 insertions(+), 205 deletions(-) delete mode 100644 packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts rename packages/manager/cypress/e2e/core/cloudpulse/{widget-verification.spec.ts => linode-widget-verification.spec.ts} (78%) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts deleted file mode 100644 index f83670fb6a7..00000000000 --- a/packages/manager/cypress/e2e/core/cloudpulse/dashboard-filters.spec.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { - selectServiceName, - selectTimeRange, - selectAndVerifyResource, - assertSelections, - resetDashboardAndVerifyPage, -} from 'support/util/cloudpulse'; -import { - mockAppendFeatureFlags, - mockGetFeatureFlagClientstream, -} from 'support/intercepts/feature-flags'; -import { - interceptCloudPulseServices, - interceptCreateMetrics, - interceptGetDashboards, - interceptGetMetricDefinitions, - mockJWSToken, - mockLinodeDashboardServicesResponse, -} from 'support/intercepts/cloudpulseAPIHandler'; -import { makeFeatureFlagData } from 'support/util/feature-flags'; -import type { Flags } from 'src/featureFlags'; -import { createMetricResponse } from '@src/factories/widget'; -import { mockGetLinodes } from 'support/intercepts/linodes'; -import { - mockGetAccount, -} from 'support/intercepts/account'; -import { ui } from 'support/ui'; -import { accountFactory ,dashboardFactory,kubeLinodeFactory,linodeFactory,metricDefinitionsFactory} from 'src/factories'; -import { timeRange, widgetDetails, granularity } from 'support/constants/widget-service'; -/** - * This test suite focuses on the standard operations and verifications for the Cloudpulse dashboard. - * - * The tests include verifying the visibility and functionality of the Cloud View when the feature flag is disabled, - * clearing and resetting dashboard preferences, and ensuring that specific selections such as dashboard name, - * time range, region, and resources are correctly applied and verified. - * - * Each test case checks the correctness and persistence of these configurations to ensure that the - * dashboard behaves as expected under various conditions. - */ - - - - const dashboardName = 'Linode Dashboard'; - const region = 'US, Chicago, IL (us-ord)'; - const actualRelativeTimeDuration = timeRange.Last24Hours; -const resource = 'test1'; -const mockKubeLinode = kubeLinodeFactory.build(); -const mockLinode = linodeFactory.build({ - label: resource, - id: mockKubeLinode.instance_id ?? undefined, -}); -const mockAccount = accountFactory.build(); - -const y_labels = [ - 'system_cpu_utilization_ratio', - 'system_memory_usage_bytes', - 'system_network_io_bytes_total', - 'system_disk_operations_total', -]; -const linodeWidgets = widgetDetails.linode; -const widgetLabels: string[] = linodeWidgets.map(widget => widget.title); -const metricsLabels: string[] = linodeWidgets.map(widget => widget.name); -const dashboard = dashboardFactory(dashboardName, widgetLabels, metricsLabels, y_labels).build(); -const metricDefinitions = metricDefinitionsFactory(widgetLabels, metricsLabels).build(); -describe('Standard Dashboard Filter Application and Configuration Tests', () => { - beforeEach(() => { - cy.visitWithLogin('monitor/cloudpulse'); - mockAppendFeatureFlags({ - aclp: makeFeatureFlagData({ beta: true, enabled: true }), - }).as('getFeatureFlags'); - mockGetAccount(mockAccount).as('getAccount'); // this enables the account to have capability for Akamai Cloud Pulse - mockGetFeatureFlagClientstream(); - interceptGetMetricDefinitions(metricDefinitions); - interceptGetDashboards(dashboard).as('dashboard'); - interceptCloudPulseServices('linode').as('services'); - mockGetLinodes([mockLinode]).as('getLinodes'); - const responsePayload = createMetricResponse(actualRelativeTimeDuration, granularity.Min5); - interceptCreateMetrics(responsePayload).as('metricAPI'); - mockJWSToken(); - mockLinodeDashboardServicesResponse(dashboard); - }); - - - it('should verify cloudpulse availability when feature flag is set to false', () => { - mockAppendFeatureFlags({ - aclp: makeFeatureFlagData({ beta: true, enabled: false }), - }); - mockGetFeatureFlagClientstream(); - cy.visitWithLogin('monitor/cloudpulse'); // since we disabled the flag here, we should have not found - cy.findByText('Not Found').should('be.visible'); // not found - }); - - it('Check the Linode Dashboard for the required global filter.', () => { - resetDashboardAndVerifyPage(dashboardName); - selectServiceName(dashboardName); - assertSelections(dashboardName); - selectTimeRange(actualRelativeTimeDuration, Object.values(timeRange)); - assertSelections(actualRelativeTimeDuration); - ui.regionSelect.find().click().type(`${region}{enter}`); - assertSelections(region); - selectAndVerifyResource(resource); - }); -}); - diff --git a/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts similarity index 78% rename from packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts rename to packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 4de2c9fce41..bfbcae05698 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -3,7 +3,7 @@ import { selectServiceName, selectAndVerifyResource, assertSelections, - resetDashboardAndVerifyPage, + waitForElementToLoad, } from 'support/util/cloudpulse'; import { mockAppendFeatureFlags, @@ -28,6 +28,7 @@ import type { Flags } from 'src/featureFlags'; import { accountFactory, dashboardFactory, kubeLinodeFactory, linodeFactory, metricDefinitionsFactory } from 'src/factories'; import { mockGetAccount } from 'support/intercepts/account'; import { mockGetLinodes } from 'support/intercepts/linodes'; +import { mockGetUserPreferences } from 'support/intercepts/profile'; @@ -62,15 +63,14 @@ const y_labels = [ const linodeWidgets = widgetDetails.linode; const widgetLabels: string[] = linodeWidgets.map(widget => widget.title); const metricsLabels: string[] = linodeWidgets.map(widget => widget.name); +const service_type='linode'; -const dashboard = dashboardFactory(dashboardName, widgetLabels, metricsLabels, y_labels).build(); +const dashboard = dashboardFactory(dashboardName, widgetLabels, metricsLabels, y_labels,service_type).build(); const metricDefinitions = metricDefinitionsFactory(widgetLabels, metricsLabels).build(); describe('Dashboard Widget Verification Tests', () => { - beforeEach(() => { - cy.visitWithLogin('monitor/cloudpulse'); - - mockAppendFeatureFlags({ + beforeEach(() => { + mockAppendFeatureFlags({ aclp: makeFeatureFlagData({ beta: true, enabled: true }), }).as('getFeatureFlags'); mockGetAccount(mockAccount).as('getAccount'); // Enables the account to have capability for Akamai Cloud Pulse @@ -83,26 +83,36 @@ describe('Dashboard Widget Verification Tests', () => { mockJWSToken(); const responsePayload = createMetricResponse(actualRelativeTimeDuration, granularity.Min5); interceptCreateMetrics(responsePayload).as('metricAPI'); - resetDashboardAndVerifyPage(dashboardName); - selectServiceName(dashboardName); - selectTimeRange(actualRelativeTimeDuration, Object.values(timeRange)); - ui.regionSelect.find().click().type(`${region}{enter}`); - selectAndVerifyResource(resource); +}); + + it('should verify cloudpulse availability when feature flag is set to false', () => { + mockAppendFeatureFlags({ + aclp: makeFeatureFlagData({ beta: true, enabled: false }), + }); + mockGetFeatureFlagClientstream(); + cy.visitWithLogin('monitor/cloudpulse'); // since we disabled the flag here, we should have not found + cy.findByText('Not Found').should('be.visible'); // not found }); - it('should set available granularity of all the widgets', () => { + it.only('should set available granularity of all the widgets', () => { + setupMethod() linodeWidgets.forEach((testData) => { + cy.wait(5000); const widgetSelector = `[data-qa-widget="${testData.title}"]`; - cy.get(widgetSelector) + waitForElementToLoad(widgetSelector); + cy.get(widgetSelector).as('widget') + cy.get('@widget') + .should('be.visible') .first() - .should('be.visible') .within(() => { ui.autocomplete .findByTitleCustom('Select an Interval') + .should('be.visible') .findByTitle('Open') .click(); ui.autocompletePopper - .findByTitle(testData.expectedGranularity) + .findByTitle(testData.expectedGranularity).as('granularityOption') + cy.get('@granularityOption') .should('be.visible') .click(); assertSelections(testData.expectedGranularity); @@ -111,6 +121,7 @@ describe('Dashboard Widget Verification Tests', () => { }); it('should verify the title of the widget', () => { + setupMethod() linodeWidgets.forEach((testData) => { const widgetSelector = `[data-qa-widget-header="${testData.title}"]`; cy.get(widgetSelector).invoke('text').then((text) => { @@ -120,7 +131,9 @@ describe('Dashboard Widget Verification Tests', () => { }); it('should set available aggregation of all the widgets', () => { + setupMethod() linodeWidgets.forEach((testData) => { + cy.wait(5000); const widgetSelector = `[data-qa-widget="${testData.title}"]`; cy.get(widgetSelector) .first() @@ -140,7 +153,9 @@ describe('Dashboard Widget Verification Tests', () => { }); it('should verify available granularity of the widget', () => { + setupMethod() linodeWidgets.forEach((testData) => { + cy.wait(5000); const widgetSelector = `[data-qa-widget="${testData.title}"]`; cy.get(widgetSelector) .first() @@ -167,7 +182,9 @@ describe('Dashboard Widget Verification Tests', () => { }); it('should verify available aggregation of the widget', () => { + setupMethod() linodeWidgets.forEach((testData) => { + cy.wait(5000); const widgetSelector = `[data-qa-widget="${testData.title}"]`; cy.get(widgetSelector) .first() @@ -195,47 +212,48 @@ describe('Dashboard Widget Verification Tests', () => { }); it('should zoom in and out of all the widgets', () => { + setupMethod() linodeWidgets.forEach((testData) => { + cy.wait(5000); const widgetSelector = `[data-qa-widget="${testData.title}"]`; - const zoomInSelector = ui.cloudpulse.findZoomButtonByTitle('zoom-in'); - const zoomOutSelector = ui.cloudpulse.findZoomButtonByTitle('zoom-out'); - cy.get(widgetSelector).each(($widget) => { - cy.wrap($widget).then(($el) => { - const zoomInElement = $el.find(zoomInSelector); - const zoomOutElement = $el.find(zoomOutSelector); - - if (zoomOutElement.length > 0) { - cy.wrap(zoomOutElement) - .should('be.visible') - .click({ timeout: 5000 }) - .then(() => { - cy.log('Zoomed Out on widget:', $el); - }); - } else if (zoomInElement.length > 0) { - cy.wrap(zoomInElement) - .should('be.visible') - .click({ timeout: 5000 }) - .then(() => { - cy.log('Zoomed In on widget:', $el); - }); - } - }); + cy.log("Name of the widget **",testData.title); + cy.get(widgetSelector).should('be.visible').within(() => { + cy.get(ui.cloudpulse.findZoomButtonByTitle('zoom-out')).should('be.visible') + .should('be.enabled') + .click(); + cy.get(ui.cloudpulse.findZoomButtonByTitle('zoom-in')).should('be.visible') + .should('be.enabled') + .click(); }); + }); }); it('should apply global refresh button and verify network calls', () => { + setupMethod() ui.cloudpulse.findRefreshIcon() - .should('be.visible') // Check if the refresh icon is visible - .click(); // Click the refresh icon - // check for specific UI elements that should be updated or appear after the refresh - // For example, check if widgets have updated data or if new data is visible + .should('be.visible') + .click(); linodeWidgets.forEach((widget) => { const widgetSelector = `[data-qa-widget="${widget.title}"]`; cy.get(widgetSelector) .should('be.visible') - .and('contain.text', widget.title); // Adjust based on what you expect after refresh + .and('contain.text', widget.title); }); }); }); + + + const setupMethod = () => { + mockGetUserPreferences({}).as('getUserPreferences'); + cy.visitWithLogin('monitor/cloudpulse'); + cy.get('[data-qa-header="Akamai Cloud Pulse"]').should('be.visible').should('have.text', 'Akamai Cloud Pulse'); + selectServiceName(dashboardName); + assertSelections(dashboardName); + selectTimeRange(actualRelativeTimeDuration, Object.values(timeRange)); + assertSelections(actualRelativeTimeDuration); + ui.regionSelect.find().click().type(`${region}{enter}`); + assertSelections(region); + selectAndVerifyResource(resource); +}; diff --git a/packages/manager/cypress/support/constants/widget-service.ts b/packages/manager/cypress/support/constants/widget-service.ts index 556ee10a8c1..b40feca2b63 100644 --- a/packages/manager/cypress/support/constants/widget-service.ts +++ b/packages/manager/cypress/support/constants/widget-service.ts @@ -37,7 +37,7 @@ export const timeUnit = { day: 'Days', hr: 'Hours', min: 'Minutes', -} ; +}; /** * Configuration object defining predefined sets of aggregation types. * These sets can be used to specify acceptable aggregation operations for different contexts. @@ -52,6 +52,40 @@ export const aggregationConfig = { * Each widget configuration includes expected aggregation types, granularity levels, and other relevant properties. */ export const widgetDetails = { + dbaas: [ + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.basic, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_cpu_utilization_percent', + title: 'CPU Utilization', + }, + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.all, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_memory_usage_by_resource', + title: 'Memory Usage', + }, + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.all, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_network_io_by_resource', + title: 'Network Traffic', + }, + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.all, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_disk_OPS_total', + title: 'Disk I/O', + }, + ], linode: [ { expectedAggregation: aggregation.Max, diff --git a/packages/manager/cypress/support/util/cloudpulse.ts b/packages/manager/cypress/support/util/cloudpulse.ts index df354c8a209..b339f61f01f 100644 --- a/packages/manager/cypress/support/util/cloudpulse.ts +++ b/packages/manager/cypress/support/util/cloudpulse.ts @@ -1,3 +1,4 @@ +/* eslint-disable sonarjs/no-all-duplicated-branches */ /** * This class provides utility functions for interacting with the Cloudpulse dashboard * in a Cypress test suite. It includes methods for: @@ -15,6 +16,16 @@ */ import { ui } from 'support/ui'; +/** + * Waits for the element matching the given CSS selector to appear and become visible. + * + * @param {string} selector - The CSS selector for the element to wait for. + */ +// command to wait for the element to be fully loaded +export const waitForElementToLoad = (selector: string) => { + cy.get(selector, { timeout: 10000 }).should('be.visible'); +}; + export const selectServiceName = (serviceName: string) => { ui.autocomplete .findByTitleCustom('Select Dashboard') @@ -52,8 +63,6 @@ export const selectAndVerifyResource = (service: string) => { const resourceInput = ui.autocomplete.findByTitleCustom('Select Resources'); resourceInput.findByTitle('Open').click(); resourceInput.click().type(`${service}{enter}`); - // Commenting out the line because resourceInput.findByTitle('closure') does not work - // resourceInput.findByTitle('Close').click(); cy.get('[title="Close"]').click(); }; /** @@ -67,55 +76,14 @@ export const assertSelections = (expectedOptions: string) => { /** * Clears the dashboard's preferences and verifies the zeroth page. - * @param {string} serviceName - The name of the service to verify. */ -export const resetDashboardAndVerifyPage = (serviceName: string) => { +export const resetDashboard = () => { ui.autocomplete - .findByTitleCustom('Select Dashboard') // Custom method to locate the dropdown - .findByTitle('Clear') // Custom method to locate the "Clear" button - .then(($clearButton) => { - if ($clearButton.is(':visible')) { - // If the "Clear" button is visible, click it - cy.wrap($clearButton).click(); - } else { - // If the "Clear" button is not visible, do nothing - cy.log('Clear button is not visible, no action taken'); - } - }); -}; - -/* export const checkZoomActions1 = (widgetName: string) => { - const widgetSelector = `[data-qa-widget="${widgetName}"]`; - const zoomInSelector = ui.cloudpulse.findZoomButtonByTitle('zoom-in'); - const zoomOutSelector = ui.cloudpulse.findZoomButtonByTitle('zoom-out'); - - cy.get(widgetSelector).each(($widget) => { - cy.wrap($widget).then(($el) => { - const zoomInAvailable = $el.find(zoomInSelector).length > 0; - const zoomOutAvailable = $el.find(zoomOutSelector).length > 0; + .findByTitleCustom('Select Dashboard') + .findByTitle('Clear') + .click(); - if (zoomInAvailable) { - cy.wrap($el) - .find(zoomInSelector) - .should('be.visible') - .click({ timeout: 5000 }) - .then(() => { - cy.log('Zoomed In on widget:', $el); - }); - } else if (zoomOutAvailable) { - cy.wrap($el) - .find(zoomOutSelector) - .should('be.visible') - .click({ timeout: 5000 }) - .then(() => { - cy.log('Zoomed Out on widget:', $el); - }); - } else { - cy.log( - 'Neither ZoomInMapIcon nor ZoomOutMapIcon found for widget:', - $el - ); - } - }); - }); -};*/ + ui.autocomplete + .findByPlaceholderCustom('Select Dashboard') + .should('have.value', ''); +}; diff --git a/packages/manager/src/factories/dashboards.ts b/packages/manager/src/factories/dashboards.ts index 8ce9a7a38f0..f12ae9b3316 100644 --- a/packages/manager/src/factories/dashboards.ts +++ b/packages/manager/src/factories/dashboards.ts @@ -13,7 +13,7 @@ const chart_type = ['area', 'area', 'area', 'line']; const scrape_interval = ['2m', '30s', '30s', '30s']; const units_interval = ['percent', 'byte', 'byte', 'ops_per_second']; -/* export const dashboardFactory1 = Factory.Sync.makeFactory({ +/* export const dashboardFactory = Factory.Sync.makeFactory({ created: new Date().toISOString(), id: Factory.each((i) => i), label: 'Linode Dashboard', @@ -25,17 +25,46 @@ const units_interval = ['percent', 'byte', 'byte', 'ops_per_second']; updated: new Date().toISOString(), widgets: Factory.each(() => widgetFactory.buildList(4)), // Create a list of 1 widgets });*/ +/** + * Factory function to create instances of the `Dashboard` model with predefined properties and values. + * + * @param {string} dashboardLabel - The label to assign to the dashboard instance. + * @param {string[]} widgetLabels - An array of labels for widgets to be included in the dashboard. + * @param {string[]} metricsLabels - An array of labels for metrics associated with the widgets. + * @param {string[]} y_labels - An array of Y-axis labels for the metrics. + * @param {string} service - The type of service to be assigned to the dashboard. + * + * @returns {Factory} A Factory instance for creating `Dashboard` objects with the specified properties. + * + * @description + * This function uses the `Factory.Sync.makeFactory` method to create a factory for generating `Dashboard` objects. + * The created `Dashboard` object includes: + * - `created`: A timestamp for when the dashboard was created, in ISO string format. + * - `id`: A unique identifier for the dashboard, generated sequentially based on the factory's index. + * - `label`: The label provided via the `dashboardLabel` parameter. + * - `service_type`: The service type provided via the `service` parameter. + * - `time_duration`: An object with a unit of 'min' and a value of 30 minutes, indicating the time duration. + * - `updated`: A timestamp for when the dashboard was last updated, in ISO string format. + * - `widgets`: A list of widgets generated by the `widgetFactory` function. The number of widgets created is equal to the length of the `widgetLabels` array. + * + * Usage Example: + * ```typescript + * const myDashboardFactory = dashboardFactory('Main Dashboard', ['Widget1', 'Widget2'], ['Metric1', 'Metric2'], ['Y1', 'Y2'], 'ServiceA'); + * const myDashboard = myDashboardFactory.build(); // Creates a Dashboard instance with the specified properties. + * ``` + */ export const dashboardFactory = ( dashboardLabel: string, widgetLabels: string[], metricsLabels: string[], - y_labels: string[] + y_labels: string[], + service: string ) => { return Factory.Sync.makeFactory({ created: new Date().toISOString(), id: Factory.each((i) => i), label: dashboardLabel, - service_type: 'linode', + service_type: service, time_duration: { unit: 'min', value: 30, @@ -48,6 +77,42 @@ export const dashboardFactory = ( ), }); }; +/** + * Factory function to create instances of the `Widgets` model with predefined properties and values. + * + * @param {string[]} widgetLabels - An array of labels for widgets to be created. + * @param {string[]} metricsLabels - An array of metrics labels associated with each widget. + * @param {string[]} y_labels - An array of Y-axis labels for the metrics. + * + * @returns {Factory} A Factory instance for creating `Widgets` objects with the specified properties. + * + * @description + * This function uses the `Factory.Sync.makeFactory` method to create a factory for generating `Widgets` objects. + * The created `Widgets` object includes: + * - `aggregate_function`: Set to 'avg' for averaging metric values. + * - `chart_type`: The type of chart for the widget, chosen from a predefined list (`chart_type`). + * - `color`: The color of the widget, chosen from a predefined list (`color`). + * - `filters`: An empty array of filters for the widget. + * - `group_by`: Set to 'region', indicating the grouping criterion for the widget data. + * - `label`: The label for the widget, chosen from the `widgetLabels` array. + * - `metric`: The metric associated with the widget, chosen from the `metricsLabels` array. + * - `namespace_id`: An identifier for the namespace, generated as the modulus of the index with 10. + * - `region_id`: An identifier for the region, generated as the modulus of the index with 5. + * - `resource_id`: A unique resource identifier formatted as `resource-{index}`. + * - `service_type`: Set to 'default', indicating the service type. + * - `serviceType`: Also set to 'default', similar to `service_type`. + * - `size`: Fixed size value of 12 for the widget. + * - `time_duration`: An object with a unit of 'min' and a value of 30 minutes, representing the time duration. + * - `time_granularity`: An object with a unit of 'hour' and a value of 1 hour, representing the granularity of time. + * - `unit`: The unit of measurement, chosen from a predefined list (`units`). + * - `y_label`: The Y-axis label for the widget, chosen from the `y_labels` array. + * + * Usage Example: + * ```typescript + * const myWidgetFactory = widgetFactory(['Widget1', 'Widget2'], ['Metric1', 'Metric2'], ['Y1', 'Y2']); + * const myWidget = myWidgetFactory.build(); // Creates a Widget instance with the specified properties. + * ``` + */ export const widgetFactory = ( widgetLabels: string[], @@ -80,22 +145,69 @@ export const widgetFactory = ( y_label: Factory.each((i) => y_labels[i % y_labels.length]), }); }; +/** + * Factory function to create instances of the `MetricDefinitions` model with predefined properties and values. + * + * @param {string[]} widgetLabels - An array of labels for widgets used in the metric definitions. + * @param {string[]} metricsLabels - An array of labels for metrics associated with the widget definitions. + * + * @returns {Factory} A Factory instance for creating `MetricDefinitions` objects with the specified properties. + * + * @description + * This function uses the `Factory.Sync.makeFactory` method to create a factory for generating `MetricDefinitions` objects. + * The created `MetricDefinitions` object includes: + * - `data`: An array of metric definitions. Each metric definition is created using the `dashboardMetricFactory` function, which provides the following properties: + * - `label`: A label for the metric, chosen from the `widgetLabels` array. The label is selected based on the index modulo the length of `widgetLabels` to ensure cycling through the labels. + * - `metric`: A metric label, chosen from the `metricsLabels` array. The metric is selected based on the index modulo the length of `metricsLabels` to ensure cycling through the labels. + * + * The `data` array contains metric definitions where the number of elements matches the length of the `widgetLabels` array. Each element in the array represents a metric definition corresponding to a widget label and a metric label. + * + * Usage Example: + * ```typescript + * const myMetricDefinitionsFactory = metricDefinitionsFactory(['Widget1', 'Widget2'], ['Metric1', 'Metric2']); + * const myMetricDefinitions = myMetricDefinitionsFactory.build(); // Creates a MetricDefinitions instance with the specified properties. + * ``` + */ export const metricDefinitionsFactory = ( widgetLabels: string[], metricsLabels: string[] ) => { return Factory.Sync.makeFactory({ data: Factory.each(() => { - // Create the list of metrics definitions by iterating over widgetLabels return widgetLabels.map((_, index) => { return dashboardMetricFactory(widgetLabels, metricsLabels).build({ label: widgetLabels[index % widgetLabels.length], - metric: metricsLabels[index % metricsLabels.length] + metric: metricsLabels[index % metricsLabels.length], }); }); }), }); }; +/** + * Factory function to create instances of the `AvailableMetrics` model with predefined properties and values. + * + * @param {string[]} widgetLabels - An array of labels for widgets that will be associated with the metrics. + * @param {string[]} metricsLabels - An array of labels for metrics to be used in the `AvailableMetrics` instances. + * + * @returns {Factory} A Factory instance for creating `AvailableMetrics` objects with the specified properties. + * + * @description + * This function uses the `Factory.Sync.makeFactory` method to create a factory for generating `AvailableMetrics` objects. + * The created `AvailableMetrics` object includes: + * - `available_aggregate_functions`: A fixed array of aggregate functions that can be applied to the metrics: `'min'`, `'max'`, `'avg'`, and `'sum'`. + * - `dimensions`: An empty array of dimensions for the metric. This property can be expanded if needed. + * - `label`: A label for the metric, chosen from the `widgetLabels` array. The label is selected based on the index modulo the length of `widgetLabels`, allowing for cycling through the provided labels. This property might be overridden if specified differently. + * - `metric`: A metric label chosen from the `metricsLabels` array. The metric is selected based on the index modulo the length of `metricsLabels`, allowing for cycling through the provided labels. This property might be overridden if specified differently. + * - `metric_type`: Set to `'gauge'`, indicating the type of metric. + * - `scrape_interval`: The interval at which metrics are scraped, chosen from a predefined list (`scrape_interval`). The value is selected based on the index modulo the length of `scrape_interval`. + * - `unit`: The unit of measurement for the metric, chosen from a predefined list (`units_interval`). The unit is selected based on the index modulo the length of `units_interval`. + * + * Usage Example: + * ```typescript + * const myDashboardMetricFactory = dashboardMetricFactory(['Widget1', 'Widget2'], ['Metric1', 'Metric2']); + * const myMetric = myDashboardMetricFactory.build(); // Creates an AvailableMetrics instance with the specified properties. + * ``` + */ const dashboardMetricFactory = ( widgetLabels: string[], @@ -113,4 +225,3 @@ const dashboardMetricFactory = ( unit: Factory.each((i) => units_interval[i % units_interval.length]), }); }; - diff --git a/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx b/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx index 6ed093ed513..443fbe2a32f 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx @@ -17,6 +17,7 @@ export const ZoomIcon = React.memo((props: ZoomIconProperties) => { if (props.zoomIn) { return ( handleClick(false)} style={{ color: 'grey', fontSize: 'x-large' }} @@ -26,6 +27,7 @@ export const ZoomIcon = React.memo((props: ZoomIconProperties) => { return ( handleClick(true)} style={{ color: 'grey', fontSize: 'x-large' }} From 2c556374df9a33d53faae0dec5788da40152249e Mon Sep 17 00:00:00 2001 From: agorthi Date: Wed, 11 Sep 2024 12:23:59 +0530 Subject: [PATCH 033/474] upcoming:[DI-20585]- renaming intercept methods to mocks --- .../linode-widget-verification.spec.ts | 19 ++++++++----------- .../intercepts/cloudpulseAPIHandler.ts | 12 ++++++------ 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index bfbcae05698..b15c8a40f83 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -10,18 +10,15 @@ import { mockGetFeatureFlagClientstream, } from 'support/intercepts/feature-flags'; import { - interceptCloudPulseServices, - interceptMetricsRequests, mockJWSToken, mockLinodeDashboardServicesResponse, + mockCreateMetrics, + mockGetDashboards, + mockGetMetricDefinitions, + mockCloudPulseServices, } from 'support/intercepts/cloudpulseAPIHandler'; import { ui } from 'support/ui'; import { timeRange, widgetDetails, granularity } from 'support/constants/widget-service'; -import { - interceptCreateMetrics, - interceptGetDashboards, - interceptGetMetricDefinitions, -} from 'support/intercepts/cloudpulseAPIHandler'; import { makeFeatureFlagData } from 'support/util/feature-flags'; import { createMetricResponse } from '@src/factories/widget'; import type { Flags } from 'src/featureFlags'; @@ -76,13 +73,13 @@ describe('Dashboard Widget Verification Tests', () => { mockGetAccount(mockAccount).as('getAccount'); // Enables the account to have capability for Akamai Cloud Pulse mockGetFeatureFlagClientstream().as('getClientStream'); mockGetLinodes([mockLinode]).as('getLinodes'); - interceptGetMetricDefinitions(metricDefinitions); - interceptGetDashboards(dashboard).as('dashboard'); - interceptCloudPulseServices('linode').as('services'); + mockGetMetricDefinitions(metricDefinitions); + mockGetDashboards(dashboard).as('dashboard'); + mockCloudPulseServices('linode').as('services'); mockLinodeDashboardServicesResponse(dashboard); mockJWSToken(); const responsePayload = createMetricResponse(actualRelativeTimeDuration, granularity.Min5); - interceptCreateMetrics(responsePayload).as('metricAPI'); + mockCreateMetrics(responsePayload).as('metricAPI'); }); it('should verify cloudpulse availability when feature flag is set to false', () => { diff --git a/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts b/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts index 2034333873f..5a28e3a3b72 100644 --- a/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts +++ b/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts @@ -6,7 +6,7 @@ import { apiMatcher } from 'support/util/intercepts'; -import type { Dashboard, MetricDefinitions } from '@linode/api-v4'; +import type { AvailableMetrics, Dashboard, MetricDefinitions } from '@linode/api-v4'; /** * Intercepts HTTP GET requests for metric definitions. @@ -17,7 +17,7 @@ import type { Dashboard, MetricDefinitions } from '@linode/api-v4'; * @returns {Cypress.Chainable} The chainable Cypress object. */ -export const interceptGetMetricDefinitions = ( +export const mockGetMetricDefinitions = ( metricDefinitions: MetricDefinitions ): Cypress.Chainable => { return cy.intercept( @@ -36,7 +36,7 @@ export const interceptGetMetricDefinitions = ( * @returns {Cypress.Chainable} The chainable Cypress object. */ -export const interceptCloudPulseServices = ( +export const mockCloudPulseServices = ( service_type: string ): Cypress.Chainable => { return cy.intercept('GET', apiMatcher('**/monitor/services'), { @@ -52,7 +52,7 @@ export const interceptCloudPulseServices = ( * @returns {Cypress.Chainable} The chainable Cypress object. */ -export const interceptGetDashboards = ( +export const mockGetDashboards = ( dashboard: Dashboard ): Cypress.Chainable => { return cy.intercept( @@ -82,8 +82,8 @@ export const interceptMetricsRequests = () => { * @param {any} mockResponse - The mock response to return for the intercepted request. * @returns {Cypress.Chainable} The chainable Cypress object. */ -export const interceptCreateMetrics = ( - mockResponse: any +export const mockCreateMetrics = ( + mockResponse: AvailableMetrics ): Cypress.Chainable => { return cy.intercept( 'POST', From a29a798f184b57ad4fde5ced40b4f62e9df36c08 Mon Sep 17 00:00:00 2001 From: nikhagra Date: Wed, 11 Sep 2024 18:32:49 +0530 Subject: [PATCH 034/474] upcoming: [DI-20360] - Changes based on review comments --- .../CloudPulse/Overview/GlobalFilters.tsx | 17 +++--- .../CloudPulse/Utils/UserPreference.ts | 2 - .../components/CloudPulseIntervalSelect.tsx | 2 +- .../shared/CloudPulseCustomSelectUtils.ts | 56 +++++++------------ .../shared/CloudPulseDashboardSelect.test.tsx | 2 +- .../shared/CloudPulseDashboardSelect.tsx | 18 +++--- .../shared/CloudPulseRegionSelect.tsx | 19 +++---- .../shared/CloudPulseResourcesSelect.test.tsx | 2 +- .../shared/CloudPulseResourcesSelect.tsx | 2 +- .../shared/CloudPulseTimeRangeSelect.tsx | 3 +- .../manager/src/queries/cloudpulse/metrics.ts | 2 +- 11 files changed, 47 insertions(+), 78 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index 33ce50a894c..b8f0f64cb56 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -22,6 +22,8 @@ export interface GlobalFilterProperties { handleTimeDurationChange(timeDuration: TimeDuration): void; } +export interface FilterChangeProperties {} + export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { const { handleAnyFilterChange, @@ -46,7 +48,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { } handleTimeDurationChange(timerDuration); }, - [] + [updatePreferences] ); const onDashboardChange = React.useCallback( @@ -59,7 +61,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { setSelectedDashboard(dashboard); handleDashboardChange(dashboard); }, - [] + [updatePreferences] ); const emitFilterChange = React.useCallback( @@ -74,13 +76,10 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { } handleAnyFilterChange(filterKey, value); }, - [] + [updatePreferences] ); - const handleGlobalRefresh = React.useCallback((dashboardObj?: Dashboard) => { - if (!dashboardObj) { - return; - } + const handleGlobalRefresh = React.useCallback(() => { handleAnyFilterChange(REFRESH, Date.now()); }, []); @@ -100,7 +99,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { @@ -116,7 +115,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { marginBlockEnd: 'auto', }} disabled={!selectedDashboard} - onClick={() => handleGlobalRefresh(selectedDashboard)} + onClick={handleGlobalRefresh} size="small" > diff --git a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts index f5763a2647b..0353f0a896a 100644 --- a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts +++ b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts @@ -17,8 +17,6 @@ export const useAclpPreference = () => { const { mutateAsync: updateFunction } = useMutatePreferences(); - // const preferenceRef = useRef({ ...(preferences?.aclpPreference ?? {}) }); - /** * * @param data AclpConfig data to be updated in preferences diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx index eb375e74932..fb8c47e0755 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx @@ -133,7 +133,7 @@ export const CloudPulseIntervalSelect = React.memo( noMarginTop={true} options={[autoIntervalOption, ...available_interval_options]} sx={{ width: { xs: '100%' } }} - value={{ ...selectedInterval }} + value={selectedInterval} /> ); } diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts index aa1fd3b8396..6ed0d38649c 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts @@ -2,14 +2,12 @@ import type { FilterValueType } from '../Dashboard/CloudPulseDashboardLanding'; import type { CloudPulseServiceTypeFiltersOptions } from '../Utils/models'; import type { AclpConfig } from '@linode/api-v4'; -/** - * The interface for selecting the default value from the user preferences - */ -interface CloudPulseCustomSelectDefaultValueProps { +interface CloudPulseCustomSelectProps { /** - * The filter Key of the current rendered custom select component + * The current filter key of the rendered custom select component */ filterKey: string; + /** * The callback for the selection changes happening in the custom select component */ @@ -21,63 +19,47 @@ interface CloudPulseCustomSelectDefaultValueProps { ) => void; /** - * Indicates whether we need multiselect for the component or not + * Last selected values from user preference */ - isMultiSelect: boolean; + preferences?: AclpConfig; /** - * The current listed options in the custom select component + * boolean variable to check whether preferences should be saved or not */ - options: CloudPulseServiceTypeFiltersOptions[]; + savePreferences?: boolean; +} +/** + * The interface for selecting the default value from the user preferences + */ +interface CloudPulseCustomSelectDefaultValueProps + extends CloudPulseCustomSelectProps { /** - * Last selected values from user preference + * Indicates whether we need multiselect for the component or not */ - preferences?: AclpConfig; + isMultiSelect: boolean; /** - * Indicates whether we need to save preferences or not + * The current listed options in the custom select component */ - savePreferences?: boolean; + options: CloudPulseServiceTypeFiltersOptions[]; } /** * The interface of publishing the selection change and updating the user preferences accordingly */ -interface CloudPulseCustomSelectionChangeProps { +interface CloudPulseCustomSelectionChangeProps + extends CloudPulseCustomSelectProps { /** * The list of filters needs to be cleared on selections */ clearSelections: string[]; - /** - * The current filter key of the rendered custom select component - */ - filterKey: string; - /** - * The callback for the selection changes happening in the custom select component - */ - handleSelectionChange: ( - filterKey: string, - value: FilterValueType, - savePref?: boolean, - updatedPreferenceData?: {} - ) => void; /** * The maximum number of selections that needs to be allowed */ maxSelections?: number; - /** - * Last selected values from user preference - */ - preferences?: AclpConfig; - - /** - * boolean variable to check whether preferences should be saved or not - */ - savePreferences?: boolean; - /** * The listed options in the custom select component */ diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx index cdbe597e75a..d9377c3b14c 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx @@ -90,7 +90,7 @@ describe('CloudPulse Dashboard select', () => { ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index f0cf89aebae..a2bb84a762e 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -62,7 +62,7 @@ export const CloudPulseDashboardSelect = React.memo( // sorts dashboards by service type. Required due to unexpected autocomplete grouping behaviour const getSortedDashboardsList = (options: Dashboard[]): Dashboard[] => { - return options.sort( + return [...options].sort( (a, b) => -b.service_type.localeCompare(a.service_type) ); }; @@ -74,21 +74,17 @@ export const CloudPulseDashboardSelect = React.memo( dashboardsList.length > 0 && selectedDashboard === undefined ) { - if (defaultValue) { - const dashboard = dashboardsList.find( - (obj: Dashboard) => obj.id === defaultValue - ); - setSelectedDashboard(dashboard); - handleDashboardChange(dashboard); - } else { - handleDashboardChange(undefined); - } + const dashboard = defaultValue + ? dashboardsList.find((obj: Dashboard) => obj.id === defaultValue) + : undefined; + setSelectedDashboard(dashboard); + handleDashboardChange(dashboard); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [dashboardsList]); return ( { + onChange={(e, dashboard: Dashboard) => { setSelectedDashboard(dashboard); handleDashboardChange(dashboard, savePreferences); }} diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index b7ba7b9cbb6..f512169ae9d 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -32,14 +32,11 @@ export const CloudPulseRegionSelect = React.memo( const defaultRegion = preferences?.region; if (regions && savePreferences) { - if (defaultRegion) { - const region = regions.find((obj) => obj.id === defaultRegion)?.id; - handleRegionChange(region); - setSelectedRegion(region); - } else { - setSelectedRegion(undefined); - handleRegionChange(undefined); - } + const region = defaultRegion + ? regions.find((regionObj) => regionObj.id === defaultRegion)?.id + : undefined; + handleRegionChange(region); + setSelectedRegion(region); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [regions, selectedDashboard]); @@ -65,8 +62,6 @@ export const CloudPulseRegionSelect = React.memo( /> ); }, - ( - oldProps: CloudPulseRegionSelectProps, - newProps: CloudPulseRegionSelectProps - ) => oldProps.selectedDashboard?.id === newProps.selectedDashboard?.id + (prevProps, nextProps) => + prevProps.selectedDashboard?.id === nextProps.selectedDashboard?.id ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx index 6a256900de6..3c05f727de9 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx @@ -178,7 +178,7 @@ describe('CloudPulseResourcesSelect component tests', () => { preferences={{ [RESOURCES]: ['12'] }} region={'us-east'} resourceType={'linode'} - savePreferences={true} + savePreferences /> ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index e5c5e315a35..3b74a692108 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -82,7 +82,7 @@ export const CloudPulseResourcesSelect = React.memo( return ( { + onChange={(e, resourceSelections: CloudPulseResources[]) => { setSelectedResources(resourceSelections); handleResourcesSelection(resourceSelections, savePreferences); }} diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx index 4ea18f3a131..49d1bc4eada 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx @@ -78,11 +78,10 @@ export const CloudPulseTimeRangeSelect = React.memo( savePreferences ); } - setSelectedTimeRange(item); // update the state variable to retain latest selections }; return ( ) => { + onChange={(e, value: Item) => { handleChange(value); }} textFieldProps={{ diff --git a/packages/manager/src/queries/cloudpulse/metrics.ts b/packages/manager/src/queries/cloudpulse/metrics.ts index be599a9e32b..cc5e0fbe1c9 100644 --- a/packages/manager/src/queries/cloudpulse/metrics.ts +++ b/packages/manager/src/queries/cloudpulse/metrics.ts @@ -80,7 +80,7 @@ export const fetchCloudPulseMetrics = ( const config: AxiosRequestConfig = { data: requestData, headers: { - 'Authentication-type': 'jwe', + 'Authentication-Type': 'jwe', Authorization: `Bearer ${token}`, }, method: 'POST', From 0341fa9bb20496bf7a623ad36467adfa3a2bbba4 Mon Sep 17 00:00:00 2001 From: nikhagra Date: Wed, 11 Sep 2024 19:07:52 +0530 Subject: [PATCH 035/474] upcoming: [DI-20360] - Passing default values to components instead of full preference object --- .../CloudPulse/Overview/GlobalFilters.tsx | 2 -- .../CloudPulse/Utils/FilterBuilder.ts | 13 ++++--- .../CloudPulse/Widget/CloudPulseWidget.tsx | 33 +++++++++-------- .../shared/CloudPulseCustomSelect.tsx | 18 +++++----- .../shared/CloudPulseCustomSelectUtils.ts | 10 ++++-- .../shared/CloudPulseRegionSelect.tsx | 12 +++---- .../shared/CloudPulseResourcesSelect.tsx | 36 +++++++++---------- 7 files changed, 64 insertions(+), 60 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index b8f0f64cb56..57ceead4e9f 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -22,8 +22,6 @@ export interface GlobalFilterProperties { handleTimeDurationChange(timeDuration: TimeDuration): void; } -export interface FilterChangeProperties {} - export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { const { handleAnyFilterChange, diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts index 3da8496ad59..b48d139eaf0 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts @@ -1,4 +1,9 @@ -import { RELATIVE_TIME_DURATION, RESOURCE_ID, RESOURCES } from './constants'; +import { + REGION, + RELATIVE_TIME_DURATION, + RESOURCE_ID, + RESOURCES, +} from './constants'; import { FILTER_CONFIG } from './FilterConfig'; import { CloudPulseSelectTypes } from './models'; @@ -54,9 +59,9 @@ export const getRegionProperties = ( const { placeholder } = props.config.configuration; const { dashboard, isServiceAnalyticsIntegration, preferences } = props; return { + defaultValue: preferences?.[REGION], handleRegionChange, placeholder, - preferences, savePreferences: !isServiceAnalyticsIntegration, selectedDashboard: dashboard, }; @@ -88,6 +93,7 @@ export const getResourcesProperties = ( preferences, } = props; return { + defaultValue: preferences?.[RESOURCES], disabled: checkIfWeNeedToDisableFilterByFilterKey( filterKey, dependentFilters ?? {}, @@ -95,7 +101,6 @@ export const getResourcesProperties = ( ), handleResourcesSelection: handleResourceChange, placeholder, - preferences, resourceType: dashboard.service_type, savePreferences: !isServiceAnalyticsIntegration, xFilter: buildXFilter(config, dependentFilters ?? {}), @@ -141,6 +146,7 @@ export const getCustomSelectProperties = ( filterKey, dashboard ), + defaultValue: preferences?.[filterKey], disabled: checkIfWeNeedToDisableFilterByFilterKey( filterKey, dependentFilters ?? {}, @@ -153,7 +159,6 @@ export const getCustomSelectProperties = ( maxSelections, options, placeholder, - preferences, savePreferences: !isServiceAnalyticsIntegration, type: options ? CloudPulseSelectTypes.static diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index c992f283468..d225d969cb4 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -144,20 +144,23 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { * * @param zoomInValue: True if zoom in clicked & False if zoom out icon clicked */ - const handleZoomToggle = React.useCallback((zoomInValue: boolean) => { - if (savePref) { - updatePreferences(widget.label, { - [SIZE]: zoomInValue ? 12 : 6, - }); - } + const handleZoomToggle = React.useCallback( + (zoomInValue: boolean) => { + if (savePref) { + updatePreferences(widget.label, { + [SIZE]: zoomInValue ? 12 : 6, + }); + } - setWidget((currentWidget: Widgets) => { - return { - ...currentWidget, - size: zoomInValue ? 12 : 6, - }; - }); - }, []); + setWidget((currentWidget: Widgets) => { + return { + ...currentWidget, + size: zoomInValue ? 12 : 6, + }; + }); + }, + [updatePreferences] + ); /** * @@ -180,7 +183,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { }; }); }, - [] + [updatePreferences] ); /** @@ -202,7 +205,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { }; }); }, - [] + [updatePreferences] ); const { diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index 5cf60b17651..732e7c0898b 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -14,7 +14,7 @@ import type { CloudPulseServiceTypeFiltersOptions, QueryFunctionAndKey, } from '../Utils/models'; -import type { AclpConfig } from '@linode/api-v4'; +import type { FilterValue } from '@linode/api-v4'; /** * These are the properties requires for CloudPulseCustomSelect Components @@ -41,6 +41,11 @@ export interface CloudPulseCustomSelectProps { */ clearDependentSelections?: string[]; + /** + * Last selected values from user preferences + */ + defaultValue?: FilterValue; + /** * This property says, whether or not to disable the selection component */ @@ -60,7 +65,6 @@ export interface CloudPulseCustomSelectProps { * The type of the filter like string, number etc., */ filterType: string; - /** * The callback function , that will be called on a filter change * @param filterKey - The filterKey of the component @@ -72,6 +76,7 @@ export interface CloudPulseCustomSelectProps { savePref?: boolean, updatedPreferenceData?: {} ) => void; + /** * If true, multiselect is allowed, otherwise false */ @@ -92,11 +97,6 @@ export interface CloudPulseCustomSelectProps { */ placeholder?: string; - /** - * Last selected values from user preferences - */ - preferences?: AclpConfig; - /** * This property controls whether to save the preferences or not */ @@ -120,6 +120,7 @@ export const CloudPulseCustomSelect = React.memo( apiResponseLabelField, apiV4QueryKey, clearDependentSelections, + defaultValue, disabled, filterKey, handleSelectionChange, @@ -127,7 +128,6 @@ export const CloudPulseCustomSelect = React.memo( maxSelections, options, placeholder, - preferences, savePreferences, type, } = props; @@ -154,11 +154,11 @@ export const CloudPulseCustomSelect = React.memo( if (!selectedResource) { setResource( getInitialDefaultSelections({ + defaultValue, filterKey, handleSelectionChange, isMultiSelect: isMultiSelect ?? false, options: options || queriedResources || [], - preferences, savePreferences: savePreferences ?? false, }) ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts index 6ed0d38649c..04d5bd23d4e 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts @@ -1,6 +1,6 @@ import type { FilterValueType } from '../Dashboard/CloudPulseDashboardLanding'; import type { CloudPulseServiceTypeFiltersOptions } from '../Utils/models'; -import type { AclpConfig } from '@linode/api-v4'; +import type { AclpConfig, FilterValue } from '@linode/api-v4'; interface CloudPulseCustomSelectProps { /** @@ -34,6 +34,11 @@ interface CloudPulseCustomSelectProps { */ interface CloudPulseCustomSelectDefaultValueProps extends CloudPulseCustomSelectProps { + /** + * Default selected value from the drop down + */ + defaultValue?: FilterValue; + /** * Indicates whether we need multiselect for the component or not */ @@ -80,15 +85,14 @@ export const getInitialDefaultSelections = ( | CloudPulseServiceTypeFiltersOptions[] | undefined => { const { + defaultValue, filterKey, handleSelectionChange, isMultiSelect, options, - preferences, savePreferences, } = defaultSelectionProps; - const defaultValue = savePreferences ? preferences?.[filterKey] : undefined; if (!options || options.length === 0) { return isMultiSelect ? [] : undefined; } diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index f512169ae9d..0b2f085bcb9 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -3,12 +3,12 @@ import * as React from 'react'; import { RegionSelect } from 'src/components/RegionSelect/RegionSelect'; import { useRegionsQuery } from 'src/queries/regions/regions'; -import type { AclpConfig, Dashboard } from '@linode/api-v4'; +import type { Dashboard, FilterValue } from '@linode/api-v4'; export interface CloudPulseRegionSelectProps { + defaultValue?: FilterValue; handleRegionChange: (region: string | undefined, savePref?: boolean) => void; placeholder?: string; - preferences?: AclpConfig; savePreferences?: boolean; selectedDashboard: Dashboard | undefined; } @@ -18,9 +18,9 @@ export const CloudPulseRegionSelect = React.memo( const { data: regions } = useRegionsQuery(); const { + defaultValue, handleRegionChange, placeholder, - preferences, savePreferences, selectedDashboard, } = props; @@ -29,11 +29,9 @@ export const CloudPulseRegionSelect = React.memo( // Once the data is loaded, set the state variable with value stored in preferences React.useEffect(() => { - const defaultRegion = preferences?.region; - if (regions && savePreferences) { - const region = defaultRegion - ? regions.find((regionObj) => regionObj.id === defaultRegion)?.id + const region = defaultValue + ? regions.find((regionObj) => regionObj.id === defaultValue)?.id : undefined; handleRegionChange(region); setSelectedRegion(region); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index 3b74a692108..f6afef81fbc 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -5,7 +5,7 @@ import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; import { useResourcesQuery } from 'src/queries/cloudpulse/resources'; import { themes } from 'src/utilities/theme'; -import type { AclpConfig, Filter } from '@linode/api-v4'; +import type { Filter, FilterValue } from '@linode/api-v4'; export interface CloudPulseResources { id: string; @@ -14,13 +14,13 @@ export interface CloudPulseResources { } export interface CloudPulseResourcesSelectProps { + defaultValue?: FilterValue; disabled?: boolean; handleResourcesSelection: ( resources: CloudPulseResources[], savePref?: boolean ) => void; placeholder?: string; - preferences?: AclpConfig; region?: string; resourceType: string | undefined; savePreferences?: boolean; @@ -30,10 +30,10 @@ export interface CloudPulseResourcesSelectProps { export const CloudPulseResourcesSelect = React.memo( (props: CloudPulseResourcesSelectProps) => { const { + defaultValue, disabled, handleResourcesSelection, placeholder, - preferences, region, resourceType, savePreferences, @@ -57,26 +57,22 @@ export const CloudPulseResourcesSelect = React.memo( // Once the data is loaded, set the state variable with value stored in preferences React.useEffect(() => { - const defaultValue = preferences?.resources; if (resources && savePreferences && !selectedResources) { - if (defaultValue && Array.isArray(defaultValue)) { - const defaultResources = defaultValue.map((resource) => - String(resource) - ); - const resource = getResourcesList().filter((resource) => - defaultResources.includes(String(resource.id)) - ); - - handleResourcesSelection(resource); - setSelectedResources(resource); - } else { - setSelectedResources([]); - handleResourcesSelection([]); - } - } else if (selectedResources) { - handleResourcesSelection([]); + const defaultResources = + defaultValue && Array.isArray(defaultValue) + ? defaultValue.map((resource) => String(resource)) + : []; + const resource = getResourcesList().filter((resource) => + defaultResources.includes(String(resource.id)) + ); + + handleResourcesSelection(resource); + setSelectedResources(resource); + } else { setSelectedResources([]); + handleResourcesSelection([]); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [resources]); From 3682243f111dbd4a6fc952dc9f7a7f216584bf71 Mon Sep 17 00:00:00 2001 From: nikhagra Date: Wed, 11 Sep 2024 19:30:27 +0530 Subject: [PATCH 036/474] upcoming: [DI-20360] - Upddated widget components to avoid infinite loop --- .../CloudPulse/Overview/GlobalFilters.tsx | 3 +-- .../components/CloudPulseAggregateFunction.tsx | 3 ++- .../components/CloudPulseIntervalSelect.tsx | 3 ++- .../CloudPulse/Widget/components/Zoomer.tsx | 15 +++++++++------ .../shared/CloudPulseResourcesSelect.tsx | 1 - 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index 57ceead4e9f..f713b659cb1 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -9,8 +9,7 @@ import { Divider } from 'src/components/Divider'; import { CloudPulseDashboardFilterBuilder } from '../shared/CloudPulseDashboardFilterBuilder'; import { CloudPulseDashboardSelect } from '../shared/CloudPulseDashboardSelect'; import { CloudPulseTimeRangeSelect } from '../shared/CloudPulseTimeRangeSelect'; -import { REFRESH } from '../Utils/constants'; -import { DASHBOARD_ID, TIME_DURATION } from '../Utils/constants'; +import { DASHBOARD_ID, REFRESH, TIME_DURATION } from '../Utils/constants'; import { useAclpPreference } from '../Utils/UserPreference'; import type { FilterValueType } from '../Dashboard/CloudPulseDashboardLanding'; diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx index bc38cedf805..e1dd4b9f83f 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx @@ -67,5 +67,6 @@ export const CloudPulseAggregateFunction = React.memo( value={selectedAggregateFunction} /> ); - } + }, + () => true ); diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx index fb8c47e0755..94ca198048e 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx @@ -136,5 +136,6 @@ export const CloudPulseIntervalSelect = React.memo( value={selectedInterval} /> ); - } + }, + () => true ); diff --git a/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx b/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx index 6ed093ed513..5f0f3d11d3e 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx @@ -8,10 +8,11 @@ export interface ZoomIconProperties { zoomIn: boolean; } -export const ZoomIcon = React.memo((props: ZoomIconProperties) => { - const handleClick = (needZoomIn: boolean) => { - props.handleZoomToggle(needZoomIn); - }; +export const ZoomIcon = React.memo( + (props: ZoomIconProperties) => { + const handleClick = (needZoomIn: boolean) => { + props.handleZoomToggle(needZoomIn); + }; const ToggleZoomer = () => { if (props.zoomIn) { @@ -33,5 +34,7 @@ export const ZoomIcon = React.memo((props: ZoomIconProperties) => { ); }; - return ; -}); + return ; + }, + (prevProps, nextProps) => prevProps.zoomIn === nextProps.zoomIn +); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index f6afef81fbc..13f3b72c0af 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -69,7 +69,6 @@ export const CloudPulseResourcesSelect = React.memo( handleResourcesSelection(resource); setSelectedResources(resource); } else { - setSelectedResources([]); handleResourcesSelection([]); } From 7d67c8ec8748801f11e1200429ebe74c48df0486 Mon Sep 17 00:00:00 2001 From: agorthi Date: Thu, 12 Sep 2024 15:08:29 +0530 Subject: [PATCH 037/474] upcoming:[DI-20585]- renaming intercept methods to mocks --- .../linode-widget-verification.spec.ts | 142 +++++++++------- .../support/constants/widget-service.ts | 151 ++++++++++-------- .../intercepts/cloudpulseAPIHandler.ts | 83 ++++++---- .../manager/cypress/support/ui/cloudpulse.ts | 20 +-- .../cypress/support/util/cloudpulse.ts | 3 - .../Dashboard/CloudPulseDashboard.tsx | 2 +- 6 files changed, 231 insertions(+), 170 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index b15c8a40f83..6cf178857a0 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -3,18 +3,17 @@ import { selectServiceName, selectAndVerifyResource, assertSelections, - waitForElementToLoad, } from 'support/util/cloudpulse'; import { mockAppendFeatureFlags, mockGetFeatureFlagClientstream, } from 'support/intercepts/feature-flags'; import { - mockJWSToken, - mockLinodeDashboardServicesResponse, - mockCreateMetrics, - mockGetDashboards, - mockGetMetricDefinitions, + mockCloudPulseJWSToken, + mockCloudPulseDashboardServicesResponse, + mockCloudPulseCreateMetrics, + mockCloudPulseGetDashboards, + mockCloudPulseGetMetricDefinitions, mockCloudPulseServices, } from 'support/intercepts/cloudpulseAPIHandler'; import { ui } from 'support/ui'; @@ -39,17 +38,8 @@ import { mockGetUserPreferences } from 'support/intercepts/profile'; * Testing widget interactions, including zooming and filtering, to ensure proper behavior. * Each test ensures that widgets on the dashboard operate correctly and display accurate information. */ -export const dashboardName = 'Linode Dashboard'; -export const region = 'US, Chicago, IL (us-ord)'; -export const actualRelativeTimeDuration = timeRange.Last24Hours; -export const resource = 'test1'; -const mockKubeLinode = kubeLinodeFactory.build(); -const mockLinode = linodeFactory.build({ - label: resource, - id: mockKubeLinode.instance_id ?? undefined, -}); -const mockAccount = accountFactory.build(); + const y_labels = [ 'system_cpu_utilization_ratio', @@ -57,13 +47,24 @@ const y_labels = [ 'system_network_io_bytes_total', 'system_disk_operations_total', ]; -const linodeWidgets = widgetDetails.linode; -const widgetLabels: string[] = linodeWidgets.map(widget => widget.title); -const metricsLabels: string[] = linodeWidgets.map(widget => widget.name); -const service_type='linode'; - +const widgets= widgetDetails.linode; +const metrics =widgets.metrics; +export const dashboardName = widgets.dashboardName; +export const region = widgets.region; +export const actualRelativeTimeDuration = timeRange.Last24Hours; +export const resource = widgets.resource +const widgetLabels: string[] = metrics.map(widget => widget.title); +const metricsLabels: string[] = metrics.map(widget => widget.name); +const service_type =widgets.service_type; +const dashboardId=widgets.id const dashboard = dashboardFactory(dashboardName, widgetLabels, metricsLabels, y_labels,service_type).build(); const metricDefinitions = metricDefinitionsFactory(widgetLabels, metricsLabels).build(); +const mockKubeLinode = kubeLinodeFactory.build(); +const mockLinode = linodeFactory.build({ + label: resource, + id: mockKubeLinode.instance_id ?? undefined, +}); +const mockAccount = accountFactory.build(); describe('Dashboard Widget Verification Tests', () => { beforeEach(() => { @@ -73,13 +74,13 @@ describe('Dashboard Widget Verification Tests', () => { mockGetAccount(mockAccount).as('getAccount'); // Enables the account to have capability for Akamai Cloud Pulse mockGetFeatureFlagClientstream().as('getClientStream'); mockGetLinodes([mockLinode]).as('getLinodes'); - mockGetMetricDefinitions(metricDefinitions); - mockGetDashboards(dashboard).as('dashboard'); - mockCloudPulseServices('linode').as('services'); - mockLinodeDashboardServicesResponse(dashboard); - mockJWSToken(); + mockCloudPulseGetMetricDefinitions(metricDefinitions,service_type); + mockCloudPulseGetDashboards(dashboard,service_type).as('dashboard'); + mockCloudPulseServices(service_type).as('services'); + mockCloudPulseDashboardServicesResponse(dashboard,dashboardId); + mockCloudPulseJWSToken(service_type); const responsePayload = createMetricResponse(actualRelativeTimeDuration, granularity.Min5); - mockCreateMetrics(responsePayload).as('metricAPI'); + mockCloudPulseCreateMetrics(responsePayload,service_type).as('getMetrics'); }); it('should verify cloudpulse availability when feature flag is set to false', () => { @@ -91,12 +92,11 @@ describe('Dashboard Widget Verification Tests', () => { cy.findByText('Not Found').should('be.visible'); // not found }); - it.only('should set available granularity of all the widgets', () => { + it('should set available granularity of all the widgets', () => { setupMethod() - linodeWidgets.forEach((testData) => { + metrics.forEach((testData) => { cy.wait(5000); const widgetSelector = `[data-qa-widget="${testData.title}"]`; - waitForElementToLoad(widgetSelector); cy.get(widgetSelector).as('widget') cy.get('@widget') .should('be.visible') @@ -111,7 +111,9 @@ describe('Dashboard Widget Verification Tests', () => { .findByTitle(testData.expectedGranularity).as('granularityOption') cy.get('@granularityOption') .should('be.visible') + .should('have.text', testData.expectedGranularity) .click(); + cy.findByDisplayValue(testData.expectedGranularity).should('exist'); assertSelections(testData.expectedGranularity); }); }); @@ -119,17 +121,17 @@ describe('Dashboard Widget Verification Tests', () => { it('should verify the title of the widget', () => { setupMethod() - linodeWidgets.forEach((testData) => { + metrics.forEach((testData) => { const widgetSelector = `[data-qa-widget-header="${testData.title}"]`; cy.get(widgetSelector).invoke('text').then((text) => { - expect(text.trim()).to.equal(testData.title); + expect(text.trim()).to.equal(testData.title); }); }); }); it('should set available aggregation of all the widgets', () => { setupMethod() - linodeWidgets.forEach((testData) => { + metrics.forEach((testData) => { cy.wait(5000); const widgetSelector = `[data-qa-widget="${testData.title}"]`; cy.get(widgetSelector) @@ -138,12 +140,15 @@ describe('Dashboard Widget Verification Tests', () => { .within(() => { ui.autocomplete .findByTitleCustom('Select an Aggregate Function') + .should('be.visible') .findByTitle('Open') .click(); ui.autocompletePopper .findByTitle(testData.expectedAggregation) .should('be.visible') + .should('have.text', testData.expectedAggregation) .click(); + cy.findByDisplayValue(testData.expectedAggregation).should('exist'); assertSelections(testData.expectedAggregation); }); }); @@ -151,7 +156,7 @@ describe('Dashboard Widget Verification Tests', () => { it('should verify available granularity of the widget', () => { setupMethod() - linodeWidgets.forEach((testData) => { + metrics.forEach((testData) => { cy.wait(5000); const widgetSelector = `[data-qa-widget="${testData.title}"]`; cy.get(widgetSelector) @@ -166,13 +171,12 @@ describe('Dashboard Widget Verification Tests', () => { ui.autocompletePopper .findByTitle(option) .should('be.visible') - .then(() => { - cy.log(`${option} is visible`); - }); }); ui.autocomplete .findByTitleCustom('Select an Interval') + .should('be.visible') .findByTitle('Close') + .should('be.visible') .click(); }); }); @@ -180,7 +184,7 @@ describe('Dashboard Widget Verification Tests', () => { it('should verify available aggregation of the widget', () => { setupMethod() - linodeWidgets.forEach((testData) => { + metrics.forEach((testData) => { cy.wait(5000); const widgetSelector = `[data-qa-widget="${testData.title}"]`; cy.get(widgetSelector) @@ -196,13 +200,12 @@ describe('Dashboard Widget Verification Tests', () => { ui.autocompletePopper .findByTitle(option) .should('be.visible') - .then(() => { - cy.log(`${option} is visible`); - }); }); ui.autocomplete .findByTitleCustom('Select an Aggregate Function') + .should('be.visible') .findByTitle('Close') + .should('be.visible') .click(); }); }); @@ -210,37 +213,58 @@ describe('Dashboard Widget Verification Tests', () => { it('should zoom in and out of all the widgets', () => { setupMethod() - linodeWidgets.forEach((testData) => { + metrics.forEach((testData) => { cy.wait(5000); - const widgetSelector = `[data-qa-widget="${testData.title}"]`; - cy.log("Name of the widget **",testData.title); - cy.get(widgetSelector).should('be.visible').within(() => { - cy.get(ui.cloudpulse.findZoomButtonByTitle('zoom-out')).should('be.visible') + cy.get(`[data-qa-widget="${testData.title}"]`).as('widget'); + cy.get('@widget').should('be.visible').within(() => { + ui.cloudpulse.findZoomButtonByTitle('zoom-in').should('be.visible') .should('be.enabled') .click(); - cy.get(ui.cloudpulse.findZoomButtonByTitle('zoom-in')).should('be.visible') + cy.get('@widget').should('be.visible'); + cy.get('[data-testid="linegraph-wrapper"] canvas').as('canvas') + .should('exist') + .and('be.visible'); + ui.cloudpulse.findZoomButtonByTitle('zoom-out').should('be.visible') .should('be.enabled') .click(); + cy.get('@widget').should('be.visible'); + cy.get('@canvas').should('exist').and('be.visible'); }); }); }); - + it('should apply global refresh button and verify network calls', () => { - setupMethod() - ui.cloudpulse.findRefreshIcon() - .should('be.visible') - .click(); - linodeWidgets.forEach((widget) => { - const widgetSelector = `[data-qa-widget="${widget.title}"]`; - cy.get(widgetSelector) - .should('be.visible') - .and('contain.text', widget.title); + setupMethod(); + + ui.cloudpulse.findRefreshIcon().should('be.visible').click(); + + cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']).then((interceptions) => { + const interceptionsArray = Array.isArray(interceptions) ? interceptions : [interceptions]; + + interceptionsArray.forEach((interception) => { + const { body: requestPayload } = interception.request; + const { metric, time_granularity: granularity, relative_time_duration: timeRange, aggregate_function: aggregateFunction } = requestPayload; + const metricData = metrics.find(data => data.name === metric); + // Check if metricData and its expected properties are available + if (!metricData || !metricData.expectedGranularity || !metricData.expectedAggregation) { + expect.fail('metricData or its expected properties are not defined.'); + } + const expectedRelativeTimeDuration = timeRange + ? `Last ${timeRange.value} ${['hour', 'hr'].includes(timeRange.unit.toLowerCase()) ? 'Hours' : timeRange.unit}` + : ''; + const currentGranularity = granularity + ? `${granularity.value} ${['hour', 'hours'].includes(granularity.unit.toLowerCase()) ? 'hr' : granularity.unit}` + : ''; + expect(metric).to.equal(metricData.name); + expect(currentGranularity).to.equal(metricData.expectedGranularity); + expect(expectedRelativeTimeDuration).to.equal(actualRelativeTimeDuration); + // expect(aggregateFunction).to.equal(metricData.expectedAggregation); + }); }); - }); }); - + const setupMethod = () => { mockGetUserPreferences({}).as('getUserPreferences'); diff --git a/packages/manager/cypress/support/constants/widget-service.ts b/packages/manager/cypress/support/constants/widget-service.ts index b40feca2b63..478de6568cf 100644 --- a/packages/manager/cypress/support/constants/widget-service.ts +++ b/packages/manager/cypress/support/constants/widget-service.ts @@ -1,3 +1,4 @@ + /** * Defines the granularity levels used for specifying time intervals in data aggregation or reporting. * Each property represents a different granularity level. @@ -52,72 +53,86 @@ export const aggregationConfig = { * Each widget configuration includes expected aggregation types, granularity levels, and other relevant properties. */ export const widgetDetails = { - dbaas: [ - { - expectedAggregation: aggregation.Max, - expectedAggregationArray: aggregationConfig.basic, - expectedGranularity: granularity.Hr1, - expectedGranularityArray: Object.values(granularity), - name: 'system_cpu_utilization_percent', - title: 'CPU Utilization', - }, - { - expectedAggregation: aggregation.Max, - expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hr1, - expectedGranularityArray: Object.values(granularity), - name: 'system_memory_usage_by_resource', - title: 'Memory Usage', - }, - { - expectedAggregation: aggregation.Max, - expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hr1, - expectedGranularityArray: Object.values(granularity), - name: 'system_network_io_by_resource', - title: 'Network Traffic', - }, - { - expectedAggregation: aggregation.Max, - expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hr1, - expectedGranularityArray: Object.values(granularity), - name: 'system_disk_OPS_total', - title: 'Disk I/O', - }, - ], - linode: [ - { - expectedAggregation: aggregation.Max, - expectedAggregationArray: aggregationConfig.basic, - expectedGranularity: granularity.Hr1, - expectedGranularityArray: Object.values(granularity), - name: 'system_cpu_utilization_percent', - title: 'CPU Utilization', - }, - { - expectedAggregation: aggregation.Max, - expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hr1, - expectedGranularityArray: Object.values(granularity), - name: 'system_memory_usage_by_resource', - title: 'Memory Usage', - }, - { - expectedAggregation: aggregation.Max, - expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hr1, - expectedGranularityArray: Object.values(granularity), - name: 'system_network_io_by_resource', - title: 'Network Traffic', - }, - { - expectedAggregation: aggregation.Max, - expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hr1, - expectedGranularityArray: Object.values(granularity), - name: 'system_disk_OPS_total', - title: 'Disk I/O', - }, - ], + dbaas: { + dashboardName: 'Dbaas Dashboard', + id: 2, + metrics: [ + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.basic, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_cpu_utilization_percent', + title: 'CPU Utilization', + }, + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.all, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_memory_usage_by_resource', + title: 'Memory Usage', + }, + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.all, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_network_io_by_resource', + title: 'Network Traffic', + }, + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.all, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_disk_OPS_total', + title: 'Disk I/O', + }, + ], + region: 'US, Chicago, IL (us-ord)', + resource: 'Dbaas-resource', + service_type: 'dbaas', + }, + linode: { + dashboardName: 'Linode Dashboard', + id: 1, + metrics: [ + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.basic, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_cpu_utilization_percent', + title: 'CPU Utilization', + }, + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.all, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_memory_usage_by_resource', + title: 'Memory Usage', + }, + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.all, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_network_io_by_resource', + title: 'Network Traffic', + }, + { + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.all, + expectedGranularity: granularity.Hr1, + expectedGranularityArray: Object.values(granularity), + name: 'system_disk_OPS_total', + title: 'Disk I/O', + }, + ], + region: 'US, Chicago, IL (us-ord)', + resource: 'linode-resource', + service_type: 'linode', + }, }; diff --git a/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts b/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts index 5a28e3a3b72..8ffca859904 100644 --- a/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts +++ b/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts @@ -6,7 +6,11 @@ import { apiMatcher } from 'support/util/intercepts'; -import type { AvailableMetrics, Dashboard, MetricDefinitions } from '@linode/api-v4'; +import type { + AvailableMetrics, + Dashboard, + MetricDefinitions, +} from '@linode/api-v4'; /** * Intercepts HTTP GET requests for metric definitions. @@ -17,12 +21,13 @@ import type { AvailableMetrics, Dashboard, MetricDefinitions } from '@linode/api * @returns {Cypress.Chainable} The chainable Cypress object. */ -export const mockGetMetricDefinitions = ( - metricDefinitions: MetricDefinitions +export const mockCloudPulseGetMetricDefinitions = ( + metricDefinitions: MetricDefinitions, + service_type: string ): Cypress.Chainable => { return cy.intercept( 'GET', - apiMatcher('**/monitor/services/linode/metric-definitions'), + apiMatcher(`/monitor/services/${service_type}/metric-definitions`), metricDefinitions ); }; @@ -39,7 +44,7 @@ export const mockGetMetricDefinitions = ( export const mockCloudPulseServices = ( service_type: string ): Cypress.Chainable => { - return cy.intercept('GET', apiMatcher('**/monitor/services'), { + return cy.intercept('GET', apiMatcher('/monitor/services'), { data: [{ service_type }], }); }; @@ -52,28 +57,17 @@ export const mockCloudPulseServices = ( * @returns {Cypress.Chainable} The chainable Cypress object. */ -export const mockGetDashboards = ( - dashboard: Dashboard +export const mockCloudPulseGetDashboards = ( + dashboard: Dashboard, + service_type: string ): Cypress.Chainable => { return cy.intercept( 'GET', - apiMatcher('**/monitor/services/linode/dashboards'), + apiMatcher(`/monitor/services/${service_type}/dashboards`), { data: [dashboard] } ); }; -/** - * Sets up an intercept for POST requests to the metrics endpoint. - * - * and assign an alias of 'getMetrics' to the intercepted request. - * - * @returns {void} - */ -export const interceptMetricsRequests = () => { - cy.intercept({ - method: 'POST', - url: '**/monitor/services/linode/metrics', - }).as('getMetrics'); -}; + /** * Intercepts POST requests to the metrics endpoint with a custom mock response. * @@ -82,28 +76,59 @@ export const interceptMetricsRequests = () => { * @param {any} mockResponse - The mock response to return for the intercepted request. * @returns {Cypress.Chainable} The chainable Cypress object. */ -export const mockCreateMetrics = ( - mockResponse: AvailableMetrics +export const mockCloudPulseCreateMetrics = ( + mockResponse: AvailableMetrics, + service_type: string ): Cypress.Chainable => { return cy.intercept( 'POST', - '**/monitor/services/linode/metrics', + `**/monitor/services/${service_type}/metrics`, mockResponse ); }; +/** + * Mocks the API response for fetching a dashboard. + * + * This function uses Cypress's `cy.intercept` to intercept GET requests to a specific API endpoint + * and return a mock response. This is useful for testing how your application handles various + * responses without making actual network requests. + * + * @param {Dashboard} dashboard - The mock response data to return for the dashboard request. + * @param {number} id - The ID of the dashboard to mock the response for. + * @returns {Cypress.Chainable} - Returns a Cypress chainable object, allowing for command chaining in tests. + */ -export const mockLinodeDashboardServicesResponse = ( - dashboard: Dashboard +export const mockCloudPulseDashboardServicesResponse = ( + dashboard: Dashboard, + id: number ): Cypress.Chainable => { - return cy.intercept('GET', apiMatcher('**/monitor/dashboards/1'), dashboard); + return cy.intercept( + 'GET', + apiMatcher(`/monitor/dashboards/${id}`), + dashboard + ); }; + +/** + * Mocks the API response for generating a JWT token for a specific service. + * + * This function sets up an interception for POST requests to the endpoint that generates + * JWT tokens for a particular service type. By returning a mock JWT token, you can test + * how your application handles authentication and authorization without making actual network + * requests to the backend service. + * + * @param {string} service_type - The type of service for which to mock the JWT token request. + * @returns {Cypress.Chainable} - Returns a Cypress chainable object, enabling command chaining in tests. + */ const JWSToken = { token: 'eyJhbGciOiAiZGlyIiwgImVuYyI6ICJBMTI4Q0JDLUhTMjU2IiwgImtpZCI6ID', }; -export const mockJWSToken = (): Cypress.Chainable => { +export const mockCloudPulseJWSToken = ( + service_type: string +): Cypress.Chainable => { return cy.intercept( 'POST', - apiMatcher('**/monitor/services/linode/token'), + apiMatcher(`/monitor/services/${service_type}/token`), JWSToken ); }; diff --git a/packages/manager/cypress/support/ui/cloudpulse.ts b/packages/manager/cypress/support/ui/cloudpulse.ts index 02f6e3115eb..069bfb48d59 100644 --- a/packages/manager/cypress/support/ui/cloudpulse.ts +++ b/packages/manager/cypress/support/ui/cloudpulse.ts @@ -12,15 +12,15 @@ export const cloudpulse = { return cy.get('[data-qa-refresh-button="true"]'); }, - /** - * Generates a selector for a zoom button within a button group based on its title. - * This method helps in locating specific zoom buttons by their title attribute within a group of buttons. - * - * @param {string} buttonTitle - The title of the zoom button to find. - * - * @returns {string} - A string representing the CSS selector for the zoom button. - */ - findZoomButtonByTitle: (buttonTitle: string): string => { - return `[data-qa-zoomer="${buttonTitle}"]`; +/** + * Generates a Cypress chainable for a zoom button based on its title. + * This method helps in locating specific zoom buttons by their title attribute within a group of buttons. + * + * @param {string} buttonTitle - The title of the zoom button to find. + * + * @returns {Cypress.Chainable} - A Cypress chainable that represents the zoom button element. + */ + findZoomButtonByTitle: (buttonTitle: string): Cypress.Chainable => { + return cy.get(`[data-qa-zoomer="${buttonTitle}"]`); }, }; diff --git a/packages/manager/cypress/support/util/cloudpulse.ts b/packages/manager/cypress/support/util/cloudpulse.ts index b339f61f01f..1d41124a4a4 100644 --- a/packages/manager/cypress/support/util/cloudpulse.ts +++ b/packages/manager/cypress/support/util/cloudpulse.ts @@ -22,9 +22,6 @@ import { ui } from 'support/ui'; * @param {string} selector - The CSS selector for the element to wait for. */ // command to wait for the element to be fully loaded -export const waitForElementToLoad = (selector: string) => { - cy.get(selector, { timeout: 10000 }).should('be.visible'); -}; export const selectServiceName = (serviceName: string) => { ui.autocomplete diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index 3d010993877..f47cb4c29d2 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -115,7 +115,7 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { if (pref) { Object.assign(widgetObj, { aggregate_function: pref.aggregateFunction, - size: pref.size, + size: pref.size ?? widgetObj.size, time_granularity: { ...pref.timeGranularity }, }); } From 6098181872900dc8842e959ab0f183683fb68822 Mon Sep 17 00:00:00 2001 From: agorthi Date: Thu, 12 Sep 2024 19:43:38 +0530 Subject: [PATCH 038/474] upcoming:[DI-20585]- renaming intercept methods to mocks --- .../linode-widget-verification.spec.ts | 4 ++-- .../cypress/support/constants/widget-service.ts | 3 ++- .../manager/cypress/support/util/cloudpulse.ts | 16 ++++++++++++++++ packages/manager/src/factories/dashboards.ts | 16 +++++++++++++++- 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 6cf178857a0..642e6caeaa3 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -21,7 +21,7 @@ import { timeRange, widgetDetails, granularity } from 'support/constants/widget- import { makeFeatureFlagData } from 'support/util/feature-flags'; import { createMetricResponse } from '@src/factories/widget'; import type { Flags } from 'src/featureFlags'; -import { accountFactory, dashboardFactory, kubeLinodeFactory, linodeFactory, metricDefinitionsFactory } from 'src/factories'; +import { accountFactory, extendedDashboardFactory, kubeLinodeFactory, linodeFactory, metricDefinitionsFactory } from 'src/factories'; import { mockGetAccount } from 'support/intercepts/account'; import { mockGetLinodes } from 'support/intercepts/linodes'; import { mockGetUserPreferences } from 'support/intercepts/profile'; @@ -57,7 +57,7 @@ const widgetLabels: string[] = metrics.map(widget => widget.title); const metricsLabels: string[] = metrics.map(widget => widget.name); const service_type =widgets.service_type; const dashboardId=widgets.id -const dashboard = dashboardFactory(dashboardName, widgetLabels, metricsLabels, y_labels,service_type).build(); +const dashboard = extendedDashboardFactory(dashboardName, widgetLabels, metricsLabels, y_labels,service_type).build(); const metricDefinitions = metricDefinitionsFactory(widgetLabels, metricsLabels).build(); const mockKubeLinode = kubeLinodeFactory.build(); const mockLinode = linodeFactory.build({ diff --git a/packages/manager/cypress/support/constants/widget-service.ts b/packages/manager/cypress/support/constants/widget-service.ts index 478de6568cf..b2335749f82 100644 --- a/packages/manager/cypress/support/constants/widget-service.ts +++ b/packages/manager/cypress/support/constants/widget-service.ts @@ -1,4 +1,3 @@ - /** * Defines the granularity levels used for specifying time intervals in data aggregation or reporting. * Each property represents a different granularity level. @@ -54,7 +53,9 @@ export const aggregationConfig = { */ export const widgetDetails = { dbaas: { + cluster: 'mysql-cluster', dashboardName: 'Dbaas Dashboard', + engine: 'mysql', id: 2, metrics: [ { diff --git a/packages/manager/cypress/support/util/cloudpulse.ts b/packages/manager/cypress/support/util/cloudpulse.ts index 1d41124a4a4..60990b3b634 100644 --- a/packages/manager/cypress/support/util/cloudpulse.ts +++ b/packages/manager/cypress/support/util/cloudpulse.ts @@ -84,3 +84,19 @@ export const resetDashboard = () => { .findByPlaceholderCustom('Select Dashboard') .should('have.value', ''); }; + +export const chooseEngine = (engine: string) => { +ui.autocomplete + .findByTitleCustom('Select a Value') + .findByTitle('Open') + .click(); + ui.autocompletePopper.findByTitle(engine).should('be.visible').click(); + cy.findByDisplayValue(engine).should('have.value', engine); +}; + +export const chooseDbCluster = (ClusterName: string) => { + const dbCluster = ui.autocomplete.findByTitleCustom('Select DB Cluster Names'); + dbCluster.findByTitle('Open').click(); + dbCluster.click().type(`${ClusterName}{enter}`); + cy.get('[title="Close"]').click(); +}; diff --git a/packages/manager/src/factories/dashboards.ts b/packages/manager/src/factories/dashboards.ts index f12ae9b3316..6e80341a754 100644 --- a/packages/manager/src/factories/dashboards.ts +++ b/packages/manager/src/factories/dashboards.ts @@ -53,7 +53,21 @@ const units_interval = ['percent', 'byte', 'byte', 'ops_per_second']; * const myDashboard = myDashboardFactory.build(); // Creates a Dashboard instance with the specified properties. * ``` */ -export const dashboardFactory = ( + +export const dashboardFactory = Factory.Sync.makeFactory({ + created: new Date().toISOString(), + id: Factory.each((i) => i), + label: Factory.each((i) => `Factory Dashboard-${i}`), + service_type: 'linode', + time_duration: { + unit: 'min', + value: 30, + }, + updated: new Date().toISOString(), + widgets: [], +}); + +export const extendedDashboardFactory = ( dashboardLabel: string, widgetLabels: string[], metricsLabels: string[], From 02f3100b927c6e7dcbef3c054e0174a849f0e0e4 Mon Sep 17 00:00:00 2001 From: agorthi Date: Thu, 12 Sep 2024 20:27:49 +0530 Subject: [PATCH 039/474] upcoming:[DI-20585]- renaming intercept methods to mocks --- .../cloudpulse/linode-widget-verification.spec.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 642e6caeaa3..4e3ae41b885 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -21,10 +21,12 @@ import { timeRange, widgetDetails, granularity } from 'support/constants/widget- import { makeFeatureFlagData } from 'support/util/feature-flags'; import { createMetricResponse } from '@src/factories/widget'; import type { Flags } from 'src/featureFlags'; -import { accountFactory, extendedDashboardFactory, kubeLinodeFactory, linodeFactory, metricDefinitionsFactory } from 'src/factories'; +import { accountFactory, extendedDashboardFactory, kubeLinodeFactory, linodeFactory, metricDefinitionsFactory, regionFactory } from 'src/factories'; import { mockGetAccount } from 'support/intercepts/account'; import { mockGetLinodes } from 'support/intercepts/linodes'; import { mockGetUserPreferences } from 'support/intercepts/profile'; +import { mockGetRegions } from 'support/intercepts/regions'; +import { extendRegion } from 'support/util/regions'; @@ -65,6 +67,14 @@ const mockLinode = linodeFactory.build({ id: mockKubeLinode.instance_id ?? undefined, }); const mockAccount = accountFactory.build(); +const mockDallasRegion = extendRegion( + regionFactory.build({ + capabilities: ['Linodes'], + id: 'us-ord', + label: 'Chicago, IL', + country: 'us', + }) +); describe('Dashboard Widget Verification Tests', () => { beforeEach(() => { @@ -81,6 +91,7 @@ describe('Dashboard Widget Verification Tests', () => { mockCloudPulseJWSToken(service_type); const responsePayload = createMetricResponse(actualRelativeTimeDuration, granularity.Min5); mockCloudPulseCreateMetrics(responsePayload,service_type).as('getMetrics'); + mockGetRegions([mockDallasRegion]).as('getRegions'); }); it('should verify cloudpulse availability when feature flag is set to false', () => { From ab5134860e45c982eb5b240081ba6cf61e4303cc Mon Sep 17 00:00:00 2001 From: agorthi Date: Thu, 12 Sep 2024 21:04:15 +0530 Subject: [PATCH 040/474] upcoming:[DI-20585]- fixing zoom-in/out canvas issue --- .../core/cloudpulse/linode-widget-verification.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 4e3ae41b885..113cd6eb8b6 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -67,7 +67,7 @@ const mockLinode = linodeFactory.build({ id: mockKubeLinode.instance_id ?? undefined, }); const mockAccount = accountFactory.build(); -const mockDallasRegion = extendRegion( +const mockRegion = extendRegion( regionFactory.build({ capabilities: ['Linodes'], id: 'us-ord', @@ -91,7 +91,7 @@ describe('Dashboard Widget Verification Tests', () => { mockCloudPulseJWSToken(service_type); const responsePayload = createMetricResponse(actualRelativeTimeDuration, granularity.Min5); mockCloudPulseCreateMetrics(responsePayload,service_type).as('getMetrics'); - mockGetRegions([mockDallasRegion]).as('getRegions'); + mockGetRegions([mockRegion]).as('getRegions'); }); it('should verify cloudpulse availability when feature flag is set to false', () => { @@ -222,7 +222,7 @@ describe('Dashboard Widget Verification Tests', () => { }); }); - it('should zoom in and out of all the widgets', () => { + it.only('should zoom in and out of all the widgets', () => { setupMethod() metrics.forEach((testData) => { cy.wait(5000); @@ -232,7 +232,7 @@ describe('Dashboard Widget Verification Tests', () => { .should('be.enabled') .click(); cy.get('@widget').should('be.visible'); - cy.get('[data-testid="linegraph-wrapper"] canvas').as('canvas') + cy.get('[data-testid="linegraph-wrapper"]').as('canvas') .should('exist') .and('be.visible'); ui.cloudpulse.findZoomButtonByTitle('zoom-out').should('be.visible') From b8bf16cb72c52181df80375236cee1b29fd4c617 Mon Sep 17 00:00:00 2001 From: agorthi Date: Fri, 13 Sep 2024 17:04:37 +0530 Subject: [PATCH 041/474] upcoming:[DI-20585]- fixing code review coments --- .../linode-widget-verification.spec.ts | 16 +++---- .../{widget-service.ts => widgets.ts} | 45 +++++++++++-------- .../intercepts/cloudpulseAPIHandler.ts | 3 +- .../cypress/support/util/cloudpulse.ts | 26 ++++++++--- packages/manager/src/factories/widget.ts | 12 ++--- 5 files changed, 61 insertions(+), 41 deletions(-) rename packages/manager/cypress/support/constants/{widget-service.ts => widgets.ts} (85%) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 113cd6eb8b6..6fcad289255 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -17,7 +17,7 @@ import { mockCloudPulseServices, } from 'support/intercepts/cloudpulseAPIHandler'; import { ui } from 'support/ui'; -import { timeRange, widgetDetails, granularity } from 'support/constants/widget-service'; +import { timeRange, widgetDetails, granularity } from 'support/constants/widgets'; import { makeFeatureFlagData } from 'support/util/feature-flags'; import { createMetricResponse } from '@src/factories/widget'; import type { Flags } from 'src/featureFlags'; @@ -89,7 +89,7 @@ describe('Dashboard Widget Verification Tests', () => { mockCloudPulseServices(service_type).as('services'); mockCloudPulseDashboardServicesResponse(dashboard,dashboardId); mockCloudPulseJWSToken(service_type); - const responsePayload = createMetricResponse(actualRelativeTimeDuration, granularity.Min5); + const responsePayload = createMetricResponse(actualRelativeTimeDuration, granularity.Minutes); mockCloudPulseCreateMetrics(responsePayload,service_type).as('getMetrics'); mockGetRegions([mockRegion]).as('getRegions'); }); @@ -106,7 +106,7 @@ describe('Dashboard Widget Verification Tests', () => { it('should set available granularity of all the widgets', () => { setupMethod() metrics.forEach((testData) => { - cy.wait(5000); + cy.wait(7000);//maintaining the wait since page flicker and rendering const widgetSelector = `[data-qa-widget="${testData.title}"]`; cy.get(widgetSelector).as('widget') cy.get('@widget') @@ -143,7 +143,7 @@ describe('Dashboard Widget Verification Tests', () => { it('should set available aggregation of all the widgets', () => { setupMethod() metrics.forEach((testData) => { - cy.wait(5000); + cy.wait(7000);//maintaining the wait since page flicker and rendering const widgetSelector = `[data-qa-widget="${testData.title}"]`; cy.get(widgetSelector) .first() @@ -168,7 +168,7 @@ describe('Dashboard Widget Verification Tests', () => { it('should verify available granularity of the widget', () => { setupMethod() metrics.forEach((testData) => { - cy.wait(5000); + cy.wait(7000);//maintaining the wait since page flicker and rendering const widgetSelector = `[data-qa-widget="${testData.title}"]`; cy.get(widgetSelector) .first() @@ -196,7 +196,7 @@ describe('Dashboard Widget Verification Tests', () => { it('should verify available aggregation of the widget', () => { setupMethod() metrics.forEach((testData) => { - cy.wait(5000); + cy.wait(7000);//maintaining the wait since page flicker and rendering const widgetSelector = `[data-qa-widget="${testData.title}"]`; cy.get(widgetSelector) .first() @@ -222,10 +222,10 @@ describe('Dashboard Widget Verification Tests', () => { }); }); - it.only('should zoom in and out of all the widgets', () => { + it('should zoom in and out of all the widgets', () => { setupMethod() metrics.forEach((testData) => { - cy.wait(5000); + cy.wait(7000);//maintaining the wait since page flicker and rendering cy.get(`[data-qa-widget="${testData.title}"]`).as('widget'); cy.get('@widget').should('be.visible').within(() => { ui.cloudpulse.findZoomButtonByTitle('zoom-in').should('be.visible') diff --git a/packages/manager/cypress/support/constants/widget-service.ts b/packages/manager/cypress/support/constants/widgets.ts similarity index 85% rename from packages/manager/cypress/support/constants/widget-service.ts rename to packages/manager/cypress/support/constants/widgets.ts index b2335749f82..98f83c87e57 100644 --- a/packages/manager/cypress/support/constants/widget-service.ts +++ b/packages/manager/cypress/support/constants/widgets.ts @@ -1,3 +1,5 @@ +import { stat } from 'fs'; + /** * Defines the granularity levels used for specifying time intervals in data aggregation or reporting. * Each property represents a different granularity level. @@ -5,8 +7,8 @@ export const granularity = { Auto: 'Auto', Day1: '1 day', - Hr1: '1 hr', - Min5: '5 min', + Hour: '1 hr', + Minutes: '5 min', }; /** @@ -55,42 +57,47 @@ export const widgetDetails = { dbaas: { cluster: 'mysql-cluster', dashboardName: 'Dbaas Dashboard', - engine: 'mysql', - id: 2, + engine: 'MySQL', + id: 1, metrics: [ { + StatsData: 'Controls for Disk I/O', + expectedAggregation: aggregation.Max, + expectedAggregationArray: aggregationConfig.all, + expectedGranularity: granularity.Hour, + expectedGranularityArray: Object.values(granularity), + name: 'system_disk_OPS_total', + title: 'Disk I/O', + }, + { + StatsData: 'Controls for CPU Utilization', expectedAggregation: aggregation.Max, expectedAggregationArray: aggregationConfig.basic, - expectedGranularity: granularity.Hr1, + expectedGranularity: granularity.Hour, expectedGranularityArray: Object.values(granularity), name: 'system_cpu_utilization_percent', title: 'CPU Utilization', }, { + StatsData: 'Controls for Memory Usage', expectedAggregation: aggregation.Max, expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hr1, + expectedGranularity: granularity.Hour, expectedGranularityArray: Object.values(granularity), name: 'system_memory_usage_by_resource', title: 'Memory Usage', }, { + StatsData: 'Controls for Network Traffic', expectedAggregation: aggregation.Max, expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hr1, + expectedGranularity: granularity.Hour, expectedGranularityArray: Object.values(granularity), name: 'system_network_io_by_resource', title: 'Network Traffic', }, - { - expectedAggregation: aggregation.Max, - expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hr1, - expectedGranularityArray: Object.values(granularity), - name: 'system_disk_OPS_total', - title: 'Disk I/O', - }, ], + nodeType: 'Primary', region: 'US, Chicago, IL (us-ord)', resource: 'Dbaas-resource', service_type: 'dbaas', @@ -102,7 +109,7 @@ export const widgetDetails = { { expectedAggregation: aggregation.Max, expectedAggregationArray: aggregationConfig.basic, - expectedGranularity: granularity.Hr1, + expectedGranularity: granularity.Hour, expectedGranularityArray: Object.values(granularity), name: 'system_cpu_utilization_percent', title: 'CPU Utilization', @@ -110,7 +117,7 @@ export const widgetDetails = { { expectedAggregation: aggregation.Max, expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hr1, + expectedGranularity: granularity.Hour, expectedGranularityArray: Object.values(granularity), name: 'system_memory_usage_by_resource', title: 'Memory Usage', @@ -118,7 +125,7 @@ export const widgetDetails = { { expectedAggregation: aggregation.Max, expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hr1, + expectedGranularity: granularity.Hour, expectedGranularityArray: Object.values(granularity), name: 'system_network_io_by_resource', title: 'Network Traffic', @@ -126,7 +133,7 @@ export const widgetDetails = { { expectedAggregation: aggregation.Max, expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hr1, + expectedGranularity: granularity.Hour, expectedGranularityArray: Object.values(granularity), name: 'system_disk_OPS_total', title: 'Disk I/O', diff --git a/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts b/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts index 8ffca859904..24ab6a053ae 100644 --- a/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts +++ b/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts @@ -8,6 +8,7 @@ import { apiMatcher } from 'support/util/intercepts'; import type { AvailableMetrics, + CloudPulseMetricsResponse, Dashboard, MetricDefinitions, } from '@linode/api-v4'; @@ -77,7 +78,7 @@ export const mockCloudPulseGetDashboards = ( * @returns {Cypress.Chainable} The chainable Cypress object. */ export const mockCloudPulseCreateMetrics = ( - mockResponse: AvailableMetrics, + mockResponse: CloudPulseMetricsResponse, service_type: string ): Cypress.Chainable => { return cy.intercept( diff --git a/packages/manager/cypress/support/util/cloudpulse.ts b/packages/manager/cypress/support/util/cloudpulse.ts index 60990b3b634..850db707e00 100644 --- a/packages/manager/cypress/support/util/cloudpulse.ts +++ b/packages/manager/cypress/support/util/cloudpulse.ts @@ -84,19 +84,31 @@ export const resetDashboard = () => { .findByPlaceholderCustom('Select Dashboard') .should('have.value', ''); }; - +/** + * Selects an engine from a dropdown menu. + * + * @param {string} engine - The engine to be selected. + */ export const chooseEngine = (engine: string) => { -ui.autocomplete + ui.autocomplete .findByTitleCustom('Select a Value') .findByTitle('Open') .click(); ui.autocompletePopper.findByTitle(engine).should('be.visible').click(); cy.findByDisplayValue(engine).should('have.value', engine); }; +/** + * Selects a node type from a dropdown menu. + * + * @param {string} node - The node type to be selected. + */ -export const chooseDbCluster = (ClusterName: string) => { - const dbCluster = ui.autocomplete.findByTitleCustom('Select DB Cluster Names'); - dbCluster.findByTitle('Open').click(); - dbCluster.click().type(`${ClusterName}{enter}`); - cy.get('[title="Close"]').click(); +export const chooseNodeType = (node: string) => { + ui.autocomplete + .findByPlaceholderCustom('Select Node Type') + .should('be.visible') + .type(node) + .click(); + ui.autocompletePopper.findByTitle(node).should('be.visible').click(); + cy.findByDisplayValue(node).should('have.value', node); }; diff --git a/packages/manager/src/factories/widget.ts b/packages/manager/src/factories/widget.ts index 69517e57b67..1da37d1a70a 100644 --- a/packages/manager/src/factories/widget.ts +++ b/packages/manager/src/factories/widget.ts @@ -1,9 +1,9 @@ import { granularity, timeRange, -} from '../../cypress/support/constants/widget-service'; +} from '../../cypress/support/constants/widgets'; -import type { AvailableMetrics } from '@linode/api-v4'; +import type { CloudPulseMetricsResponse } from '@linode/api-v4'; /** * Generates a mock metric response based on the specified time range and granularity. @@ -16,19 +16,19 @@ import type { AvailableMetrics } from '@linode/api-v4'; * * @param {string} time - The time range for the metric data (e.g., "Last12Hours"). * @param {string} granularityData - The granularity of the metric data (e.g., "Min5"). - * @returns {AvailableMetrics} - The generated mock metric response. + * @returns {CloudPulseMetricsResponse} - The generated mock metric response. */ export const createMetricResponse = ( time: string, granularityData: string -): AvailableMetrics => { +): CloudPulseMetricsResponse => { const currentTime = Math.floor(Date.now() / 1000); const intervals: Record = { [granularity.Auto]: 3600, [granularity.Day1]: 86400, - [granularity.Hr1]: 3600, - [granularity.Min5]: 5 * 60, + [granularity.Hour]: 3600, + [granularity.Minutes]: 5 * 60, }; const timeRanges: Record = { From 991fe7a0bff32b7932bc5d4cc100babbd74935b2 Mon Sep 17 00:00:00 2001 From: agorthi Date: Fri, 13 Sep 2024 17:44:18 +0530 Subject: [PATCH 042/474] upcoming:[DI-20585]- fixing code review coments --- .../linode-widget-verification.spec.ts | 66 +++++++++++++++++-- 1 file changed, 60 insertions(+), 6 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 6fcad289255..7a0692c0116 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -27,6 +27,9 @@ import { mockGetLinodes } from 'support/intercepts/linodes'; import { mockGetUserPreferences } from 'support/intercepts/profile'; import { mockGetRegions } from 'support/intercepts/regions'; import { extendRegion } from 'support/util/regions'; +import { CloudPulseMetricsResponse } from '@linode/api-v4'; +import { transformData } from 'src/features/CloudPulse/Utils/unitConversion'; +import { getMetrics } from 'src/utilities/statMetrics'; @@ -75,6 +78,7 @@ const mockRegion = extendRegion( country: 'us', }) ); +let responsePayload: CloudPulseMetricsResponse; describe('Dashboard Widget Verification Tests', () => { beforeEach(() => { @@ -89,7 +93,7 @@ describe('Dashboard Widget Verification Tests', () => { mockCloudPulseServices(service_type).as('services'); mockCloudPulseDashboardServicesResponse(dashboard,dashboardId); mockCloudPulseJWSToken(service_type); - const responsePayload = createMetricResponse(actualRelativeTimeDuration, granularity.Minutes); + responsePayload = createMetricResponse(actualRelativeTimeDuration, granularity.Minutes); mockCloudPulseCreateMetrics(responsePayload,service_type).as('getMetrics'); mockGetRegions([mockRegion]).as('getRegions'); }); @@ -125,8 +129,24 @@ describe('Dashboard Widget Verification Tests', () => { .should('have.text', testData.expectedGranularity) .click(); cy.findByDisplayValue(testData.expectedGranularity).should('exist'); + cy.findByTestId('linegraph-wrapper').as('canvas') + .should('be.visible') + .find('tbody tr') + .each(($tr, index) => { + const cells = $tr.find('td').map((i, el) => { + const text = Cypress.$(el).text().trim(); + return text.replace(/^\s*\([^)]+\)/, ''); + }).get(); + + const [title, actualMax, actualAvg, actualLast] = cells; + const widgetValues = verifyWidgetValues(responsePayload, testData.title); + assert(Math.abs(widgetValues.max - parseFloat(actualMax)) <= 0.01, `Expected ${widgetValues.max} to be close to ${actualMax}`); + assert(Math.abs(widgetValues.average - parseFloat(actualAvg)) <= 0.01, `Expected ${widgetValues.average} to be close to ${actualAvg}`); + assert(Math.abs(widgetValues.last - parseFloat(actualLast)) <= 0.01, `Expected ${widgetValues.last} to be close to ${actualLast}`); + assertSelections(testData.expectedGranularity); }); + }); }); }); @@ -160,10 +180,26 @@ describe('Dashboard Widget Verification Tests', () => { .should('have.text', testData.expectedAggregation) .click(); cy.findByDisplayValue(testData.expectedAggregation).should('exist'); + cy.findByTestId('linegraph-wrapper').as('canvas') + .should('be.visible') + .find('tbody tr') + .each(($tr, index) => { + const cells = $tr.find('td').map((i, el) => { + const text = Cypress.$(el).text().trim(); + return text.replace(/^\s*\([^)]+\)/, ''); + }).get(); + + const [title, actualMax, actualAvg, actualLast] = cells; + const widgetValues = verifyWidgetValues(responsePayload, testData.title); + assert(Math.abs(widgetValues.max - parseFloat(actualMax)) <= 0.01, `Expected ${widgetValues.max} to be close to ${actualMax}`); + assert(Math.abs(widgetValues.average - parseFloat(actualAvg)) <= 0.01, `Expected ${widgetValues.average} to be close to ${actualAvg}`); + assert(Math.abs(widgetValues.last - parseFloat(actualLast)) <= 0.01, `Expected ${widgetValues.last} to be close to ${actualLast}`); + assertSelections(testData.expectedAggregation); }); }); }); +}); it('should verify available granularity of the widget', () => { setupMethod() @@ -232,14 +268,24 @@ describe('Dashboard Widget Verification Tests', () => { .should('be.enabled') .click(); cy.get('@widget').should('be.visible'); - cy.get('[data-testid="linegraph-wrapper"]').as('canvas') - .should('exist') - .and('be.visible'); + cy.findByTestId('linegraph-wrapper').as('canvas') + .should('be.visible') + .find('tbody tr') + .each(($tr, index) => { + const cells = $tr.find('td').map((i, el) => { + const text = Cypress.$(el).text().trim(); + return text.replace(/^\s*\([^)]+\)/, ''); + }).get(); + + const [title, actualMax, actualAvg, actualLast] = cells; + const widgetValues = verifyWidgetValues(responsePayload, testData.title); + assert(Math.abs(widgetValues.max - parseFloat(actualMax)) <= 0.01, `Expected ${widgetValues.max} to be close to ${actualMax}`); + assert(Math.abs(widgetValues.average - parseFloat(actualAvg)) <= 0.01, `Expected ${widgetValues.average} to be close to ${actualAvg}`); + assert(Math.abs(widgetValues.last - parseFloat(actualLast)) <= 0.01, `Expected ${widgetValues.last} to be close to ${actualLast}`); + ui.cloudpulse.findZoomButtonByTitle('zoom-out').should('be.visible') .should('be.enabled') .click(); - cy.get('@widget').should('be.visible'); - cy.get('@canvas').should('exist').and('be.visible'); }); }); @@ -275,6 +321,7 @@ describe('Dashboard Widget Verification Tests', () => { }); }); }); +}); const setupMethod = () => { @@ -289,3 +336,10 @@ describe('Dashboard Widget Verification Tests', () => { assertSelections(region); selectAndVerifyResource(resource); }; + +const verifyWidgetValues = (responsePayload:CloudPulseMetricsResponse, widgetTitle:string) => { + const data= transformData(responsePayload.data.result[0].values,'Bytes') + const { average, last, max }= getMetrics(data) + return { average, last, max } + +}; \ No newline at end of file From bb1cb317c2762fff8a65a7c8084ce95008014742 Mon Sep 17 00:00:00 2001 From: agorthi Date: Mon, 16 Sep 2024 11:39:22 +0530 Subject: [PATCH 043/474] upcoming:[DI-20585]- Added code review comments and adding placeholder values in CloudPulseCustomSelect.tsx --- .../linode-widget-verification.spec.ts | 166 ++++++++++-------- packages/manager/src/factories/widget.ts | 9 +- .../shared/CloudPulseCustomSelect.tsx | 2 +- 3 files changed, 94 insertions(+), 83 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 7a0692c0116..43bf5aa947a 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -30,9 +30,6 @@ import { extendRegion } from 'support/util/regions'; import { CloudPulseMetricsResponse } from '@linode/api-v4'; import { transformData } from 'src/features/CloudPulse/Utils/unitConversion'; import { getMetrics } from 'src/utilities/statMetrics'; - - - /** * This test ensures that widget titles are displayed correctly on the dashboard. * This test suite is dedicated to verifying the functionality and display of widgets on the Cloudpulse dashboard. @@ -44,14 +41,7 @@ import { getMetrics } from 'src/utilities/statMetrics'; * Each test ensures that widgets on the dashboard operate correctly and display accurate information. */ - - -const y_labels = [ - 'system_cpu_utilization_ratio', - 'system_memory_usage_bytes', - 'system_network_io_bytes_total', - 'system_disk_operations_total', -]; +const y_labels = ['system_cpu_utilization_ratio','system_memory_usage_bytes','system_network_io_bytes_total','system_disk_operations_total',]; const widgets= widgetDetails.linode; const metrics =widgets.metrics; export const dashboardName = widgets.dashboardName; @@ -79,7 +69,6 @@ const mockRegion = extendRegion( }) ); let responsePayload: CloudPulseMetricsResponse; - describe('Dashboard Widget Verification Tests', () => { beforeEach(() => { mockAppendFeatureFlags({ @@ -137,14 +126,10 @@ describe('Dashboard Widget Verification Tests', () => { const text = Cypress.$(el).text().trim(); return text.replace(/^\s*\([^)]+\)/, ''); }).get(); - const [title, actualMax, actualAvg, actualLast] = cells; - const widgetValues = verifyWidgetValues(responsePayload, testData.title); - assert(Math.abs(widgetValues.max - parseFloat(actualMax)) <= 0.01, `Expected ${widgetValues.max} to be close to ${actualMax}`); - assert(Math.abs(widgetValues.average - parseFloat(actualAvg)) <= 0.01, `Expected ${widgetValues.average} to be close to ${actualAvg}`); - assert(Math.abs(widgetValues.last - parseFloat(actualLast)) <= 0.01, `Expected ${widgetValues.last} to be close to ${actualLast}`); - - assertSelections(testData.expectedGranularity); + const widgetValues = verifyWidgetValues(responsePayload); + compareWidgetValues( {title, max: parseFloat(actualMax), average: parseFloat(actualAvg),last: parseFloat(actualLast)}, widgetValues,testData.title); + assertSelections(testData.expectedGranularity); }); }); }); @@ -188,15 +173,11 @@ describe('Dashboard Widget Verification Tests', () => { const text = Cypress.$(el).text().trim(); return text.replace(/^\s*\([^)]+\)/, ''); }).get(); - - const [title, actualMax, actualAvg, actualLast] = cells; - const widgetValues = verifyWidgetValues(responsePayload, testData.title); - assert(Math.abs(widgetValues.max - parseFloat(actualMax)) <= 0.01, `Expected ${widgetValues.max} to be close to ${actualMax}`); - assert(Math.abs(widgetValues.average - parseFloat(actualAvg)) <= 0.01, `Expected ${widgetValues.average} to be close to ${actualAvg}`); - assert(Math.abs(widgetValues.last - parseFloat(actualLast)) <= 0.01, `Expected ${widgetValues.last} to be close to ${actualLast}`); - - assertSelections(testData.expectedAggregation); - }); + const [title, actualMax, actualAvg, actualLast] = cells; + const widgetValues = verifyWidgetValues(responsePayload); + compareWidgetValues( {title, max: parseFloat(actualMax), average: parseFloat(actualAvg),last: parseFloat(actualLast)}, widgetValues,testData.title); + assertSelections(testData.expectedAggregation); + }); }); }); }); @@ -257,53 +238,16 @@ describe('Dashboard Widget Verification Tests', () => { }); }); }); - - it('should zoom in and out of all the widgets', () => { - setupMethod() - metrics.forEach((testData) => { - cy.wait(7000);//maintaining the wait since page flicker and rendering - cy.get(`[data-qa-widget="${testData.title}"]`).as('widget'); - cy.get('@widget').should('be.visible').within(() => { - ui.cloudpulse.findZoomButtonByTitle('zoom-in').should('be.visible') - .should('be.enabled') - .click(); - cy.get('@widget').should('be.visible'); - cy.findByTestId('linegraph-wrapper').as('canvas') - .should('be.visible') - .find('tbody tr') - .each(($tr, index) => { - const cells = $tr.find('td').map((i, el) => { - const text = Cypress.$(el).text().trim(); - return text.replace(/^\s*\([^)]+\)/, ''); - }).get(); - - const [title, actualMax, actualAvg, actualLast] = cells; - const widgetValues = verifyWidgetValues(responsePayload, testData.title); - assert(Math.abs(widgetValues.max - parseFloat(actualMax)) <= 0.01, `Expected ${widgetValues.max} to be close to ${actualMax}`); - assert(Math.abs(widgetValues.average - parseFloat(actualAvg)) <= 0.01, `Expected ${widgetValues.average} to be close to ${actualAvg}`); - assert(Math.abs(widgetValues.last - parseFloat(actualLast)) <= 0.01, `Expected ${widgetValues.last} to be close to ${actualLast}`); - - ui.cloudpulse.findZoomButtonByTitle('zoom-out').should('be.visible') - .should('be.enabled') - .click(); - }); - - }); - }); - it('should apply global refresh button and verify network calls', () => { setupMethod(); - ui.cloudpulse.findRefreshIcon().should('be.visible').click(); - - cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']).then((interceptions) => { - const interceptionsArray = Array.isArray(interceptions) ? interceptions : [interceptions]; - - interceptionsArray.forEach((interception) => { + ui.cloudpulse.findRefreshIcon().should('be.visible').click(); + cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']).then((interceptions) => { + const interceptionsArray = Array.isArray(interceptions) ? interceptions : [interceptions]; + interceptionsArray.forEach((interception) => { const { body: requestPayload } = interception.request; const { metric, time_granularity: granularity, relative_time_duration: timeRange, aggregate_function: aggregateFunction } = requestPayload; const metricData = metrics.find(data => data.name === metric); - // Check if metricData and its expected properties are available if (!metricData || !metricData.expectedGranularity || !metricData.expectedAggregation) { expect.fail('metricData or its expected properties are not defined.'); } @@ -319,10 +263,50 @@ describe('Dashboard Widget Verification Tests', () => { // expect(aggregateFunction).to.equal(metricData.expectedAggregation); }); }); + + }); + + it('should zoom in and out of all the widgets', () => { + setupMethod(); + metrics.forEach((testData) => { + cy.wait(7000); // Maintaining the wait since page flicker and rendering + cy.get(`[data-qa-widget="${testData.title}"]`).as('widget'); + cy.get('@widget').should('be.visible').within(() => { + ui.cloudpulse.findZoomButtonByTitle('zoom-in') + .should('be.visible') + .should('be.enabled') + .click(); + cy.get('@widget').should('be.visible'); + cy.findByTestId('linegraph-wrapper').as('canvas') + .should('be.visible') + .find('tbody tr') + .each(($tr) => { + const cells = $tr.find('td').map((i, el) => Cypress.$(el).text().trim()).get(); + const [title, actualMax, actualAvg, actualLast] = cells; + const widgetValues = verifyWidgetValues(responsePayload); + compareWidgetValues({ title, max: parseFloat(actualMax), average: parseFloat(actualAvg),last: parseFloat(actualLast) + }, widgetValues, testData.title); + }); + ui.cloudpulse.findZoomButtonByTitle('zoom-out') + .should('be.visible') + .should('be.enabled') + .scrollIntoView() + .click({ force: true }); + cy.get('@widget').should('be.visible'); + cy.findByTestId('linegraph-wrapper').as('canvas') + .should('be.visible') + .find('tbody tr') + .each(($tr) => { + const cells = $tr.find('td').map((i, el) => Cypress.$(el).text().trim()).get(); + const [title, actualMax, actualAvg, actualLast] = cells; + const widgetValues = verifyWidgetValues(responsePayload); + compareWidgetValues({ title, max: parseFloat(actualMax),average: parseFloat(actualAvg),last: parseFloat(actualLast) + }, widgetValues, testData.title); + }); + }); + }); + }); }); -}); -}); - const setupMethod = () => { mockGetUserPreferences({}).as('getUserPreferences'); @@ -337,9 +321,37 @@ describe('Dashboard Widget Verification Tests', () => { selectAndVerifyResource(resource); }; -const verifyWidgetValues = (responsePayload:CloudPulseMetricsResponse, widgetTitle:string) => { - const data= transformData(responsePayload.data.result[0].values,'Bytes') - const { average, last, max }= getMetrics(data) - return { average, last, max } +const verifyWidgetValues = (responsePayload: CloudPulseMetricsResponse) => { + const data = transformData(responsePayload.data.result[0].values, 'Bytes'); + const { average, last, max } = getMetrics(data); + const roundedAverage = Math.round(average * 100) / 100; + const roundedLast = Math.round(last * 100) / 100; + const roundedMax = Math.round(max * 100) / 100; + return {average: roundedAverage,last: roundedLast,max: roundedMax }; +}; + +/** + * Compares actual widget values to the expected values and asserts their equality. + * + * @param actualValues - The actual values retrieved from the widget, consisting of: + * @param actualValues.max - The maximum value shown on the widget. + * @param actualValues.average - The average value shown on the widget. + * @param actualValues.last - The last or most recent value shown on the widget. + * + * @param expectedValues - The expected values that the widget should display, consisting of: + * @param expectedValues.max - The expected maximum value. + * @param expectedValues.average - The expected average value. + * @param expectedValues.last - The expected last or most recent value. + */ -}; \ No newline at end of file +const compareWidgetValues = ( + actualValues: { title:string, max: number, average: number, last: number }, + expectedValues: { max: number, average: number, last: number }, + title:string +) => { + expect(actualValues.max).to.equal(expectedValues.max, `Expected ${expectedValues.max} for max, but got ${actualValues.max}`); + expect(actualValues.average).to.equal(expectedValues.average, `Expected ${expectedValues.average} for average, but got ${actualValues.average}`); + expect(actualValues.last).to.equal(expectedValues.last, `Expected ${expectedValues.last} for last, but got ${actualValues.last}`); + const extractedTitle = actualValues.title.substring(0, actualValues.title.indexOf(' ', actualValues.title.indexOf(' ') + 1)); + expect(extractedTitle).to.equal(title, `Expected ${title} for title ${extractedTitle}`); +}; diff --git a/packages/manager/src/factories/widget.ts b/packages/manager/src/factories/widget.ts index 1da37d1a70a..6ecc3b259ee 100644 --- a/packages/manager/src/factories/widget.ts +++ b/packages/manager/src/factories/widget.ts @@ -55,7 +55,7 @@ export const createMetricResponse = ( { length: Math.ceil(timeRangeInSeconds / interval) + 1 }, (_, i) => { const timestamp = startTime + i * interval; - const value = (Math.random() * 100).toFixed(2); + const value = (Math.round(Math.random() * 100 * 100) / 100).toFixed(2); // Round and convert to string with 2 decimal places return [timestamp, value]; } ); @@ -63,13 +63,12 @@ export const createMetricResponse = ( return { data: { result: [{ metric: {}, values }], - resultType: 'matrix', + result_type: 'matrix', }, isPartial: false, stats: { - executionTimeMsec: 53, - seriesFetched: '6', + series_fetched: 53, }, status: 'success', }; -}; +}; \ No newline at end of file diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index 098d3a301e7..9ee0d16debd 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -211,7 +211,7 @@ export const CloudPulseCustomSelect = React.memo( disabled={isAutoCompleteDisabled} errorText={staticErrorText} isOptionEqualToValue={(option, value) => option.label === value.label} - label="Select a Value" + label={placeholder || 'Select a Value'} multiple={isMultiSelect} onChange={handleChange} placeholder={placeholder ?? 'Select a Value'} From e5d825773dad17b8ecc0058a44e66a6e8d3e6a08 Mon Sep 17 00:00:00 2001 From: nikhagra Date: Mon, 16 Sep 2024 19:24:49 +0530 Subject: [PATCH 044/474] upcoming: [DI-20360] - Updated review comment suggestions & test cases --- .../CloudPulse/Overview/GlobalFilters.tsx | 4 ++-- .../features/CloudPulse/Utils/FilterBuilder.ts | 3 +-- .../CloudPulse/Utils/UserPreference.ts | 18 ++++++++++-------- .../components/CloudPulseAggregateFunction.tsx | 2 +- .../components/CloudPulseIntervalSelect.tsx | 2 +- .../shared/CloudPulseCustomSelect.tsx | 4 ++-- .../shared/CloudPulseCustomSelectUtils.test.ts | 8 ++------ .../shared/CloudPulseCustomSelectUtils.ts | 3 +-- .../CloudPulseDashboardFilterBuilder.tsx | 2 +- .../shared/CloudPulseDashboardSelect.tsx | 4 ++-- .../shared/CloudPulseResourcesSelect.test.tsx | 3 +-- .../shared/CloudPulseResourcesSelect.tsx | 13 +++++++------ .../shared/CloudPulseTimeRangeSelect.tsx | 4 ++-- 13 files changed, 33 insertions(+), 37 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index f713b659cb1..b5b2c2f9a4a 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -13,7 +13,7 @@ import { DASHBOARD_ID, REFRESH, TIME_DURATION } from '../Utils/constants'; import { useAclpPreference } from '../Utils/UserPreference'; import type { FilterValueType } from '../Dashboard/CloudPulseDashboardLanding'; -import type { Dashboard, TimeDuration } from '@linode/api-v4'; +import type { AclpConfig, Dashboard, TimeDuration } from '@linode/api-v4'; export interface GlobalFilterProperties { handleAnyFilterChange(filterKey: string, filterValue: FilterValueType): void; @@ -66,7 +66,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { filterKey: string, value: FilterValueType, savePref: boolean = false, - updatedPreferenceData: {} = {} + updatedPreferenceData: AclpConfig = {} ) => { if (savePref) { updatePreferences(updatedPreferenceData); diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts index b48d139eaf0..36a5b9cfa0a 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts @@ -187,8 +187,7 @@ export const getTimeDurationProperties = ( const timeDuration = preferences?.timeDuration; return { - defaultValue: - timeDuration !== undefined ? (timeDuration as string) : undefined, + defaultValue: timeDuration, handleStatsChange: handleTimeRangeChange, placeholder, savePreferences: !isServiceAnalyticsIntegration, diff --git a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts index 0353f0a896a..9409ae8e96f 100644 --- a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts +++ b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts @@ -5,14 +5,16 @@ import { import { DASHBOARD_ID, TIME_DURATION } from './constants'; -import type { AclpWidget } from '@linode/api-v4'; +import type { AclpConfig, AclpWidget } from '@linode/api-v4'; -/** - * - * This hook is used in CloudPulseDashboardLanding, GlobalFilters & CloudPulseWidget component - */ +interface AclpPreferenceObject { + isLoading: boolean; + preferences: AclpConfig; + updateGlobalFilterPreference: (data: AclpConfig) => void; + updateWidgetPreference: (label: string, data: Partial) => void; +} -export const useAclpPreference = () => { +export const useAclpPreference = (): AclpPreferenceObject => { const { data: preferences, isLoading } = usePreferences(); const { mutateAsync: updateFunction } = useMutatePreferences(); @@ -21,7 +23,7 @@ export const useAclpPreference = () => { * * @param data AclpConfig data to be updated in preferences */ - const updateGlobalFilterPreference = (data: {}) => { + const updateGlobalFilterPreference = (data: AclpConfig) => { let currentPreferences = { ...(preferences?.aclpPreference ?? {}) }; const keys = Object.keys(data); @@ -60,7 +62,7 @@ export const useAclpPreference = () => { }; return { isLoading, - preferences: preferences?.aclpPreference ?? {}, + preferences: { ...(preferences?.aclpPreference ?? {}) }, updateGlobalFilterPreference, updateWidgetPreference, }; diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx index e1dd4b9f83f..dcc4fe5d270 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx @@ -16,7 +16,7 @@ export interface AggregateFunctionProperties { /** * Function to be triggered on aggregate function changed from dropdown */ - onAggregateFuncChange: any; + onAggregateFuncChange: (aggregatevalue: string) => void; } export const CloudPulseAggregateFunction = React.memo( diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx index 94ca198048e..8a0bdde88e7 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx @@ -13,7 +13,7 @@ export interface IntervalSelectProperties { /** * Function to be triggered on aggregate function changed from dropdown */ - onIntervalChange: any; + onIntervalChange: (intervalValue: TimeGranularity) => void; /** * scrape intervalto filter out minimum time granularity diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index 732e7c0898b..7e992151c20 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -14,7 +14,7 @@ import type { CloudPulseServiceTypeFiltersOptions, QueryFunctionAndKey, } from '../Utils/models'; -import type { FilterValue } from '@linode/api-v4'; +import type { AclpConfig, FilterValue } from '@linode/api-v4'; /** * These are the properties requires for CloudPulseCustomSelect Components @@ -74,7 +74,7 @@ export interface CloudPulseCustomSelectProps { filterKey: string, value: FilterValueType, savePref?: boolean, - updatedPreferenceData?: {} + updatedPreferenceData?: AclpConfig ) => void; /** diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.test.ts b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.test.ts index afe36ed2778..d7458ebd729 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.test.ts +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.test.ts @@ -55,13 +55,11 @@ it('test getInitialDefaultSelections method for single selection', () => { ]; let result = getInitialDefaultSelections({ + defaultValue: '1', filterKey: 'test', handleSelectionChange, isMultiSelect: false, options, - preferences: { - test: '1', - }, savePreferences: true, }); @@ -94,13 +92,11 @@ it('test getInitialDefaultSelections method for multi selection', () => { ]; let result = getInitialDefaultSelections({ + defaultValue: ['1'], filterKey: 'test', handleSelectionChange, isMultiSelect: true, options, - preferences: { - test: '1', - }, savePreferences: true, }); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts index 04d5bd23d4e..f4128a4b69b 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts @@ -15,7 +15,7 @@ interface CloudPulseCustomSelectProps { filterKey: string, value: FilterValueType, savePref?: boolean, - updatedPreferenceData?: {} + updatedPreferenceData?: AclpConfig ) => void; /** @@ -106,7 +106,6 @@ export const getInitialDefaultSelections = ( ); return initialSelection; } - const selectedValues = options.filter(({ id }) => (Array.isArray(defaultValue) ? defaultValue : [defaultValue]).includes( String(id) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index 089f69fe418..b9afbb1d2e4 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -104,7 +104,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( filterKey: string, filterValue: FilterValueType, savePref: boolean = false, - updatedPreferenceData: {} = {} + updatedPreferenceData: AclpConfig = {} ) => { emitFilterChange( filterKey, diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index a2bb84a762e..c83f680f93f 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -8,10 +8,10 @@ import { useCloudPulseServiceTypes } from 'src/queries/cloudpulse/services'; import { formattedServiceTypes, getAllDashboards } from '../Utils/utils'; -import type { Dashboard } from '@linode/api-v4'; +import type { Dashboard, FilterValue } from '@linode/api-v4'; export interface CloudPulseDashboardSelectProps { - defaultValue?: number; + defaultValue?: Partial; handleDashboardChange: ( dashboard: Dashboard | undefined, savePref?: boolean diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx index 3c05f727de9..18a9396baa0 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx @@ -4,7 +4,6 @@ import * as React from 'react'; import { linodeFactory } from 'src/factories'; import { renderWithTheme } from 'src/utilities/testHelpers'; -import { RESOURCES } from '../Utils/constants'; import { CloudPulseResourcesSelect } from './CloudPulseResourcesSelect'; const queryMocks = vi.hoisted(() => ({ @@ -174,8 +173,8 @@ describe('CloudPulseResourcesSelect component tests', () => { renderWithTheme( ; disabled?: boolean; handleResourcesSelection: ( resources: CloudPulseResources[], @@ -51,9 +51,9 @@ export const CloudPulseResourcesSelect = React.memo( CloudPulseResources[] >(); - const getResourcesList = (): CloudPulseResources[] => { + const getResourcesList = React.useMemo(() => { return resources && resources.length > 0 ? resources : []; - }; + }, [resources]); // Once the data is loaded, set the state variable with value stored in preferences React.useEffect(() => { @@ -62,18 +62,19 @@ export const CloudPulseResourcesSelect = React.memo( defaultValue && Array.isArray(defaultValue) ? defaultValue.map((resource) => String(resource)) : []; - const resource = getResourcesList().filter((resource) => + const resource = getResourcesList.filter((resource) => defaultResources.includes(String(resource.id)) ); handleResourcesSelection(resource); setSelectedResources(resource); } else { + setSelectedResources([]); handleResourcesSelection([]); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [resources]); + }, [resources, region, xFilter, resourceType]); return ( diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx index 49d1bc4eada..b22a96681ef 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; -import type { TimeDuration } from '@linode/api-v4'; +import type { FilterValue, TimeDuration } from '@linode/api-v4'; import type { BaseSelectProps, Item, @@ -13,7 +13,7 @@ export interface CloudPulseTimeRangeSelectProps BaseSelectProps, false>, 'defaultValue' | 'onChange' > { - defaultValue?: string; + defaultValue?: Partial; handleStatsChange?: ( timeDuration: TimeDuration, timeDurationValue?: string, From a2744c00c46fa210afd148c1fb7c5df93c8ae202 Mon Sep 17 00:00:00 2001 From: nikhagra Date: Mon, 16 Sep 2024 20:49:31 +0530 Subject: [PATCH 045/474] upcoming: [DI-20360] - Updated review comments --- packages/api-v4/src/cloudpulse/types.ts | 1 + .../CloudPulse/Dashboard/CloudPulseDashboard.tsx | 11 ++++++----- .../CloudPulse/Widget/CloudPulseWidget.tsx | 4 ++-- .../Widget/components/CloudPulseIntervalSelect.tsx | 14 +++++++------- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/packages/api-v4/src/cloudpulse/types.ts b/packages/api-v4/src/cloudpulse/types.ts index e2979316945..9d24aca5857 100644 --- a/packages/api-v4/src/cloudpulse/types.ts +++ b/packages/api-v4/src/cloudpulse/types.ts @@ -11,6 +11,7 @@ export interface Dashboard { export interface TimeGranularity { unit: string; value: number; + label?: string; } export interface TimeDuration { diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index 0b70b139912..34fa3753216 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -106,7 +106,7 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { widget: { ...widget }, }; if (savePref) { - setPreferredWidgetPlan(graphProp.widget); + graphProp.widget = setPreferredWidgetPlan(graphProp.widget); } return graphProp; }; @@ -120,23 +120,24 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { const pref = widgetPreferences?.[widgetObj.label]; // if preference is present then update the widget properties present in preference if (pref) { - Object.assign(widgetObj, { + return { + ...widgetObj, aggregate_function: pref.aggregateFunction ?? widgetObj.aggregate_function, size: pref.size ?? widgetObj.size, time_granularity: { ...(pref.timeGranularity ?? widgetObj.time_granularity), }, - }); + }; } else { - Object.assign(widgetObj, { + return { ...widgetObj, time_granularity: { label: 'Auto', unit: 'Auto', value: -1, }, - }); + }; } }; diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index d225d969cb4..962f4a5d09f 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -287,9 +287,9 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { > {availableMetrics?.scrape_interval && ( )} {Boolean( diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx index 8a0bdde88e7..36a4ac68e86 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx @@ -8,7 +8,7 @@ export interface IntervalSelectProperties { /** * Default time granularity to be selected */ - default_interval?: TimeGranularity | undefined; + defaultInterval?: TimeGranularity | undefined; /** * Function to be triggered on aggregate function changed from dropdown @@ -18,7 +18,7 @@ export interface IntervalSelectProperties { /** * scrape intervalto filter out minimum time granularity */ - scrape_interval: string; + scrapeInterval: string; } export const getInSeconds = (interval: string) => { @@ -78,8 +78,8 @@ export const getIntervalIndex = (scrapeIntervalValue: number) => { export const CloudPulseIntervalSelect = React.memo( (props: IntervalSelectProperties) => { - const { default_interval, onIntervalChange, scrape_interval } = props; - const scrapeIntervalValue = getInSeconds(scrape_interval); + const { defaultInterval, onIntervalChange, scrapeInterval } = props; + const scrapeIntervalValue = getInSeconds(scrapeInterval); const firstIntervalIndex = getIntervalIndex(scrapeIntervalValue); @@ -93,12 +93,12 @@ export const CloudPulseIntervalSelect = React.memo( ); let default_value = - default_interval?.unit === 'Auto' + defaultInterval?.unit === 'Auto' ? autoIntervalOption : available_interval_options.find( (obj) => - obj.value === default_interval?.value && - obj.unit === default_interval?.unit + obj.value === defaultInterval?.value && + obj.unit === defaultInterval?.unit ); if (!default_value) { From 836a37fd7a972e35ea0690c95e64b4342edeb1f8 Mon Sep 17 00:00:00 2001 From: agorthi Date: Tue, 17 Sep 2024 15:17:23 +0530 Subject: [PATCH 046/474] DI-20360: Added change set --- .../pr-10891-tests-1726565438335.md | 5 + .../linode-widget-verification.spec.ts | 409 ++++++++++++------ .../cypress/support/constants/widgets.ts | 2 - .../intercepts/cloudpulseAPIHandler.ts | 1 - 4 files changed, 271 insertions(+), 146 deletions(-) create mode 100644 packages/manager/.changeset/pr-10891-tests-1726565438335.md diff --git a/packages/manager/.changeset/pr-10891-tests-1726565438335.md b/packages/manager/.changeset/pr-10891-tests-1726565438335.md new file mode 100644 index 00000000000..f0a1d6956e3 --- /dev/null +++ b/packages/manager/.changeset/pr-10891-tests-1726565438335.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Tests +--- + +Add cypress e2e test cases for cloudpulse ([#10891](https://github.com/linode/manager/pull/10891)) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 43bf5aa947a..0cef3d2ec9b 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -17,11 +17,22 @@ import { mockCloudPulseServices, } from 'support/intercepts/cloudpulseAPIHandler'; import { ui } from 'support/ui'; -import { timeRange, widgetDetails, granularity } from 'support/constants/widgets'; +import { + timeRange, + widgetDetails, + granularity, +} from 'support/constants/widgets'; import { makeFeatureFlagData } from 'support/util/feature-flags'; import { createMetricResponse } from '@src/factories/widget'; import type { Flags } from 'src/featureFlags'; -import { accountFactory, extendedDashboardFactory, kubeLinodeFactory, linodeFactory, metricDefinitionsFactory, regionFactory } from 'src/factories'; +import { + accountFactory, + extendedDashboardFactory, + kubeLinodeFactory, + linodeFactory, + metricDefinitionsFactory, + regionFactory, +} from 'src/factories'; import { mockGetAccount } from 'support/intercepts/account'; import { mockGetLinodes } from 'support/intercepts/linodes'; import { mockGetUserPreferences } from 'support/intercepts/profile'; @@ -41,19 +52,33 @@ import { getMetrics } from 'src/utilities/statMetrics'; * Each test ensures that widgets on the dashboard operate correctly and display accurate information. */ -const y_labels = ['system_cpu_utilization_ratio','system_memory_usage_bytes','system_network_io_bytes_total','system_disk_operations_total',]; -const widgets= widgetDetails.linode; -const metrics =widgets.metrics; +const y_labels = [ + 'system_cpu_utilization_ratio', + 'system_memory_usage_bytes', + 'system_network_io_bytes_total', + 'system_disk_operations_total', +]; +const widgets = widgetDetails.linode; +const metrics = widgets.metrics; export const dashboardName = widgets.dashboardName; export const region = widgets.region; export const actualRelativeTimeDuration = timeRange.Last24Hours; -export const resource = widgets.resource -const widgetLabels: string[] = metrics.map(widget => widget.title); -const metricsLabels: string[] = metrics.map(widget => widget.name); -const service_type =widgets.service_type; -const dashboardId=widgets.id -const dashboard = extendedDashboardFactory(dashboardName, widgetLabels, metricsLabels, y_labels,service_type).build(); -const metricDefinitions = metricDefinitionsFactory(widgetLabels, metricsLabels).build(); +export const resource = widgets.resource; +const widgetLabels: string[] = metrics.map((widget) => widget.title); +const metricsLabels: string[] = metrics.map((widget) => widget.name); +const service_type = widgets.service_type; +const dashboardId = widgets.id; +const dashboard = extendedDashboardFactory( + dashboardName, + widgetLabels, + metricsLabels, + y_labels, + service_type +).build(); +const metricDefinitions = metricDefinitionsFactory( + widgetLabels, + metricsLabels +).build(); const mockKubeLinode = kubeLinodeFactory.build(); const mockLinode = linodeFactory.build({ label: resource, @@ -70,22 +95,25 @@ const mockRegion = extendRegion( ); let responsePayload: CloudPulseMetricsResponse; describe('Dashboard Widget Verification Tests', () => { - beforeEach(() => { - mockAppendFeatureFlags({ + beforeEach(() => { + mockAppendFeatureFlags({ aclp: makeFeatureFlagData({ beta: true, enabled: true }), }).as('getFeatureFlags'); mockGetAccount(mockAccount).as('getAccount'); // Enables the account to have capability for Akamai Cloud Pulse mockGetFeatureFlagClientstream().as('getClientStream'); mockGetLinodes([mockLinode]).as('getLinodes'); - mockCloudPulseGetMetricDefinitions(metricDefinitions,service_type); - mockCloudPulseGetDashboards(dashboard,service_type).as('dashboard'); + mockCloudPulseGetMetricDefinitions(metricDefinitions, service_type); + mockCloudPulseGetDashboards(dashboard, service_type).as('dashboard'); mockCloudPulseServices(service_type).as('services'); - mockCloudPulseDashboardServicesResponse(dashboard,dashboardId); + mockCloudPulseDashboardServicesResponse(dashboard, dashboardId); mockCloudPulseJWSToken(service_type); - responsePayload = createMetricResponse(actualRelativeTimeDuration, granularity.Minutes); - mockCloudPulseCreateMetrics(responsePayload,service_type).as('getMetrics'); + responsePayload = createMetricResponse( + actualRelativeTimeDuration, + granularity.Minutes + ); + mockCloudPulseCreateMetrics(responsePayload, service_type).as('getMetrics'); mockGetRegions([mockRegion]).as('getRegions'); -}); + }); it('should verify cloudpulse availability when feature flag is set to false', () => { mockAppendFeatureFlags({ @@ -97,13 +125,13 @@ describe('Dashboard Widget Verification Tests', () => { }); it('should set available granularity of all the widgets', () => { - setupMethod() + setupMethod(); metrics.forEach((testData) => { - cy.wait(7000);//maintaining the wait since page flicker and rendering + cy.wait(7000); //maintaining the wait since page flicker and rendering const widgetSelector = `[data-qa-widget="${testData.title}"]`; - cy.get(widgetSelector).as('widget') + cy.get(widgetSelector).as('widget'); cy.get('@widget') - .should('be.visible') + .should('be.visible') .first() .within(() => { ui.autocomplete @@ -111,44 +139,60 @@ describe('Dashboard Widget Verification Tests', () => { .should('be.visible') .findByTitle('Open') .click(); - ui.autocompletePopper - .findByTitle(testData.expectedGranularity).as('granularityOption') - cy.get('@granularityOption') + ui.autocompletePopper + .findByTitle(testData.expectedGranularity) + .as('granularityOption'); + cy.get('@granularityOption') .should('be.visible') .should('have.text', testData.expectedGranularity) .click(); - cy.findByDisplayValue(testData.expectedGranularity).should('exist'); - cy.findByTestId('linegraph-wrapper').as('canvas') + cy.findByDisplayValue(testData.expectedGranularity).should('exist'); + cy.findByTestId('linegraph-wrapper') + .as('canvas') .should('be.visible') .find('tbody tr') .each(($tr, index) => { - const cells = $tr.find('td').map((i, el) => { - const text = Cypress.$(el).text().trim(); - return text.replace(/^\s*\([^)]+\)/, ''); - }).get(); + const cells = $tr + .find('td') + .map((i, el) => { + const text = Cypress.$(el).text().trim(); + return text.replace(/^\s*\([^)]+\)/, ''); + }) + .get(); const [title, actualMax, actualAvg, actualLast] = cells; const widgetValues = verifyWidgetValues(responsePayload); - compareWidgetValues( {title, max: parseFloat(actualMax), average: parseFloat(actualAvg),last: parseFloat(actualLast)}, widgetValues,testData.title); - assertSelections(testData.expectedGranularity); + compareWidgetValues( + { + title, + max: parseFloat(actualMax), + average: parseFloat(actualAvg), + last: parseFloat(actualLast), + }, + widgetValues, + testData.title + ); + assertSelections(testData.expectedGranularity); + }); }); - }); }); }); - + it('should verify the title of the widget', () => { - setupMethod() + setupMethod(); metrics.forEach((testData) => { const widgetSelector = `[data-qa-widget-header="${testData.title}"]`; - cy.get(widgetSelector).invoke('text').then((text) => { - expect(text.trim()).to.equal(testData.title); - }); + cy.get(widgetSelector) + .invoke('text') + .then((text) => { + expect(text.trim()).to.equal(testData.title); + }); }); }); it('should set available aggregation of all the widgets', () => { - setupMethod() + setupMethod(); metrics.forEach((testData) => { - cy.wait(7000);//maintaining the wait since page flicker and rendering + cy.wait(7000); //maintaining the wait since page flicker and rendering const widgetSelector = `[data-qa-widget="${testData.title}"]`; cy.get(widgetSelector) .first() @@ -164,41 +208,53 @@ describe('Dashboard Widget Verification Tests', () => { .should('be.visible') .should('have.text', testData.expectedAggregation) .click(); - cy.findByDisplayValue(testData.expectedAggregation).should('exist'); - cy.findByTestId('linegraph-wrapper').as('canvas') + cy.findByDisplayValue(testData.expectedAggregation).should('exist'); + cy.findByTestId('linegraph-wrapper') + .as('canvas') .should('be.visible') .find('tbody tr') .each(($tr, index) => { - const cells = $tr.find('td').map((i, el) => { - const text = Cypress.$(el).text().trim(); - return text.replace(/^\s*\([^)]+\)/, ''); - }).get(); - const [title, actualMax, actualAvg, actualLast] = cells; + const cells = $tr + .find('td') + .map((i, el) => { + const text = Cypress.$(el).text().trim(); + return text.replace(/^\s*\([^)]+\)/, ''); + }) + .get(); + const [title, actualMax, actualAvg, actualLast] = cells; const widgetValues = verifyWidgetValues(responsePayload); - compareWidgetValues( {title, max: parseFloat(actualMax), average: parseFloat(actualAvg),last: parseFloat(actualLast)}, widgetValues,testData.title); - assertSelections(testData.expectedAggregation); + compareWidgetValues( + { + title, + max: parseFloat(actualMax), + average: parseFloat(actualAvg), + last: parseFloat(actualLast), + }, + widgetValues, + testData.title + ); + assertSelections(testData.expectedAggregation); }); + }); }); }); -}); it('should verify available granularity of the widget', () => { - setupMethod() + setupMethod(); metrics.forEach((testData) => { - cy.wait(7000);//maintaining the wait since page flicker and rendering + cy.wait(7000); //maintaining the wait since page flicker and rendering const widgetSelector = `[data-qa-widget="${testData.title}"]`; cy.get(widgetSelector) .first() .scrollIntoView() .should('be.visible') .within(() => { - ui.autocomplete.findByTitleCustom('Select an Interval') + ui.autocomplete + .findByTitleCustom('Select an Interval') .findByTitle('Open') .click(); testData.expectedGranularityArray.forEach((option) => { - ui.autocompletePopper - .findByTitle(option) - .should('be.visible') + ui.autocompletePopper.findByTitle(option).should('be.visible'); }); ui.autocomplete .findByTitleCustom('Select an Interval') @@ -211,9 +267,9 @@ describe('Dashboard Widget Verification Tests', () => { }); it('should verify available aggregation of the widget', () => { - setupMethod() + setupMethod(); metrics.forEach((testData) => { - cy.wait(7000);//maintaining the wait since page flicker and rendering + cy.wait(7000); //maintaining the wait since page flicker and rendering const widgetSelector = `[data-qa-widget="${testData.title}"]`; cy.get(widgetSelector) .first() @@ -225,9 +281,7 @@ describe('Dashboard Widget Verification Tests', () => { .findByTitle('Open') .click(); testData.expectedAggregationArray.forEach((option) => { - ui.autocompletePopper - .findByTitle(option) - .should('be.visible') + ui.autocompletePopper.findByTitle(option).should('be.visible'); }); ui.autocomplete .findByTitleCustom('Select an Aggregate Function') @@ -240,85 +294,139 @@ describe('Dashboard Widget Verification Tests', () => { }); it('should apply global refresh button and verify network calls', () => { setupMethod(); - - ui.cloudpulse.findRefreshIcon().should('be.visible').click(); - cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']).then((interceptions) => { - const interceptionsArray = Array.isArray(interceptions) ? interceptions : [interceptions]; - interceptionsArray.forEach((interception) => { - const { body: requestPayload } = interception.request; - const { metric, time_granularity: granularity, relative_time_duration: timeRange, aggregate_function: aggregateFunction } = requestPayload; - const metricData = metrics.find(data => data.name === metric); - if (!metricData || !metricData.expectedGranularity || !metricData.expectedAggregation) { - expect.fail('metricData or its expected properties are not defined.'); - } - const expectedRelativeTimeDuration = timeRange - ? `Last ${timeRange.value} ${['hour', 'hr'].includes(timeRange.unit.toLowerCase()) ? 'Hours' : timeRange.unit}` - : ''; - const currentGranularity = granularity - ? `${granularity.value} ${['hour', 'hours'].includes(granularity.unit.toLowerCase()) ? 'hr' : granularity.unit}` - : ''; - expect(metric).to.equal(metricData.name); - expect(currentGranularity).to.equal(metricData.expectedGranularity); - expect(expectedRelativeTimeDuration).to.equal(actualRelativeTimeDuration); - // expect(aggregateFunction).to.equal(metricData.expectedAggregation); - }); - }); - + + ui.cloudpulse.findRefreshIcon().should('be.visible').click(); + cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']).then( + (interceptions) => { + const interceptionsArray = Array.isArray(interceptions) + ? interceptions + : [interceptions]; + interceptionsArray.forEach((interception) => { + const { body: requestPayload } = interception.request; + // const { metric, time_granularity: granularity, relative_time_duration: timeRange, aggregate_function: aggregateFunction } = requestPayload; + const { + metric, + time_granularity: granularity, + relative_time_duration: timeRange, + } = requestPayload; + const metricData = metrics.find((data) => data.name === metric); + if ( + !metricData || + !metricData.expectedGranularity || + !metricData.expectedAggregation + ) { + expect.fail( + 'metricData or its expected properties are not defined.' + ); + } + const expectedRelativeTimeDuration = timeRange + ? `Last ${timeRange.value} ${ + ['hour', 'hr'].includes(timeRange.unit.toLowerCase()) + ? 'Hours' + : timeRange.unit + }` + : ''; + const currentGranularity = granularity + ? `${granularity.value} ${ + ['hour', 'hours'].includes(granularity.unit.toLowerCase()) + ? 'hr' + : granularity.unit + }` + : ''; + expect(metric).to.equal(metricData.name); + expect(currentGranularity).to.equal(metricData.expectedGranularity); + expect(expectedRelativeTimeDuration).to.equal( + actualRelativeTimeDuration + ); + // expect(aggregateFunction).to.equal(metricData.expectedAggregation); + }); + } + ); }); it('should zoom in and out of all the widgets', () => { setupMethod(); metrics.forEach((testData) => { - cy.wait(7000); // Maintaining the wait since page flicker and rendering + cy.wait(7000); // Maintaining the wait since page flicker and rendering cy.get(`[data-qa-widget="${testData.title}"]`).as('widget'); - cy.get('@widget').should('be.visible').within(() => { - ui.cloudpulse.findZoomButtonByTitle('zoom-in') - .should('be.visible') - .should('be.enabled') - .click(); - cy.get('@widget').should('be.visible'); - cy.findByTestId('linegraph-wrapper').as('canvas') - .should('be.visible') - .find('tbody tr') - .each(($tr) => { - const cells = $tr.find('td').map((i, el) => Cypress.$(el).text().trim()).get(); - const [title, actualMax, actualAvg, actualLast] = cells; - const widgetValues = verifyWidgetValues(responsePayload); - compareWidgetValues({ title, max: parseFloat(actualMax), average: parseFloat(actualAvg),last: parseFloat(actualLast) - }, widgetValues, testData.title); - }); - ui.cloudpulse.findZoomButtonByTitle('zoom-out') - .should('be.visible') - .should('be.enabled') - .scrollIntoView() - .click({ force: true }); - cy.get('@widget').should('be.visible'); - cy.findByTestId('linegraph-wrapper').as('canvas') - .should('be.visible') - .find('tbody tr') - .each(($tr) => { - const cells = $tr.find('td').map((i, el) => Cypress.$(el).text().trim()).get(); - const [title, actualMax, actualAvg, actualLast] = cells; - const widgetValues = verifyWidgetValues(responsePayload); - compareWidgetValues({ title, max: parseFloat(actualMax),average: parseFloat(actualAvg),last: parseFloat(actualLast) - }, widgetValues, testData.title); - }); - }); + cy.get('@widget') + .should('be.visible') + .within(() => { + ui.cloudpulse + .findZoomButtonByTitle('zoom-in') + .should('be.visible') + .should('be.enabled') + .click(); + cy.get('@widget').should('be.visible'); + cy.findByTestId('linegraph-wrapper') + .as('canvas') + .should('be.visible') + .find('tbody tr') + .each(($tr) => { + const cells = $tr + .find('td') + .map((i, el) => Cypress.$(el).text().trim()) + .get(); + const [title, actualMax, actualAvg, actualLast] = cells; + const widgetValues = verifyWidgetValues(responsePayload); + compareWidgetValues( + { + title, + max: parseFloat(actualMax), + average: parseFloat(actualAvg), + last: parseFloat(actualLast), + }, + widgetValues, + testData.title + ); + }); + ui.cloudpulse + .findZoomButtonByTitle('zoom-out') + .should('be.visible') + .should('be.enabled') + .scrollIntoView() + .click({ force: true }); + cy.get('@widget').should('be.visible'); + cy.findByTestId('linegraph-wrapper') + .as('canvas') + .should('be.visible') + .find('tbody tr') + .each(($tr) => { + const cells = $tr + .find('td') + .map((i, el) => Cypress.$(el).text().trim()) + .get(); + const [title, actualMax, actualAvg, actualLast] = cells; + const widgetValues = verifyWidgetValues(responsePayload); + compareWidgetValues( + { + title, + max: parseFloat(actualMax), + average: parseFloat(actualAvg), + last: parseFloat(actualLast), + }, + widgetValues, + testData.title + ); + }); + }); }); }); - }); +}); - const setupMethod = () => { - mockGetUserPreferences({}).as('getUserPreferences'); - cy.visitWithLogin('monitor/cloudpulse'); - cy.get('[data-qa-header="Akamai Cloud Pulse"]').should('be.visible').should('have.text', 'Akamai Cloud Pulse'); - selectServiceName(dashboardName); - assertSelections(dashboardName); - selectTimeRange(actualRelativeTimeDuration, Object.values(timeRange)); - assertSelections(actualRelativeTimeDuration); - ui.regionSelect.find().click().type(`${region}{enter}`); - assertSelections(region); - selectAndVerifyResource(resource); +const setupMethod = () => { + mockGetUserPreferences({}).as('getUserPreferences'); + cy.visitWithLogin('monitor/cloudpulse'); + cy.get('[data-qa-header="Akamai Cloud Pulse"]') + .should('be.visible') + .should('have.text', 'Akamai Cloud Pulse'); + selectServiceName(dashboardName); + assertSelections(dashboardName); + selectTimeRange(actualRelativeTimeDuration, Object.values(timeRange)); + assertSelections(actualRelativeTimeDuration); + ui.regionSelect.find().click().type(`${region}{enter}`); + assertSelections(region); + selectAndVerifyResource(resource); }; const verifyWidgetValues = (responsePayload: CloudPulseMetricsResponse) => { @@ -327,7 +435,7 @@ const verifyWidgetValues = (responsePayload: CloudPulseMetricsResponse) => { const roundedAverage = Math.round(average * 100) / 100; const roundedLast = Math.round(last * 100) / 100; const roundedMax = Math.round(max * 100) / 100; - return {average: roundedAverage,last: roundedLast,max: roundedMax }; + return { average: roundedAverage, last: roundedLast, max: roundedMax }; }; /** @@ -345,13 +453,28 @@ const verifyWidgetValues = (responsePayload: CloudPulseMetricsResponse) => { */ const compareWidgetValues = ( - actualValues: { title:string, max: number, average: number, last: number }, - expectedValues: { max: number, average: number, last: number }, - title:string + actualValues: { title: string; max: number; average: number; last: number }, + expectedValues: { max: number; average: number; last: number }, + title: string ) => { - expect(actualValues.max).to.equal(expectedValues.max, `Expected ${expectedValues.max} for max, but got ${actualValues.max}`); - expect(actualValues.average).to.equal(expectedValues.average, `Expected ${expectedValues.average} for average, but got ${actualValues.average}`); - expect(actualValues.last).to.equal(expectedValues.last, `Expected ${expectedValues.last} for last, but got ${actualValues.last}`); - const extractedTitle = actualValues.title.substring(0, actualValues.title.indexOf(' ', actualValues.title.indexOf(' ') + 1)); - expect(extractedTitle).to.equal(title, `Expected ${title} for title ${extractedTitle}`); + expect(actualValues.max).to.equal( + expectedValues.max, + `Expected ${expectedValues.max} for max, but got ${actualValues.max}` + ); + expect(actualValues.average).to.equal( + expectedValues.average, + `Expected ${expectedValues.average} for average, but got ${actualValues.average}` + ); + expect(actualValues.last).to.equal( + expectedValues.last, + `Expected ${expectedValues.last} for last, but got ${actualValues.last}` + ); + const extractedTitle = actualValues.title.substring( + 0, + actualValues.title.indexOf(' ', actualValues.title.indexOf(' ') + 1) + ); + expect(extractedTitle).to.equal( + title, + `Expected ${title} for title ${extractedTitle}` + ); }; diff --git a/packages/manager/cypress/support/constants/widgets.ts b/packages/manager/cypress/support/constants/widgets.ts index 98f83c87e57..19d9f156ceb 100644 --- a/packages/manager/cypress/support/constants/widgets.ts +++ b/packages/manager/cypress/support/constants/widgets.ts @@ -1,5 +1,3 @@ -import { stat } from 'fs'; - /** * Defines the granularity levels used for specifying time intervals in data aggregation or reporting. * Each property represents a different granularity level. diff --git a/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts b/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts index 24ab6a053ae..f9edcd78718 100644 --- a/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts +++ b/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts @@ -7,7 +7,6 @@ import { apiMatcher } from 'support/util/intercepts'; import type { - AvailableMetrics, CloudPulseMetricsResponse, Dashboard, MetricDefinitions, From 2a662ae2c5ba61db2a6f2475f3786f6c0d03559a Mon Sep 17 00:00:00 2001 From: nikhagra Date: Wed, 18 Sep 2024 11:50:25 +0530 Subject: [PATCH 047/474] upcoming: [DI-20360] - Test cases updated --- .../Widget/components/CloudPulseIntervalSelect.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.test.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.test.tsx index 96023a33da8..822707a6865 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.test.tsx @@ -15,9 +15,9 @@ describe('Interval select component', () => { const { getByRole } = renderWithTheme( ); From 25fe43527704eb251e0f00e8f1f8bd3bc77107ca Mon Sep 17 00:00:00 2001 From: agorthi Date: Wed, 18 Sep 2024 15:59:28 +0530 Subject: [PATCH 048/474] upcoming:[DI-20585]- Added code review comments --- .../linode-widget-verification.spec.ts | 31 +++++++++- .../cypress/support/constants/widgets.ts | 62 +++++++++---------- .../cypress/support/util/cloudpulse.ts | 2 +- packages/manager/src/factories/widget.ts | 18 +++--- 4 files changed, 69 insertions(+), 44 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 0cef3d2ec9b..7b820a1a36c 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -62,7 +62,7 @@ const widgets = widgetDetails.linode; const metrics = widgets.metrics; export const dashboardName = widgets.dashboardName; export const region = widgets.region; -export const actualRelativeTimeDuration = timeRange.Last24Hours; +export const actualRelativeTimeDuration = timeRange.last24Hours; export const resource = widgets.resource; const widgetLabels: string[] = metrics.map((widget) => widget.title); const metricsLabels: string[] = metrics.map((widget) => widget.name); @@ -109,7 +109,7 @@ describe('Dashboard Widget Verification Tests', () => { mockCloudPulseJWSToken(service_type); responsePayload = createMetricResponse( actualRelativeTimeDuration, - granularity.Minutes + granularity.minutes ); mockCloudPulseCreateMetrics(responsePayload, service_type).as('getMetrics'); mockGetRegions([mockRegion]).as('getRegions'); @@ -413,6 +413,20 @@ describe('Dashboard Widget Verification Tests', () => { }); }); }); +/** + * `setupMethod` initializes the Cloud Pulse dashboard for testing by performing a series of setup actions. + * This method mocks user preferences, navigates to the Cloud Pulse page, and configures various settings + * including service name, time range, engine, region, resource, and node type. It also verifies each selection + * to ensure the dashboard is correctly configured before running further tests. + * + * Steps: + * 1. Mock user preferences to ensure a consistent test environment. + * 2. Navigate to the Cloud Pulse page and verify that it has loaded correctly. + * 3. Select and verify the service name. + * 4. Set and verify the time range for the dashboard. + * 5. Select and verify the region. + * 6. Choose and verify the resource from available widgets. + */ const setupMethod = () => { mockGetUserPreferences({}).as('getUserPreferences'); @@ -428,7 +442,18 @@ const setupMethod = () => { assertSelections(region); selectAndVerifyResource(resource); }; - +/** + * `verifyWidgetValues` processes and verifies the metric values of a widget from the provided response payload. + * + * This method performs the following steps: + * 1. Transforms the raw data from the response payload into a more manageable format using `transformData`. + * 2. Extracts key metrics (average, last, and max) from the transformed data using `getMetrics`. + * 3. Rounds these metrics to two decimal places for accuracy. + * 4. Returns an object containing the rounded average, last, and max values for further verification or comparison. + * + * @param {CloudPulseMetricsResponse} responsePayload - The response payload containing metric data for a widget. + * @returns {Object} An object with the rounded average, last, and max metric values. + */ const verifyWidgetValues = (responsePayload: CloudPulseMetricsResponse) => { const data = transformData(responsePayload.data.result[0].values, 'Bytes'); const { average, last, max } = getMetrics(data); diff --git a/packages/manager/cypress/support/constants/widgets.ts b/packages/manager/cypress/support/constants/widgets.ts index 19d9f156ceb..511325a395e 100644 --- a/packages/manager/cypress/support/constants/widgets.ts +++ b/packages/manager/cypress/support/constants/widgets.ts @@ -3,10 +3,10 @@ * Each property represents a different granularity level. */ export const granularity = { - Auto: 'Auto', - Day1: '1 day', - Hour: '1 hr', - Minutes: '5 min', + auto: 'Auto', + day1: '1 day', + hour: '1 hr', + minutes: '5 min', }; /** @@ -14,20 +14,20 @@ export const granularity = { * Each property represents a different type of aggregation operation. */ export const aggregation = { - Avg: 'avg', - Max: 'max', - Min: 'min', - Sum: 'sum', + avg: 'avg', + max: 'max', + min: 'min', + sum: 'sum', }; // Define a constant object named `timeRange` to represent various time periods. // This object maps time range identifiers to their descriptive strings. export const timeRange = { - Last7Days: 'Last 7 Days', - Last12Hours: 'Last 12 Hours', - Last24Hours: 'Last 24 Hours', - Last30Days: 'Last 30 Days', - Last30Minutes: 'Last 30 Minutes', + last7Days: 'Last 7 Days', + last12Hours: 'Last 12 Hours', + last24Hours: 'Last 24 Hours', + last30Days: 'Last 30 Days', + last30Minutes: 'Last 30 Minutes', }; // Define a constant object named `timeUnit` which serves as a mapping @@ -44,8 +44,8 @@ export const timeUnit = { */ export const aggregationConfig = { - all: [aggregation.Avg, aggregation.Max, aggregation.Min, aggregation.Sum], - basic: [aggregation.Avg, aggregation.Max, aggregation.Min], + all: [aggregation.avg, aggregation.max, aggregation.min, aggregation.sum], + basic: [aggregation.avg, aggregation.max, aggregation.min], }; /** * Configuration object for widget details. @@ -60,36 +60,36 @@ export const widgetDetails = { metrics: [ { StatsData: 'Controls for Disk I/O', - expectedAggregation: aggregation.Max, + expectedAggregation: aggregation.max, expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hour, + expectedGranularity: granularity.hour, expectedGranularityArray: Object.values(granularity), name: 'system_disk_OPS_total', title: 'Disk I/O', }, { StatsData: 'Controls for CPU Utilization', - expectedAggregation: aggregation.Max, + expectedAggregation: aggregation.max, expectedAggregationArray: aggregationConfig.basic, - expectedGranularity: granularity.Hour, + expectedGranularity: granularity.hour, expectedGranularityArray: Object.values(granularity), name: 'system_cpu_utilization_percent', title: 'CPU Utilization', }, { StatsData: 'Controls for Memory Usage', - expectedAggregation: aggregation.Max, + expectedAggregation: aggregation.max, expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hour, + expectedGranularity: granularity.hour, expectedGranularityArray: Object.values(granularity), name: 'system_memory_usage_by_resource', title: 'Memory Usage', }, { StatsData: 'Controls for Network Traffic', - expectedAggregation: aggregation.Max, + expectedAggregation: aggregation.max, expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hour, + expectedGranularity: granularity.hour, expectedGranularityArray: Object.values(granularity), name: 'system_network_io_by_resource', title: 'Network Traffic', @@ -105,33 +105,33 @@ export const widgetDetails = { id: 1, metrics: [ { - expectedAggregation: aggregation.Max, + expectedAggregation: aggregation.max, expectedAggregationArray: aggregationConfig.basic, - expectedGranularity: granularity.Hour, + expectedGranularity: granularity.hour, expectedGranularityArray: Object.values(granularity), name: 'system_cpu_utilization_percent', title: 'CPU Utilization', }, { - expectedAggregation: aggregation.Max, + expectedAggregation: aggregation.max, expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hour, + expectedGranularity: granularity.hour, expectedGranularityArray: Object.values(granularity), name: 'system_memory_usage_by_resource', title: 'Memory Usage', }, { - expectedAggregation: aggregation.Max, + expectedAggregation: aggregation.max, expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hour, + expectedGranularity: granularity.hour, expectedGranularityArray: Object.values(granularity), name: 'system_network_io_by_resource', title: 'Network Traffic', }, { - expectedAggregation: aggregation.Max, + expectedAggregation: aggregation.max, expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.Hour, + expectedGranularity: granularity.hour, expectedGranularityArray: Object.values(granularity), name: 'system_disk_OPS_total', title: 'Disk I/O', diff --git a/packages/manager/cypress/support/util/cloudpulse.ts b/packages/manager/cypress/support/util/cloudpulse.ts index 850db707e00..80c2c084bb5 100644 --- a/packages/manager/cypress/support/util/cloudpulse.ts +++ b/packages/manager/cypress/support/util/cloudpulse.ts @@ -91,7 +91,7 @@ export const resetDashboard = () => { */ export const chooseEngine = (engine: string) => { ui.autocomplete - .findByTitleCustom('Select a Value') + .findByTitleCustom('Select an Engine') .findByTitle('Open') .click(); ui.autocompletePopper.findByTitle(engine).should('be.visible').click(); diff --git a/packages/manager/src/factories/widget.ts b/packages/manager/src/factories/widget.ts index 6ecc3b259ee..324fee1f34d 100644 --- a/packages/manager/src/factories/widget.ts +++ b/packages/manager/src/factories/widget.ts @@ -25,18 +25,18 @@ export const createMetricResponse = ( const currentTime = Math.floor(Date.now() / 1000); const intervals: Record = { - [granularity.Auto]: 3600, - [granularity.Day1]: 86400, - [granularity.Hour]: 3600, - [granularity.Minutes]: 5 * 60, + [granularity.auto]: 3600, + [granularity.day1]: 86400, + [granularity.hour]: 3600, + [granularity.minutes]: 5 * 60, }; const timeRanges: Record = { - [timeRange.Last7Days]: 7 * 24 * 3600, - [timeRange.Last12Hours]: 12 * 3600, - [timeRange.Last24Hours]: 24 * 3600, - [timeRange.Last30Days]: 30 * 24 * 3600, - [timeRange.Last30Minutes]: 30 * 60, + [timeRange.last7Days]: 7 * 24 * 3600, + [timeRange.last12Hours]: 12 * 3600, + [timeRange.last24Hours]: 24 * 3600, + [timeRange.last30Days]: 30 * 24 * 3600, + [timeRange.last30Minutes]: 30 * 60, }; const interval = From 9326eca5414dc40e0b7fcc0690bd17e15305b8e1 Mon Sep 17 00:00:00 2001 From: agorthi Date: Sat, 21 Sep 2024 11:31:31 +0530 Subject: [PATCH 049/474] upcoming:[DI-20585]- Added code review comments --- packages/manager/cypress/support/constants/widgets.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/manager/cypress/support/constants/widgets.ts b/packages/manager/cypress/support/constants/widgets.ts index 511325a395e..9b44637d03b 100644 --- a/packages/manager/cypress/support/constants/widgets.ts +++ b/packages/manager/cypress/support/constants/widgets.ts @@ -53,7 +53,7 @@ export const aggregationConfig = { */ export const widgetDetails = { dbaas: { - cluster: 'mysql-cluster', + clusterName: 'mysql-cluster', dashboardName: 'Dbaas Dashboard', engine: 'MySQL', id: 1, @@ -95,7 +95,7 @@ export const widgetDetails = { title: 'Network Traffic', }, ], - nodeType: 'Primary', + nodeType: 'Secondary', region: 'US, Chicago, IL (us-ord)', resource: 'Dbaas-resource', service_type: 'dbaas', From a3525f402f2345c6ffdbbbc6879a953a5ea203fd Mon Sep 17 00:00:00 2001 From: agorthi Date: Mon, 23 Sep 2024 10:51:36 +0530 Subject: [PATCH 050/474] upcoming:[DI-20585]- fixing conflict --- .../features/CloudPulse/Overview/GlobalFilters.tsx | 9 +++++---- .../features/CloudPulse/Widget/CloudPulseWidget.tsx | 13 +++++++++---- .../DetailTabs/Processes/ProcessesLanding.tsx | 2 +- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index 4efeaa276d3..107cf97d9e3 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -98,10 +98,10 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { sx={{ marginBlockEnd: 'auto', }} - data-qa-refresh-button - disabled={!selectedDashboard} - onClick={() => handleGlobalRefresh(selectedDashboard)} - size="small" + data-qa-refresh-button + disabled={!selectedDashboard} + onClick={() => handleGlobalRefresh(selectedDashboard)} + size="small" > @@ -115,6 +115,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { borderColor: theme.color.grey5, margin: 0, }} + /> )} diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 5b6ed61d478..0c820cd2900 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -292,7 +292,10 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { return ( - + { marginBottom={1} padding={1} > - + marginLeft={1} + variant="h2" + > {convertStringToCamelCasesWithSpaces(widget.label)} ({currentUnit} {unit.endsWith('ps') ? '/s' : ''}) diff --git a/packages/manager/src/features/Longview/LongviewDetail/DetailTabs/Processes/ProcessesLanding.tsx b/packages/manager/src/features/Longview/LongviewDetail/DetailTabs/Processes/ProcessesLanding.tsx index 3157c738200..91c29ac8a10 100644 --- a/packages/manager/src/features/Longview/LongviewDetail/DetailTabs/Processes/ProcessesLanding.tsx +++ b/packages/manager/src/features/Longview/LongviewDetail/DetailTabs/Processes/ProcessesLanding.tsx @@ -128,7 +128,7 @@ export const ProcessesLanding = React.memo((props: Props) => { defaultValue={'Past 30 Minutes'} handleStatsChange={handleStatsChange} hideLabel - label="Select Time Range" + label="Select a Time Range" /> Date: Mon, 23 Sep 2024 12:26:54 +0530 Subject: [PATCH 051/474] upcoming:[DI-20585]- fixing place holder values --- .../manager/cypress/support/util/cloudpulse.ts | 14 +++++++------- .../shared/CloudPulseDashboardSelect.tsx | 2 +- .../shared/CloudPulseResourcesSelect.tsx | 2 +- .../shared/CloudPulseTimeRangeSelect.tsx | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/manager/cypress/support/util/cloudpulse.ts b/packages/manager/cypress/support/util/cloudpulse.ts index 80c2c084bb5..14440af7b63 100644 --- a/packages/manager/cypress/support/util/cloudpulse.ts +++ b/packages/manager/cypress/support/util/cloudpulse.ts @@ -25,12 +25,12 @@ import { ui } from 'support/ui'; export const selectServiceName = (serviceName: string) => { ui.autocomplete - .findByTitleCustom('Select Dashboard') + .findByTitleCustom('Select a Dashboard') .findByTitle('Open') .should('be.visible') .click(); ui.autocomplete - .findByPlaceholderCustom('Select Dashboard') + .findByPlaceholderCustom('Select a Dashboard') .type(`${serviceName}{enter}`); cy.findByDisplayValue(serviceName).should('have.value', serviceName); }; @@ -43,7 +43,7 @@ export const selectServiceName = (serviceName: string) => { */ export const selectTimeRange = (timeRange: string, timeSegments: string[]) => { ui.autocomplete - .findByTitleCustom('Select Time Duration') + .findByTitleCustom('Select a Time Duration') .findByTitle('Open') .click(); timeSegments.forEach((option) => { @@ -57,7 +57,7 @@ export const selectTimeRange = (timeRange: string, timeSegments: string[]) => { * @param {string} service - The name of the service to select. */ export const selectAndVerifyResource = (service: string) => { - const resourceInput = ui.autocomplete.findByTitleCustom('Select Resources'); + const resourceInput = ui.autocomplete.findByTitleCustom('Select a Resources'); resourceInput.findByTitle('Open').click(); resourceInput.click().type(`${service}{enter}`); cy.get('[title="Close"]').click(); @@ -76,12 +76,12 @@ export const assertSelections = (expectedOptions: string) => { */ export const resetDashboard = () => { ui.autocomplete - .findByTitleCustom('Select Dashboard') + .findByTitleCustom('Select a Dashboard') .findByTitle('Clear') .click(); ui.autocomplete - .findByPlaceholderCustom('Select Dashboard') + .findByPlaceholderCustom('Select a Dashboard') .should('have.value', ''); }; /** @@ -105,7 +105,7 @@ export const chooseEngine = (engine: string) => { export const chooseNodeType = (node: string) => { ui.autocomplete - .findByPlaceholderCustom('Select Node Type') + .findByPlaceholderCustom('Select a Node Type') .should('be.visible') .type(node) .click(); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index a27e9051d87..6b62eba2ea2 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -116,7 +116,7 @@ export const CloudPulseDashboardSelect = React.memo( fullWidth groupBy={(option: Dashboard) => option.service_type} isOptionEqualToValue={(option, value) => option.id === value.id} - label="Select Dashboard" + label="Select a Dashboard" loading={dashboardsLoading || serviceTypesLoading} options={getSortedDashboardsList(dashboardsList ?? [])} placeholder={placeHolder} diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index adaf971e1ba..bd95fb07869 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -110,7 +110,7 @@ export const CloudPulseResourcesSelect = React.memo( data-testid="resource-select" disabled={disabled || isLoading} isOptionEqualToValue={(option, value) => option.id === value.id} - label="Select Resources" + label="Select a Resources" limitTags={2} multiple options={getResourcesList()} diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx index b270743305f..0ab3dd8ac8f 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx @@ -83,7 +83,7 @@ export const CloudPulseTimeRangeSelect = React.memo( disableClearable fullWidth isOptionEqualToValue={(option, value) => option.value === value.value} - label="Select Time Duration" + label="Select a Time Duration" options={options} placeholder={placeholder ?? 'Select a Time Duration'} value={selectedTimeRange} From 1e7e89715b3aae68149acfb944ec2a9c2715e6e9 Mon Sep 17 00:00:00 2001 From: nikhagra Date: Mon, 26 Aug 2024 09:45:26 +0530 Subject: [PATCH 052/474] upcoming: [DI-20360] - Modified user preference logic --- packages/api-v4/src/cloudpulse/dashboards.ts | 13 ++++++++++--- packages/api-v4/src/cloudpulse/services.ts | 6 +++++- packages/manager/src/MainContent.tsx | 2 +- .../src/components/PrimaryNav/PrimaryNav.tsx | 2 +- .../Dashboard/CloudPulseDashboardLanding.tsx | 1 + .../src/features/CloudPulse/Utils/FilterBuilder.ts | 6 ++++++ .../src/features/CloudPulse/Utils/UserPreference.ts | 3 +++ .../features/CloudPulse/Widget/CloudPulseWidget.tsx | 1 + .../CloudPulse/shared/CloudPulseRegionSelect.tsx | 8 +++++++- .../CloudPulse/shared/CloudPulseResourcesSelect.tsx | 4 +++- .../CloudPulse/shared/CloudPulseTimeRangeSelect.tsx | 2 ++ packages/manager/src/queries/cloudpulse/metrics.ts | 6 ++++-- packages/manager/src/request.tsx | 2 +- 13 files changed, 45 insertions(+), 11 deletions(-) diff --git a/packages/api-v4/src/cloudpulse/dashboards.ts b/packages/api-v4/src/cloudpulse/dashboards.ts index c8802747e52..90390a10106 100644 --- a/packages/api-v4/src/cloudpulse/dashboards.ts +++ b/packages/api-v4/src/cloudpulse/dashboards.ts @@ -1,5 +1,5 @@ import { ResourcePage } from 'src/types'; -import Request, { setMethod, setURL } from '../request'; +import Request, { setHeaders, setMethod, setURL } from '../request'; import { Dashboard } from './types'; import { BETA_API_ROOT as API_ROOT } from 'src/constants'; @@ -16,6 +16,13 @@ export const getDashboards = (serviceType: string) => export const getDashboardById = (dashboardId: number) => Request( - setURL(`${API_ROOT}/monitor/dashboards/${encodeURIComponent(dashboardId)}`), - setMethod('GET') + setURL( + `https://blr-lhv95n.bangalore.corp.akamai.com:9000/v4beta/monitor/dashboards/${encodeURIComponent( + dashboardId + )}` + ), + setMethod('GET'), + setHeaders({ + Authorization: 'Bearer vagrant', + }) ); diff --git a/packages/api-v4/src/cloudpulse/services.ts b/packages/api-v4/src/cloudpulse/services.ts index 5eb06faa0e5..37abc6d0d75 100644 --- a/packages/api-v4/src/cloudpulse/services.ts +++ b/packages/api-v4/src/cloudpulse/services.ts @@ -22,12 +22,16 @@ export const getMetricDefinitionsByServiceType = (serviceType: string) => { export const getJWEToken = (data: JWETokenPayLoad, serviceType: string) => Request( setURL( - `${API_ROOT}/monitor/services/${encodeURIComponent(serviceType)}/token` + `${API_ROOT}/monitor/services/${encodeURIComponent( + serviceType + )}/token` ), setMethod('POST'), setData(data) ); + + // Returns the list of service types available export const getCloudPulseServiceTypes = () => Request( diff --git a/packages/manager/src/MainContent.tsx b/packages/manager/src/MainContent.tsx index 9172bf218c4..dabeec77a3b 100644 --- a/packages/manager/src/MainContent.tsx +++ b/packages/manager/src/MainContent.tsx @@ -356,7 +356,7 @@ export const MainContent = () => { )} - {isACLPEnabled && ( + {!isACLPEnabled && ( { }, { display: 'Monitor', - hide: !isACLPEnabled, + hide: isACLPEnabled, href: '/monitor/cloudpulse', icon: , isBeta: flags.aclp?.beta, diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx index f43ea8daed8..8c1654e9060 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx @@ -38,6 +38,7 @@ export const CloudPulseDashboardLanding = () => { const onDashboardChange = React.useCallback((dashboardObj: Dashboard) => { setDashboard(dashboardObj); setFilterValue({}); // clear the filter values on dashboard change + }, []); const onTimeDurationChange = React.useCallback( (timeDurationObj: TimeDuration) => { diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts index 36a5b9cfa0a..9ac3a32cced 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts @@ -62,8 +62,10 @@ export const getRegionProperties = ( defaultValue: preferences?.[REGION], handleRegionChange, placeholder, + preferences, savePreferences: !isServiceAnalyticsIntegration, selectedDashboard: dashboard, + updatePreferences, }; }; @@ -101,8 +103,10 @@ export const getResourcesProperties = ( ), handleResourcesSelection: handleResourceChange, placeholder, + preferences, resourceType: dashboard.service_type, savePreferences: !isServiceAnalyticsIntegration, + updatePreferences, xFilter: buildXFilter(config, dependentFilters ?? {}), }; }; @@ -190,7 +194,9 @@ export const getTimeDurationProperties = ( defaultValue: timeDuration, handleStatsChange: handleTimeRangeChange, placeholder, + preferences, savePreferences: !isServiceAnalyticsIntegration, + updatePreferences, }; }; diff --git a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts index 9409ae8e96f..5516495ad19 100644 --- a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts +++ b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts @@ -1,8 +1,11 @@ +import { useRef } from 'react'; + import { useMutatePreferences, usePreferences, } from 'src/queries/profile/preferences'; + import { DASHBOARD_ID, TIME_DURATION } from './constants'; import type { AclpConfig, AclpWidget } from '@linode/api-v4'; diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 962f4a5d09f..44970648394 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -259,6 +259,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { } const metricsApiCallError = error?.[0]?.reason; + return ( diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index 0b2f085bcb9..4c5c9bdc5b9 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -3,18 +3,24 @@ import * as React from 'react'; import { RegionSelect } from 'src/components/RegionSelect/RegionSelect'; import { useRegionsQuery } from 'src/queries/regions/regions'; -import type { Dashboard, FilterValue } from '@linode/api-v4'; +import type { AclpConfig, Dashboard, FilterValue } from '@linode/api-v4'; export interface CloudPulseRegionSelectProps { defaultValue?: FilterValue; handleRegionChange: (region: string | undefined, savePref?: boolean) => void; placeholder?: string; + preferences: AclpConfig; savePreferences?: boolean; selectedDashboard: Dashboard | undefined; + updatePreferences: (data: {}) => void; } export const CloudPulseRegionSelect = React.memo( (props: CloudPulseRegionSelectProps) => { + // const { + // preferences, + // updateGlobalFilterPreference: updatePreferences, + // } = useAclpPreference(); const { data: regions } = useRegionsQuery(); const { diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index c2d30c281f8..d9f2d93e9ea 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -21,9 +21,11 @@ export interface CloudPulseResourcesSelectProps { savePref?: boolean ) => void; placeholder?: string; + preferences: AclpConfig; region?: string; resourceType: string | undefined; savePreferences?: boolean; + updatePreferences: (data: {}) => void; xFilter?: Filter; } @@ -34,6 +36,7 @@ export const CloudPulseResourcesSelect = React.memo( disabled, handleResourcesSelection, placeholder, + preferences, region, resourceType, savePreferences, @@ -103,7 +106,6 @@ export const CloudPulseResourcesSelect = React.memo( limitTags={2} multiple options={getResourcesList} - placeholder={placeholder ? placeholder : 'Select Resources'} value={selectedResources ?? []} /> ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx index b22a96681ef..91c5409d50b 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx @@ -20,7 +20,9 @@ export interface CloudPulseTimeRangeSelectProps savePref?: boolean ) => void; placeholder?: string; + preferences?: AclpConfig; savePreferences?: boolean; + updatePreferences?: (data: {}) => void; } const PAST_7_DAYS = 'Last 7 Days'; diff --git a/packages/manager/src/queries/cloudpulse/metrics.ts b/packages/manager/src/queries/cloudpulse/metrics.ts index cc5e0fbe1c9..df983c5a7b9 100644 --- a/packages/manager/src/queries/cloudpulse/metrics.ts +++ b/packages/manager/src/queries/cloudpulse/metrics.ts @@ -80,11 +80,13 @@ export const fetchCloudPulseMetrics = ( const config: AxiosRequestConfig = { data: requestData, headers: { - 'Authentication-Type': 'jwe', + 'Authentication-type': 'jwe', Authorization: `Bearer ${token}`, }, method: 'POST', - url: `${readApiEndpoint}${encodeURIComponent(serviceType!)}/metrics`, + url: `https://metrics-query.aclp.linode.com/v1/monitor/services/${encodeURIComponent( + serviceType! + )}/metrics`, }; return axiosInstance diff --git a/packages/manager/src/request.tsx b/packages/manager/src/request.tsx index 9f2b7659e38..15489afcc4e 100644 --- a/packages/manager/src/request.tsx +++ b/packages/manager/src/request.tsx @@ -34,7 +34,7 @@ export const handleError = ( * this will blow out redux state and the componentDidUpdate in the * AuthenticationWrapper.tsx will be responsible for redirecting to Login */ - store.dispatch(handleLogout()); + // store.dispatch(handleLogout()); } const status: number = error.response?.status ?? 0; From c4e4845c20c52911c20d7a6587dd8c57cabc0fb4 Mon Sep 17 00:00:00 2001 From: nikhagra Date: Tue, 27 Aug 2024 21:27:15 +0530 Subject: [PATCH 053/474] upcoming: [DI-20360] - Modified user preference logic --- packages/api-v4/src/cloudpulse/dashboards.ts | 6 +----- packages/manager/src/MainContent.tsx | 2 +- packages/manager/src/components/PrimaryNav/PrimaryNav.tsx | 2 +- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/api-v4/src/cloudpulse/dashboards.ts b/packages/api-v4/src/cloudpulse/dashboards.ts index 90390a10106..c870498968d 100644 --- a/packages/api-v4/src/cloudpulse/dashboards.ts +++ b/packages/api-v4/src/cloudpulse/dashboards.ts @@ -16,11 +16,7 @@ export const getDashboards = (serviceType: string) => export const getDashboardById = (dashboardId: number) => Request( - setURL( - `https://blr-lhv95n.bangalore.corp.akamai.com:9000/v4beta/monitor/dashboards/${encodeURIComponent( - dashboardId - )}` - ), + setURL(`${API_ROOT}/monitor/dashboards/${encodeURIComponent(dashboardId)}`), setMethod('GET'), setHeaders({ Authorization: 'Bearer vagrant', diff --git a/packages/manager/src/MainContent.tsx b/packages/manager/src/MainContent.tsx index dabeec77a3b..9172bf218c4 100644 --- a/packages/manager/src/MainContent.tsx +++ b/packages/manager/src/MainContent.tsx @@ -356,7 +356,7 @@ export const MainContent = () => { )} - {!isACLPEnabled && ( + {isACLPEnabled && ( { }, { display: 'Monitor', - hide: isACLPEnabled, + hide: !isACLPEnabled, href: '/monitor/cloudpulse', icon: , isBeta: flags.aclp?.beta, From c03e981925e4144500cb3840a3d653776a047649 Mon Sep 17 00:00:00 2001 From: nikhagra Date: Thu, 29 Aug 2024 19:13:09 +0530 Subject: [PATCH 054/474] upcoming: [DI-20360] - Updated request.tsx file --- packages/manager/src/request.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/request.tsx b/packages/manager/src/request.tsx index 15489afcc4e..9f2b7659e38 100644 --- a/packages/manager/src/request.tsx +++ b/packages/manager/src/request.tsx @@ -34,7 +34,7 @@ export const handleError = ( * this will blow out redux state and the componentDidUpdate in the * AuthenticationWrapper.tsx will be responsible for redirecting to Login */ - // store.dispatch(handleLogout()); + store.dispatch(handleLogout()); } const status: number = error.response?.status ?? 0; From ddc1dca17501be39c2b792273021092470842459 Mon Sep 17 00:00:00 2001 From: nikhagra Date: Thu, 29 Aug 2024 19:40:42 +0530 Subject: [PATCH 055/474] upcoming: [DI-20360] - remove sensitive information --- packages/api-v4/src/cloudpulse/dashboards.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/api-v4/src/cloudpulse/dashboards.ts b/packages/api-v4/src/cloudpulse/dashboards.ts index c870498968d..c8802747e52 100644 --- a/packages/api-v4/src/cloudpulse/dashboards.ts +++ b/packages/api-v4/src/cloudpulse/dashboards.ts @@ -1,5 +1,5 @@ import { ResourcePage } from 'src/types'; -import Request, { setHeaders, setMethod, setURL } from '../request'; +import Request, { setMethod, setURL } from '../request'; import { Dashboard } from './types'; import { BETA_API_ROOT as API_ROOT } from 'src/constants'; @@ -17,8 +17,5 @@ export const getDashboards = (serviceType: string) => export const getDashboardById = (dashboardId: number) => Request( setURL(`${API_ROOT}/monitor/dashboards/${encodeURIComponent(dashboardId)}`), - setMethod('GET'), - setHeaders({ - Authorization: 'Bearer vagrant', - }) + setMethod('GET') ); From 32c723cecc03eb57fa5b5e9738ecd0221c43be52 Mon Sep 17 00:00:00 2001 From: nikhagra Date: Mon, 2 Sep 2024 16:45:24 +0530 Subject: [PATCH 056/474] upcoming: [DI-20360] - Update preference logic to avoid extra re-renderings --- .../src/features/CloudPulse/Overview/GlobalFilters.tsx | 1 + .../src/features/CloudPulse/Utils/FilterBuilder.ts | 1 - .../features/CloudPulse/shared/CloudPulseRegionSelect.tsx | 8 ++------ .../CloudPulse/shared/CloudPulseResourcesSelect.tsx | 4 ++-- .../CloudPulse/shared/CloudPulseTimeRangeSelect.tsx | 1 - 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index b5b2c2f9a4a..6bd42f476ba 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -27,6 +27,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { handleDashboardChange, handleTimeDurationChange, } = props; + const { preferences, updateGlobalFilterPreference: updatePreferences, diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts index 9ac3a32cced..e510e2e804f 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts @@ -194,7 +194,6 @@ export const getTimeDurationProperties = ( defaultValue: timeDuration, handleStatsChange: handleTimeRangeChange, placeholder, - preferences, savePreferences: !isServiceAnalyticsIntegration, updatePreferences, }; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index 4c5c9bdc5b9..ded76c02239 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -9,18 +9,14 @@ export interface CloudPulseRegionSelectProps { defaultValue?: FilterValue; handleRegionChange: (region: string | undefined, savePref?: boolean) => void; placeholder?: string; - preferences: AclpConfig; + preferences?: AclpConfig; savePreferences?: boolean; selectedDashboard: Dashboard | undefined; - updatePreferences: (data: {}) => void; + updatePreferences?: (data: {}) => void; } export const CloudPulseRegionSelect = React.memo( (props: CloudPulseRegionSelectProps) => { - // const { - // preferences, - // updateGlobalFilterPreference: updatePreferences, - // } = useAclpPreference(); const { data: regions } = useRegionsQuery(); const { diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index d9f2d93e9ea..c1e001bf2e4 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -21,11 +21,11 @@ export interface CloudPulseResourcesSelectProps { savePref?: boolean ) => void; placeholder?: string; - preferences: AclpConfig; + preferences?: AclpConfig; region?: string; resourceType: string | undefined; savePreferences?: boolean; - updatePreferences: (data: {}) => void; + updatePreferences?: (data: {}) => void; xFilter?: Filter; } diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx index 91c5409d50b..6e0750f9829 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx @@ -20,7 +20,6 @@ export interface CloudPulseTimeRangeSelectProps savePref?: boolean ) => void; placeholder?: string; - preferences?: AclpConfig; savePreferences?: boolean; updatePreferences?: (data: {}) => void; } From 2261c75633e04391ef8c410a30a8dce507b472ed Mon Sep 17 00:00:00 2001 From: nikhagra Date: Mon, 2 Sep 2024 17:32:53 +0530 Subject: [PATCH 057/474] upcoming: [DI-20360] - Updated preference logic in custom select --- .../manager/src/features/CloudPulse/Utils/FilterBuilder.ts | 2 ++ .../features/CloudPulse/shared/CloudPulseCustomSelect.tsx | 7 +++++++ .../CloudPulse/shared/CloudPulseCustomSelectUtils.ts | 6 ++++++ 3 files changed, 15 insertions(+) diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts index e510e2e804f..cc77fe1bc44 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts @@ -163,10 +163,12 @@ export const getCustomSelectProperties = ( maxSelections, options, placeholder, + preferences, savePreferences: !isServiceAnalyticsIntegration, type: options ? CloudPulseSelectTypes.static : CloudPulseSelectTypes.dynamic, + updatePreferences, }; }; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index 7e992151c20..1ce46ebe891 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -97,6 +97,8 @@ export interface CloudPulseCustomSelectProps { */ placeholder?: string; + preferences?: AclpConfig; + /** * This property controls whether to save the preferences or not */ @@ -106,6 +108,8 @@ export interface CloudPulseCustomSelectProps { * The cloud pulse select types, it can be static or dynamic depending on the use case */ type: CloudPulseSelectTypes; + + updatePreferences?: (data: {}) => void; } export enum CloudPulseSelectTypes { @@ -128,8 +132,10 @@ export const CloudPulseCustomSelect = React.memo( maxSelections, options, placeholder, + preferences, savePreferences, type, + updatePreferences, } = props; const [selectedResource, setResource] = React.useState< @@ -159,6 +165,7 @@ export const CloudPulseCustomSelect = React.memo( handleSelectionChange, isMultiSelect: isMultiSelect ?? false, options: options || queriedResources || [], + preferences, savePreferences: savePreferences ?? false, }) ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts index f4128a4b69b..ed25319c59f 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts @@ -65,6 +65,11 @@ interface CloudPulseCustomSelectionChangeProps */ maxSelections?: number; + preferences?: AclpConfig; + savePreferences?: boolean; + + updatePreferences?: (data: {}) => void; + /** * The listed options in the custom select component */ @@ -90,6 +95,7 @@ export const getInitialDefaultSelections = ( handleSelectionChange, isMultiSelect, options, + preferences, savePreferences, } = defaultSelectionProps; From a24d22a8ab7c6a71c991e7709c9a406f3ff83834 Mon Sep 17 00:00:00 2001 From: nikhagra Date: Mon, 9 Sep 2024 17:31:42 +0530 Subject: [PATCH 058/474] upcoming: [DI-20360] - Optimized user preferences to avoid passing update function as props --- .../manager/src/features/CloudPulse/Utils/FilterBuilder.ts | 4 ---- .../src/features/CloudPulse/Widget/CloudPulseWidget.tsx | 2 +- .../src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx | 3 --- .../features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts | 2 -- .../src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx | 2 -- .../features/CloudPulse/shared/CloudPulseResourcesSelect.tsx | 3 --- .../features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx | 1 - 7 files changed, 1 insertion(+), 16 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts index cc77fe1bc44..8ffc205279d 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts @@ -65,7 +65,6 @@ export const getRegionProperties = ( preferences, savePreferences: !isServiceAnalyticsIntegration, selectedDashboard: dashboard, - updatePreferences, }; }; @@ -106,7 +105,6 @@ export const getResourcesProperties = ( preferences, resourceType: dashboard.service_type, savePreferences: !isServiceAnalyticsIntegration, - updatePreferences, xFilter: buildXFilter(config, dependentFilters ?? {}), }; }; @@ -168,7 +166,6 @@ export const getCustomSelectProperties = ( type: options ? CloudPulseSelectTypes.static : CloudPulseSelectTypes.dynamic, - updatePreferences, }; }; @@ -197,7 +194,6 @@ export const getTimeDurationProperties = ( handleStatsChange: handleTimeRangeChange, placeholder, savePreferences: !isServiceAnalyticsIntegration, - updatePreferences, }; }; diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 44970648394..7e22dde9df2 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -262,7 +262,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { return ( - + void; } export enum CloudPulseSelectTypes { @@ -135,7 +133,6 @@ export const CloudPulseCustomSelect = React.memo( preferences, savePreferences, type, - updatePreferences, } = props; const [selectedResource, setResource] = React.useState< diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts index ed25319c59f..56b3ba5d9ac 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts @@ -68,8 +68,6 @@ interface CloudPulseCustomSelectionChangeProps preferences?: AclpConfig; savePreferences?: boolean; - updatePreferences?: (data: {}) => void; - /** * The listed options in the custom select component */ diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index ded76c02239..5b288e01bfd 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -9,10 +9,8 @@ export interface CloudPulseRegionSelectProps { defaultValue?: FilterValue; handleRegionChange: (region: string | undefined, savePref?: boolean) => void; placeholder?: string; - preferences?: AclpConfig; savePreferences?: boolean; selectedDashboard: Dashboard | undefined; - updatePreferences?: (data: {}) => void; } export const CloudPulseRegionSelect = React.memo( diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index c1e001bf2e4..be17ec426f1 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -21,11 +21,9 @@ export interface CloudPulseResourcesSelectProps { savePref?: boolean ) => void; placeholder?: string; - preferences?: AclpConfig; region?: string; resourceType: string | undefined; savePreferences?: boolean; - updatePreferences?: (data: {}) => void; xFilter?: Filter; } @@ -36,7 +34,6 @@ export const CloudPulseResourcesSelect = React.memo( disabled, handleResourcesSelection, placeholder, - preferences, region, resourceType, savePreferences, diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx index 6e0750f9829..b22a96681ef 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx @@ -21,7 +21,6 @@ export interface CloudPulseTimeRangeSelectProps ) => void; placeholder?: string; savePreferences?: boolean; - updatePreferences?: (data: {}) => void; } const PAST_7_DAYS = 'Last 7 Days'; From ef4f6475de7bd93959a59abf04a36095c78016a1 Mon Sep 17 00:00:00 2001 From: nikhagra Date: Wed, 11 Sep 2024 18:32:49 +0530 Subject: [PATCH 059/474] upcoming: [DI-20360] - Changes based on review comments --- .../CloudPulse/Overview/GlobalFilters.tsx | 2 + .../shared/CloudPulseCustomSelectUtils.ts | 40 +++++++++++++++++-- .../manager/src/queries/cloudpulse/metrics.ts | 2 +- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index 6bd42f476ba..d3f118f5069 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -21,6 +21,8 @@ export interface GlobalFilterProperties { handleTimeDurationChange(timeDuration: TimeDuration): void; } +export interface FilterChangeProperties {} + export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { const { handleAnyFilterChange, diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts index 56b3ba5d9ac..5d0b3f9df63 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts @@ -39,6 +39,43 @@ interface CloudPulseCustomSelectDefaultValueProps */ defaultValue?: FilterValue; + /** + * Last selected values from user preference + */ + preferences?: AclpConfig; + + /** + * boolean variable to check whether preferences should be saved or not + */ + savePreferences?: boolean; +} + +/** + * The interface for selecting the default value from the user preferences + */ +interface CloudPulseCustomSelectDefaultValueProps + extends CloudPulseCustomSelectProps { + /** + * Default selected value from the drop down + */ + defaultValue?: FilterValue; + + /** + * Last selected values from user preference + */ + preferences?: AclpConfig; + + /** + * boolean variable to check whether preferences should be saved or not + */ + savePreferences?: boolean; +} + +/** + * The interface for selecting the default value from the user preferences + */ +interface CloudPulseCustomSelectDefaultValueProps + extends CloudPulseCustomSelectProps { /** * Indicates whether we need multiselect for the component or not */ @@ -65,9 +102,6 @@ interface CloudPulseCustomSelectionChangeProps */ maxSelections?: number; - preferences?: AclpConfig; - savePreferences?: boolean; - /** * The listed options in the custom select component */ diff --git a/packages/manager/src/queries/cloudpulse/metrics.ts b/packages/manager/src/queries/cloudpulse/metrics.ts index df983c5a7b9..88b6adf02d9 100644 --- a/packages/manager/src/queries/cloudpulse/metrics.ts +++ b/packages/manager/src/queries/cloudpulse/metrics.ts @@ -80,7 +80,7 @@ export const fetchCloudPulseMetrics = ( const config: AxiosRequestConfig = { data: requestData, headers: { - 'Authentication-type': 'jwe', + 'Authentication-Type': 'jwe', Authorization: `Bearer ${token}`, }, method: 'POST', From 22374c66dc5d2f8fc4ce09b7bd3510be2141c54a Mon Sep 17 00:00:00 2001 From: nikhagra Date: Wed, 11 Sep 2024 19:30:27 +0530 Subject: [PATCH 060/474] upcoming: [DI-20360] - Upddated widget components to avoid infinite loop --- .../src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index be17ec426f1..f1024678a0f 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -69,7 +69,6 @@ export const CloudPulseResourcesSelect = React.memo( handleResourcesSelection(resource); setSelectedResources(resource); } else { - setSelectedResources([]); handleResourcesSelection([]); } From a7a1b0f4c9c4fe074b91cdeb148c90b2af9d530d Mon Sep 17 00:00:00 2001 From: nikhagra Date: Mon, 16 Sep 2024 19:24:49 +0530 Subject: [PATCH 061/474] upcoming: [DI-20360] - Updated review comment suggestions & test cases --- .../src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index f1024678a0f..be17ec426f1 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -69,6 +69,7 @@ export const CloudPulseResourcesSelect = React.memo( handleResourcesSelection(resource); setSelectedResources(resource); } else { + setSelectedResources([]); handleResourcesSelection([]); } From 427cd4e08bc577659b185bde437651e921f336e7 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Thu, 19 Sep 2024 17:36:15 +0530 Subject: [PATCH 062/474] upcoming: [DI-20360] - Updated useAclpPreference hook to use ref for preserving the changes without re-rendering --- .../Dashboard/CloudPulseDashboard.tsx | 172 ++------------- .../Dashboard/CloudPulseDashboardLanding.tsx | 106 ++++++---- .../CloudPulse/Overview/GlobalFilters.tsx | 7 +- .../CloudPulse/Utils/FilterBuilder.ts | 1 + .../CloudPulse/Utils/UserPreference.ts | 9 +- .../Widget/CloudPulseWidgetRenderer.tsx | 200 ++++++++++++++++++ .../shared/CloudPulseCustomSelect.tsx | 15 +- .../shared/CloudPulseDashboardSelect.tsx | 3 +- .../shared/CloudPulseRegionSelect.tsx | 10 +- .../shared/CloudPulseResourcesSelect.tsx | 5 +- .../shared/CloudPulseTimeRangeSelect.tsx | 6 +- 11 files changed, 331 insertions(+), 203 deletions(-) create mode 100644 packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index 34fa3753216..220c8b2813b 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -1,10 +1,8 @@ -import { Grid, Paper } from '@mui/material'; +import { Grid } from '@mui/material'; import React from 'react'; -import CloudPulseIcon from 'src/assets/icons/entityIcons/monitor.svg'; import { CircleProgress } from 'src/components/CircleProgress'; import { ErrorState } from 'src/components/ErrorState/ErrorState'; -import { Placeholder } from 'src/components/Placeholder/Placeholder'; import { useCloudPulseDashboardByIdQuery } from 'src/queries/cloudpulse/dashboards'; import { useResourcesQuery } from 'src/queries/cloudpulse/resources'; import { @@ -13,25 +11,10 @@ import { } from 'src/queries/cloudpulse/services'; import { useAclpPreference } from '../Utils/UserPreference'; -import { createObjectCopy } from '../Utils/utils'; -import { CloudPulseWidget } from '../Widget/CloudPulseWidget'; -import { - all_interval_options, - getInSeconds, - getIntervalIndex, -} from '../Widget/components/CloudPulseIntervalSelect'; +import { RenderWidgets } from '../Widget/CloudPulseWidgetRenderer'; -import type { - CloudPulseMetricsAdditionalFilters, - CloudPulseWidgetProperties, -} from '../Widget/CloudPulseWidget'; -import type { - AvailableMetrics, - Dashboard, - JWETokenPayLoad, - TimeDuration, - Widgets, -} from '@linode/api-v4'; +import type { CloudPulseMetricsAdditionalFilters } from '../Widget/CloudPulseWidget'; +import type { JWETokenPayLoad, TimeDuration } from '@linode/api-v4'; export interface DashboardProperties { /** @@ -52,7 +35,7 @@ export interface DashboardProperties { /** * optional timestamp to pass as react query param to forcefully re-fetch data */ - manualRefreshTimeStamp?: number | undefined; + manualRefreshTimeStamp?: number; /** * Selected region for the dashboard @@ -88,65 +71,6 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { }; }; - const getCloudPulseGraphProperties = ( - widget: Widgets - ): CloudPulseWidgetProperties => { - const graphProp: CloudPulseWidgetProperties = { - additionalFilters, - ariaLabel: widget.label, - authToken: '', - availableMetrics: undefined, - duration, - errorLabel: 'Error While Loading Data', - resourceIds: resources, - resources: [], - serviceType: dashboard?.service_type ?? '', - timeStamp: manualRefreshTimeStamp, - unit: widget.unit ?? '%', - widget: { ...widget }, - }; - if (savePref) { - graphProp.widget = setPreferredWidgetPlan(graphProp.widget); - } - return graphProp; - }; - - /** - * - * @param widgetObj Widget configuration received from metrics-definition api - */ - const setPreferredWidgetPlan = (widgetObj: Widgets) => { - const widgetPreferences = preferences.widgets; - const pref = widgetPreferences?.[widgetObj.label]; - // if preference is present then update the widget properties present in preference - if (pref) { - return { - ...widgetObj, - aggregate_function: - pref.aggregateFunction ?? widgetObj.aggregate_function, - size: pref.size ?? widgetObj.size, - time_granularity: { - ...(pref.timeGranularity ?? widgetObj.time_granularity), - }, - }; - } else { - return { - ...widgetObj, - time_granularity: { - label: 'Auto', - unit: 'Auto', - value: -1, - }, - }; - } - }; - - const getTimeGranularity = (scrapeInterval: string) => { - const scrapeIntervalValue = getInSeconds(scrapeInterval); - const index = getIntervalIndex(scrapeIntervalValue); - return index < 0 ? all_interval_options[0] : all_interval_options[index]; - }; - const { data: dashboard, isLoading: isDashboardLoading, @@ -202,76 +126,18 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { return ; } - const RenderWidgets = () => { - if (!dashboard || !dashboard.widgets?.length) { - return renderPlaceHolder( - 'No visualizations are available at this moment. Create Dashboards to list here.' - ); - } - - if ( - !dashboard.service_type || - !Boolean(resources.length > 0) || - !jweToken?.token || - !Boolean(resourceList?.length) - ) { - return renderPlaceHolder( - 'Select Dashboard, Region and Resource to visualize metrics' - ); - } - - // maintain a copy - const newDashboard: Dashboard = createObjectCopy(dashboard)!; - return ( - - {{ ...newDashboard }.widgets.map((widget, index) => { - // check if widget metric definition is available or not - if (widget) { - // find the metric defintion of the widget label - const availMetrics = metricDefinitions?.data.find( - (availMetrics: AvailableMetrics) => - widget.label === availMetrics.label - ); - const cloudPulseWidgetProperties = getCloudPulseGraphProperties({ - ...widget, - }); - - // metric definition is available but time_granularity is not present - if ( - availMetrics && - !cloudPulseWidgetProperties.widget.time_granularity - ) { - cloudPulseWidgetProperties.widget.time_granularity = getTimeGranularity( - availMetrics.scrape_interval - ); - } - return ( - - ); - } else { - return ; - } - })} - - ); - }; - - const renderPlaceHolder = (title: string) => { - return ( - - - - - - ); - }; - - return ; + return ( + + ); }; diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx index 8c1654e9060..93af705b915 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx @@ -1,4 +1,5 @@ import { Grid, Paper } from '@mui/material'; +import deepEqual from 'fast-deep-equal'; import * as React from 'react'; import CloudPulseIcon from 'src/assets/icons/entityIcons/monitor.svg'; @@ -17,6 +18,17 @@ import type { Dashboard, TimeDuration } from '@linode/api-v4'; export type FilterValueType = number | number[] | string | string[] | undefined; +interface DashboardProp { + dashboard?: Dashboard; + filterValue: { + [key: string]: FilterValueType; + }; + timeDuration?: TimeDuration; +} + +const selectDashboardAndFilterMessage = + 'Select Dashboard and filters to visualize metrics.'; + export const CloudPulseDashboardLanding = () => { const [filterValue, setFilterValue] = React.useState<{ [key: string]: FilterValueType; @@ -25,12 +37,12 @@ export const CloudPulseDashboardLanding = () => { const [dashboard, setDashboard] = React.useState(); - const selectDashboardAndFilterMessage = - 'Select Dashboard and filters to visualize metrics.'; - const onFilterChange = React.useCallback( (filterKey: string, filterValue: FilterValueType) => { - setFilterValue((prev) => ({ ...prev, [filterKey]: filterValue })); + setFilterValue((prev: { [key: string]: FilterValueType }) => ({ + ...prev, + [filterKey]: filterValue, + })); }, [] ); @@ -46,32 +58,33 @@ export const CloudPulseDashboardLanding = () => { }, [] ); - - /** - * Takes an error message as input and renders a placeholder with the error message - * @param errorMessage {string} - Error message which will be displayed - * - */ - const renderErrorPlaceholder = (errorMessage: string) => { - return ( + return ( + - - ); - }; + + + ); +}; - /** - * Incase of errors and filter criteria not met, this renders the required error message placeholder and in case of success checks, renders a dashboard - * @returns Placeholder | Dashboard - */ - const RenderDashboard = () => { +/** + * Incase of errors and filter criteria not met, this renders the required error message placeholder and in case of success checks, renders a dashboard + * @returns Placeholder | Dashboard + */ +const RenderDashboard = React.memo( + (props: DashboardProp) => { + const { dashboard, filterValue, timeDuration } = props; if (!dashboard) { return renderErrorPlaceholder(selectDashboardAndFilterMessage); } @@ -119,19 +132,40 @@ export const CloudPulseDashboardLanding = () => { savePref={true} /> ); - }; + }, + (oldProps: DashboardProp, newProps: DashboardProp) => { + if (!deepEqual(oldProps.dashboard, newProps.dashboard)) { + return false; + } + + if (!deepEqual(oldProps.filterValue, newProps.filterValue)) { + return false; + } + + if (!deepEqual(oldProps.timeDuration, newProps.timeDuration)) { + return false; + } + + return true; + } +); + +/** + * Takes an error message as input and renders a placeholder with the error message + * @param errorMessage {string} - Error message which will be displayed + * + */ +const renderErrorPlaceholder = (errorMessage: string) => { return ( - - - - - - - + + + + ); }; diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index d3f118f5069..9b82f33ed46 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -37,6 +37,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { const [selectedDashboard, setSelectedDashboard] = React.useState< Dashboard | undefined >(); + const handleTimeRangeChange = React.useCallback( ( timerDuration: TimeDuration, @@ -48,7 +49,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { } handleTimeDurationChange(timerDuration); }, - [updatePreferences] + [] ); const onDashboardChange = React.useCallback( @@ -61,7 +62,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { setSelectedDashboard(dashboard); handleDashboardChange(dashboard); }, - [updatePreferences] + [] ); const emitFilterChange = React.useCallback( @@ -76,7 +77,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { } handleAnyFilterChange(filterKey, value); }, - [updatePreferences] + [] ); const handleGlobalRefresh = React.useCallback(() => { diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts index 8ffc205279d..1d7be10a290 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts @@ -148,6 +148,7 @@ export const getCustomSelectProperties = ( filterKey, dashboard ), + dashboard, defaultValue: preferences?.[filterKey], disabled: checkIfWeNeedToDisableFilterByFilterKey( filterKey, diff --git a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts index 5516495ad19..ba44285d319 100644 --- a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts +++ b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts @@ -22,12 +22,14 @@ export const useAclpPreference = (): AclpPreferenceObject => { const { mutateAsync: updateFunction } = useMutatePreferences(); + const preferenceRef = useRef(preferences?.aclpPreference ?? {}); + /** * * @param data AclpConfig data to be updated in preferences */ const updateGlobalFilterPreference = (data: AclpConfig) => { - let currentPreferences = { ...(preferences?.aclpPreference ?? {}) }; + let currentPreferences = { ...preferenceRef.current }; const keys = Object.keys(data); if (keys.includes(DASHBOARD_ID)) { @@ -41,6 +43,7 @@ export const useAclpPreference = (): AclpPreferenceObject => { ...data, }; } + preferenceRef.current = currentPreferences; updateFunction({ aclpPreference: currentPreferences }); }; @@ -50,7 +53,7 @@ export const useAclpPreference = (): AclpPreferenceObject => { * @param data AclpWidget data for the label that is to be updated in preference */ const updateWidgetPreference = (label: string, data: Partial) => { - const updatedPreferences = { ...(preferences?.aclpPreference ?? {}) }; + const updatedPreferences = { ...preferenceRef.current }; if (!updatedPreferences.widgets) { updatedPreferences.widgets = {}; @@ -61,6 +64,8 @@ export const useAclpPreference = (): AclpPreferenceObject => { label, ...data, }; + + preferenceRef.current = updatedPreferences; updateFunction({ aclpPreference: updatedPreferences }); }; return { diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx new file mode 100644 index 00000000000..f4b4ca4baac --- /dev/null +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx @@ -0,0 +1,200 @@ +import { Grid, Paper } from '@mui/material'; +import deepEqual from 'fast-deep-equal'; +import React from 'react'; + +import CloudPulseIcon from 'src/assets/icons/entityIcons/monitor.svg'; +import { Placeholder } from 'src/components/Placeholder/Placeholder'; + +import { createObjectCopy } from '../Utils/utils'; +import { CloudPulseWidget } from './CloudPulseWidget'; +import { + allIntervalOptions, + getInSeconds, + getIntervalIndex, +} from './components/CloudPulseIntervalSelect'; + +import type { CloudPulseResources } from '../shared/CloudPulseResourcesSelect'; +import type { + CloudPulseMetricsAdditionalFilters, + CloudPulseWidgetProperties, +} from './CloudPulseWidget'; +import type { + AclpConfig, + AvailableMetrics, + Dashboard, + JWEToken, + TimeDuration, + Widgets, +} from '@linode/api-v4'; + +interface WidgetProps { + additionalFilters?: CloudPulseMetricsAdditionalFilters[]; + dashboard?: Dashboard | undefined; + duration: TimeDuration; + jweToken?: JWEToken | undefined; + manualRefreshTimeStamp?: number; + metricDefinitions: any; + preferences?: AclpConfig; + resourceList: CloudPulseResources[] | undefined; + resources: string[]; + savePref?: boolean; +} + +const renderPlaceHolder = (subtitle: string) => { + return ( + + + + + + ); +}; + +export const RenderWidgets = React.memo( + (props: WidgetProps) => { + const { + additionalFilters, + dashboard, + duration, + jweToken, + manualRefreshTimeStamp, + metricDefinitions, + preferences, + resourceList, + resources, + savePref, + } = props; + + const getCloudPulseGraphProperties = ( + widget: Widgets + ): CloudPulseWidgetProperties => { + const graphProp: CloudPulseWidgetProperties = { + additionalFilters, + ariaLabel: widget.label, + authToken: '', + availableMetrics: undefined, + duration, + errorLabel: 'Error While Loading Data', + resourceIds: resources, + resources: [], + serviceType: dashboard?.service_type ?? '', + timeStamp: manualRefreshTimeStamp, + unit: widget.unit ?? '%', + widget: { ...widget }, + }; + if (savePref) { + graphProp.widget = setPreferredWidgetPlan(graphProp.widget); + } + return graphProp; + }; + + const getTimeGranularity = (scrapeInterval: string) => { + const scrapeIntervalValue = getInSeconds(scrapeInterval); + const index = getIntervalIndex(scrapeIntervalValue); + return index < 0 ? allIntervalOptions[0] : allIntervalOptions[index]; + }; + + const setPreferredWidgetPlan = (widgetObj: Widgets): Widgets => { + const widgetPreferences = preferences?.widgets; + const pref = widgetPreferences?.[widgetObj.label]; + if (pref) { + return { + ...widgetObj, + aggregate_function: + pref.aggregateFunction ?? widgetObj.aggregate_function, + size: pref.size ?? widgetObj.size, + time_granularity: { + ...(pref.timeGranularity ?? widgetObj.time_granularity), + }, + }; + } else { + return { + ...widgetObj, + time_granularity: { + label: 'Auto', + unit: 'Auto', + value: -1, + }, + }; + } + }; + + if (!dashboard || !dashboard.widgets?.length) { + return renderPlaceHolder( + 'No visualizations are available at this moment. Create Dashboards to list here.' + ); + } + + if ( + !dashboard.service_type || + !Boolean(resources.length > 0) || + !jweToken?.token || + !Boolean(resourceList?.length) + ) { + return renderPlaceHolder( + 'Select Dashboard, Region and Resource to visualize metrics' + ); + } + + // maintain a copy + const newDashboard: Dashboard = createObjectCopy(dashboard)!; + return ( + + {{ ...newDashboard }.widgets.map((widget, index) => { + // check if widget metric definition is available or not + if (widget) { + // find the metric defintion of the widget label + const availMetrics = metricDefinitions?.data.find( + (availMetrics: AvailableMetrics) => + widget.label === availMetrics.label + ); + const cloudPulseWidgetProperties = getCloudPulseGraphProperties({ + ...widget, + }); + + // metric definition is available but time_granularity is not present + if ( + availMetrics && + !cloudPulseWidgetProperties.widget.time_granularity + ) { + cloudPulseWidgetProperties.widget.time_granularity = getTimeGranularity( + availMetrics.scrape_interval + ); + } + return ( + + ); + } else { + return ; + } + })} + + ); + }, + (oldProps: WidgetProps, newProps: WidgetProps) => { + if ( + !deepEqual(oldProps.dashboard, newProps.dashboard) || + !deepEqual(oldProps.additionalFilters, newProps.additionalFilters) || + !deepEqual(oldProps.duration, newProps.duration) || + !deepEqual(oldProps.jweToken, newProps.jweToken) || + !deepEqual( + oldProps.manualRefreshTimeStamp, + newProps.manualRefreshTimeStamp + ) || + !deepEqual(oldProps.metricDefinitions, newProps.metricDefinitions) || + !deepEqual(oldProps.resourceList, newProps.resourceList) || + !deepEqual(oldProps.resources, newProps.resources) + ) { + return false; + } + + return true; + } +); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index ef8c27c1d3b..db1e44bf76a 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -14,7 +14,7 @@ import type { CloudPulseServiceTypeFiltersOptions, QueryFunctionAndKey, } from '../Utils/models'; -import type { AclpConfig, FilterValue } from '@linode/api-v4'; +import type { AclpConfig, Dashboard, FilterValue } from '@linode/api-v4'; /** * These are the properties requires for CloudPulseCustomSelect Components @@ -41,6 +41,8 @@ export interface CloudPulseCustomSelectProps { */ clearDependentSelections?: string[]; + dashboard: Dashboard; + /** * Last selected values from user preferences */ @@ -60,11 +62,11 @@ export interface CloudPulseCustomSelectProps { * The filterKey that needs to be used */ filterKey: string; - /** * The type of the filter like string, number etc., */ filterType: string; + /** * The callback function , that will be called on a filter change * @param filterKey - The filterKey of the component @@ -122,6 +124,7 @@ export const CloudPulseCustomSelect = React.memo( apiResponseLabelField, apiV4QueryKey, clearDependentSelections, + dashboard, defaultValue, disabled, filterKey, @@ -170,6 +173,14 @@ export const CloudPulseCustomSelect = React.memo( // eslint-disable-next-line react-hooks/exhaustive-deps }, [savePreferences, options, apiV4QueryKey, queriedResources]); // only execute this use efffect one time or if savePreferences or options or dataApiUrl changes + React.useEffect(() => { + if (!selectedResource) { + setResource(isMultiSelect ? [] : undefined); + handleSelectionChange(filterKey, isMultiSelect ? [] : undefined); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [dashboard?.id]); + const handleChange = ( _: React.SyntheticEvent, value: diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index c83f680f93f..2902285b3ca 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -118,5 +118,6 @@ export const CloudPulseDashboardSelect = React.memo( /> ); }, - () => true + (prevProps, newProps) => + prevProps.handleDashboardChange === newProps.handleDashboardChange ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index 5b288e01bfd..bfe4494a7ee 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -26,7 +26,6 @@ export const CloudPulseRegionSelect = React.memo( } = props; const [selectedRegion, setSelectedRegion] = React.useState(); - // Once the data is loaded, set the state variable with value stored in preferences React.useEffect(() => { if (regions && savePreferences) { @@ -37,7 +36,14 @@ export const CloudPulseRegionSelect = React.memo( setSelectedRegion(region); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [regions, selectedDashboard]); + }, [regions]); + + // Once the data is loaded, set the state variable with value stored in preferences + React.useEffect(() => { + handleRegionChange(undefined); + setSelectedRegion(undefined); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [selectedDashboard?.id]); return ( => { if (!savePreferences) { return options[0]; @@ -67,7 +66,6 @@ export const CloudPulseTimeRangeSelect = React.memo( } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // need to execute only once, during mounting of this component - const handleChange = (item: Item) => { setSelectedTimeRange(item); @@ -99,7 +97,9 @@ export const CloudPulseTimeRangeSelect = React.memo( /> ); }, - () => true + (prevProps, newProps) => + prevProps.handleStatsChange === newProps.handleStatsChange && + prevProps.placeholder === newProps.placeholder ); /** From c18780589943c1a3803b11af609ac4155f88647e Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Mon, 23 Sep 2024 15:02:21 +0530 Subject: [PATCH 063/474] upcoming: [DI-20360] - Updated compare props logic --- .../src/features/CloudPulse/Utils/FilterBuilder.ts | 2 -- .../Widget/components/CloudPulseIntervalSelect.tsx | 10 +++++----- .../CloudPulse/shared/CloudPulseCustomSelect.tsx | 8 -------- .../shared/CloudPulseDashboardFilterBuilder.tsx | 7 ++++++- .../CloudPulse/shared/CloudPulseRegionSelect.tsx | 9 +-------- 5 files changed, 12 insertions(+), 24 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts index 1d7be10a290..5e38a64fbc9 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts @@ -62,7 +62,6 @@ export const getRegionProperties = ( defaultValue: preferences?.[REGION], handleRegionChange, placeholder, - preferences, savePreferences: !isServiceAnalyticsIntegration, selectedDashboard: dashboard, }; @@ -102,7 +101,6 @@ export const getResourcesProperties = ( ), handleResourcesSelection: handleResourceChange, placeholder, - preferences, resourceType: dashboard.service_type, savePreferences: !isServiceAnalyticsIntegration, xFilter: buildXFilter(config, dependentFilters ?? {}), diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx index 36a4ac68e86..c139ff2fef9 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx @@ -39,7 +39,7 @@ export const getInSeconds = (interval: string) => { }; // Intervals must be in ascending order here -export const all_interval_options = [ +export const allIntervalOptions = [ { label: '1 min', unit: 'min', @@ -69,7 +69,7 @@ const autoIntervalOption = { }; export const getIntervalIndex = (scrapeIntervalValue: number) => { - return all_interval_options.findIndex( + return allIntervalOptions.findIndex( (interval) => scrapeIntervalValue <= getInSeconds(String(interval.value) + interval.unit.slice(0, 1)) @@ -86,10 +86,10 @@ export const CloudPulseIntervalSelect = React.memo( // all intervals displayed if srape interval > highest available interval. Error handling done by api const available_interval_options = firstIntervalIndex < 0 - ? all_interval_options.slice() - : all_interval_options.slice( + ? allIntervalOptions.slice() + : allIntervalOptions.slice( firstIntervalIndex, - all_interval_options.length + allIntervalOptions.length ); let default_value = diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index db1e44bf76a..cdfae869b4a 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -173,14 +173,6 @@ export const CloudPulseCustomSelect = React.memo( // eslint-disable-next-line react-hooks/exhaustive-deps }, [savePreferences, options, apiV4QueryKey, queriedResources]); // only execute this use efffect one time or if savePreferences or options or dataApiUrl changes - React.useEffect(() => { - if (!selectedResource) { - setResource(isMultiSelect ? [] : undefined); - handleSelectionChange(filterKey, isMultiSelect ? [] : undefined); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [dashboard?.id]); - const handleChange = ( _: React.SyntheticEvent, value: diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index b9afbb1d2e4..d979986aefc 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -11,6 +11,7 @@ import NullComponent from 'src/components/NullComponent'; import RenderComponent from '../shared/CloudPulseComponentRenderer'; import { + DASHBOARD_ID, REGION, RELATIVE_TIME_DURATION, RESOURCE_ID, @@ -308,5 +309,9 @@ function compareProps( oldProps: CloudPulseDashboardFilterBuilderProps, newProps: CloudPulseDashboardFilterBuilderProps ) { - return oldProps.dashboard?.id === newProps.dashboard?.id; + return ( + oldProps.dashboard?.id === newProps.dashboard?.id && + oldProps.preferences?.[DASHBOARD_ID] === + newProps.preferences?.[DASHBOARD_ID] + ); } diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index bfe4494a7ee..0a0b9a7dd57 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -3,7 +3,7 @@ import * as React from 'react'; import { RegionSelect } from 'src/components/RegionSelect/RegionSelect'; import { useRegionsQuery } from 'src/queries/regions/regions'; -import type { AclpConfig, Dashboard, FilterValue } from '@linode/api-v4'; +import type { Dashboard, FilterValue } from '@linode/api-v4'; export interface CloudPulseRegionSelectProps { defaultValue?: FilterValue; @@ -38,13 +38,6 @@ export const CloudPulseRegionSelect = React.memo( // eslint-disable-next-line react-hooks/exhaustive-deps }, [regions]); - // Once the data is loaded, set the state variable with value stored in preferences - React.useEffect(() => { - handleRegionChange(undefined); - setSelectedRegion(undefined); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [selectedDashboard?.id]); - return ( { From 885a9b6cd253d3e4b1ad1dd32de7598b507f1095 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 24 Sep 2024 12:02:52 +0530 Subject: [PATCH 064/474] tests: [DI-20585] - Use Icon button with aria label for svg icons and remove ui.cloudpulse --- .../linode-widget-verification.spec.ts | 28 +++++++++---------- .../manager/cypress/support/ui/cloudpulse.ts | 26 ----------------- packages/manager/cypress/support/ui/index.ts | 2 -- .../CloudPulse/Overview/GlobalFilters.tsx | 2 +- .../CloudPulse/Widget/components/Zoomer.tsx | 21 +++++++++----- 5 files changed, 28 insertions(+), 51 deletions(-) delete mode 100644 packages/manager/cypress/support/ui/cloudpulse.ts diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 7b820a1a36c..021bd858f0a 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -295,7 +295,7 @@ describe('Dashboard Widget Verification Tests', () => { it('should apply global refresh button and verify network calls', () => { setupMethod(); - ui.cloudpulse.findRefreshIcon().should('be.visible').click(); + ui.button.findByAttribute('aria-label', 'cloudpulse-refresh').should('be.visible').click(); cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']).then( (interceptions) => { const interceptionsArray = Array.isArray(interceptions) @@ -320,18 +320,16 @@ describe('Dashboard Widget Verification Tests', () => { ); } const expectedRelativeTimeDuration = timeRange - ? `Last ${timeRange.value} ${ - ['hour', 'hr'].includes(timeRange.unit.toLowerCase()) - ? 'Hours' - : timeRange.unit - }` + ? `Last ${timeRange.value} ${['hour', 'hr'].includes(timeRange.unit.toLowerCase()) + ? 'Hours' + : timeRange.unit + }` : ''; const currentGranularity = granularity - ? `${granularity.value} ${ - ['hour', 'hours'].includes(granularity.unit.toLowerCase()) - ? 'hr' - : granularity.unit - }` + ? `${granularity.value} ${['hour', 'hours'].includes(granularity.unit.toLowerCase()) + ? 'hr' + : granularity.unit + }` : ''; expect(metric).to.equal(metricData.name); expect(currentGranularity).to.equal(metricData.expectedGranularity); @@ -352,8 +350,8 @@ describe('Dashboard Widget Verification Tests', () => { cy.get('@widget') .should('be.visible') .within(() => { - ui.cloudpulse - .findZoomButtonByTitle('zoom-in') + ui.button + .findByAttribute('aria-label', 'zoom-out') .should('be.visible') .should('be.enabled') .click(); @@ -380,8 +378,8 @@ describe('Dashboard Widget Verification Tests', () => { testData.title ); }); - ui.cloudpulse - .findZoomButtonByTitle('zoom-out') + ui.button + .findByAttribute('aria-label', 'zoom-out') .should('be.visible') .should('be.enabled') .scrollIntoView() diff --git a/packages/manager/cypress/support/ui/cloudpulse.ts b/packages/manager/cypress/support/ui/cloudpulse.ts deleted file mode 100644 index 069bfb48d59..00000000000 --- a/packages/manager/cypress/support/ui/cloudpulse.ts +++ /dev/null @@ -1,26 +0,0 @@ -/** - * cloudpulse RefreshIcon,Zoom Button UI element. - */ -export const cloudpulse = { - /** - * Finds a refresh button within the UI and returns the corresponding Cypress chainable object. - * This method is useful for locating and interacting with the refresh button in the user interface. - * - * @returns {Cypress.Chainable} - A Cypress chainable object representing the refresh button. - */ - findRefreshIcon: (): Cypress.Chainable => { - return cy.get('[data-qa-refresh-button="true"]'); - }, - -/** - * Generates a Cypress chainable for a zoom button based on its title. - * This method helps in locating specific zoom buttons by their title attribute within a group of buttons. - * - * @param {string} buttonTitle - The title of the zoom button to find. - * - * @returns {Cypress.Chainable} - A Cypress chainable that represents the zoom button element. - */ - findZoomButtonByTitle: (buttonTitle: string): Cypress.Chainable => { - return cy.get(`[data-qa-zoomer="${buttonTitle}"]`); - }, -}; diff --git a/packages/manager/cypress/support/ui/index.ts b/packages/manager/cypress/support/ui/index.ts index 963dbab83e8..1cba6746bcb 100644 --- a/packages/manager/cypress/support/ui/index.ts +++ b/packages/manager/cypress/support/ui/index.ts @@ -4,7 +4,6 @@ import * as appBar from './app-bar'; import * as autocomplete from './autocomplete'; import * as breadcrumb from './breadcrumb'; import * as buttons from './buttons'; -import * as cloudpulse from './cloudpulse'; import * as dialog from './dialog'; import * as drawer from './drawer'; import * as entityHeader from './entity-header'; @@ -41,5 +40,4 @@ export const ui = { ...toggle, ...tooltip, ...userMenu, - ...cloudpulse, }; diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index 107cf97d9e3..0decb47dd9a 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -98,7 +98,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { sx={{ marginBlockEnd: 'auto', }} - data-qa-refresh-button + aria-label='cloudpulse-refresh' disabled={!selectedDashboard} onClick={() => handleGlobalRefresh(selectedDashboard)} size="small" diff --git a/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx b/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx index b4142013b17..e450726d5e3 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx @@ -1,4 +1,4 @@ -import { useTheme } from '@mui/material'; +import { IconButton, useTheme } from '@mui/material'; import * as React from 'react'; import ZoomInMap from 'src/assets/icons/zoomin.svg'; @@ -20,30 +20,37 @@ export const ZoomIcon = React.memo((props: ZoomIconProperties) => { const ToggleZoomer = () => { if (props.zoomIn) { return ( - handleClick(false)} - /> + > + + ); } return ( - handleClick(true)} - /> + > + + ); }; From 1d4a76497406bb4a0ab93409e78f122e9c3b474b Mon Sep 17 00:00:00 2001 From: agorthi Date: Tue, 24 Sep 2024 12:12:08 +0530 Subject: [PATCH 065/474] upcoming:[DI-20585]- Added code review comments --- .../linode-widget-verification.spec.ts | 18 ++++++++++-------- .../{cloudpulseAPIHandler.ts => cloudpulse.ts} | 0 2 files changed, 10 insertions(+), 8 deletions(-) rename packages/manager/cypress/support/intercepts/{cloudpulseAPIHandler.ts => cloudpulse.ts} (100%) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 7b820a1a36c..f3f6e652d24 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -15,7 +15,7 @@ import { mockCloudPulseGetDashboards, mockCloudPulseGetMetricDefinitions, mockCloudPulseServices, -} from 'support/intercepts/cloudpulseAPIHandler'; +} from 'support/intercepts/cloudpulse'; import { ui } from 'support/ui'; import { timeRange, @@ -60,10 +60,10 @@ const y_labels = [ ]; const widgets = widgetDetails.linode; const metrics = widgets.metrics; -export const dashboardName = widgets.dashboardName; -export const region = widgets.region; -export const actualRelativeTimeDuration = timeRange.last24Hours; -export const resource = widgets.resource; + const dashboardName = widgets.dashboardName; + const region = widgets.region; +const actualRelativeTimeDuration = timeRange.last24Hours; + const resource = widgets.resource; const widgetLabels: string[] = metrics.map((widget) => widget.title); const metricsLabels: string[] = metrics.map((widget) => widget.name); const service_type = widgets.service_type; @@ -97,10 +97,12 @@ let responsePayload: CloudPulseMetricsResponse; describe('Dashboard Widget Verification Tests', () => { beforeEach(() => { mockAppendFeatureFlags({ - aclp: makeFeatureFlagData({ beta: true, enabled: true }), + aclp: makeFeatureFlagData({ beta: true, enabled: true }), + }).as('getFeatureFlags'); + mockAppendFeatureFlags({ + aclp: { beta: true, enabled: true }, }).as('getFeatureFlags'); mockGetAccount(mockAccount).as('getAccount'); // Enables the account to have capability for Akamai Cloud Pulse - mockGetFeatureFlagClientstream().as('getClientStream'); mockGetLinodes([mockLinode]).as('getLinodes'); mockCloudPulseGetMetricDefinitions(metricDefinitions, service_type); mockCloudPulseGetDashboards(dashboard, service_type).as('dashboard'); @@ -177,7 +179,7 @@ describe('Dashboard Widget Verification Tests', () => { }); }); - it('should verify the title of the widget', () => { + it.only('should verify the title of the widget', () => { setupMethod(); metrics.forEach((testData) => { const widgetSelector = `[data-qa-widget-header="${testData.title}"]`; diff --git a/packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts b/packages/manager/cypress/support/intercepts/cloudpulse.ts similarity index 100% rename from packages/manager/cypress/support/intercepts/cloudpulseAPIHandler.ts rename to packages/manager/cypress/support/intercepts/cloudpulse.ts From eff50de613cf7446983d25bf9765adb62102cac3 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 24 Sep 2024 12:43:23 +0530 Subject: [PATCH 066/474] tests: [DI-20585] - Factories implementation instead of functions --- .../linode-widget-verification.spec.ts | 37 +++-- packages/manager/src/factories/dashboards.ts | 147 ++++-------------- 2 files changed, 54 insertions(+), 130 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 021bd858f0a..685bc81a77e 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -27,11 +27,12 @@ import { createMetricResponse } from '@src/factories/widget'; import type { Flags } from 'src/featureFlags'; import { accountFactory, - extendedDashboardFactory, + dashboardFactory, + dashboardMetricFactory, kubeLinodeFactory, linodeFactory, - metricDefinitionsFactory, regionFactory, + widgetFactory, } from 'src/factories'; import { mockGetAccount } from 'support/intercepts/account'; import { mockGetLinodes } from 'support/intercepts/linodes'; @@ -68,17 +69,25 @@ const widgetLabels: string[] = metrics.map((widget) => widget.title); const metricsLabels: string[] = metrics.map((widget) => widget.name); const service_type = widgets.service_type; const dashboardId = widgets.id; -const dashboard = extendedDashboardFactory( - dashboardName, - widgetLabels, - metricsLabels, - y_labels, - service_type -).build(); -const metricDefinitions = metricDefinitionsFactory( - widgetLabels, - metricsLabels -).build(); + +const dashboard = dashboardFactory.build({ + label: dashboardName, + service_type: service_type, + widgets: [...widgetLabels.map((label: string, index: number) => + widgetFactory.build({ + label, + y_label: y_labels[index], + metric: metricsLabels[index], + }))] +}) + +const metricDefinitions = { + data: [...widgetLabels.map((label, index) => + dashboardMetricFactory.build({ + label, + metric: metricsLabels[index], + }))] +} const mockKubeLinode = kubeLinodeFactory.build(); const mockLinode = linodeFactory.build({ label: resource, @@ -124,7 +133,7 @@ describe('Dashboard Widget Verification Tests', () => { cy.findByText('Not Found').should('be.visible'); // not found }); - it('should set available granularity of all the widgets', () => { + it.only('should set available granularity of all the widgets', () => { setupMethod(); metrics.forEach((testData) => { cy.wait(7000); //maintaining the wait since page flicker and rendering diff --git a/packages/manager/src/factories/dashboards.ts b/packages/manager/src/factories/dashboards.ts index 6e80341a754..a34933b8138 100644 --- a/packages/manager/src/factories/dashboards.ts +++ b/packages/manager/src/factories/dashboards.ts @@ -13,18 +13,6 @@ const chart_type = ['area', 'area', 'area', 'line']; const scrape_interval = ['2m', '30s', '30s', '30s']; const units_interval = ['percent', 'byte', 'byte', 'ops_per_second']; -/* export const dashboardFactory = Factory.Sync.makeFactory({ - created: new Date().toISOString(), - id: Factory.each((i) => i), - label: 'Linode Dashboard', - service_type: 'linode', - time_duration: { - unit: 'min', - value: 30, - }, - updated: new Date().toISOString(), - widgets: Factory.each(() => widgetFactory.buildList(4)), // Create a list of 1 widgets -});*/ /** * Factory function to create instances of the `Dashboard` model with predefined properties and values. * @@ -66,31 +54,6 @@ export const dashboardFactory = Factory.Sync.makeFactory({ updated: new Date().toISOString(), widgets: [], }); - -export const extendedDashboardFactory = ( - dashboardLabel: string, - widgetLabels: string[], - metricsLabels: string[], - y_labels: string[], - service: string -) => { - return Factory.Sync.makeFactory({ - created: new Date().toISOString(), - id: Factory.each((i) => i), - label: dashboardLabel, - service_type: service, - time_duration: { - unit: 'min', - value: 30, - }, - updated: new Date().toISOString(), - widgets: Factory.each(() => - widgetFactory(widgetLabels, metricsLabels, y_labels).buildList( - widgetLabels.length - ) - ), - }); -}; /** * Factory function to create instances of the `Widgets` model with predefined properties and values. * @@ -127,76 +90,31 @@ export const extendedDashboardFactory = ( * const myWidget = myWidgetFactory.build(); // Creates a Widget instance with the specified properties. * ``` */ - -export const widgetFactory = ( - widgetLabels: string[], - metricsLabels: string[], - y_labels: string[] -) => { - return Factory.Sync.makeFactory({ - aggregate_function: 'avg', - chart_type: Factory.each((i) => chart_type[i % chart_type.length]), - color: Factory.each((i) => color[i % color.length]), - filters: [], - group_by: 'region', - label: Factory.each((i) => widgetLabels[i % widgetLabels.length]), - metric: Factory.each((i) => metricsLabels[i % metricsLabels.length]), - namespace_id: Factory.each((i) => i % 10), - region_id: Factory.each((i) => i % 5), - resource_id: Factory.each((i) => [`resource-${i}`]), - service_type: 'default', - serviceType: 'default', - size: 12, - time_duration: { - unit: 'min', - value: 30, - }, - time_granularity: { - unit: 'hour', - value: 1, - }, - unit: Factory.each((i) => units[i % units.length]), - y_label: Factory.each((i) => y_labels[i % y_labels.length]), - }); -}; -/** - * Factory function to create instances of the `MetricDefinitions` model with predefined properties and values. - * - * @param {string[]} widgetLabels - An array of labels for widgets used in the metric definitions. - * @param {string[]} metricsLabels - An array of labels for metrics associated with the widget definitions. - * - * @returns {Factory} A Factory instance for creating `MetricDefinitions` objects with the specified properties. - * - * @description - * This function uses the `Factory.Sync.makeFactory` method to create a factory for generating `MetricDefinitions` objects. - * The created `MetricDefinitions` object includes: - * - `data`: An array of metric definitions. Each metric definition is created using the `dashboardMetricFactory` function, which provides the following properties: - * - `label`: A label for the metric, chosen from the `widgetLabels` array. The label is selected based on the index modulo the length of `widgetLabels` to ensure cycling through the labels. - * - `metric`: A metric label, chosen from the `metricsLabels` array. The metric is selected based on the index modulo the length of `metricsLabels` to ensure cycling through the labels. - * - * The `data` array contains metric definitions where the number of elements matches the length of the `widgetLabels` array. Each element in the array represents a metric definition corresponding to a widget label and a metric label. - * - * Usage Example: - * ```typescript - * const myMetricDefinitionsFactory = metricDefinitionsFactory(['Widget1', 'Widget2'], ['Metric1', 'Metric2']); - * const myMetricDefinitions = myMetricDefinitionsFactory.build(); // Creates a MetricDefinitions instance with the specified properties. - * ``` - */ -export const metricDefinitionsFactory = ( - widgetLabels: string[], - metricsLabels: string[] -) => { - return Factory.Sync.makeFactory({ - data: Factory.each(() => { - return widgetLabels.map((_, index) => { - return dashboardMetricFactory(widgetLabels, metricsLabels).build({ - label: widgetLabels[index % widgetLabels.length], - metric: metricsLabels[index % metricsLabels.length], - }); - }); - }), - }); -}; +export const widgetFactory = Factory.Sync.makeFactory({ + aggregate_function: 'avg', + chart_type: Factory.each((i) => chart_type[i % chart_type.length]), + color: Factory.each((i) => color[i % color.length]), + filters: [], + group_by: 'region', + label: Factory.each((i) => 'widget_label_' + i), + metric: Factory.each((i) => 'widget_metric_' + i), + namespace_id: Factory.each((i) => i % 10), + region_id: Factory.each((i) => i % 5), + resource_id: Factory.each((i) => [`resource-${i}`]), + service_type: 'default', + serviceType: 'default', + size: 12, + time_duration: { + unit: 'min', + value: 30, + }, + time_granularity: { + unit: 'hour', + value: 1, + }, + unit: Factory.each((i) => units[i % units.length]), + y_label: Factory.each((i) => 'y_label_' + i), +}); /** * Factory function to create instances of the `AvailableMetrics` model with predefined properties and values. * @@ -223,19 +141,16 @@ export const metricDefinitionsFactory = ( * ``` */ -const dashboardMetricFactory = ( - widgetLabels: string[], - metricsLabels: string[] -) => { - return Factory.Sync.makeFactory({ +export const dashboardMetricFactory = Factory.Sync.makeFactory( + { available_aggregate_functions: ['min', 'max', 'avg', 'sum'], dimensions: [], - label: Factory.each((i) => widgetLabels[i % widgetLabels.length]), // This might be overridden - metric: Factory.each((i) => metricsLabels[i % metricsLabels.length]), // This might be overridden + label: Factory.each((i) => 'widget_label_' + i), // This might be overridden + metric: Factory.each((i) => 'widget_metric_' + i), // This might be overridden metric_type: 'gauge', scrape_interval: Factory.each( (i) => scrape_interval[i % scrape_interval.length] ), unit: Factory.each((i) => units_interval[i % units_interval.length]), - }); -}; + } +); From b411b94ffa1e902003bb8aa3a424ed0f489ae8fe Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Tue, 24 Sep 2024 13:29:23 +0530 Subject: [PATCH 067/474] upcoming: [DI-20360] - Test cases updated --- .../CloudPulse/shared/CloudPulseResourcesSelect.test.tsx | 1 + .../src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx index 18a9396baa0..2a416fdec81 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx @@ -33,6 +33,7 @@ describe('CloudPulseResourcesSelect component tests', () => { const { getByPlaceholderText, getByTestId } = renderWithTheme( diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index 44d7147dc30..a8be0f9c06b 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -105,6 +105,7 @@ export const CloudPulseResourcesSelect = React.memo( limitTags={2} multiple options={getResourcesList} + placeholder={placeholder ?? 'Select a Resource'} value={selectedResources ?? []} /> ); From 9468109b9cce4320fa6679a7771332b663765f43 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Tue, 24 Sep 2024 14:59:29 +0530 Subject: [PATCH 068/474] upcoming: [DI-20360] - Updated ESLint issues --- packages/api-v4/src/cloudpulse/services.ts | 6 +-- .../Dashboard/CloudPulseDashboardLanding.tsx | 1 - .../CloudPulse/Overview/GlobalFilters.tsx | 10 ++--- .../CloudPulse/Utils/FilterBuilder.ts | 1 - .../CloudPulse/Utils/UserPreference.ts | 1 - .../CloudPulse/Widget/components/Zoomer.tsx | 40 +++++++++---------- .../shared/CloudPulseCustomSelect.tsx | 5 +-- .../shared/CloudPulseCustomSelectUtils.ts | 1 - .../shared/CloudPulseResourcesSelect.test.tsx | 1 - 9 files changed, 26 insertions(+), 40 deletions(-) diff --git a/packages/api-v4/src/cloudpulse/services.ts b/packages/api-v4/src/cloudpulse/services.ts index 37abc6d0d75..5eb06faa0e5 100644 --- a/packages/api-v4/src/cloudpulse/services.ts +++ b/packages/api-v4/src/cloudpulse/services.ts @@ -22,16 +22,12 @@ export const getMetricDefinitionsByServiceType = (serviceType: string) => { export const getJWEToken = (data: JWETokenPayLoad, serviceType: string) => Request( setURL( - `${API_ROOT}/monitor/services/${encodeURIComponent( - serviceType - )}/token` + `${API_ROOT}/monitor/services/${encodeURIComponent(serviceType)}/token` ), setMethod('POST'), setData(data) ); - - // Returns the list of service types available export const getCloudPulseServiceTypes = () => Request( diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx index 93af705b915..372d8f34053 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx @@ -50,7 +50,6 @@ export const CloudPulseDashboardLanding = () => { const onDashboardChange = React.useCallback((dashboardObj: Dashboard) => { setDashboard(dashboardObj); setFilterValue({}); // clear the filter values on dashboard change - }, []); const onTimeDurationChange = React.useCallback( (timeDurationObj: TimeDuration) => { diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index ff689917a05..b19ce3f8555 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -21,8 +21,6 @@ export interface GlobalFilterProperties { handleTimeDurationChange(timeDuration: TimeDuration): void; } -export interface FilterChangeProperties {} - export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { const { handleAnyFilterChange, @@ -99,18 +97,18 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { + /> + /> { - const theme = useTheme(); + const theme = useTheme(); const handleClick = (needZoomIn: boolean) => { props.handleZoomToggle(needZoomIn); }; - const ToggleZoomer = () => { - if (props.zoomIn) { + const ToggleZoomer = () => { + if (props.zoomIn) { + return ( + handleClick(false)} + /> + ); + } + return ( - handleClick(false)} + data-testid="zoom-out" + onClick={() => handleClick(true)} /> ); - } - - return ( - handleClick(true)} - /> - ); - }; + }; return ; }, diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index 82004f1d2e5..a50c12f7f4f 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -14,7 +14,7 @@ import type { CloudPulseServiceTypeFiltersOptions, QueryFunctionAndKey, } from '../Utils/models'; -import type { AclpConfig, Dashboard, FilterValue } from '@linode/api-v4'; +import type { AclpConfig, FilterValue } from '@linode/api-v4'; /** * These are the properties requires for CloudPulseCustomSelect Components @@ -41,8 +41,6 @@ export interface CloudPulseCustomSelectProps { */ clearDependentSelections?: string[]; - dashboard: Dashboard; - /** * Last selected values from user preferences */ @@ -124,7 +122,6 @@ export const CloudPulseCustomSelect = React.memo( apiResponseLabelField, apiV4QueryKey, clearDependentSelections, - dashboard, defaultValue, disabled, filterKey, diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts index 5d0b3f9df63..ce6dabc4a02 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts @@ -127,7 +127,6 @@ export const getInitialDefaultSelections = ( handleSelectionChange, isMultiSelect, options, - preferences, savePreferences, } = defaultSelectionProps; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx index f6c33bcb54a..019d038369b 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx @@ -33,7 +33,6 @@ describe('CloudPulseResourcesSelect component tests', () => { const { getByPlaceholderText, getByTestId } = renderWithTheme( From 3bd5d3b12f682a1e4c8888aa521cded46805011b Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Tue, 24 Sep 2024 18:51:38 +0530 Subject: [PATCH 069/474] upcoming: [DI-20360] - Updated review comments --- .../CloudPulse/Utils/UserPreference.ts | 2 +- .../CloudPulse/Widget/CloudPulseWidget.tsx | 33 +++++------ .../CloudPulseAggregateFunction.tsx | 3 +- .../components/CloudPulseIntervalSelect.tsx | 3 +- .../CloudPulse/Widget/components/Zoomer.tsx | 55 +++++++++---------- .../shared/CloudPulseDashboardSelect.tsx | 3 +- .../shared/CloudPulseResourcesSelect.tsx | 1 - .../shared/CloudPulseTimeRangeSelect.tsx | 13 +---- 8 files changed, 47 insertions(+), 66 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts index 8eadef9586d..9e8baaa0a48 100644 --- a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts +++ b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts @@ -21,7 +21,7 @@ export const useAclpPreference = (): AclpPreferenceObject => { const { mutateAsync: updateFunction } = useMutatePreferences(); - const preferenceRef = useRef(preferences?.aclpPreference ?? {}); + const preferenceRef = useRef(preferences?.aclpPreference ?? {}); /** * diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index ce23b5d68e7..202d8f3466a 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -147,23 +147,20 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { * * @param zoomInValue: True if zoom in clicked & False if zoom out icon clicked */ - const handleZoomToggle = React.useCallback( - (zoomInValue: boolean) => { - if (savePref) { - updatePreferences(widget.label, { - [SIZE]: zoomInValue ? 12 : 6, - }); - } - - setWidget((currentWidget: Widgets) => { - return { - ...currentWidget, - size: zoomInValue ? 12 : 6, - }; + const handleZoomToggle = React.useCallback((zoomInValue: boolean) => { + if (savePref) { + updatePreferences(widget.label, { + [SIZE]: zoomInValue ? 12 : 6, }); - }, - [updatePreferences] - ); + } + + setWidget((currentWidget: Widgets) => { + return { + ...currentWidget, + size: zoomInValue ? 12 : 6, + }; + }); + }, []); /** * @@ -186,7 +183,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { }; }); }, - [updatePreferences] + [] ); /** @@ -208,7 +205,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { }; }); }, - [updatePreferences] + [] ); const { diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx index bdb312b6bf7..a166d691859 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx @@ -67,6 +67,5 @@ export const CloudPulseAggregateFunction = React.memo( value={selectedAggregateFunction} /> ); - }, - () => true + } ); diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx index 3bb7f1b4e16..595bc95a2b2 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx @@ -148,6 +148,5 @@ export const CloudPulseIntervalSelect = React.memo( value={selectedInterval} /> ); - }, - () => true + } ); diff --git a/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx b/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx index ca5d6c3ef24..f21148cc831 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx @@ -10,43 +10,40 @@ export interface ZoomIconProperties { zoomIn: boolean; } -export const ZoomIcon = React.memo( - (props: ZoomIconProperties) => { - const theme = useTheme(); +export const ZoomIcon = React.memo((props: ZoomIconProperties) => { + const theme = useTheme(); - const handleClick = (needZoomIn: boolean) => { - props.handleZoomToggle(needZoomIn); - }; - - const ToggleZoomer = () => { - if (props.zoomIn) { - return ( - handleClick(false)} - /> - ); - } + const handleClick = (needZoomIn: boolean) => { + props.handleZoomToggle(needZoomIn); + }; + const ToggleZoomer = () => { + if (props.zoomIn) { return ( - handleClick(true)} + data-testid="zoom-in" + onClick={() => handleClick(false)} /> ); - }; + } + + return ( + handleClick(true)} + /> + ); + }; - return ; - }, - (prevProps, nextProps) => prevProps.zoomIn === nextProps.zoomIn -); + return ; +}); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index 84d8d7eb2dc..07a67f809f7 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -118,6 +118,5 @@ export const CloudPulseDashboardSelect = React.memo( /> ); }, - (prevProps, newProps) => - prevProps.handleDashboardChange === newProps.handleDashboardChange + () => true ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index fdd771005e7..d4ccd0957ea 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -123,7 +123,6 @@ function compareProps( const keysToCompare: (keyof CloudPulseResourcesSelectProps)[] = [ 'region', 'resourceType', - 'handleResourcesSelection', ]; for (const key of keysToCompare) { diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx index ca401c8e197..cfad88d9298 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx @@ -19,7 +19,6 @@ export interface CloudPulseTimeRangeSelectProps timeDurationValue?: string, savePref?: boolean ) => void; - placeholder?: string; savePreferences?: boolean; } @@ -37,12 +36,7 @@ export type Labels = export const CloudPulseTimeRangeSelect = React.memo( (props: CloudPulseTimeRangeSelectProps) => { - const { - defaultValue, - handleStatsChange, - placeholder, - savePreferences, - } = props; + const { defaultValue, handleStatsChange, savePreferences } = props; const options = generateSelectOptions(); const getDefaultValue = React.useCallback((): Item => { if (!savePreferences) { @@ -92,14 +86,11 @@ export const CloudPulseTimeRangeSelect = React.memo( isOptionEqualToValue={(option, value) => option.value === value.value} label="Select Time Duration" options={options} - placeholder={placeholder ?? 'Select a Time Duration'} value={selectedTimeRange} /> ); }, - (prevProps, newProps) => - prevProps.handleStatsChange === newProps.handleStatsChange && - prevProps.placeholder === newProps.placeholder + () => true ); /** From 56af5619b9d9c99798c459367f8f74bbcd297ab8 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Tue, 24 Sep 2024 19:15:41 +0530 Subject: [PATCH 070/474] upcoming: [DI-20360] - Test cases updated --- .../Dashboard/CloudPulseDashboardWithFilters.test.tsx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.test.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.test.tsx index 0b3d44ae1ac..7492ac04900 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.test.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.test.tsx @@ -63,9 +63,6 @@ describe('CloudPulseDashboardWithFilters component tests', () => { ); - expect( - screen.getByPlaceholderText(selectTimeDurationPlaceholder) - ).toBeDefined(); expect(screen.getByTestId(circleProgress)).toBeDefined(); // the dashboards started to render }); @@ -81,9 +78,6 @@ describe('CloudPulseDashboardWithFilters component tests', () => { ); - expect( - screen.getByPlaceholderText(selectTimeDurationPlaceholder) - ).toBeDefined(); expect(screen.getByTestId(circleProgress)).toBeDefined(); // the dashboards started to render }); From 383dd1a7fd0a8128408160af21a8abf934a021a1 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Tue, 24 Sep 2024 19:32:43 +0530 Subject: [PATCH 071/474] upcoming: [DI-20360] - Updated logic to prevent widget preference to override --- .../manager/src/features/CloudPulse/Utils/UserPreference.ts | 3 ++- packages/manager/src/features/CloudPulse/Utils/constants.ts | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts index 9e8baaa0a48..cd2df713d8e 100644 --- a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts +++ b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts @@ -5,7 +5,7 @@ import { usePreferences, } from 'src/queries/profile/preferences'; -import { DASHBOARD_ID, TIME_DURATION } from './constants'; +import { DASHBOARD_ID, TIME_DURATION, WIDGETS } from './constants'; import type { AclpConfig, AclpWidget } from '@linode/api-v4'; @@ -35,6 +35,7 @@ export const useAclpPreference = (): AclpPreferenceObject => { currentPreferences = { ...data, [TIME_DURATION]: currentPreferences[TIME_DURATION], + [WIDGETS]: {}, }; } else { currentPreferences = { diff --git a/packages/manager/src/features/CloudPulse/Utils/constants.ts b/packages/manager/src/features/CloudPulse/Utils/constants.ts index 05b97cc0c6a..c3e31b022d9 100644 --- a/packages/manager/src/features/CloudPulse/Utils/constants.ts +++ b/packages/manager/src/features/CloudPulse/Utils/constants.ts @@ -21,3 +21,5 @@ export const TIME_GRANULARITY = 'timeGranularity'; export const RELATIVE_TIME_DURATION = 'relative_time_duration'; export const RESOURCE_ID = 'resource_id'; + +export const WIDGETS = 'widgets'; From 28b5ff93b4e5e04b39ab940b7a24b4cd4a4f3450 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Tue, 24 Sep 2024 22:04:43 +0530 Subject: [PATCH 072/474] upcoming: [DI-20360] - Separated components into different files --- .../Dashboard/CloudPulseDashboardLanding.tsx | 111 +----------------- .../Dashboard/CloudPulseDashboardRenderer.tsx | 96 +++++++++++++++ .../shared/CloudPulseErrorPlaceholder.tsx | 23 ++++ 3 files changed, 122 insertions(+), 108 deletions(-) create mode 100644 packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx create mode 100644 packages/manager/src/features/CloudPulse/shared/CloudPulseErrorPlaceholder.tsx diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx index 372d8f34053..828a05301c7 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx @@ -1,24 +1,14 @@ import { Grid, Paper } from '@mui/material'; -import deepEqual from 'fast-deep-equal'; import * as React from 'react'; -import CloudPulseIcon from 'src/assets/icons/entityIcons/monitor.svg'; -import { StyledPlaceholder } from 'src/features/StackScripts/StackScriptBase/StackScriptBase.styles'; - import { GlobalFilters } from '../Overview/GlobalFilters'; -import { REFRESH, REGION, RESOURCE_ID } from '../Utils/constants'; -import { - checkIfAllMandatoryFiltersAreSelected, - getMetricsCallCustomFilters, -} from '../Utils/FilterBuilder'; -import { FILTER_CONFIG } from '../Utils/FilterConfig'; -import { CloudPulseDashboard } from './CloudPulseDashboard'; +import { CloudPulseDashboardRenderer } from './CloudPulseDashboardRenderer'; import type { Dashboard, TimeDuration } from '@linode/api-v4'; export type FilterValueType = number | number[] | string | string[] | undefined; -interface DashboardProp { +export interface DashboardProp { dashboard?: Dashboard; filterValue: { [key: string]: FilterValueType; @@ -26,9 +16,6 @@ interface DashboardProp { timeDuration?: TimeDuration; } -const selectDashboardAndFilterMessage = - 'Select Dashboard and filters to visualize metrics.'; - export const CloudPulseDashboardLanding = () => { const [filterValue, setFilterValue] = React.useState<{ [key: string]: FilterValueType; @@ -68,7 +55,7 @@ export const CloudPulseDashboardLanding = () => { /> - { ); }; - -/** - * Incase of errors and filter criteria not met, this renders the required error message placeholder and in case of success checks, renders a dashboard - * @returns Placeholder | Dashboard - */ -const RenderDashboard = React.memo( - (props: DashboardProp) => { - const { dashboard, filterValue, timeDuration } = props; - if (!dashboard) { - return renderErrorPlaceholder(selectDashboardAndFilterMessage); - } - - if (!FILTER_CONFIG.get(dashboard.service_type)) { - return renderErrorPlaceholder( - "No Filters Configured for selected dashboard's service type" - ); - } - - if ( - !checkIfAllMandatoryFiltersAreSelected({ - dashboard, - filterValue, - timeDuration, - }) || - !timeDuration - ) { - return renderErrorPlaceholder(selectDashboardAndFilterMessage); - } - - return ( - - ); - }, - (oldProps: DashboardProp, newProps: DashboardProp) => { - if (!deepEqual(oldProps.dashboard, newProps.dashboard)) { - return false; - } - - if (!deepEqual(oldProps.filterValue, newProps.filterValue)) { - return false; - } - - if (!deepEqual(oldProps.timeDuration, newProps.timeDuration)) { - return false; - } - - return true; - } -); - -/** - * Takes an error message as input and renders a placeholder with the error message - * @param errorMessage {string} - Error message which will be displayed - * - */ -const renderErrorPlaceholder = (errorMessage: string) => { - return ( - - - - - - ); -}; diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx new file mode 100644 index 00000000000..a5e2eb54885 --- /dev/null +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx @@ -0,0 +1,96 @@ +import deepEqual from 'fast-deep-equal'; +import React from 'react'; + +import { CloudPulseErrorPlaceholder } from '../shared/CloudPulseErrorPlaceholder'; +import { REFRESH, REGION, RESOURCE_ID } from '../Utils/constants'; +import { + checkIfAllMandatoryFiltersAreSelected, + getMetricsCallCustomFilters, +} from '../Utils/FilterBuilder'; +import { FILTER_CONFIG } from '../Utils/FilterConfig'; +import { CloudPulseDashboard } from './CloudPulseDashboard'; + +import type { DashboardProp } from './CloudPulseDashboardLanding'; + +export const CloudPulseDashboardRenderer = React.memo( + (props: DashboardProp) => { + const { dashboard, filterValue, timeDuration } = props; + + const selectDashboardAndFilterMessage = + 'Select Dashboard and filters to visualize metrics.'; + + if (!dashboard) { + return ( + + ); + } + + if (!FILTER_CONFIG.get(dashboard.service_type)) { + return ( + + ); + } + + if ( + !checkIfAllMandatoryFiltersAreSelected({ + dashboard, + filterValue, + timeDuration, + }) || + !timeDuration + ) { + return ( + + ); + } + + return ( + + ); + }, + (oldProps: DashboardProp, newProps: DashboardProp) => { + if (oldProps.dashboard?.id !== newProps.dashboard?.id) { + return false; + } + + if (!deepEqual(oldProps.filterValue, newProps.filterValue)) { + return false; + } + + if ( + oldProps.timeDuration?.unit !== newProps.timeDuration?.unit || + oldProps.timeDuration?.value !== newProps.timeDuration?.value + ) { + return false; + } + + return true; + } +); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseErrorPlaceholder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseErrorPlaceholder.tsx new file mode 100644 index 00000000000..fefa287ee1c --- /dev/null +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseErrorPlaceholder.tsx @@ -0,0 +1,23 @@ +import { Grid, Paper } from '@mui/material'; +import React from 'react'; + +import CloudPulseIcon from 'src/assets/icons/entityIcons/monitor.svg'; +import { StyledPlaceholder } from 'src/features/StackScripts/StackScriptBase/StackScriptBase.styles'; + +export const CloudPulseErrorPlaceholder = React.memo( + (props: { errorMessage: string }) => { + const { errorMessage } = props; + return ( + + + + + + ); + } +); From 1f164c329049095a5b76fd8e10c2e2cd29330074 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Tue, 24 Sep 2024 22:16:38 +0530 Subject: [PATCH 073/474] upcoming: [DI-20360] - updated funcntions with useMemo --- .../Dashboard/CloudPulseDashboardRenderer.tsx | 10 ++++++---- .../src/features/CloudPulse/Utils/FilterBuilder.ts | 6 ++++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx index a5e2eb54885..e7fb8ad3df6 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx @@ -19,6 +19,11 @@ export const CloudPulseDashboardRenderer = React.memo( const selectDashboardAndFilterMessage = 'Select Dashboard and filters to visualize metrics.'; + const getMetricsCall = React.useMemo( + () => getMetricsCallCustomFilters(filterValue, dashboard?.service_type), + [dashboard?.service_type, filterValue] + ); + if (!dashboard) { return ( { - const serviceTypeConfig = FILTER_CONFIG.get(serviceType); + const serviceTypeConfig = serviceType + ? FILTER_CONFIG.get(serviceType) + : undefined; // If configuration exists, filter and map it to the desired CloudPulseMetricsAdditionalFilters format return ( From a8ee8c929227a400a75d05ce4cc2dd191f0ce32d Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Tue, 24 Sep 2024 22:23:48 +0530 Subject: [PATCH 074/474] upcoming: [DI-20360] - updated eslint issues --- .../CloudPulse/Dashboard/CloudPulseDashboardWithFilters.test.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.test.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.test.tsx index 7492ac04900..68bf5750647 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.test.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.test.tsx @@ -10,7 +10,6 @@ const queryMocks = vi.hoisted(() => ({ useCloudPulseDashboardByIdQuery: vi.fn().mockReturnValue({}), })); -const selectTimeDurationPlaceholder = 'Select a Time Duration'; const circleProgress = 'circle-progress'; const mandatoryFiltersError = 'Mandatory Filters not Selected'; From 92f5bf9678b7a2ffcb7b93d792b3f76f4979d143 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Wed, 25 Sep 2024 11:02:49 +0530 Subject: [PATCH 075/474] upcoming: [DI-20800] - cypress changes --- .../e2e/core/cloudpulse/linode-widget-verification.spec.ts | 4 ++++ .../src/features/CloudPulse/Widget/CloudPulseWidget.tsx | 3 +++ 2 files changed, 7 insertions(+) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 685bc81a77e..9a333af95b3 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -143,6 +143,8 @@ describe('Dashboard Widget Verification Tests', () => { .should('be.visible') .first() .within(() => { + const widgetFilterSelector = `[data-qa-widget-filters="${testData.title}"]`; + cy.get(widgetFilterSelector).invoke('attr', 'style', 'overflow:visible'); ui.autocomplete .findByTitleCustom('Select an Interval') .should('be.visible') @@ -262,6 +264,8 @@ describe('Dashboard Widget Verification Tests', () => { .findByTitleCustom('Select an Interval') .findByTitle('Open') .click(); + const widgetFilterSelector = `[data-qa-widget-filter="${testData.title}"]`; + cy.get(widgetFilterSelector).invoke('attr', 'style', 'overflow:visible'); testData.expectedGranularityArray.forEach((option) => { ui.autocompletePopper.findByTitle(option).should('be.visible'); }); diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 0c820cd2900..bb3ab1e2aef 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -315,6 +315,9 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { {unit.endsWith('ps') ? '/s' : ''}) Date: Wed, 25 Sep 2024 12:52:52 +0530 Subject: [PATCH 076/474] upcoming: [DI-20360] - Updated widget preferences logic --- .../features/CloudPulse/Utils/UserPreference.ts | 16 ++++++++++------ .../Widget/CloudPulseWidgetRenderer.tsx | 2 -- .../CloudPulse/shared/CloudPulseCustomSelect.tsx | 5 ----- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts index cd2df713d8e..8074268e4ad 100644 --- a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts +++ b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts @@ -23,6 +23,9 @@ export const useAclpPreference = (): AclpPreferenceObject => { const preferenceRef = useRef(preferences?.aclpPreference ?? {}); + if (preferences?.aclpPreference) { + preferenceRef.current = preferences.aclpPreference; + } /** * * @param data AclpConfig data to be updated in preferences @@ -53,12 +56,13 @@ export const useAclpPreference = (): AclpPreferenceObject => { * @param data AclpWidget data for the label that is to be updated in preference */ const updateWidgetPreference = (label: string, data: Partial) => { - const updatedPreferences = { ...preferenceRef.current }; - - if (!updatedPreferences.widgets) { - updatedPreferences.widgets = {}; - } - + // sync with latest preferences + const updatedPreferences = { + ...preferenceRef.current, + [WIDGETS]: { + ...(preferenceRef.current.widgets ?? {}), + }, + }; updatedPreferences.widgets[label] = { ...updatedPreferences.widgets[label], label, diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx index f4b4ca4baac..2544d26ffef 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx @@ -188,8 +188,6 @@ export const RenderWidgets = React.memo( oldProps.manualRefreshTimeStamp, newProps.manualRefreshTimeStamp ) || - !deepEqual(oldProps.metricDefinitions, newProps.metricDefinitions) || - !deepEqual(oldProps.resourceList, newProps.resourceList) || !deepEqual(oldProps.resources, newProps.resources) ) { return false; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index a50c12f7f4f..7b471da131e 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -260,11 +260,6 @@ function compareProps( } } - // Deep comparison for options - if (!deepEqual(prevProps.options, nextProps.options)) { - return false; - } - // Ignore function props in comparison return true; } From d20cb1b02becf37341f93bcc93eedfb1f418c199 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Wed, 25 Sep 2024 17:00:52 +0530 Subject: [PATCH 077/474] upcoming: [DI-20800] - Tooltip changes --- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 23 +++++++ .../CloudPulseAggregateFunction.tsx | 51 +++++++++----- .../components/CloudPulseIntervalSelect.tsx | 69 +++++++++++-------- .../CloudPulse/Widget/components/Zoomer.tsx | 57 ++++++++++----- 4 files changed, 135 insertions(+), 65 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index 29eabd3a7a9..a2350a18849 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -26,6 +26,7 @@ import type { } from '@linode/api-v4'; import type { DataSet } from 'src/components/LineGraph/LineGraph'; import type { CloudPulseResourceTypeMapFlag, FlagSet } from 'src/featureFlags'; +import { Tooltip } from 'src/components/Tooltip'; interface LabelNameOptionsProps { /** @@ -349,3 +350,25 @@ export const StyledWidgetAutocomplete = styled(Autocomplete, { width: '90px', }, })); + +// popperProps.ts +export const commonPopperProps = { + modifiers: [ + { + name: 'offset', + options: { + offset: [0, -8], // Adjust offset if needed + }, + }, + ], + sx: { + '& .MuiTooltip-tooltip': { + bgcolor: 'black', + color: 'white', + fontSize: '13px', + maxHeight: '28px', + maxWidth: '64px', + padding: '6px', + }, + }, +}; diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx index 3f881d67b32..9d7f69a0af5 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx @@ -1,6 +1,11 @@ import React from 'react'; -import { StyledWidgetAutocomplete } from '../../Utils/CloudPulseWidgetUtils'; +import { Tooltip } from 'src/components/Tooltip'; + +import { + StyledWidgetAutocomplete, + commonPopperProps, +} from '../../Utils/CloudPulseWidgetUtils'; export interface AggregateFunctionProperties { /** @@ -37,24 +42,32 @@ export const CloudPulseAggregateFunction = React.memo( ) || props.availableAggregateFunctions[0]; return ( - { - return option.label == value.label; - }} - onChange={(_: any, selectedAggregateFunc: any) => { - props.onAggregateFuncChange(selectedAggregateFunc.label); - }} - textFieldProps={{ - hideLabel: true, - }} - defaultValue={defaultAggregateFunc} - disableClearable - fullWidth={false} - label="Select an Aggregate Function" - noMarginTop={true} - options={availableAggregateFunc} - sx={{ width: '100%' }} - /> + + + { + return option.label == value.label; + }} + onChange={(_: any, selectedAggregateFunc: any) => { + props.onAggregateFuncChange(selectedAggregateFunc.label); + }} + textFieldProps={{ + hideLabel: true, + }} + defaultValue={defaultAggregateFunc} + disableClearable + fullWidth={false} + label="Select an Aggregate Function" + noMarginTop={true} + options={availableAggregateFunc} + sx={{ width: '100%' }} + /> + + ); } ); diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx index 7370937f1e3..a665815bac4 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx @@ -1,6 +1,12 @@ import React from 'react'; -import { StyledWidgetAutocomplete } from '../../Utils/CloudPulseWidgetUtils'; +import { Box } from 'src/components/Box'; +import { Tooltip } from 'src/components/Tooltip'; + +import { + StyledWidgetAutocomplete, + commonPopperProps, +} from '../../Utils/CloudPulseWidgetUtils'; import type { TimeGranularity } from '@linode/api-v4'; @@ -115,33 +121,40 @@ export const CloudPulseIntervalSelect = React.memo( } return ( - { - return option?.value === value?.value && option?.unit === value?.unit; - }} - onChange={( - _: React.SyntheticEvent, - selectedInterval: IntervalOptions - ) => { - props.onIntervalChange({ - unit: selectedInterval?.unit, - value: selectedInterval?.value, - }); - }} - textFieldProps={{ - hideLabel: true, - }} - defaultValue={{ ...default_interval }} - disableClearable - fullWidth={false} - label="Select an Interval" - noMarginTop={true} - options={[autoIntervalOption, ...availableIntervalOptions]} - sx={{ width: { xs: '100%' } }} - /> + + + option?.value === value?.value && option?.unit === value?.unit} + onChange={( + _: React.SyntheticEvent, + selectedInterval: IntervalOptions + ) => { + props.onIntervalChange({ + unit: selectedInterval?.unit, + value: selectedInterval?.value, + }); + }} + textFieldProps={{ + hideLabel: true, + }} + defaultValue={{ ...default_interval }} + disableClearable + fullWidth={false} + label="Select an Interval" + noMarginTop={true} + options={[autoIntervalOption, ...availableIntervalOptions]} + sx={{ width: { xs: '100%' } }} + autoHighlight + /> + + ); } ); diff --git a/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx b/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx index f21148cc831..028bcd8882e 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx @@ -1,8 +1,11 @@ -import { useTheme } from '@mui/material'; +import { IconButton, useTheme } from '@mui/material'; import * as React from 'react'; import ZoomInMap from 'src/assets/icons/zoomin.svg'; import ZoomOutMap from 'src/assets/icons/zoomout.svg'; +import { Tooltip } from 'src/components/Tooltip'; + +import { commonPopperProps } from '../../Utils/CloudPulseWidgetUtils'; export interface ZoomIconProperties { className?: string; @@ -20,28 +23,46 @@ export const ZoomIcon = React.memo((props: ZoomIconProperties) => { const ToggleZoomer = () => { if (props.zoomIn) { return ( - + handleClick(false)} + > + + + + ); + } + + return ( + + handleClick(false)} - /> - ); - } - - return ( - handleClick(true)} - /> + data-testid="zoom-out" + onClick={() => handleClick(true)} + > + + + ); }; From 51f98f3e1387df6f9a04549d398f96cdd6e22813 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Wed, 25 Sep 2024 17:02:06 +0530 Subject: [PATCH 078/474] tests: [DI-20585] - Enabling auto highlight for selections --- .../CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx | 1 + .../CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx index 3f881d67b32..21c00e69dbb 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx @@ -47,6 +47,7 @@ export const CloudPulseAggregateFunction = React.memo( textFieldProps={{ hideLabel: true, }} + autoHighlight defaultValue={defaultAggregateFunc} disableClearable fullWidth={false} diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx index 7370937f1e3..2ae64ee1e03 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx @@ -134,6 +134,7 @@ export const CloudPulseIntervalSelect = React.memo( textFieldProps={{ hideLabel: true, }} + autoHighlight defaultValue={{ ...default_interval }} disableClearable fullWidth={false} From 0b5b3f24ff2d4f414d9419d20e3e006be387a035 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Wed, 25 Sep 2024 17:06:42 +0530 Subject: [PATCH 079/474] tests: [DI-20585] - Revert not needed changes --- .../e2e/core/cloudpulse/linode-widget-verification.spec.ts | 4 ---- .../src/features/CloudPulse/Widget/CloudPulseWidget.tsx | 3 --- 2 files changed, 7 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 9a333af95b3..685bc81a77e 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -143,8 +143,6 @@ describe('Dashboard Widget Verification Tests', () => { .should('be.visible') .first() .within(() => { - const widgetFilterSelector = `[data-qa-widget-filters="${testData.title}"]`; - cy.get(widgetFilterSelector).invoke('attr', 'style', 'overflow:visible'); ui.autocomplete .findByTitleCustom('Select an Interval') .should('be.visible') @@ -264,8 +262,6 @@ describe('Dashboard Widget Verification Tests', () => { .findByTitleCustom('Select an Interval') .findByTitle('Open') .click(); - const widgetFilterSelector = `[data-qa-widget-filter="${testData.title}"]`; - cy.get(widgetFilterSelector).invoke('attr', 'style', 'overflow:visible'); testData.expectedGranularityArray.forEach((option) => { ui.autocompletePopper.findByTitle(option).should('be.visible'); }); diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index bb3ab1e2aef..0c820cd2900 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -315,9 +315,6 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { {unit.endsWith('ps') ? '/s' : ''}) Date: Wed, 25 Sep 2024 17:30:20 +0530 Subject: [PATCH 080/474] tests: [DI-20585] - Selection update for custom select component --- .../src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index 7c054aa4e11..a4b186a2514 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -213,6 +213,7 @@ export const CloudPulseCustomSelect = React.memo( textFieldProps={{ hideLabel: true, }} + autoHighlight disabled={isAutoCompleteDisabled} errorText={staticErrorText} isOptionEqualToValue={(option, value) => option.label === value.label} From 432f48d41f308264a78aca6976154af727045784 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 25 Sep 2024 18:39:49 +0530 Subject: [PATCH 081/474] upcoming: [DI-20360] - Updated deep equal logic --- .../Dashboard/CloudPulseDashboardRenderer.tsx | 29 +++++++++--- .../src/features/CloudPulse/Utils/utils.ts | 33 ++++++++++++++ .../Widget/CloudPulseWidgetRenderer.tsx | 44 ++++++++++++------- .../components/CloudPulseIntervalSelect.tsx | 12 ++--- .../shared/CloudPulseCustomSelect.tsx | 1 - .../shared/CloudPulseResourcesSelect.tsx | 5 +-- 6 files changed, 93 insertions(+), 31 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx index e7fb8ad3df6..20efa560008 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx @@ -1,4 +1,3 @@ -import deepEqual from 'fast-deep-equal'; import React from 'react'; import { CloudPulseErrorPlaceholder } from '../shared/CloudPulseErrorPlaceholder'; @@ -8,6 +7,7 @@ import { getMetricsCallCustomFilters, } from '../Utils/FilterBuilder'; import { FILTER_CONFIG } from '../Utils/FilterConfig'; +import { arrayDeepEqual } from '../Utils/utils'; import { CloudPulseDashboard } from './CloudPulseDashboard'; import type { DashboardProp } from './CloudPulseDashboardLanding'; @@ -82,10 +82,6 @@ export const CloudPulseDashboardRenderer = React.memo( return false; } - if (!deepEqual(oldProps.filterValue, newProps.filterValue)) { - return false; - } - if ( oldProps.timeDuration?.unit !== newProps.timeDuration?.unit || oldProps.timeDuration?.value !== newProps.timeDuration?.value @@ -93,6 +89,29 @@ export const CloudPulseDashboardRenderer = React.memo( return false; } + const oldKeys = Object.keys(oldProps.filterValue); + const newKeys = Object.keys(newProps.filterValue); + + if (oldKeys.length !== newKeys.length) { + return false; + } + + for (const key of oldKeys) { + const oldValue = oldProps.filterValue[key]; + const newValue = newProps.filterValue[key]; + + if ( + Array.isArray(oldValue) && + Array.isArray(newValue) && + !arrayDeepEqual(oldValue, newValue) + ) { + return false; + } + + if (oldValue !== newValue) { + return false; + } + } return true; } ); diff --git a/packages/manager/src/features/CloudPulse/Utils/utils.ts b/packages/manager/src/features/CloudPulse/Utils/utils.ts index 7c168f4e487..92599e6971b 100644 --- a/packages/manager/src/features/CloudPulse/Utils/utils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/utils.ts @@ -158,3 +158,36 @@ export const getAllDashboards = ( isLoading, }; }; + +/** + * + * @param oldValue array of old values + * @param newValue array of new values + * @returns true if both the arrays are equals otherwise false + */ +export const arrayDeepEqual = ( + oldValue: number[] | string[], + newValue: number[] | string[] +): boolean => { + if (oldValue === newValue) { + return true; + } + + if (!oldValue || !newValue) { + return false; + } + + if (oldValue.length !== newValue.length) { + return false; + } + oldValue.sort(); + newValue.sort(); + + for (let i = 0; i < oldValue.length; i++) { + if (oldValue[i] !== newValue[i]) { + return false; + } + } + + return true; +}; diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx index 2544d26ffef..5bb2a9b7f44 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx @@ -1,11 +1,10 @@ import { Grid, Paper } from '@mui/material'; -import deepEqual from 'fast-deep-equal'; import React from 'react'; import CloudPulseIcon from 'src/assets/icons/entityIcons/monitor.svg'; import { Placeholder } from 'src/components/Placeholder/Placeholder'; -import { createObjectCopy } from '../Utils/utils'; +import { arrayDeepEqual, createObjectCopy } from '../Utils/utils'; import { CloudPulseWidget } from './CloudPulseWidget'; import { allIntervalOptions, @@ -23,17 +22,22 @@ import type { AvailableMetrics, Dashboard, JWEToken, + MetricDefinitions, TimeDuration, Widgets, } from '@linode/api-v4'; +interface CompareProperties { + [key: string]: number | string | undefined; +} + interface WidgetProps { additionalFilters?: CloudPulseMetricsAdditionalFilters[]; dashboard?: Dashboard | undefined; duration: TimeDuration; jweToken?: JWEToken | undefined; manualRefreshTimeStamp?: number; - metricDefinitions: any; + metricDefinitions: MetricDefinitions | undefined; preferences?: AclpConfig; resourceList: CloudPulseResources[] | undefined; resources: string[]; @@ -179,20 +183,30 @@ export const RenderWidgets = React.memo( ); }, (oldProps: WidgetProps, newProps: WidgetProps) => { - if ( - !deepEqual(oldProps.dashboard, newProps.dashboard) || - !deepEqual(oldProps.additionalFilters, newProps.additionalFilters) || - !deepEqual(oldProps.duration, newProps.duration) || - !deepEqual(oldProps.jweToken, newProps.jweToken) || - !deepEqual( - oldProps.manualRefreshTimeStamp, - newProps.manualRefreshTimeStamp - ) || - !deepEqual(oldProps.resources, newProps.resources) - ) { + const oldValue: CompareProperties = { + id: oldProps.dashboard?.id, + timeStamp: oldProps.manualRefreshTimeStamp, + token: oldProps.jweToken?.token, + unit: oldProps.duration?.unit, + value: oldProps.duration?.value, + }; + + const newValue: CompareProperties = { + id: newProps.dashboard?.id, + timeStamp: newProps.manualRefreshTimeStamp, + token: newProps.jweToken?.token, + unit: newProps.duration?.unit, + value: newProps.duration?.value, + }; + + for (const key of Object.keys(oldValue)) { + if (oldValue[key] !== newValue[key]) { + return false; + } + } + if (!arrayDeepEqual(oldProps.resources, newProps.resources)) { return false; } - return true; } ); diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx index 595bc95a2b2..13a5bdee9eb 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx @@ -98,7 +98,7 @@ export const CloudPulseIntervalSelect = React.memo( allIntervalOptions.length ); - let default_value = + let defaultValue = defaultInterval?.unit === 'Auto' ? autoIntervalOption : availableIntervalOptions.find( @@ -107,15 +107,15 @@ export const CloudPulseIntervalSelect = React.memo( obj.unit === defaultInterval?.unit ); - if (!default_value) { - default_value = autoIntervalOption; + if (!defaultValue) { + defaultValue = autoIntervalOption; onIntervalChange({ - unit: default_value.unit, - value: default_value.value, + unit: defaultValue.unit, + value: defaultValue.value, }); } const [selectedInterval, setSelectedInterval] = React.useState( - default_value + defaultValue ); return ( diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index 7b471da131e..63a98134585 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -1,4 +1,3 @@ -import deepEqual from 'fast-deep-equal'; import React from 'react'; import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index d4ccd0957ea..c9ad5c13d3f 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -1,4 +1,3 @@ -import deepEqual from 'fast-deep-equal'; import React from 'react'; import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; @@ -130,9 +129,7 @@ function compareProps( return false; } } - - // Deep comparison for xFilter - if (!deepEqual(prevProps.xFilter, nextProps.xFilter)) { + if (prevProps.xFilter !== nextProps.xFilter) { return false; } From 186c3df9af640304613efc74dab43643316d3061 Mon Sep 17 00:00:00 2001 From: agorthi Date: Wed, 25 Sep 2024 20:30:46 +0530 Subject: [PATCH 082/474] upcoming:[DI-20585]- Added code review comments --- .../linode-widget-verification.spec.ts | 367 +++++++++--------- .../cypress/support/constants/widgets.ts | 116 ++---- packages/manager/src/factories/dashboards.ts | 13 +- packages/manager/src/factories/widget.ts | 25 +- 4 files changed, 227 insertions(+), 294 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 878e077a874..ef1a0dbf109 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -4,10 +4,7 @@ import { selectAndVerifyResource, assertSelections, } from 'support/util/cloudpulse'; -import { - mockAppendFeatureFlags, - mockGetFeatureFlagClientstream, -} from 'support/intercepts/feature-flags'; +import { mockAppendFeatureFlags } from 'support/intercepts/feature-flags'; import { mockCloudPulseJWSToken, mockCloudPulseDashboardServicesResponse, @@ -17,14 +14,8 @@ import { mockCloudPulseServices, } from 'support/intercepts/cloudpulse'; import { ui } from 'support/ui'; -import { - timeRange, - widgetDetails, - granularity, -} from 'support/constants/widgets'; -import { makeFeatureFlagData } from 'support/util/feature-flags'; +import { widgetDetails } from 'support/constants/widgets'; import { createMetricResponse } from '@src/factories/widget'; -import type { Flags } from 'src/featureFlags'; import { accountFactory, dashboardFactory, @@ -42,6 +33,21 @@ import { extendRegion } from 'support/util/regions'; import { CloudPulseMetricsResponse } from '@linode/api-v4'; import { transformData } from 'src/features/CloudPulse/Utils/unitConversion'; import { getMetrics } from 'src/utilities/statMetrics'; +const timeRanges = { + last7Days: 'Last 7 Days', + last12Hours: 'Last 12 Hours', + last24Hours: 'Last 24 Hours', + last30Days: 'Last 30 Days', + last30Minutes: 'Last 30 Minutes', +}; +const y_labels = [ + 'system_cpu_utilization_ratio', + 'system_memory_usage_bytes', + 'system_network_io_bytes_total', + 'system_disk_operations_total', +]; +const expectedGranularityArray = ['Auto', '1 day', '1 hr', '5 min']; + /** * This test ensures that widget titles are displayed correctly on the dashboard. * This test suite is dedicated to verifying the functionality and display of widgets on the Cloudpulse dashboard. @@ -53,44 +59,39 @@ import { getMetrics } from 'src/utilities/statMetrics'; * Each test ensures that widgets on the dashboard operate correctly and display accurate information. */ -const y_labels = [ - 'system_cpu_utilization_ratio', - 'system_memory_usage_bytes', - 'system_network_io_bytes_total', - 'system_disk_operations_total', -]; -const widgets = widgetDetails.linode; -const metrics = widgets.metrics; - const dashboardName = widgets.dashboardName; - const region = widgets.region; -const actualRelativeTimeDuration = timeRange.last24Hours; - const resource = widgets.resource; +const metrics = widgetDetails.linode.metrics; const widgetLabels: string[] = metrics.map((widget) => widget.title); const metricsLabels: string[] = metrics.map((widget) => widget.name); -const service_type = widgets.service_type; -const dashboardId = widgets.id; - +const unit: string[] = metrics.map((widget) => widget.unit); const dashboard = dashboardFactory.build({ - label: dashboardName, - service_type: service_type, - widgets: [...widgetLabels.map((label: string, index: number) => - widgetFactory.build({ - label, - y_label: y_labels[index], - metric: metricsLabels[index], - }))] -}) + label: widgetDetails.linode.dashboardName, + service_type: widgetDetails.linode.service_type, + widgets: [ + ...widgetLabels.map((label: string, index: number) => + widgetFactory.build({ + label, + y_label: y_labels[index], + metric: metricsLabels[index], + unit: unit[index], + }) + ), + ], +}); const metricDefinitions = { - data: [...widgetLabels.map((label, index) => - dashboardMetricFactory.build({ - label, - metric: metricsLabels[index], - }))] -} + data: [ + ...widgetLabels.map((label, index) => + dashboardMetricFactory.build({ + label, + metric: metricsLabels[index], + unit: unit[index], + }) + ), + ], +}; const mockKubeLinode = kubeLinodeFactory.build(); const mockLinode = linodeFactory.build({ - label: resource, + label: widgetDetails.linode.resource, id: mockKubeLinode.instance_id ?? undefined, }); const mockAccount = accountFactory.build(); @@ -106,57 +107,141 @@ let responsePayload: CloudPulseMetricsResponse; describe('Dashboard Widget Verification Tests', () => { beforeEach(() => { mockAppendFeatureFlags({ - aclp: makeFeatureFlagData({ beta: true, enabled: true }), - }).as('getFeatureFlags'); - mockAppendFeatureFlags({ - aclp: { beta: true, enabled: true }, + aclp: { beta: true, enabled: true }, }).as('getFeatureFlags'); mockGetAccount(mockAccount).as('getAccount'); // Enables the account to have capability for Akamai Cloud Pulse mockGetLinodes([mockLinode]).as('getLinodes'); - mockCloudPulseGetMetricDefinitions(metricDefinitions, service_type); - mockCloudPulseGetDashboards(dashboard, service_type).as('dashboard'); - mockCloudPulseServices(service_type).as('services'); - mockCloudPulseDashboardServicesResponse(dashboard, dashboardId); - mockCloudPulseJWSToken(service_type); - responsePayload = createMetricResponse( - actualRelativeTimeDuration, - granularity.minutes + mockCloudPulseGetMetricDefinitions( + metricDefinitions, + widgetDetails.linode.service_type ); - mockCloudPulseCreateMetrics(responsePayload, service_type).as('getMetrics'); + mockCloudPulseGetDashboards( + dashboard, + widgetDetails.linode.service_type + ).as('dashboard'); + mockCloudPulseServices(widgetDetails.linode.service_type).as('services'); + mockCloudPulseDashboardServicesResponse(dashboard, widgetDetails.linode.id); + mockCloudPulseJWSToken(widgetDetails.linode.service_type); + responsePayload = createMetricResponse(timeRanges.last24Hours, '5 min'); + mockCloudPulseCreateMetrics( + responsePayload, + widgetDetails.linode.service_type + ).as('getMetrics'); mockGetRegions([mockRegion]).as('getRegions'); }); - it('should verify cloudpulse availability when feature flag is set to false', () => { + it('should verify cloudpulse availability when feature flag is set to true', () => { mockAppendFeatureFlags({ - aclp: makeFeatureFlagData({ beta: true, enabled: false }), - }); - mockGetFeatureFlagClientstream(); - cy.visitWithLogin('monitor/cloudpulse'); // since we disabled the flag here, we should have not found + aclp: { beta: true, enabled: true }, + }).as('getFeatureFlags'); + cy.visitWithLogin('/linodes'); // since we disabled the flag here, we should have not found + cy.wait('@getFeatureFlags'); + ui.nav.findItemByTitle('Monitor').should('be.visible').click(); + cy.url().should('endWith', '/cloudpulse'); + }); + + it('should verify CloudPulse availability when feature flag is set to false and accessed directly', () => { + mockAppendFeatureFlags({ + aclp: { beta: true, enabled: false }, + }).as('getFeatureFlags'); + cy.visitWithLogin('monitor/cloudpulse'); + cy.wait('@getFeatureFlags'); cy.findByText('Not Found').should('be.visible'); // not found + // Check that the Monitor button is not present in the sidebar + cy.get('[data-testid="menu-item-Monitor"]').should('not.exist'); }); - it.only('should set available granularity of all the widgets', () => { + it('should verify that the Monitor button is not available in the sidebar when the feature flag is disabled', () => { + mockAppendFeatureFlags({ + aclp: { beta: true, enabled: false }, + }).as('getFeatureFlags'); + cy.visitWithLogin('/linodes'); + cy.wait('@getFeatureFlags'); + // Check that the Monitor button is not present in the sidebar + cy.get('[data-testid="menu-item-Monitor"]').should('not.exist'); + }); + it('should verify the title of the widget', () => { + setupMethod(); + metrics.forEach((testData) => { + const widgetSelector = `[data-qa-widget-header="${testData.title}"]`; + cy.get(widgetSelector) + .invoke('text') + .then((text) => { + expect(text.trim()).to.equal( + `${testData.title} (${testData.unit.trim()})` + ); + }); + }); + }); + it('should verify available granularity of the widget', () => { setupMethod(); metrics.forEach((testData) => { cy.wait(7000); //maintaining the wait since page flicker and rendering const widgetSelector = `[data-qa-widget="${testData.title}"]`; - cy.get(widgetSelector).as('widget'); - cy.get('@widget') - .should('be.visible') + cy.get(widgetSelector) .first() + .scrollIntoView() + .should('be.visible') .within(() => { ui.autocomplete .findByTitleCustom('Select an Interval') + .findByTitle('Open') + .click(); + expectedGranularityArray.forEach((option) => { + ui.autocompletePopper.findByTitle(option).should('exist'); + }); + ui.autocomplete + .findByTitleCustom('Select an Interval') + .should('be.visible') + .findByTitle('Close') .should('be.visible') + .click(); + }); + }); + }); + + it('should verify available aggregation of the widget', () => { + setupMethod(); + metrics.forEach((testData) => { + cy.wait(7000); //maintaining the wait since page flicker and rendering + const widgetSelector = `[data-qa-widget="${testData.title}"]`; + cy.get(widgetSelector) + .first() + .scrollIntoView() + .should('be.visible') + .within(() => { + ui.autocomplete + .findByTitleCustom('Select an Aggregate Function') .findByTitle('Open') .click(); - ui.autocompletePopper - .findByTitle(testData.expectedGranularity) - .as('granularityOption'); - cy.get('@granularityOption') + testData.expectedAggregationArray.forEach((option) => { + ui.autocompletePopper.findByTitle(option).should('exist'); + }); + ui.autocomplete + .findByTitleCustom('Select an Aggregate Function') + .should('be.visible') + .findByTitle('Close') .should('be.visible') - .should('have.text', testData.expectedGranularity) .click(); + }); + }); + }); + it('should set available granularity of all the widgets', () => { + setupMethod(); + metrics.forEach((testData) => { + cy.wait(7000); //maintaining the wait since page flicker and rendering + const widgetSelector = `[data-qa-widget="${testData.title}"]`; + cy.get(widgetSelector).as('widget'); + cy.get('@widget') + .should('be.visible') + .first() + .within(() => { + ui.autocomplete + .findByTitleCustom('Select an Interval') + .should('be.visible') + .findByTitle('Open') + .click() + .type(`${testData.expectedGranularity}{enter}`); cy.findByDisplayValue(testData.expectedGranularity).should('exist'); cy.findByTestId('linegraph-wrapper') .as('canvas') @@ -187,19 +272,6 @@ describe('Dashboard Widget Verification Tests', () => { }); }); }); - - it.only('should verify the title of the widget', () => { - setupMethod(); - metrics.forEach((testData) => { - const widgetSelector = `[data-qa-widget-header="${testData.title}"]`; - cy.get(widgetSelector) - .invoke('text') - .then((text) => { - expect(text.trim()).to.equal(testData.title); - }); - }); - }); - it('should set available aggregation of all the widgets', () => { setupMethod(); metrics.forEach((testData) => { @@ -213,12 +285,8 @@ describe('Dashboard Widget Verification Tests', () => { .findByTitleCustom('Select an Aggregate Function') .should('be.visible') .findByTitle('Open') - .click(); - ui.autocompletePopper - .findByTitle(testData.expectedAggregation) - .should('be.visible') - .should('have.text', testData.expectedAggregation) - .click(); + .click() + .type(`${testData.expectedAggregation}{enter}`); cy.findByDisplayValue(testData.expectedAggregation).should('exist'); cy.findByTestId('linegraph-wrapper') .as('canvas') @@ -250,63 +318,13 @@ describe('Dashboard Widget Verification Tests', () => { }); }); - it('should verify available granularity of the widget', () => { - setupMethod(); - metrics.forEach((testData) => { - cy.wait(7000); //maintaining the wait since page flicker and rendering - const widgetSelector = `[data-qa-widget="${testData.title}"]`; - cy.get(widgetSelector) - .first() - .scrollIntoView() - .should('be.visible') - .within(() => { - ui.autocomplete - .findByTitleCustom('Select an Interval') - .findByTitle('Open') - .click(); - testData.expectedGranularityArray.forEach((option) => { - ui.autocompletePopper.findByTitle(option).should('be.visible'); - }); - ui.autocomplete - .findByTitleCustom('Select an Interval') - .should('be.visible') - .findByTitle('Close') - .should('be.visible') - .click(); - }); - }); - }); - - it('should verify available aggregation of the widget', () => { - setupMethod(); - metrics.forEach((testData) => { - cy.wait(7000); //maintaining the wait since page flicker and rendering - const widgetSelector = `[data-qa-widget="${testData.title}"]`; - cy.get(widgetSelector) - .first() - .scrollIntoView() - .should('be.visible') - .within(() => { - ui.autocomplete - .findByTitleCustom('Select an Aggregate Function') - .findByTitle('Open') - .click(); - testData.expectedAggregationArray.forEach((option) => { - ui.autocompletePopper.findByTitle(option).should('be.visible'); - }); - ui.autocomplete - .findByTitleCustom('Select an Aggregate Function') - .should('be.visible') - .findByTitle('Close') - .should('be.visible') - .click(); - }); - }); - }); it('should apply global refresh button and verify network calls', () => { setupMethod(); - - ui.button.findByAttribute('aria-label', 'cloudpulse-refresh').should('be.visible').click(); + cy.wait(7000); //maintaining the wait since page flicker and rendering + ui.button + .findByAttribute('aria-label', 'cloudpulse-refresh') + .should('be.visible') + .click(); cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']).then( (interceptions) => { const interceptionsArray = Array.isArray(interceptions) @@ -314,40 +332,22 @@ describe('Dashboard Widget Verification Tests', () => { : [interceptions]; interceptionsArray.forEach((interception) => { const { body: requestPayload } = interception.request; - // const { metric, time_granularity: granularity, relative_time_duration: timeRange, aggregate_function: aggregateFunction } = requestPayload; - const { - metric, - time_granularity: granularity, - relative_time_duration: timeRange, - } = requestPayload; + const { metric, relative_time_duration: timeRange } = requestPayload; const metricData = metrics.find((data) => data.name === metric); - if ( - !metricData || - !metricData.expectedGranularity || - !metricData.expectedAggregation - ) { + if (!metricData) { expect.fail( 'metricData or its expected properties are not defined.' ); } const expectedRelativeTimeDuration = timeRange - ? `Last ${timeRange.value} ${['hour', 'hr'].includes(timeRange.unit.toLowerCase()) - ? 'Hours' - : timeRange.unit - }` - : ''; - const currentGranularity = granularity - ? `${granularity.value} ${['hour', 'hours'].includes(granularity.unit.toLowerCase()) - ? 'hr' - : granularity.unit - }` + ? `Last ${timeRange.value} ${ + ['hour', 'hr'].includes(timeRange.unit.toLowerCase()) + ? 'Hours' + : timeRange.unit + }` : ''; expect(metric).to.equal(metricData.name); - expect(currentGranularity).to.equal(metricData.expectedGranularity); - expect(expectedRelativeTimeDuration).to.equal( - actualRelativeTimeDuration - ); - // expect(aggregateFunction).to.equal(metricData.expectedAggregation); + expect(expectedRelativeTimeDuration).to.equal(timeRanges.last24Hours); }); } ); @@ -356,13 +356,13 @@ describe('Dashboard Widget Verification Tests', () => { it('should zoom in and out of all the widgets', () => { setupMethod(); metrics.forEach((testData) => { - cy.wait(7000); // Maintaining the wait since page flicker and rendering + cy.wait(7000); //maintaining the wait since page flicker and rendering cy.get(`[data-qa-widget="${testData.title}"]`).as('widget'); cy.get('@widget') .should('be.visible') .within(() => { ui.button - .findByAttribute('aria-label', 'zoom-out') + .findByAttribute('aria-label', 'zoom-in') .should('be.visible') .should('be.enabled') .click(); @@ -425,9 +425,9 @@ describe('Dashboard Widget Verification Tests', () => { /** * `setupMethod` initializes the Cloud Pulse dashboard for testing by performing a series of setup actions. * This method mocks user preferences, navigates to the Cloud Pulse page, and configures various settings - * including service name, time range, engine, region, resource, and node type. It also verifies each selection + * including service name, time range, engine, region, resource, and node type. It also verifies each selection * to ensure the dashboard is correctly configured before running further tests. - * + * * Steps: * 1. Mock user preferences to ensure a consistent test environment. * 2. Navigate to the Cloud Pulse page and verify that it has loaded correctly. @@ -440,26 +440,23 @@ describe('Dashboard Widget Verification Tests', () => { const setupMethod = () => { mockGetUserPreferences({}).as('getUserPreferences'); cy.visitWithLogin('monitor/cloudpulse'); - cy.get('[data-qa-header="Akamai Cloud Pulse"]') - .should('be.visible') - .should('have.text', 'Akamai Cloud Pulse'); - selectServiceName(dashboardName); - assertSelections(dashboardName); - selectTimeRange(actualRelativeTimeDuration, Object.values(timeRange)); - assertSelections(actualRelativeTimeDuration); - ui.regionSelect.find().click().type(`${region}{enter}`); - assertSelections(region); - selectAndVerifyResource(resource); + selectServiceName(widgetDetails.linode.dashboardName); + assertSelections(widgetDetails.linode.dashboardName); + selectTimeRange(timeRanges.last24Hours, Object.values(timeRanges)); + assertSelections(timeRanges.last24Hours); + ui.regionSelect.find().click().type(`${widgetDetails.linode.region}{enter}`); + assertSelections(widgetDetails.linode.region); + selectAndVerifyResource(widgetDetails.linode.resource); }; /** * `verifyWidgetValues` processes and verifies the metric values of a widget from the provided response payload. - * + * * This method performs the following steps: * 1. Transforms the raw data from the response payload into a more manageable format using `transformData`. * 2. Extracts key metrics (average, last, and max) from the transformed data using `getMetrics`. * 3. Rounds these metrics to two decimal places for accuracy. * 4. Returns an object containing the rounded average, last, and max values for further verification or comparison. - * + * * @param {CloudPulseMetricsResponse} responsePayload - The response payload containing metric data for a widget. * @returns {Object} An object with the rounded average, last, and max metric values. */ diff --git a/packages/manager/cypress/support/constants/widgets.ts b/packages/manager/cypress/support/constants/widgets.ts index 9b44637d03b..19e5c137cbc 100644 --- a/packages/manager/cypress/support/constants/widgets.ts +++ b/packages/manager/cypress/support/constants/widgets.ts @@ -2,55 +2,7 @@ * Defines the granularity levels used for specifying time intervals in data aggregation or reporting. * Each property represents a different granularity level. */ -export const granularity = { - auto: 'Auto', - day1: '1 day', - hour: '1 hr', - minutes: '5 min', -}; - -/** - * Defines various aggregation types that can be applied to data. - * Each property represents a different type of aggregation operation. - */ -export const aggregation = { - avg: 'avg', - max: 'max', - min: 'min', - sum: 'sum', -}; - -// Define a constant object named `timeRange` to represent various time periods. -// This object maps time range identifiers to their descriptive strings. -export const timeRange = { - last7Days: 'Last 7 Days', - last12Hours: 'Last 12 Hours', - last24Hours: 'Last 24 Hours', - last30Days: 'Last 30 Days', - last30Minutes: 'Last 30 Minutes', -}; -// Define a constant object named `timeUnit` which serves as a mapping -// between time unit identifiers and their full descriptive names. -// This object provides a convenient way to reference standard time units. -export const timeUnit = { - day: 'Days', - hr: 'Hours', - min: 'Minutes', -}; -/** - * Configuration object defining predefined sets of aggregation types. - * These sets can be used to specify acceptable aggregation operations for different contexts. - */ - -export const aggregationConfig = { - all: [aggregation.avg, aggregation.max, aggregation.min, aggregation.sum], - basic: [aggregation.avg, aggregation.max, aggregation.min], -}; -/** - * Configuration object for widget details. - * Each widget configuration includes expected aggregation types, granularity levels, and other relevant properties. - */ export const widgetDetails = { dbaas: { clusterName: 'mysql-cluster', @@ -59,40 +11,36 @@ export const widgetDetails = { id: 1, metrics: [ { - StatsData: 'Controls for Disk I/O', - expectedAggregation: aggregation.max, - expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.hour, - expectedGranularityArray: Object.values(granularity), + expectedAggregation: 'max', + expectedAggregationArray: ['avg', 'max', 'min', 'sum'], + expectedGranularity: '1 hr', name: 'system_disk_OPS_total', title: 'Disk I/O', + unit: 'OPS', }, { - StatsData: 'Controls for CPU Utilization', - expectedAggregation: aggregation.max, - expectedAggregationArray: aggregationConfig.basic, - expectedGranularity: granularity.hour, - expectedGranularityArray: Object.values(granularity), + expectedAggregation: 'max', + expectedAggregationArray: ['avg', 'max', 'min'], + expectedGranularity: '1 hr', name: 'system_cpu_utilization_percent', title: 'CPU Utilization', + unit: '%', }, { - StatsData: 'Controls for Memory Usage', - expectedAggregation: aggregation.max, - expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.hour, - expectedGranularityArray: Object.values(granularity), + expectedAggregation: 'max', + expectedAggregationArray: ['avg', 'max', 'min', 'sum'], + expectedGranularity: '1 hr', name: 'system_memory_usage_by_resource', title: 'Memory Usage', + unit: 'Bytes', }, { - StatsData: 'Controls for Network Traffic', - expectedAggregation: aggregation.max, - expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.hour, - expectedGranularityArray: Object.values(granularity), + expectedAggregation: 'max', + expectedAggregationArray: ['avg', 'max', 'min', 'sum'], + expectedGranularity: '1 hr', name: 'system_network_io_by_resource', title: 'Network Traffic', + unit: 'Bytes', }, ], nodeType: 'Secondary', @@ -105,36 +53,36 @@ export const widgetDetails = { id: 1, metrics: [ { - expectedAggregation: aggregation.max, - expectedAggregationArray: aggregationConfig.basic, - expectedGranularity: granularity.hour, - expectedGranularityArray: Object.values(granularity), + expectedAggregation: 'max', + expectedAggregationArray: ['avg', 'max', 'min'], + expectedGranularity: '1 hr', name: 'system_cpu_utilization_percent', title: 'CPU Utilization', + unit: '%', }, { - expectedAggregation: aggregation.max, - expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.hour, - expectedGranularityArray: Object.values(granularity), + expectedAggregation: 'max', + expectedAggregationArray: ['avg', 'max', 'min', 'sum'], + expectedGranularity: '1 hr', name: 'system_memory_usage_by_resource', title: 'Memory Usage', + unit: 'Bytes', }, { - expectedAggregation: aggregation.max, - expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.hour, - expectedGranularityArray: Object.values(granularity), + expectedAggregation: 'max', + expectedAggregationArray: ['avg', 'max', 'min', 'sum'], + expectedGranularity: '1 hr', name: 'system_network_io_by_resource', title: 'Network Traffic', + unit: 'Bytes', }, { - expectedAggregation: aggregation.max, - expectedAggregationArray: aggregationConfig.all, - expectedGranularity: granularity.hour, - expectedGranularityArray: Object.values(granularity), + expectedAggregation: 'max', + expectedAggregationArray: ['avg', 'max', 'min', 'sum'], + expectedGranularity: '1 hr', name: 'system_disk_OPS_total', title: 'Disk I/O', + unit: 'OPS', }, ], region: 'US, Chicago, IL (us-ord)', diff --git a/packages/manager/src/factories/dashboards.ts b/packages/manager/src/factories/dashboards.ts index a34933b8138..72b5d80ede3 100644 --- a/packages/manager/src/factories/dashboards.ts +++ b/packages/manager/src/factories/dashboards.ts @@ -1,17 +1,10 @@ import Factory from 'src/factories/factoryProxy'; -import type { - AvailableMetrics, - Dashboard, - MetricDefinitions, - Widgets, -} from '@linode/api-v4'; +import type { AvailableMetrics, Dashboard, Widgets } from '@linode/api-v4'; -const units = ['%', '%', 'Bytes', 'OPS']; const color = ['blue', 'red', 'green', 'yellow']; const chart_type = ['area', 'area', 'area', 'line']; const scrape_interval = ['2m', '30s', '30s', '30s']; -const units_interval = ['percent', 'byte', 'byte', 'ops_per_second']; /** * Factory function to create instances of the `Dashboard` model with predefined properties and values. @@ -112,7 +105,7 @@ export const widgetFactory = Factory.Sync.makeFactory({ unit: 'hour', value: 1, }, - unit: Factory.each((i) => units[i % units.length]), + unit: 'defaultUnit', y_label: Factory.each((i) => 'y_label_' + i), }); /** @@ -151,6 +144,6 @@ export const dashboardMetricFactory = Factory.Sync.makeFactory scrape_interval: Factory.each( (i) => scrape_interval[i % scrape_interval.length] ), - unit: Factory.each((i) => units_interval[i % units_interval.length]), + unit: 'defaultUnit', } ); diff --git a/packages/manager/src/factories/widget.ts b/packages/manager/src/factories/widget.ts index 324fee1f34d..65ba26c0381 100644 --- a/packages/manager/src/factories/widget.ts +++ b/packages/manager/src/factories/widget.ts @@ -1,8 +1,3 @@ -import { - granularity, - timeRange, -} from '../../cypress/support/constants/widgets'; - import type { CloudPulseMetricsResponse } from '@linode/api-v4'; /** @@ -25,18 +20,18 @@ export const createMetricResponse = ( const currentTime = Math.floor(Date.now() / 1000); const intervals: Record = { - [granularity.auto]: 3600, - [granularity.day1]: 86400, - [granularity.hour]: 3600, - [granularity.minutes]: 5 * 60, + ['1 day']: 86400, + ['1 hr']: 3600, + ['5 min']: 5 * 60, + ['Auto']: 3600, }; const timeRanges: Record = { - [timeRange.last7Days]: 7 * 24 * 3600, - [timeRange.last12Hours]: 12 * 3600, - [timeRange.last24Hours]: 24 * 3600, - [timeRange.last30Days]: 30 * 24 * 3600, - [timeRange.last30Minutes]: 30 * 60, + ['Last 7 Days']: 7 * 24 * 3600, + ['Last 12 Hours']: 12 * 3600, + ['Last 24 Hours']: 24 * 3600, + ['Last 30 Days']: 30 * 24 * 3600, + ['Last 30 Minutes']: 30 * 60, }; const interval = @@ -71,4 +66,4 @@ export const createMetricResponse = ( }, status: 'success', }; -}; \ No newline at end of file +}; From d68bc537f52cf9fd7dea170ba8a436a8bba3a148 Mon Sep 17 00:00:00 2001 From: agorthi Date: Thu, 26 Sep 2024 11:43:05 +0530 Subject: [PATCH 083/474] upcoming:[DI-20585]- Added code review commennts --- .../cloudpulse/cloudpulse-navigation.spec.ts | 71 +++++++++++++++++++ .../linode-widget-verification.spec.ts | 30 -------- 2 files changed, 71 insertions(+), 30 deletions(-) create mode 100644 packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts new file mode 100644 index 00000000000..6c8f0e07f06 --- /dev/null +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts @@ -0,0 +1,71 @@ +/** + * @file Integration tests for CloudPulse navigation. + */ + +import { mockAppendFeatureFlags } from 'support/intercepts/feature-flags'; +import { mockGetAccount } from 'support/intercepts/account'; +import { accountFactory } from 'src/factories'; +import { ui } from 'support/ui'; + +const mockAccount = accountFactory.build(); + +describe('CloudPulse navigation', () => { + beforeEach(() => { + mockGetAccount(mockAccount).as('getAccount'); + }); + + /* + * - Confirms that Cloudpulse navigation item is shown when feature flag is enabled. + * - Confirms that clicking Cloudpulse navigation item directs user to Cloudpulse landing page. + */ + it('can navigate to Cloudpulse landing page', () => { + mockAppendFeatureFlags({ + aclp: { + beta: true, + enabled: true, + }, + }).as('getFeatureFlags'); + + cy.visitWithLogin('/linodes'); + cy.wait('@getFeatureFlags'); + + ui.nav.findItemByTitle('Monitor').should('be.visible').click(); + cy.url().should('endWith', '/cloudpulse'); + }); + + /* + * - Confirms that Cloudpulse navigation item is not shown when feature flag is disabled. + */ + it('does not show Cloudpulse navigation item when feature is disabled', () => { + mockAppendFeatureFlags({ + aclp: { + beta: true, + enabled: false, + }, + }).as('getFeatureFlags'); + + cy.visitWithLogin('/linodes'); + cy.wait('@getFeatureFlags'); + + ui.nav.find().within(() => { + cy.findByText('Monitor').should('not.exist'); + }); + }); + + /* + * - Confirms that manual navigation to Cloudpulse landing page with feature is disabled displays Not Found to user. + */ + it('displays Not Found when manually navigating to /placement-groups with feature flag disabled', () => { + mockAppendFeatureFlags({ + aclp: { + beta: true, + enabled: false, + }, + }).as('getFeatureFlags'); + + cy.visitWithLogin('monitor/cloudpulse'); + cy.wait('@getFeatureFlags'); + + cy.findByText('Not Found').should('be.visible'); + }); +}); diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index ef1a0dbf109..20d2da26029 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -130,36 +130,6 @@ describe('Dashboard Widget Verification Tests', () => { mockGetRegions([mockRegion]).as('getRegions'); }); - it('should verify cloudpulse availability when feature flag is set to true', () => { - mockAppendFeatureFlags({ - aclp: { beta: true, enabled: true }, - }).as('getFeatureFlags'); - cy.visitWithLogin('/linodes'); // since we disabled the flag here, we should have not found - cy.wait('@getFeatureFlags'); - ui.nav.findItemByTitle('Monitor').should('be.visible').click(); - cy.url().should('endWith', '/cloudpulse'); - }); - - it('should verify CloudPulse availability when feature flag is set to false and accessed directly', () => { - mockAppendFeatureFlags({ - aclp: { beta: true, enabled: false }, - }).as('getFeatureFlags'); - cy.visitWithLogin('monitor/cloudpulse'); - cy.wait('@getFeatureFlags'); - cy.findByText('Not Found').should('be.visible'); // not found - // Check that the Monitor button is not present in the sidebar - cy.get('[data-testid="menu-item-Monitor"]').should('not.exist'); - }); - - it('should verify that the Monitor button is not available in the sidebar when the feature flag is disabled', () => { - mockAppendFeatureFlags({ - aclp: { beta: true, enabled: false }, - }).as('getFeatureFlags'); - cy.visitWithLogin('/linodes'); - cy.wait('@getFeatureFlags'); - // Check that the Monitor button is not present in the sidebar - cy.get('[data-testid="menu-item-Monitor"]').should('not.exist'); - }); it('should verify the title of the widget', () => { setupMethod(); metrics.forEach((testData) => { From b51e591efd9a9b5a253ca0338d0b949ed4ece179 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Thu, 26 Sep 2024 13:20:11 +0530 Subject: [PATCH 084/474] Updated aggregate function type --- .../components/CloudPulseAggregateFunction.tsx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx index a166d691859..dba98c8726f 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx @@ -19,6 +19,11 @@ export interface AggregateFunctionProperties { onAggregateFuncChange: (aggregatevalue: string) => void; } +interface AggregateFunction { + label: string; + value: string; +} + export const CloudPulseAggregateFunction = React.memo( (props: AggregateFunctionProperties) => { const { @@ -28,7 +33,7 @@ export const CloudPulseAggregateFunction = React.memo( } = props; // Convert list of availableAggregateFunc into a proper response structure accepted by Autocomplete component - const availableAggregateFunc = availableAggregateFunctions?.map( + const availableAggregateFunc: AggregateFunction[] = availableAggregateFunctions?.map( (aggrFunc) => { return { label: aggrFunc, @@ -39,19 +44,19 @@ export const CloudPulseAggregateFunction = React.memo( const defaultValue = availableAggregateFunc.find( (obj) => obj.label === defaultAggregateFunction - ) || availableAggregateFunctions[0]; + ) || availableAggregateFunc[0]; const [ selectedAggregateFunction, setSelectedAggregateFunction, - ] = React.useState(defaultValue); + ] = React.useState(defaultValue); return ( { return option.label == value.label; }} - onChange={(_: any, selectedAggregateFunc: any) => { + onChange={(e, selectedAggregateFunc: AggregateFunction) => { setSelectedAggregateFunction(selectedAggregateFunc); onAggregateFuncChange(selectedAggregateFunc.label); }} From 7a1e419ec2ca60e5acbf91f9663f4d8b455e3772 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Thu, 26 Sep 2024 14:18:03 +0530 Subject: [PATCH 085/474] upcoming: [DI-20360] - Updated global filter test cases --- .../Overview/GlobalFilters.test.tsx | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 packages/manager/src/features/CloudPulse/Overview/GlobalFilters.test.tsx diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.test.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.test.tsx new file mode 100644 index 00000000000..b752c27a6c8 --- /dev/null +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.test.tsx @@ -0,0 +1,42 @@ +import { fireEvent } from '@testing-library/react'; +import React from 'react'; + +import { renderWithTheme } from 'src/utilities/testHelpers'; + +import { GlobalFilters } from './GlobalFilters'; + +const mockHandleAnyFilterChange = vi.fn(); +const mockHandleDashboardChange = vi.fn(); +const mockHandleTimeDurationChange = vi.fn(); +const timeRangeSelectId = 'cloudpulse-time-duration'; +const setup = () => { + return renderWithTheme( + + ); +}; +describe('Global filters component test', () => { + it('Should render refresh button', () => { + const { getByTestId } = setup(); + expect(getByTestId('global-refresh')).toBeInTheDocument(); + }), + it('Should show dashboard selectcomponent', () => { + const { getByTestId } = setup(); + + expect(getByTestId('cloudpulse-dashboard-select')).toBeInTheDocument(); + }), + it('Should have time range select with default value', () => { + const screen = setup(); + + const timeRangeSelect = screen.getByTestId(timeRangeSelectId); + + expect(timeRangeSelect).toBeInTheDocument(); + + expect( + screen.getByRole('combobox', { name: 'Select Time Duration' }) + ).toHaveAttribute('value', 'Last 30 Minutes'); + }); +}); From 88c8c900f79e86304301edb576dba472b2c32f0e Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Thu, 26 Sep 2024 14:22:50 +0530 Subject: [PATCH 086/474] upcoming: [DI-20360] - Updated eslint issue --- .../src/features/CloudPulse/Overview/GlobalFilters.test.tsx | 1 - .../manager/src/features/CloudPulse/Overview/GlobalFilters.tsx | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.test.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.test.tsx index b752c27a6c8..d2d9e9a2ebc 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.test.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.test.tsx @@ -1,4 +1,3 @@ -import { fireEvent } from '@testing-library/react'; import React from 'react'; import { renderWithTheme } from 'src/utilities/testHelpers'; diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index b19ce3f8555..0cd8b7c95bf 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -113,6 +113,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { sx={{ marginBlockEnd: 'auto', }} + data-testid="global-refresh" disabled={!selectedDashboard} onClick={handleGlobalRefresh} size="small" From 8ae6dbce09db98ee79de63d73968925a3275d3d1 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Thu, 26 Sep 2024 14:30:48 +0530 Subject: [PATCH 087/474] tests: [DI-20585] - PR comments for aria label --- .../linode-widget-verification.spec.ts | 18 ++++++++---------- .../manager/cypress/support/util/cloudpulse.ts | 2 +- .../CloudPulse/Overview/GlobalFilters.tsx | 2 +- .../CloudPulse/Widget/components/Zoomer.tsx | 4 ++-- .../shared/CloudPulseResourcesSelect.tsx | 2 +- 5 files changed, 13 insertions(+), 15 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 20d2da26029..515c066d8c2 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -103,7 +103,7 @@ const mockRegion = extendRegion( country: 'us', }) ); -let responsePayload: CloudPulseMetricsResponse; +const responsePayload: CloudPulseMetricsResponse = createMetricResponse(timeRanges.last24Hours, '5 min'); describe('Dashboard Widget Verification Tests', () => { beforeEach(() => { mockAppendFeatureFlags({ @@ -122,7 +122,6 @@ describe('Dashboard Widget Verification Tests', () => { mockCloudPulseServices(widgetDetails.linode.service_type).as('services'); mockCloudPulseDashboardServicesResponse(dashboard, widgetDetails.linode.id); mockCloudPulseJWSToken(widgetDetails.linode.service_type); - responsePayload = createMetricResponse(timeRanges.last24Hours, '5 min'); mockCloudPulseCreateMetrics( responsePayload, widgetDetails.linode.service_type @@ -292,7 +291,7 @@ describe('Dashboard Widget Verification Tests', () => { setupMethod(); cy.wait(7000); //maintaining the wait since page flicker and rendering ui.button - .findByAttribute('aria-label', 'cloudpulse-refresh') + .findByAttribute('aria-label', 'Refresh Dashboard Metrics') .should('be.visible') .click(); cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']).then( @@ -310,11 +309,10 @@ describe('Dashboard Widget Verification Tests', () => { ); } const expectedRelativeTimeDuration = timeRange - ? `Last ${timeRange.value} ${ - ['hour', 'hr'].includes(timeRange.unit.toLowerCase()) - ? 'Hours' - : timeRange.unit - }` + ? `Last ${timeRange.value} ${['hour', 'hr'].includes(timeRange.unit.toLowerCase()) + ? 'Hours' + : timeRange.unit + }` : ''; expect(metric).to.equal(metricData.name); expect(expectedRelativeTimeDuration).to.equal(timeRanges.last24Hours); @@ -332,7 +330,7 @@ describe('Dashboard Widget Verification Tests', () => { .should('be.visible') .within(() => { ui.button - .findByAttribute('aria-label', 'zoom-in') + .findByAttribute('aria-label', 'Zoom In') .should('be.visible') .should('be.enabled') .click(); @@ -360,7 +358,7 @@ describe('Dashboard Widget Verification Tests', () => { ); }); ui.button - .findByAttribute('aria-label', 'zoom-out') + .findByAttribute('aria-label', 'Zoom Out') .should('be.visible') .should('be.enabled') .scrollIntoView() diff --git a/packages/manager/cypress/support/util/cloudpulse.ts b/packages/manager/cypress/support/util/cloudpulse.ts index 14440af7b63..0af462598aa 100644 --- a/packages/manager/cypress/support/util/cloudpulse.ts +++ b/packages/manager/cypress/support/util/cloudpulse.ts @@ -57,7 +57,7 @@ export const selectTimeRange = (timeRange: string, timeSegments: string[]) => { * @param {string} service - The name of the service to select. */ export const selectAndVerifyResource = (service: string) => { - const resourceInput = ui.autocomplete.findByTitleCustom('Select a Resources'); + const resourceInput = ui.autocomplete.findByTitleCustom('Select a Resource'); resourceInput.findByTitle('Open').click(); resourceInput.click().type(`${service}{enter}`); cy.get('[title="Close"]').click(); diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index 0decb47dd9a..de286855873 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -98,7 +98,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { sx={{ marginBlockEnd: 'auto', }} - aria-label='cloudpulse-refresh' + aria-label="Refresh Dashboard Metrics" disabled={!selectedDashboard} onClick={() => handleGlobalRefresh(selectedDashboard)} size="small" diff --git a/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx b/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx index e450726d5e3..8ee05b40c6b 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx @@ -27,7 +27,7 @@ export const ZoomIcon = React.memo((props: ZoomIconProperties) => { height: '34px', padding:0, }} - aria-label="zoom-in" + aria-label="Zoom In" data-testid="zoom-in" onClick={() => handleClick(false)} > @@ -45,7 +45,7 @@ export const ZoomIcon = React.memo((props: ZoomIconProperties) => { minWidth: 'auto', padding: 0, }} - aria-label="zoom-out" + aria-label="Zoom Out" data-testid="zoom-out" onClick={() => handleClick(true)} > diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index bd95fb07869..590f1b70dac 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -110,7 +110,7 @@ export const CloudPulseResourcesSelect = React.memo( data-testid="resource-select" disabled={disabled || isLoading} isOptionEqualToValue={(option, value) => option.id === value.id} - label="Select a Resources" + label="Select a Resource" limitTags={2} multiple options={getResourcesList()} From 29d0d25c0cbe87c4615b521c18b5e81cf271b54c Mon Sep 17 00:00:00 2001 From: agorthi Date: Thu, 26 Sep 2024 15:39:19 +0530 Subject: [PATCH 088/474] upcoming:[DI-20585]- Added code review commennts --- .../cloudpulse/cloudpulse-navigation.spec.ts | 2 +- .../linode-widget-verification.spec.ts | 117 +++++++----------- .../cypress/support/ui/autocomplete.ts | 29 +---- .../cypress/support/util/cloudpulse.ts | 69 +++-------- packages/manager/src/factories/widget.ts | 2 +- 5 files changed, 69 insertions(+), 150 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts index 6c8f0e07f06..8196496aca3 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts @@ -55,7 +55,7 @@ describe('CloudPulse navigation', () => { /* * - Confirms that manual navigation to Cloudpulse landing page with feature is disabled displays Not Found to user. */ - it('displays Not Found when manually navigating to /placement-groups with feature flag disabled', () => { + it('displays Not Found when manually navigating to /cloudpulse with feature flag disabled', () => { mockAppendFeatureFlags({ aclp: { beta: true, diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 20d2da26029..7edc15cd62d 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -1,9 +1,3 @@ -import { - selectTimeRange, - selectServiceName, - selectAndVerifyResource, - assertSelections, -} from 'support/util/cloudpulse'; import { mockAppendFeatureFlags } from 'support/intercepts/feature-flags'; import { mockCloudPulseJWSToken, @@ -15,7 +9,7 @@ import { } from 'support/intercepts/cloudpulse'; import { ui } from 'support/ui'; import { widgetDetails } from 'support/constants/widgets'; -import { createMetricResponse } from '@src/factories/widget'; +import { CloudPulseMetricsResponses } from '@src/factories/widget'; import { accountFactory, dashboardFactory, @@ -103,7 +97,10 @@ const mockRegion = extendRegion( country: 'us', }) ); -let responsePayload: CloudPulseMetricsResponse; +const responsePayload = CloudPulseMetricsResponses( + timeRanges.last24Hours, + '5 min' +); describe('Dashboard Widget Verification Tests', () => { beforeEach(() => { mockAppendFeatureFlags({ @@ -122,16 +119,44 @@ describe('Dashboard Widget Verification Tests', () => { mockCloudPulseServices(widgetDetails.linode.service_type).as('services'); mockCloudPulseDashboardServicesResponse(dashboard, widgetDetails.linode.id); mockCloudPulseJWSToken(widgetDetails.linode.service_type); - responsePayload = createMetricResponse(timeRanges.last24Hours, '5 min'); mockCloudPulseCreateMetrics( responsePayload, widgetDetails.linode.service_type ).as('getMetrics'); mockGetRegions([mockRegion]).as('getRegions'); - }); + mockGetUserPreferences({}).as('getUserPreferences'); + cy.visitWithLogin('monitor/cloudpulse').as('cloudPulsePage'); + cy.get('@cloudPulsePage'); + + // Selecting a dashboard from the autocomplete input. + ui.autocomplete + .findByLabel('Select a Dashboard') + .should('be.visible') + .type(`${widgetDetails.linode.dashboardName}{enter}`) + .should('have.value', widgetDetails.linode.dashboardName); + + // Select a time duration from the autocomplete input. + ui.autocomplete + .findByLabel('Select a Time Duration') + .should('be.visible') + .type(`${timeRanges.last24Hours}{enter}`) + .should('have.value', timeRanges.last24Hours); + + // Select a region from the dropdown. + ui.regionSelect + .find() + .click() + .type(`${widgetDetails.linode.region}{enter}`); - it('should verify the title of the widget', () => { - setupMethod(); + // Select a resource from the autocomplete input. + ui.autocomplete + .findByLabel('Select a Resources') + .should('be.visible') + .type(`${widgetDetails.linode.resource}{enter}`) + .click(); + cy.findByText(widgetDetails.linode.resource).should('be.visible'); + + // Verify that the titles of the widgets are displayed correctly, including the unit. metrics.forEach((testData) => { const widgetSelector = `[data-qa-widget-header="${testData.title}"]`; cy.get(widgetSelector) @@ -143,8 +168,8 @@ describe('Dashboard Widget Verification Tests', () => { }); }); }); + it('should verify available granularity of the widget', () => { - setupMethod(); metrics.forEach((testData) => { cy.wait(7000); //maintaining the wait since page flicker and rendering const widgetSelector = `[data-qa-widget="${testData.title}"]`; @@ -153,25 +178,14 @@ describe('Dashboard Widget Verification Tests', () => { .scrollIntoView() .should('be.visible') .within(() => { - ui.autocomplete - .findByTitleCustom('Select an Interval') - .findByTitle('Open') - .click(); + ui.autocomplete.findByLabel('Select an Interval').click(); expectedGranularityArray.forEach((option) => { ui.autocompletePopper.findByTitle(option).should('exist'); }); - ui.autocomplete - .findByTitleCustom('Select an Interval') - .should('be.visible') - .findByTitle('Close') - .should('be.visible') - .click(); }); }); }); - it('should verify available aggregation of the widget', () => { - setupMethod(); metrics.forEach((testData) => { cy.wait(7000); //maintaining the wait since page flicker and rendering const widgetSelector = `[data-qa-widget="${testData.title}"]`; @@ -180,24 +194,14 @@ describe('Dashboard Widget Verification Tests', () => { .scrollIntoView() .should('be.visible') .within(() => { - ui.autocomplete - .findByTitleCustom('Select an Aggregate Function') - .findByTitle('Open') - .click(); + ui.autocomplete.findByLabel('Select an Aggregate Function').click(); testData.expectedAggregationArray.forEach((option) => { ui.autocompletePopper.findByTitle(option).should('exist'); }); - ui.autocomplete - .findByTitleCustom('Select an Aggregate Function') - .should('be.visible') - .findByTitle('Close') - .should('be.visible') - .click(); }); }); }); it('should set available granularity of all the widgets', () => { - setupMethod(); metrics.forEach((testData) => { cy.wait(7000); //maintaining the wait since page flicker and rendering const widgetSelector = `[data-qa-widget="${testData.title}"]`; @@ -207,12 +211,9 @@ describe('Dashboard Widget Verification Tests', () => { .first() .within(() => { ui.autocomplete - .findByTitleCustom('Select an Interval') + .findByLabel('Select an Interval') .should('be.visible') - .findByTitle('Open') - .click() .type(`${testData.expectedGranularity}{enter}`); - cy.findByDisplayValue(testData.expectedGranularity).should('exist'); cy.findByTestId('linegraph-wrapper') .as('canvas') .should('be.visible') @@ -237,13 +238,11 @@ describe('Dashboard Widget Verification Tests', () => { widgetValues, testData.title ); - assertSelections(testData.expectedGranularity); }); }); }); }); it('should set available aggregation of all the widgets', () => { - setupMethod(); metrics.forEach((testData) => { cy.wait(7000); //maintaining the wait since page flicker and rendering const widgetSelector = `[data-qa-widget="${testData.title}"]`; @@ -252,12 +251,9 @@ describe('Dashboard Widget Verification Tests', () => { .should('be.visible') .within(() => { ui.autocomplete - .findByTitleCustom('Select an Aggregate Function') + .findByLabel('Select an Aggregate Function') .should('be.visible') - .findByTitle('Open') - .click() .type(`${testData.expectedAggregation}{enter}`); - cy.findByDisplayValue(testData.expectedAggregation).should('exist'); cy.findByTestId('linegraph-wrapper') .as('canvas') .should('be.visible') @@ -282,14 +278,12 @@ describe('Dashboard Widget Verification Tests', () => { widgetValues, testData.title ); - assertSelections(testData.expectedAggregation); }); }); }); }); it('should apply global refresh button and verify network calls', () => { - setupMethod(); cy.wait(7000); //maintaining the wait since page flicker and rendering ui.button .findByAttribute('aria-label', 'cloudpulse-refresh') @@ -324,7 +318,6 @@ describe('Dashboard Widget Verification Tests', () => { }); it('should zoom in and out of all the widgets', () => { - setupMethod(); metrics.forEach((testData) => { cy.wait(7000); //maintaining the wait since page flicker and rendering cy.get(`[data-qa-widget="${testData.title}"]`).as('widget'); @@ -392,32 +385,6 @@ describe('Dashboard Widget Verification Tests', () => { }); }); }); -/** - * `setupMethod` initializes the Cloud Pulse dashboard for testing by performing a series of setup actions. - * This method mocks user preferences, navigates to the Cloud Pulse page, and configures various settings - * including service name, time range, engine, region, resource, and node type. It also verifies each selection - * to ensure the dashboard is correctly configured before running further tests. - * - * Steps: - * 1. Mock user preferences to ensure a consistent test environment. - * 2. Navigate to the Cloud Pulse page and verify that it has loaded correctly. - * 3. Select and verify the service name. - * 4. Set and verify the time range for the dashboard. - * 5. Select and verify the region. - * 6. Choose and verify the resource from available widgets. - */ - -const setupMethod = () => { - mockGetUserPreferences({}).as('getUserPreferences'); - cy.visitWithLogin('monitor/cloudpulse'); - selectServiceName(widgetDetails.linode.dashboardName); - assertSelections(widgetDetails.linode.dashboardName); - selectTimeRange(timeRanges.last24Hours, Object.values(timeRanges)); - assertSelections(timeRanges.last24Hours); - ui.regionSelect.find().click().type(`${widgetDetails.linode.region}{enter}`); - assertSelections(widgetDetails.linode.region); - selectAndVerifyResource(widgetDetails.linode.resource); -}; /** * `verifyWidgetValues` processes and verifies the metric values of a widget from the provided response payload. * diff --git a/packages/manager/cypress/support/ui/autocomplete.ts b/packages/manager/cypress/support/ui/autocomplete.ts index b6567d7d798..ff7f4a318d2 100644 --- a/packages/manager/cypress/support/ui/autocomplete.ts +++ b/packages/manager/cypress/support/ui/autocomplete.ts @@ -30,33 +30,16 @@ export const autocomplete = { find: (): Cypress.Chainable => { return cy.get('[data-qa-autocomplete] input'); }, - /** - * Finds an autocomplete input element by its placeholder text. - * This method is useful for locating input fields within autocomplete components - * when the placeholder text is known. - * - * @param {string} title - The placeholder text of the input element. - * @param {SelectorMatcherOptions} [options] - Optional additional options for selecting elements. - * @returns {Cypress.Chainable} - A Cypress chainable object that represents the located element. - */ - findByPlaceholderCustom: ( - title: string, - options?: SelectorMatcherOptions - ): Cypress.Chainable => { - return cy.get("[data-qa-autocomplete] input[placeholder='" + title + "']"); - }, /** - * Finds an autocomplete element by its title attribute. - * This method is used to locate elements with a specific title attribute within - * autocomplete components, useful for when you need to interact with elements - * identified by their title. + * Finds an autocomplete element by its label. + * + * @param label - Label of the autocomplete to select. * - * @param {string} title - The value of the title attribute for the autocomplete element. - * @returns {Cypress.Chainable} - A Cypress chainable object that represents the located element. + * @returns A Cypress chainable object that represents the located element. */ - findByTitleCustom: (title: string): Cypress.Chainable => { - return cy.get('[data-qa-autocomplete="' + title + '"]'); + findByLabel: (label: string): Cypress.Chainable => { + return cy.get(`[data-qa-autocomplete="${label}"] input`); }, }; diff --git a/packages/manager/cypress/support/util/cloudpulse.ts b/packages/manager/cypress/support/util/cloudpulse.ts index 14440af7b63..348933bbc53 100644 --- a/packages/manager/cypress/support/util/cloudpulse.ts +++ b/packages/manager/cypress/support/util/cloudpulse.ts @@ -25,14 +25,10 @@ import { ui } from 'support/ui'; export const selectServiceName = (serviceName: string) => { ui.autocomplete - .findByTitleCustom('Select a Dashboard') - .findByTitle('Open') + .findByLabel('Select a Dashboard') .should('be.visible') - .click(); - ui.autocomplete - .findByPlaceholderCustom('Select a Dashboard') - .type(`${serviceName}{enter}`); - cy.findByDisplayValue(serviceName).should('have.value', serviceName); + .type(`${serviceName}{enter}`) + .should('have.value', serviceName); }; /** @@ -41,49 +37,25 @@ export const selectServiceName = (serviceName: string) => { * @param {Array} timeSegments - An array of time segment values (e.g., ["2024-01-01", "2024-01-02"]). */ -export const selectTimeRange = (timeRange: string, timeSegments: string[]) => { +export const selectTimeRange = (timeRange: string) => { ui.autocomplete - .findByTitleCustom('Select a Time Duration') - .findByTitle('Open') - .click(); - timeSegments.forEach((option) => { - ui.autocompletePopper.findByTitle(option).should('be.visible'); - }); - ui.autocompletePopper.findByTitle(timeRange).should('be.visible').click(); - cy.findByDisplayValue(timeRange).should('have.value', timeRange); + .findByLabel('Select a Time Duration') + .should('be.visible') + .type(`${timeRange}{enter}`) + .should('have.value', timeRange); }; /** * Selects a resource name from the resources dropdown and verifies the selection. * @param {string} service - The name of the service to select. */ export const selectAndVerifyResource = (service: string) => { - const resourceInput = ui.autocomplete.findByTitleCustom('Select a Resources'); - resourceInput.findByTitle('Open').click(); - resourceInput.click().type(`${service}{enter}`); + ui.autocomplete + .findByLabel('Select a Resources') + .should('be.visible') + .type(`${service}{enter}`); cy.get('[title="Close"]').click(); }; -/** - * Asserts that the selected options match the expected values. - * @param {string} expectedOptions - The expected options to verify. - */ -export const assertSelections = (expectedOptions: string) => { - cy.get(`[value*='${expectedOptions}']`).should('be.visible'); - cy.get(`[value*='${expectedOptions}']`).should('have.value', expectedOptions); -}; -/** - * Clears the dashboard's preferences and verifies the zeroth page. - */ -export const resetDashboard = () => { - ui.autocomplete - .findByTitleCustom('Select a Dashboard') - .findByTitle('Clear') - .click(); - - ui.autocomplete - .findByPlaceholderCustom('Select a Dashboard') - .should('have.value', ''); -}; /** * Selects an engine from a dropdown menu. * @@ -91,11 +63,10 @@ export const resetDashboard = () => { */ export const chooseEngine = (engine: string) => { ui.autocomplete - .findByTitleCustom('Select an Engine') - .findByTitle('Open') - .click(); - ui.autocompletePopper.findByTitle(engine).should('be.visible').click(); - cy.findByDisplayValue(engine).should('have.value', engine); + .findByLabel('Select an Engine') + .should('be.visible') + .type(`${engine}{enter}`) + .should('have.value', engine); }; /** * Selects a node type from a dropdown menu. @@ -105,10 +76,8 @@ export const chooseEngine = (engine: string) => { export const chooseNodeType = (node: string) => { ui.autocomplete - .findByPlaceholderCustom('Select a Node Type') + .findByLabel('Select a Node Type') .should('be.visible') - .type(node) - .click(); - ui.autocompletePopper.findByTitle(node).should('be.visible').click(); - cy.findByDisplayValue(node).should('have.value', node); + .type(`${node}{enter}`) + .should('have.value', node); }; diff --git a/packages/manager/src/factories/widget.ts b/packages/manager/src/factories/widget.ts index 65ba26c0381..8a299144955 100644 --- a/packages/manager/src/factories/widget.ts +++ b/packages/manager/src/factories/widget.ts @@ -13,7 +13,7 @@ import type { CloudPulseMetricsResponse } from '@linode/api-v4'; * @param {string} granularityData - The granularity of the metric data (e.g., "Min5"). * @returns {CloudPulseMetricsResponse} - The generated mock metric response. */ -export const createMetricResponse = ( +export const CloudPulseMetricsResponses = ( time: string, granularityData: string ): CloudPulseMetricsResponse => { From cc2010f55af80a0f8f8fbf11e960fa6649c329bd Mon Sep 17 00:00:00 2001 From: agorthi Date: Thu, 26 Sep 2024 16:23:57 +0530 Subject: [PATCH 089/474] upcoming:[DI-20585]- Added code review commennts --- .../linode-widget-verification.spec.ts | 141 +++++++++++------- .../cypress/support/util/cloudpulse.ts | 83 ----------- 2 files changed, 85 insertions(+), 139 deletions(-) delete mode 100644 packages/manager/cypress/support/util/cloudpulse.ts diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 234d18d6cf9..ad923f0e63a 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -133,14 +133,14 @@ describe('Dashboard Widget Verification Tests', () => { .findByLabel('Select a Dashboard') .should('be.visible') .type(`${widgetDetails.linode.dashboardName}{enter}`) - .should('have.value', widgetDetails.linode.dashboardName); + .should('be.visible'); // Select a time duration from the autocomplete input. ui.autocomplete .findByLabel('Select a Time Duration') .should('be.visible') .type(`${timeRanges.last24Hours}{enter}`) - .should('have.value', timeRanges.last24Hours); + .should('be.visible'); // Select a region from the dropdown. ui.regionSelect @@ -150,7 +150,7 @@ describe('Dashboard Widget Verification Tests', () => { // Select a resource from the autocomplete input. ui.autocomplete - .findByLabel('Select a Resources') + .findByLabel('Select a Resource') .should('be.visible') .type(`${widgetDetails.linode.resource}{enter}`) .click(); @@ -169,56 +169,47 @@ describe('Dashboard Widget Verification Tests', () => { }); }); - it('should verify available granularity of the widget', () => { - metrics.forEach((testData) => { + it('should allow users to select their desired granularity and see the most recent data from the API reflected in the graph', () => { + // validate the widget level granularity selection and its metrics + for (const testData of metrics) { cy.wait(7000); //maintaining the wait since page flicker and rendering const widgetSelector = `[data-qa-widget="${testData.title}"]`; + cy.get(widgetSelector) - .first() - .scrollIntoView() .should('be.visible') - .within(() => { - ui.autocomplete.findByLabel('Select an Interval').click(); - expectedGranularityArray.forEach((option) => { - ui.autocompletePopper.findByTitle(option).should('exist'); - }); - }); - }); - }); - it('should verify available aggregation of the widget', () => { - metrics.forEach((testData) => { - cy.wait(7000); //maintaining the wait since page flicker and rendering - const widgetSelector = `[data-qa-widget="${testData.title}"]`; - cy.get(widgetSelector) .first() - .scrollIntoView() - .should('be.visible') .within(() => { - ui.autocomplete.findByLabel('Select an Aggregate Function').click(); - testData.expectedAggregationArray.forEach((option) => { + // check for all available granularity in popper + ui.autocomplete + .findByLabel('Select an Interval') + .should('be.visible') + .click(); + + expectedGranularityArray.forEach((option) => { ui.autocompletePopper.findByTitle(option).should('exist'); }); - }); - }); - }); - it('should set available granularity of all the widgets', () => { - metrics.forEach((testData) => { - cy.wait(7000); //maintaining the wait since page flicker and rendering - const widgetSelector = `[data-qa-widget="${testData.title}"]`; - cy.get(widgetSelector).as('widget'); - cy.get('@widget') - .should('be.visible') - .first() - .within(() => { + + //find the interval component and select the expected granularity ui.autocomplete .findByLabel('Select an Interval') .should('be.visible') - .type(`${testData.expectedGranularity}{enter}`); + .type(`${testData.expectedGranularity}{enter}`); //type expected granularity + + //check if the API call is made correctly with time granularity value selected + cy.wait('@getMetrics').then((interception) => { + expect(interception) + .to.have.property('response') + .with.property('statusCode', 200); + expect(testData.expectedGranularity).to.include( + interception.request.body.time_granularity.value + ); + }); + + //validate the widget linegrah is present cy.findByTestId('linegraph-wrapper') - .as('canvas') .should('be.visible') .find('tbody tr') - .each(($tr, index) => { + .each(($tr) => { const cells = $tr .find('td') .map((i, el) => { @@ -226,9 +217,12 @@ describe('Dashboard Widget Verification Tests', () => { return text.replace(/^\s*\([^)]+\)/, ''); }) .get(); - const [title, actualMax, actualAvg, actualLast] = cells; - const widgetValues = verifyWidgetValues(responsePayload); + const [title, actualMax, actualAvg, actualLast] = cells; // the average, max and last present in the widget + const widgetValues = getWidgetLegendRowValuesFromResponse( + responsePayload + ); // the average, max and last from the response payload compareWidgetValues( + // compare both { title, max: parseFloat(actualMax), @@ -240,25 +234,45 @@ describe('Dashboard Widget Verification Tests', () => { ); }); }); - }); + } }); - it('should set available aggregation of all the widgets', () => { - metrics.forEach((testData) => { + + it('should allow users to select the desired aggregation and view the latest data from the API displayed in the graph', () => { + for (const testData of metrics) { cy.wait(7000); //maintaining the wait since page flicker and rendering const widgetSelector = `[data-qa-widget="${testData.title}"]`; + cy.get(widgetSelector) - .first() .should('be.visible') + .first() .within(() => { + mockCloudPulseCreateMetrics( + responsePayload, + widgetDetails.linode.service_type + ).as('getAggregationMetrics'); + + //find the interval component and select the expected granularity ui.autocomplete .findByLabel('Select an Aggregate Function') .should('be.visible') - .type(`${testData.expectedAggregation}{enter}`); + .type(`${testData.expectedAggregation}{enter}`); //type expected granularity + + //check if the API call is made correctly with time granularity value selected + cy.wait('@getAggregationMetrics').then((interception) => { + expect(interception) + .to.have.property('response') + .with.property('statusCode', 200); + // cy.log(JSON.stringify(interception.request.body)); + expect(testData.expectedAggregation).to.equal( + interception.request.body.aggregate_function + ); + }); + + //validate the widget linegrah is present cy.findByTestId('linegraph-wrapper') - .as('canvas') .should('be.visible') .find('tbody tr') - .each(($tr, index) => { + .each(($tr) => { const cells = $tr .find('td') .map((i, el) => { @@ -266,9 +280,12 @@ describe('Dashboard Widget Verification Tests', () => { return text.replace(/^\s*\([^)]+\)/, ''); }) .get(); - const [title, actualMax, actualAvg, actualLast] = cells; - const widgetValues = verifyWidgetValues(responsePayload); + const [title, actualMax, actualAvg, actualLast] = cells; // the average, max and last present in the widget + const widgetValues = getWidgetLegendRowValuesFromResponse( + responsePayload + ); // the average, max and last from the response payload compareWidgetValues( + // compare both { title, max: parseFloat(actualMax), @@ -280,15 +297,18 @@ describe('Dashboard Widget Verification Tests', () => { ); }); }); - }); + } }); - - it('should apply global refresh button and verify network calls', () => { + it('should trigger the global refresh button and verify the corresponding network calls', () => { cy.wait(7000); //maintaining the wait since page flicker and rendering + + // click the global refresh button ui.button .findByAttribute('aria-label', 'Refresh Dashboard Metrics') .should('be.visible') .click(); + + // validate the API calls are going with intended payload cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']).then( (interceptions) => { const interceptionsArray = Array.isArray(interceptions) @@ -318,6 +338,7 @@ describe('Dashboard Widget Verification Tests', () => { }); it('should zoom in and out of all the widgets', () => { + // do zoom in and zoom out test on all the widgets metrics.forEach((testData) => { cy.wait(7000); //maintaining the wait since page flicker and rendering cy.get(`[data-qa-widget="${testData.title}"]`).as('widget'); @@ -340,7 +361,9 @@ describe('Dashboard Widget Verification Tests', () => { .map((i, el) => Cypress.$(el).text().trim()) .get(); const [title, actualMax, actualAvg, actualLast] = cells; - const widgetValues = verifyWidgetValues(responsePayload); + const widgetValues = getWidgetLegendRowValuesFromResponse( + responsePayload + ); compareWidgetValues( { title, @@ -352,6 +375,8 @@ describe('Dashboard Widget Verification Tests', () => { testData.title ); }); + + // click zoom out and validate the same ui.button .findByAttribute('aria-label', 'Zoom Out') .should('be.visible') @@ -369,7 +394,9 @@ describe('Dashboard Widget Verification Tests', () => { .map((i, el) => Cypress.$(el).text().trim()) .get(); const [title, actualMax, actualAvg, actualLast] = cells; - const widgetValues = verifyWidgetValues(responsePayload); + const widgetValues = getWidgetLegendRowValuesFromResponse( + responsePayload + ); compareWidgetValues( { title, @@ -397,7 +424,9 @@ describe('Dashboard Widget Verification Tests', () => { * @param {CloudPulseMetricsResponse} responsePayload - The response payload containing metric data for a widget. * @returns {Object} An object with the rounded average, last, and max metric values. */ -const verifyWidgetValues = (responsePayload: CloudPulseMetricsResponse) => { +const getWidgetLegendRowValuesFromResponse = ( + responsePayload: CloudPulseMetricsResponse +) => { const data = transformData(responsePayload.data.result[0].values, 'Bytes'); const { average, last, max } = getMetrics(data); const roundedAverage = Math.round(average * 100) / 100; diff --git a/packages/manager/cypress/support/util/cloudpulse.ts b/packages/manager/cypress/support/util/cloudpulse.ts deleted file mode 100644 index 348933bbc53..00000000000 --- a/packages/manager/cypress/support/util/cloudpulse.ts +++ /dev/null @@ -1,83 +0,0 @@ -/* eslint-disable sonarjs/no-all-duplicated-branches */ -/** - * This class provides utility functions for interacting with the Cloudpulse dashboard - * in a Cypress test suite. It includes methods for: - * - Navigating to the Cloudpulse page - * - Selecting and verifying dashboard options (service names, regions, time ranges) - * - Managing feature flags - * - Setting and validating widget configurations (granularity, aggregation) - * - Performing actions like zooming in and out on widgets - * These utilities ensure efficient and consistent test execution and validation. - */ - -/** - * Selects a service name from the dashboard dropdown. - * @param {string} serviceName - The name of the service to select. - */ -import { ui } from 'support/ui'; - -/** - * Waits for the element matching the given CSS selector to appear and become visible. - * - * @param {string} selector - The CSS selector for the element to wait for. - */ -// command to wait for the element to be fully loaded - -export const selectServiceName = (serviceName: string) => { - ui.autocomplete - .findByLabel('Select a Dashboard') - .should('be.visible') - .type(`${serviceName}{enter}`) - .should('have.value', serviceName); -}; - -/** - * Selects a time range from the time range dropdown. - * @param {string} timeRange - The time range to select. - * @param {Array} timeSegments - An array of time segment values (e.g., ["2024-01-01", "2024-01-02"]). - - */ -export const selectTimeRange = (timeRange: string) => { - ui.autocomplete - .findByLabel('Select a Time Duration') - .should('be.visible') - .type(`${timeRange}{enter}`) - .should('have.value', timeRange); -}; -/** - * Selects a resource name from the resources dropdown and verifies the selection. - * @param {string} service - The name of the service to select. - */ -export const selectAndVerifyResource = (service: string) => { - ui.autocomplete - .findByLabel('Select a Resources') - .should('be.visible') - .type(`${service}{enter}`); - cy.get('[title="Close"]').click(); -}; - -/** - * Selects an engine from a dropdown menu. - * - * @param {string} engine - The engine to be selected. - */ -export const chooseEngine = (engine: string) => { - ui.autocomplete - .findByLabel('Select an Engine') - .should('be.visible') - .type(`${engine}{enter}`) - .should('have.value', engine); -}; -/** - * Selects a node type from a dropdown menu. - * - * @param {string} node - The node type to be selected. - */ - -export const chooseNodeType = (node: string) => { - ui.autocomplete - .findByLabel('Select a Node Type') - .should('be.visible') - .type(`${node}{enter}`) - .should('have.value', node); -}; From 1af0beadfc053ff9be6980374ffddc9386266272 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Thu, 26 Sep 2024 17:28:46 +0530 Subject: [PATCH 090/474] tests: [DI-20585] - Code clean ups and refactoring --- .../linode-widget-verification.spec.ts | 154 ++++++++---------- .../cypress/support/constants/widgets.ts | 8 + packages/manager/src/factories/widget.ts | 2 +- 3 files changed, 81 insertions(+), 83 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index ad923f0e63a..bedf3de068f 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -9,7 +9,7 @@ import { } from 'support/intercepts/cloudpulse'; import { ui } from 'support/ui'; import { widgetDetails } from 'support/constants/widgets'; -import { CloudPulseMetricsResponses } from '@src/factories/widget'; +import { cloudPulseMetricsResponses } from 'src/factories/widget'; import { accountFactory, dashboardFactory, @@ -27,20 +27,9 @@ import { extendRegion } from 'support/util/regions'; import { CloudPulseMetricsResponse } from '@linode/api-v4'; import { transformData } from 'src/features/CloudPulse/Utils/unitConversion'; import { getMetrics } from 'src/utilities/statMetrics'; -const timeRanges = { - last7Days: 'Last 7 Days', - last12Hours: 'Last 12 Hours', - last24Hours: 'Last 24 Hours', - last30Days: 'Last 30 Days', - last30Minutes: 'Last 30 Minutes', -}; -const y_labels = [ - 'system_cpu_utilization_ratio', - 'system_memory_usage_bytes', - 'system_network_io_bytes_total', - 'system_disk_operations_total', -]; + const expectedGranularityArray = ['Auto', '1 day', '1 hr', '5 min']; +const timeDurationToSelect = 'Last 24 Hours'; /** * This test ensures that widget titles are displayed correctly on the dashboard. @@ -53,41 +42,38 @@ const expectedGranularityArray = ['Auto', '1 day', '1 hr', '5 min']; * Each test ensures that widgets on the dashboard operate correctly and display accurate information. */ -const metrics = widgetDetails.linode.metrics; -const widgetLabels: string[] = metrics.map((widget) => widget.title); -const metricsLabels: string[] = metrics.map((widget) => widget.name); -const unit: string[] = metrics.map((widget) => widget.unit); +const { metrics, id, service_type, dashboardName, region, resource } = widgetDetails.linode + const dashboard = dashboardFactory.build({ - label: widgetDetails.linode.dashboardName, - service_type: widgetDetails.linode.service_type, - widgets: [ - ...widgetLabels.map((label: string, index: number) => - widgetFactory.build({ - label, - y_label: y_labels[index], - metric: metricsLabels[index], - unit: unit[index], + label: dashboardName, + service_type, + widgets: + metrics.map(({ title, yLabel, name, unit }) => { + return widgetFactory.build({ + label: title, + y_label: yLabel, + metric: name, + unit }) - ), - ], + }) }); const metricDefinitions = { - data: [ - ...widgetLabels.map((label, index) => + data: + metrics.map(({ title, name, unit }) => dashboardMetricFactory.build({ - label, - metric: metricsLabels[index], - unit: unit[index], + label: title, + metric: name, + unit, }) ), - ], }; -const mockKubeLinode = kubeLinodeFactory.build(); + const mockLinode = linodeFactory.build({ - label: widgetDetails.linode.resource, - id: mockKubeLinode.instance_id ?? undefined, + label: resource, + id: kubeLinodeFactory.build().instance_id ?? undefined, }); + const mockAccount = accountFactory.build(); const mockRegion = extendRegion( regionFactory.build({ @@ -97,34 +83,37 @@ const mockRegion = extendRegion( country: 'us', }) ); -const responsePayload = CloudPulseMetricsResponses( - timeRanges.last24Hours, +const metricsAPIResponsePayload = cloudPulseMetricsResponses( + timeDurationToSelect, '5 min' ); + describe('Dashboard Widget Verification Tests', () => { beforeEach(() => { mockAppendFeatureFlags({ aclp: { beta: true, enabled: true }, - }).as('getFeatureFlags'); - mockGetAccount(mockAccount).as('getAccount'); // Enables the account to have capability for Akamai Cloud Pulse - mockGetLinodes([mockLinode]).as('getLinodes'); + }); + mockGetAccount(mockAccount); // Enables the account to have capability for Akamai Cloud Pulse + mockGetLinodes([mockLinode]); mockCloudPulseGetMetricDefinitions( metricDefinitions, - widgetDetails.linode.service_type + service_type ); mockCloudPulseGetDashboards( dashboard, - widgetDetails.linode.service_type - ).as('dashboard'); - mockCloudPulseServices(widgetDetails.linode.service_type).as('services'); - mockCloudPulseDashboardServicesResponse(dashboard, widgetDetails.linode.id); - mockCloudPulseJWSToken(widgetDetails.linode.service_type); + service_type + ); + mockCloudPulseServices(service_type); + mockCloudPulseDashboardServicesResponse(dashboard, id); + mockCloudPulseJWSToken(service_type); mockCloudPulseCreateMetrics( - responsePayload, - widgetDetails.linode.service_type + metricsAPIResponsePayload, + service_type ).as('getMetrics'); - mockGetRegions([mockRegion]).as('getRegions'); - mockGetUserPreferences({}).as('getUserPreferences'); + mockGetRegions([mockRegion]); + mockGetUserPreferences({}); + + // navigate to the cloudpulse page cy.visitWithLogin('monitor/cloudpulse').as('cloudPulsePage'); cy.get('@cloudPulsePage'); @@ -132,29 +121,30 @@ describe('Dashboard Widget Verification Tests', () => { ui.autocomplete .findByLabel('Select a Dashboard') .should('be.visible') - .type(`${widgetDetails.linode.dashboardName}{enter}`) + .type(`${dashboardName}{enter}`) .should('be.visible'); // Select a time duration from the autocomplete input. ui.autocomplete .findByLabel('Select a Time Duration') .should('be.visible') - .type(`${timeRanges.last24Hours}{enter}`) + .type(`${timeDurationToSelect}{enter}`) .should('be.visible'); // Select a region from the dropdown. ui.regionSelect .find() .click() - .type(`${widgetDetails.linode.region}{enter}`); + .type(`${region}{enter}`); // Select a resource from the autocomplete input. ui.autocomplete .findByLabel('Select a Resource') .should('be.visible') - .type(`${widgetDetails.linode.resource}{enter}`) + .type(`${resource}{enter}`) .click(); - cy.findByText(widgetDetails.linode.resource).should('be.visible'); + + cy.findByText(resource).should('be.visible'); // Verify that the titles of the widgets are displayed correctly, including the unit. metrics.forEach((testData) => { @@ -169,14 +159,13 @@ describe('Dashboard Widget Verification Tests', () => { }); }); - it('should allow users to select their desired granularity and see the most recent data from the API reflected in the graph', () => { + it('should allow users to select desired granularity and see the most recent data from the API reflected in the graph', () => { // validate the widget level granularity selection and its metrics for (const testData of metrics) { cy.wait(7000); //maintaining the wait since page flicker and rendering const widgetSelector = `[data-qa-widget="${testData.title}"]`; cy.get(widgetSelector) - .should('be.visible') .first() .within(() => { // check for all available granularity in popper @@ -193,9 +182,9 @@ describe('Dashboard Widget Verification Tests', () => { ui.autocomplete .findByLabel('Select an Interval') .should('be.visible') - .type(`${testData.expectedGranularity}{enter}`); //type expected granularity + .type(`${testData.expectedGranularity}{enter}`); - //check if the API call is made correctly with time granularity value selected + //check if the API call is made correctly with the selected time granularity value cy.wait('@getMetrics').then((interception) => { expect(interception) .to.have.property('response') @@ -205,7 +194,7 @@ describe('Dashboard Widget Verification Tests', () => { ); }); - //validate the widget linegrah is present + //validate the widget line graph is present and its legend rows cy.findByTestId('linegraph-wrapper') .should('be.visible') .find('tbody tr') @@ -219,7 +208,7 @@ describe('Dashboard Widget Verification Tests', () => { .get(); const [title, actualMax, actualAvg, actualLast] = cells; // the average, max and last present in the widget const widgetValues = getWidgetLegendRowValuesFromResponse( - responsePayload + metricsAPIResponsePayload ); // the average, max and last from the response payload compareWidgetValues( // compare both @@ -237,38 +226,36 @@ describe('Dashboard Widget Verification Tests', () => { } }); - it('should allow users to select the desired aggregation and view the latest data from the API displayed in the graph', () => { + it('should allow users to select the desired aggregation and see the most recent data from the API displayed in the graph', () => { for (const testData of metrics) { cy.wait(7000); //maintaining the wait since page flicker and rendering const widgetSelector = `[data-qa-widget="${testData.title}"]`; cy.get(widgetSelector) - .should('be.visible') .first() .within(() => { mockCloudPulseCreateMetrics( - responsePayload, - widgetDetails.linode.service_type + metricsAPIResponsePayload, + service_type ).as('getAggregationMetrics'); //find the interval component and select the expected granularity ui.autocomplete .findByLabel('Select an Aggregate Function') .should('be.visible') - .type(`${testData.expectedAggregation}{enter}`); //type expected granularity + .type(`${testData.expectedAggregation}{enter}`); //check if the API call is made correctly with time granularity value selected cy.wait('@getAggregationMetrics').then((interception) => { expect(interception) .to.have.property('response') .with.property('statusCode', 200); - // cy.log(JSON.stringify(interception.request.body)); expect(testData.expectedAggregation).to.equal( interception.request.body.aggregate_function ); }); - //validate the widget linegrah is present + //validate the widget line graph is present and its legend rows cy.findByTestId('linegraph-wrapper') .should('be.visible') .find('tbody tr') @@ -282,7 +269,7 @@ describe('Dashboard Widget Verification Tests', () => { .get(); const [title, actualMax, actualAvg, actualLast] = cells; // the average, max and last present in the widget const widgetValues = getWidgetLegendRowValuesFromResponse( - responsePayload + metricsAPIResponsePayload ); // the average, max and last from the response payload compareWidgetValues( // compare both @@ -324,14 +311,13 @@ describe('Dashboard Widget Verification Tests', () => { ); } const expectedRelativeTimeDuration = timeRange - ? `Last ${timeRange.value} ${ - ['hour', 'hr'].includes(timeRange.unit.toLowerCase()) - ? 'Hours' - : timeRange.unit - }` + ? `Last ${timeRange.value} ${['hour', 'hr'].includes(timeRange.unit.toLowerCase()) + ? 'Hours' + : timeRange.unit + }` : ''; expect(metric).to.equal(metricData.name); - expect(expectedRelativeTimeDuration).to.equal(timeRanges.last24Hours); + expect(expectedRelativeTimeDuration).to.equal(timeDurationToSelect); }); } ); @@ -345,12 +331,15 @@ describe('Dashboard Widget Verification Tests', () => { cy.get('@widget') .should('be.visible') .within(() => { + + // find and click the zoom in button ui.button .findByAttribute('aria-label', 'Zoom In') .should('be.visible') - .should('be.enabled') .click(); cy.get('@widget').should('be.visible'); + + // validate the widget details cy.findByTestId('linegraph-wrapper') .as('canvas') .should('be.visible') @@ -362,7 +351,7 @@ describe('Dashboard Widget Verification Tests', () => { .get(); const [title, actualMax, actualAvg, actualLast] = cells; const widgetValues = getWidgetLegendRowValuesFromResponse( - responsePayload + metricsAPIResponsePayload ); compareWidgetValues( { @@ -380,10 +369,11 @@ describe('Dashboard Widget Verification Tests', () => { ui.button .findByAttribute('aria-label', 'Zoom Out') .should('be.visible') - .should('be.enabled') .scrollIntoView() .click({ force: true }); cy.get('@widget').should('be.visible'); + + // validate the widget details cy.findByTestId('linegraph-wrapper') .as('canvas') .should('be.visible') @@ -395,7 +385,7 @@ describe('Dashboard Widget Verification Tests', () => { .get(); const [title, actualMax, actualAvg, actualLast] = cells; const widgetValues = getWidgetLegendRowValuesFromResponse( - responsePayload + metricsAPIResponsePayload ); compareWidgetValues( { diff --git a/packages/manager/cypress/support/constants/widgets.ts b/packages/manager/cypress/support/constants/widgets.ts index 19e5c137cbc..e774e939cad 100644 --- a/packages/manager/cypress/support/constants/widgets.ts +++ b/packages/manager/cypress/support/constants/widgets.ts @@ -17,6 +17,7 @@ export const widgetDetails = { name: 'system_disk_OPS_total', title: 'Disk I/O', unit: 'OPS', + yLabel: 'system_disk_operations_total', }, { expectedAggregation: 'max', @@ -25,6 +26,7 @@ export const widgetDetails = { name: 'system_cpu_utilization_percent', title: 'CPU Utilization', unit: '%', + yLabel: 'system_cpu_utilization_ratio', }, { expectedAggregation: 'max', @@ -33,6 +35,7 @@ export const widgetDetails = { name: 'system_memory_usage_by_resource', title: 'Memory Usage', unit: 'Bytes', + yLabel: 'system_memory_usage_bytes', }, { expectedAggregation: 'max', @@ -41,6 +44,7 @@ export const widgetDetails = { name: 'system_network_io_by_resource', title: 'Network Traffic', unit: 'Bytes', + yLabel: 'system_network_io_bytes_total', }, ], nodeType: 'Secondary', @@ -59,6 +63,7 @@ export const widgetDetails = { name: 'system_cpu_utilization_percent', title: 'CPU Utilization', unit: '%', + yLabel: 'system_cpu_utilization_ratio', }, { expectedAggregation: 'max', @@ -67,6 +72,7 @@ export const widgetDetails = { name: 'system_memory_usage_by_resource', title: 'Memory Usage', unit: 'Bytes', + yLabel: 'system_memory_usage_bytes', }, { expectedAggregation: 'max', @@ -75,6 +81,7 @@ export const widgetDetails = { name: 'system_network_io_by_resource', title: 'Network Traffic', unit: 'Bytes', + yLabel: 'system_network_io_bytes_total', }, { expectedAggregation: 'max', @@ -83,6 +90,7 @@ export const widgetDetails = { name: 'system_disk_OPS_total', title: 'Disk I/O', unit: 'OPS', + yLabel: 'system_disk_operations_total', }, ], region: 'US, Chicago, IL (us-ord)', diff --git a/packages/manager/src/factories/widget.ts b/packages/manager/src/factories/widget.ts index 8a299144955..086631d102c 100644 --- a/packages/manager/src/factories/widget.ts +++ b/packages/manager/src/factories/widget.ts @@ -13,7 +13,7 @@ import type { CloudPulseMetricsResponse } from '@linode/api-v4'; * @param {string} granularityData - The granularity of the metric data (e.g., "Min5"). * @returns {CloudPulseMetricsResponse} - The generated mock metric response. */ -export const CloudPulseMetricsResponses = ( +export const cloudPulseMetricsResponses = ( time: string, granularityData: string ): CloudPulseMetricsResponse => { From 58d6ceed18f954023ad77803cb6c26612b0bb096 Mon Sep 17 00:00:00 2001 From: agorthi Date: Thu, 26 Sep 2024 17:50:56 +0530 Subject: [PATCH 091/474] upcoming:[DI-20585]- Added code review commennts --- .../linode-widget-verification.spec.ts | 84 +++++++++---------- 1 file changed, 41 insertions(+), 43 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index bedf3de068f..5b484fcdec9 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -1,3 +1,6 @@ +/** + * @file Integration Tests for CloudPulse Linode Dashboard. + */ import { mockAppendFeatureFlags } from 'support/intercepts/feature-flags'; import { mockCloudPulseJWSToken, @@ -42,31 +45,36 @@ const timeDurationToSelect = 'Last 24 Hours'; * Each test ensures that widgets on the dashboard operate correctly and display accurate information. */ -const { metrics, id, service_type, dashboardName, region, resource } = widgetDetails.linode +const { + metrics, + id, + service_type, + dashboardName, + region, + resource, +} = widgetDetails.linode; const dashboard = dashboardFactory.build({ label: dashboardName, service_type, - widgets: - metrics.map(({ title, yLabel, name, unit }) => { - return widgetFactory.build({ - label: title, - y_label: yLabel, - metric: name, - unit - }) - }) + widgets: metrics.map(({ title, yLabel, name, unit }) => { + return widgetFactory.build({ + label: title, + y_label: yLabel, + metric: name, + unit, + }); + }), }); const metricDefinitions = { - data: - metrics.map(({ title, name, unit }) => - dashboardMetricFactory.build({ - label: title, - metric: name, - unit, - }) - ), + data: metrics.map(({ title, name, unit }) => + dashboardMetricFactory.build({ + label: title, + metric: name, + unit, + }) + ), }; const mockLinode = linodeFactory.build({ @@ -88,28 +96,21 @@ const metricsAPIResponsePayload = cloudPulseMetricsResponses( '5 min' ); -describe('Dashboard Widget Verification Tests', () => { +describe('Integration Tests for Linode Dashboard ', () => { beforeEach(() => { mockAppendFeatureFlags({ aclp: { beta: true, enabled: true }, }); mockGetAccount(mockAccount); // Enables the account to have capability for Akamai Cloud Pulse mockGetLinodes([mockLinode]); - mockCloudPulseGetMetricDefinitions( - metricDefinitions, - service_type - ); - mockCloudPulseGetDashboards( - dashboard, - service_type - ); + mockCloudPulseGetMetricDefinitions(metricDefinitions, service_type); + mockCloudPulseGetDashboards(dashboard, service_type); mockCloudPulseServices(service_type); mockCloudPulseDashboardServicesResponse(dashboard, id); mockCloudPulseJWSToken(service_type); - mockCloudPulseCreateMetrics( - metricsAPIResponsePayload, - service_type - ).as('getMetrics'); + mockCloudPulseCreateMetrics(metricsAPIResponsePayload, service_type).as( + 'getMetrics' + ); mockGetRegions([mockRegion]); mockGetUserPreferences({}); @@ -132,10 +133,7 @@ describe('Dashboard Widget Verification Tests', () => { .should('be.visible'); // Select a region from the dropdown. - ui.regionSelect - .find() - .click() - .type(`${region}{enter}`); + ui.regionSelect.find().click().type(`${region}{enter}`); // Select a resource from the autocomplete input. ui.autocomplete @@ -201,7 +199,7 @@ describe('Dashboard Widget Verification Tests', () => { .each(($tr) => { const cells = $tr .find('td') - .map((i, el) => { + .map((_i, el) => { const text = Cypress.$(el).text().trim(); return text.replace(/^\s*\([^)]+\)/, ''); }) @@ -262,7 +260,7 @@ describe('Dashboard Widget Verification Tests', () => { .each(($tr) => { const cells = $tr .find('td') - .map((i, el) => { + .map((_i, el) => { const text = Cypress.$(el).text().trim(); return text.replace(/^\s*\([^)]+\)/, ''); }) @@ -311,10 +309,11 @@ describe('Dashboard Widget Verification Tests', () => { ); } const expectedRelativeTimeDuration = timeRange - ? `Last ${timeRange.value} ${['hour', 'hr'].includes(timeRange.unit.toLowerCase()) - ? 'Hours' - : timeRange.unit - }` + ? `Last ${timeRange.value} ${ + ['hour', 'hr'].includes(timeRange.unit.toLowerCase()) + ? 'Hours' + : timeRange.unit + }` : ''; expect(metric).to.equal(metricData.name); expect(expectedRelativeTimeDuration).to.equal(timeDurationToSelect); @@ -331,7 +330,6 @@ describe('Dashboard Widget Verification Tests', () => { cy.get('@widget') .should('be.visible') .within(() => { - // find and click the zoom in button ui.button .findByAttribute('aria-label', 'Zoom In') @@ -347,7 +345,7 @@ describe('Dashboard Widget Verification Tests', () => { .each(($tr) => { const cells = $tr .find('td') - .map((i, el) => Cypress.$(el).text().trim()) + .map((_i, el) => Cypress.$(el).text().trim()) .get(); const [title, actualMax, actualAvg, actualLast] = cells; const widgetValues = getWidgetLegendRowValuesFromResponse( From 285341d7dea51ca0aea4e3f9d606673e96d3eb2e Mon Sep 17 00:00:00 2001 From: vmangalr Date: Thu, 26 Sep 2024 18:02:14 +0530 Subject: [PATCH 092/474] tests: [DI-20585] - CamelCase for variables --- .../linode-widget-verification.spec.ts | 25 +++++++++---------- .../cypress/support/constants/widgets.ts | 4 +-- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 5b484fcdec9..8db21327489 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -48,7 +48,7 @@ const timeDurationToSelect = 'Last 24 Hours'; const { metrics, id, - service_type, + serviceType, dashboardName, region, resource, @@ -56,7 +56,7 @@ const { const dashboard = dashboardFactory.build({ label: dashboardName, - service_type, + service_type: serviceType, widgets: metrics.map(({ title, yLabel, name, unit }) => { return widgetFactory.build({ label: title, @@ -103,12 +103,12 @@ describe('Integration Tests for Linode Dashboard ', () => { }); mockGetAccount(mockAccount); // Enables the account to have capability for Akamai Cloud Pulse mockGetLinodes([mockLinode]); - mockCloudPulseGetMetricDefinitions(metricDefinitions, service_type); - mockCloudPulseGetDashboards(dashboard, service_type); - mockCloudPulseServices(service_type); + mockCloudPulseGetMetricDefinitions(metricDefinitions, serviceType); + mockCloudPulseGetDashboards(dashboard, serviceType); + mockCloudPulseServices(serviceType); mockCloudPulseDashboardServicesResponse(dashboard, id); - mockCloudPulseJWSToken(service_type); - mockCloudPulseCreateMetrics(metricsAPIResponsePayload, service_type).as( + mockCloudPulseJWSToken(serviceType); + mockCloudPulseCreateMetrics(metricsAPIResponsePayload, serviceType).as( 'getMetrics' ); mockGetRegions([mockRegion]); @@ -234,7 +234,7 @@ describe('Integration Tests for Linode Dashboard ', () => { .within(() => { mockCloudPulseCreateMetrics( metricsAPIResponsePayload, - service_type + serviceType ).as('getAggregationMetrics'); //find the interval component and select the expected granularity @@ -309,11 +309,10 @@ describe('Integration Tests for Linode Dashboard ', () => { ); } const expectedRelativeTimeDuration = timeRange - ? `Last ${timeRange.value} ${ - ['hour', 'hr'].includes(timeRange.unit.toLowerCase()) - ? 'Hours' - : timeRange.unit - }` + ? `Last ${timeRange.value} ${['hour', 'hr'].includes(timeRange.unit.toLowerCase()) + ? 'Hours' + : timeRange.unit + }` : ''; expect(metric).to.equal(metricData.name); expect(expectedRelativeTimeDuration).to.equal(timeDurationToSelect); diff --git a/packages/manager/cypress/support/constants/widgets.ts b/packages/manager/cypress/support/constants/widgets.ts index e774e939cad..39fe8ce5f30 100644 --- a/packages/manager/cypress/support/constants/widgets.ts +++ b/packages/manager/cypress/support/constants/widgets.ts @@ -50,7 +50,7 @@ export const widgetDetails = { nodeType: 'Secondary', region: 'US, Chicago, IL (us-ord)', resource: 'Dbaas-resource', - service_type: 'dbaas', + serviceType: 'dbaas', }, linode: { dashboardName: 'Linode Dashboard', @@ -95,6 +95,6 @@ export const widgetDetails = { ], region: 'US, Chicago, IL (us-ord)', resource: 'linode-resource', - service_type: 'linode', + serviceType: 'linode', }, }; From 4e7a731e6261d84ea6ef94339305a4eab93a1866 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Thu, 26 Sep 2024 19:03:48 +0530 Subject: [PATCH 093/474] tests: [DI-20585] - Title validations --- .../linode-widget-verification.spec.ts | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 8db21327489..2596a2e4e12 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -143,18 +143,6 @@ describe('Integration Tests for Linode Dashboard ', () => { .click(); cy.findByText(resource).should('be.visible'); - - // Verify that the titles of the widgets are displayed correctly, including the unit. - metrics.forEach((testData) => { - const widgetSelector = `[data-qa-widget-header="${testData.title}"]`; - cy.get(widgetSelector) - .invoke('text') - .then((text) => { - expect(text.trim()).to.equal( - `${testData.title} (${testData.unit.trim()})` - ); - }); - }); }); it('should allow users to select desired granularity and see the most recent data from the API reflected in the graph', () => { @@ -325,6 +313,16 @@ describe('Integration Tests for Linode Dashboard ', () => { // do zoom in and zoom out test on all the widgets metrics.forEach((testData) => { cy.wait(7000); //maintaining the wait since page flicker and rendering + + // validate the widget title along with the unit + cy.get(`[data-qa-widget-header="${testData.title}"]`) + .invoke('text') + .then((text) => { + expect(text.trim()).to.equal( + `${testData.title} (${testData.unit.trim()})` + ); + }); + cy.get(`[data-qa-widget="${testData.title}"]`).as('widget'); cy.get('@widget') .should('be.visible') From 467c9f64cb896498c21eb68450b1992ae6788be2 Mon Sep 17 00:00:00 2001 From: agorthi Date: Thu, 26 Sep 2024 20:14:49 +0530 Subject: [PATCH 094/474] upcoming:[DI-20585]- Added code review commennts --- .../linode-widget-verification.spec.ts | 11 ++- packages/manager/src/factories/dashboards.ts | 80 ++++++++++++++++++- 2 files changed, 84 insertions(+), 7 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 5b484fcdec9..f3a194d89a5 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -12,11 +12,12 @@ import { } from 'support/intercepts/cloudpulse'; import { ui } from 'support/ui'; import { widgetDetails } from 'support/constants/widgets'; -import { cloudPulseMetricsResponses } from 'src/factories/widget'; import { accountFactory, + cloudPulseMetricsResponseFactory, dashboardFactory, dashboardMetricFactory, + generateValues, kubeLinodeFactory, linodeFactory, regionFactory, @@ -91,10 +92,8 @@ const mockRegion = extendRegion( country: 'us', }) ); -const metricsAPIResponsePayload = cloudPulseMetricsResponses( - timeDurationToSelect, - '5 min' -); +const metricsAPIResponsePayload = cloudPulseMetricsResponseFactory.build( {data:generateValues( timeDurationToSelect, + '5 min')}); describe('Integration Tests for Linode Dashboard ', () => { beforeEach(() => { @@ -144,7 +143,7 @@ describe('Integration Tests for Linode Dashboard ', () => { cy.findByText(resource).should('be.visible'); - // Verify that the titles of the widgets are displayed correctly, including the unit. + // Verify that the expected widgets areloaded. metrics.forEach((testData) => { const widgetSelector = `[data-qa-widget-header="${testData.title}"]`; cy.get(widgetSelector) diff --git a/packages/manager/src/factories/dashboards.ts b/packages/manager/src/factories/dashboards.ts index 72b5d80ede3..fb607a70e48 100644 --- a/packages/manager/src/factories/dashboards.ts +++ b/packages/manager/src/factories/dashboards.ts @@ -1,6 +1,12 @@ import Factory from 'src/factories/factoryProxy'; -import type { AvailableMetrics, Dashboard, Widgets } from '@linode/api-v4'; +import type { + AvailableMetrics, + CloudPulseMetricsResponse, + CloudPulseMetricsResponseData, + Dashboard, + Widgets, +} from '@linode/api-v4'; const color = ['blue', 'red', 'green', 'yellow']; const chart_type = ['area', 'area', 'area', 'line']; @@ -147,3 +153,75 @@ export const dashboardMetricFactory = Factory.Sync.makeFactory unit: 'defaultUnit', } ); +// Function to generate random values based on the number of points +export const generateValues = ( + time: string, + granularityData: string +): CloudPulseMetricsResponseData => { + const currentTime = Math.floor(Date.now() / 1000); + + const intervals: Record = { + ['1 day']: 86400, + ['1 hr']: 3600, + ['5 min']: 5 * 60, + ['Auto']: 3600, + }; + + const timeRanges: Record = { + ['Last 7 Days']: 7 * 24 * 3600, + ['Last 12 Hours']: 12 * 3600, + ['Last 24 Hours']: 24 * 3600, + ['Last 30 Days']: 30 * 24 * 3600, + ['Last 30 Minutes']: 30 * 60, + }; + + const interval = + intervals[granularityData] || + (() => { + throw new Error(`Unsupported granularity: ${granularityData}`); + })(); + const timeRangeInSeconds = + timeRanges[time] || + (() => { + throw new Error(`Unsupported time range: ${time}`); + })(); + const startTime = currentTime - timeRangeInSeconds; + + const values: [number, string][] = Array.from( + { length: Math.ceil(timeRangeInSeconds / interval) + 1 }, + (_, i) => { + const timestamp = startTime + i * interval; + const value = (Math.round(Math.random() * 100 * 100) / 100).toFixed(2); // Round and convert to string with 2 decimal places + return [timestamp, value]; + } + ); + return { + result: [{ metric: {}, values }], + result_type: 'matrix', + } +}; + +// Factory for CloudPulseMetricsResponseData +export const cloudPulseMetricsResponseDataFactory = Factory.Sync.makeFactory( + { + result: [ + { + metric: {}, + values: [], // Generate 10 data points with 1-minute interval + }, + ], + result_type: 'matrix', // Default result type + } +); + +// Factory for CloudPulseMetricsResponse +export const cloudPulseMetricsResponseFactory = Factory.Sync.makeFactory( + { + data: cloudPulseMetricsResponseDataFactory.build(), // Use the data factory here + isPartial: false, + stats: { + series_fetched: 2, // Adjust based on the number of metrics + }, + status: 'success', + } +); From 7b0c9910913f4c4ec28fb5664542b9902ae8ba4a Mon Sep 17 00:00:00 2001 From: agorthi Date: Thu, 26 Sep 2024 20:45:39 +0530 Subject: [PATCH 095/474] upcoming:[DI-20585]- Added code review commennts --- .../linode-widget-verification.spec.ts | 7 +- packages/manager/src/factories/widget.ts | 69 ------------------- 2 files changed, 3 insertions(+), 73 deletions(-) delete mode 100644 packages/manager/src/factories/widget.ts diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index fe921423df5..e46a445549b 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -32,9 +32,6 @@ import { CloudPulseMetricsResponse } from '@linode/api-v4'; import { transformData } from 'src/features/CloudPulse/Utils/unitConversion'; import { getMetrics } from 'src/utilities/statMetrics'; -const expectedGranularityArray = ['Auto', '1 day', '1 hr', '5 min']; -const timeDurationToSelect = 'Last 24 Hours'; - /** * This test ensures that widget titles are displayed correctly on the dashboard. * This test suite is dedicated to verifying the functionality and display of widgets on the Cloudpulse dashboard. @@ -45,6 +42,8 @@ const timeDurationToSelect = 'Last 24 Hours'; * Testing widget interactions, including zooming and filtering, to ensure proper behavior. * Each test ensures that widgets on the dashboard operate correctly and display accurate information. */ +const expectedGranularityArray = ['Auto', '1 day', '1 hr', '5 min']; +const timeDurationToSelect = 'Last 24 Hours'; const { metrics, @@ -143,7 +142,7 @@ describe('Integration Tests for Linode Dashboard ', () => { cy.findByText(resource).should('be.visible'); - // Verify that the expected widgets areloaded. + // Verifies that the expected widgets are loaded on the dashboard. metrics.forEach((testData) => { const widgetSelector = `[data-qa-widget-header="${testData.title}"]`; cy.get(widgetSelector) diff --git a/packages/manager/src/factories/widget.ts b/packages/manager/src/factories/widget.ts deleted file mode 100644 index 086631d102c..00000000000 --- a/packages/manager/src/factories/widget.ts +++ /dev/null @@ -1,69 +0,0 @@ -import type { CloudPulseMetricsResponse } from '@linode/api-v4'; - -/** - * Generates a mock metric response based on the specified time range and granularity. - * - * This function: - * 1. Determines the time interval based on the granularity (e.g., 5 minutes, 1 hour, 1 day). - * 2. Calculates the time range in seconds based on the specified time range (e.g., last 12 hours, last 30 days). - * 3. Creates a series of random metric values for the given time range at the specified interval. - * 4. Returns a mock response object containing the generated metric data. - * - * @param {string} time - The time range for the metric data (e.g., "Last12Hours"). - * @param {string} granularityData - The granularity of the metric data (e.g., "Min5"). - * @returns {CloudPulseMetricsResponse} - The generated mock metric response. - */ -export const cloudPulseMetricsResponses = ( - time: string, - granularityData: string -): CloudPulseMetricsResponse => { - const currentTime = Math.floor(Date.now() / 1000); - - const intervals: Record = { - ['1 day']: 86400, - ['1 hr']: 3600, - ['5 min']: 5 * 60, - ['Auto']: 3600, - }; - - const timeRanges: Record = { - ['Last 7 Days']: 7 * 24 * 3600, - ['Last 12 Hours']: 12 * 3600, - ['Last 24 Hours']: 24 * 3600, - ['Last 30 Days']: 30 * 24 * 3600, - ['Last 30 Minutes']: 30 * 60, - }; - - const interval = - intervals[granularityData] || - (() => { - throw new Error(`Unsupported granularity: ${granularityData}`); - })(); - const timeRangeInSeconds = - timeRanges[time] || - (() => { - throw new Error(`Unsupported time range: ${time}`); - })(); - const startTime = currentTime - timeRangeInSeconds; - - const values: [number, string][] = Array.from( - { length: Math.ceil(timeRangeInSeconds / interval) + 1 }, - (_, i) => { - const timestamp = startTime + i * interval; - const value = (Math.round(Math.random() * 100 * 100) / 100).toFixed(2); // Round and convert to string with 2 decimal places - return [timestamp, value]; - } - ); - - return { - data: { - result: [{ metric: {}, values }], - result_type: 'matrix', - }, - isPartial: false, - stats: { - series_fetched: 53, - }, - status: 'success', - }; -}; From e25a62789abfc8af14628e1f1f44b0daab73650f Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Thu, 26 Sep 2024 20:48:28 +0530 Subject: [PATCH 096/474] upcoming: [DI-20360] - Removed unnecessary compare functions --- .../Dashboard/CloudPulseDashboardRenderer.tsx | 38 ------------------- .../CloudPulse/Utils/UserPreference.ts | 2 +- .../src/features/CloudPulse/Utils/utils.ts | 33 ---------------- .../Widget/CloudPulseWidgetRenderer.tsx | 38 ++++++------------- .../shared/CloudPulseDashboardSelect.tsx | 3 +- .../shared/CloudPulseTimeRangeSelect.tsx | 3 +- 6 files changed, 15 insertions(+), 102 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx index 20efa560008..83abd618a98 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx @@ -7,7 +7,6 @@ import { getMetricsCallCustomFilters, } from '../Utils/FilterBuilder'; import { FILTER_CONFIG } from '../Utils/FilterConfig'; -import { arrayDeepEqual } from '../Utils/utils'; import { CloudPulseDashboard } from './CloudPulseDashboard'; import type { DashboardProp } from './CloudPulseDashboardLanding'; @@ -76,42 +75,5 @@ export const CloudPulseDashboardRenderer = React.memo( savePref={true} /> ); - }, - (oldProps: DashboardProp, newProps: DashboardProp) => { - if (oldProps.dashboard?.id !== newProps.dashboard?.id) { - return false; - } - - if ( - oldProps.timeDuration?.unit !== newProps.timeDuration?.unit || - oldProps.timeDuration?.value !== newProps.timeDuration?.value - ) { - return false; - } - - const oldKeys = Object.keys(oldProps.filterValue); - const newKeys = Object.keys(newProps.filterValue); - - if (oldKeys.length !== newKeys.length) { - return false; - } - - for (const key of oldKeys) { - const oldValue = oldProps.filterValue[key]; - const newValue = newProps.filterValue[key]; - - if ( - Array.isArray(oldValue) && - Array.isArray(newValue) && - !arrayDeepEqual(oldValue, newValue) - ) { - return false; - } - - if (oldValue !== newValue) { - return false; - } - } - return true; } ); diff --git a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts index 8074268e4ad..18550ae5f25 100644 --- a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts +++ b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts @@ -74,7 +74,7 @@ export const useAclpPreference = (): AclpPreferenceObject => { }; return { isLoading, - preferences: { ...(preferences?.aclpPreference ?? {}) }, + preferences: preferences?.aclpPreference ?? {}, updateGlobalFilterPreference, updateWidgetPreference, }; diff --git a/packages/manager/src/features/CloudPulse/Utils/utils.ts b/packages/manager/src/features/CloudPulse/Utils/utils.ts index 92599e6971b..7c168f4e487 100644 --- a/packages/manager/src/features/CloudPulse/Utils/utils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/utils.ts @@ -158,36 +158,3 @@ export const getAllDashboards = ( isLoading, }; }; - -/** - * - * @param oldValue array of old values - * @param newValue array of new values - * @returns true if both the arrays are equals otherwise false - */ -export const arrayDeepEqual = ( - oldValue: number[] | string[], - newValue: number[] | string[] -): boolean => { - if (oldValue === newValue) { - return true; - } - - if (!oldValue || !newValue) { - return false; - } - - if (oldValue.length !== newValue.length) { - return false; - } - oldValue.sort(); - newValue.sort(); - - for (let i = 0; i < oldValue.length; i++) { - if (oldValue[i] !== newValue[i]) { - return false; - } - } - - return true; -}; diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx index 5bb2a9b7f44..734d20e6822 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx @@ -4,7 +4,7 @@ import React from 'react'; import CloudPulseIcon from 'src/assets/icons/entityIcons/monitor.svg'; import { Placeholder } from 'src/components/Placeholder/Placeholder'; -import { arrayDeepEqual, createObjectCopy } from '../Utils/utils'; +import { createObjectCopy } from '../Utils/utils'; import { CloudPulseWidget } from './CloudPulseWidget'; import { allIntervalOptions, @@ -27,10 +27,6 @@ import type { Widgets, } from '@linode/api-v4'; -interface CompareProperties { - [key: string]: number | string | undefined; -} - interface WidgetProps { additionalFilters?: CloudPulseMetricsAdditionalFilters[]; dashboard?: Dashboard | undefined; @@ -183,30 +179,20 @@ export const RenderWidgets = React.memo( ); }, (oldProps: WidgetProps, newProps: WidgetProps) => { - const oldValue: CompareProperties = { - id: oldProps.dashboard?.id, - timeStamp: oldProps.manualRefreshTimeStamp, - token: oldProps.jweToken?.token, - unit: oldProps.duration?.unit, - value: oldProps.duration?.value, - }; - - const newValue: CompareProperties = { - id: newProps.dashboard?.id, - timeStamp: newProps.manualRefreshTimeStamp, - token: newProps.jweToken?.token, - unit: newProps.duration?.unit, - value: newProps.duration?.value, - }; - - for (const key of Object.keys(oldValue)) { - if (oldValue[key] !== newValue[key]) { + const keysToCompare: (keyof WidgetProps)[] = [ + 'dashboard', + 'manualRefreshTimeStamp', + 'jweToken', + 'duration', + 'resources', + ]; + + for (const key of keysToCompare) { + if (oldProps[key] !== newProps[key]) { return false; } } - if (!arrayDeepEqual(oldProps.resources, newProps.resources)) { - return false; - } + return true; } ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index 07a67f809f7..80ee4f335ad 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -117,6 +117,5 @@ export const CloudPulseDashboardSelect = React.memo( value={selectedDashboard ?? null} // Undefined is not allowed for uncontrolled component /> ); - }, - () => true + } ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx index cfad88d9298..8c288622307 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx @@ -89,8 +89,7 @@ export const CloudPulseTimeRangeSelect = React.memo( value={selectedTimeRange} /> ); - }, - () => true + } ); /** From 0277edb05596242670fc648603955bdc60e9d20b Mon Sep 17 00:00:00 2001 From: vmangalr Date: Fri, 27 Sep 2024 10:06:28 +0530 Subject: [PATCH 097/474] tests: [DI-20585] - Code clean up and refactoring work --- .../linode-widget-verification.spec.ts | 94 ++++++++++++------- 1 file changed, 59 insertions(+), 35 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 05e317e7092..a766357352a 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -145,13 +145,13 @@ describe('Integration Tests for Linode Dashboard ', () => { cy.findByText(resource).should('be.visible'); // Verifies that the expected widgets are loaded on the dashboard. - metrics.forEach((testData) => { - const widgetSelector = `[data-qa-widget-header="${testData.title}"]`; + metrics.forEach(({ title, unit }) => { + const widgetSelector = `[data-qa-widget-header="${title}"]`; cy.get(widgetSelector) .invoke('text') .then((text) => { expect(text.trim()).to.equal( - `${testData.title} (${testData.unit.trim()})` + `${title} (${unit.trim()})` ); }); }); @@ -160,8 +160,11 @@ describe('Integration Tests for Linode Dashboard ', () => { it('should allow users to select desired granularity and see the most recent data from the API reflected in the graph', () => { // validate the widget level granularity selection and its metrics for (const testData of metrics) { + + const { title: testDataTitle, expectedGranularity } = testData; + cy.wait(7000); //maintaining the wait since page flicker and rendering - const widgetSelector = `[data-qa-widget="${testData.title}"]`; + const widgetSelector = `[data-qa-widget="${testDataTitle}"]`; cy.get(widgetSelector) .first() @@ -180,14 +183,14 @@ describe('Integration Tests for Linode Dashboard ', () => { ui.autocomplete .findByLabel('Select an Interval') .should('be.visible') - .type(`${testData.expectedGranularity}{enter}`); + .type(`${expectedGranularity}{enter}`); //check if the API call is made correctly with the selected time granularity value cy.wait('@getMetrics').then((interception) => { expect(interception) .to.have.property('response') .with.property('statusCode', 200); - expect(testData.expectedGranularity).to.include( + expect(expectedGranularity).to.include( interception.request.body.time_granularity.value ); }); @@ -217,7 +220,7 @@ describe('Integration Tests for Linode Dashboard ', () => { last: parseFloat(actualLast), }, widgetValues, - testData.title + testDataTitle ); }); }); @@ -226,12 +229,25 @@ describe('Integration Tests for Linode Dashboard ', () => { it('should allow users to select the desired aggregation and see the most recent data from the API displayed in the graph', () => { for (const testData of metrics) { + + const { title: testDataTitle, expectedAggregation, expectedAggregationArray } = testData; + cy.wait(7000); //maintaining the wait since page flicker and rendering - const widgetSelector = `[data-qa-widget="${testData.title}"]`; + const widgetSelector = `[data-qa-widget="${testDataTitle}"]`; cy.get(widgetSelector) .first() .within(() => { + // check for all available aggregation in popper + ui.autocomplete + .findByLabel('Select an Aggregate Function') + .should('be.visible') + .click(); + + expectedAggregationArray.forEach((option) => { + ui.autocompletePopper.findByTitle(option).should('exist'); + }); + mockCloudPulseCreateMetrics( metricsAPIResponsePayload, serviceType @@ -241,14 +257,14 @@ describe('Integration Tests for Linode Dashboard ', () => { ui.autocomplete .findByLabel('Select an Aggregate Function') .should('be.visible') - .type(`${testData.expectedAggregation}{enter}`); + .type(`${expectedAggregation}{enter}`); //check if the API call is made correctly with time granularity value selected cy.wait('@getAggregationMetrics').then((interception) => { expect(interception) .to.have.property('response') .with.property('statusCode', 200); - expect(testData.expectedAggregation).to.equal( + expect(expectedAggregation).to.equal( interception.request.body.aggregate_function ); }); @@ -278,7 +294,7 @@ describe('Integration Tests for Linode Dashboard ', () => { last: parseFloat(actualLast), }, widgetValues, - testData.title + testDataTitle ); }); }); @@ -302,7 +318,7 @@ describe('Integration Tests for Linode Dashboard ', () => { interceptionsArray.forEach((interception) => { const { body: requestPayload } = interception.request; const { metric, relative_time_duration: timeRange } = requestPayload; - const metricData = metrics.find((data) => data.name === metric); + const metricData = metrics.find(({ name }) => name === metric); if (!metricData) { expect.fail( 'metricData or its expected properties are not defined.' @@ -324,18 +340,12 @@ describe('Integration Tests for Linode Dashboard ', () => { it('should zoom in and out of all the widgets', () => { // do zoom in and zoom out test on all the widgets metrics.forEach((testData) => { - cy.wait(7000); //maintaining the wait since page flicker and rendering - // validate the widget title along with the unit - cy.get(`[data-qa-widget-header="${testData.title}"]`) - .invoke('text') - .then((text) => { - expect(text.trim()).to.equal( - `${testData.title} (${testData.unit.trim()})` - ); - }); + const { title: testDataTitle } = testData; + + cy.wait(7000); //maintaining the wait since page flicker and rendering - cy.get(`[data-qa-widget="${testData.title}"]`).as('widget'); + cy.get(`[data-qa-widget="${testDataTitle}"]`).as('widget'); cy.get('@widget') .should('be.visible') .within(() => { @@ -368,7 +378,7 @@ describe('Integration Tests for Linode Dashboard ', () => { last: parseFloat(actualLast), }, widgetValues, - testData.title + testDataTitle ); }); @@ -394,6 +404,7 @@ describe('Integration Tests for Linode Dashboard ', () => { const widgetValues = getWidgetLegendRowValuesFromResponse( metricsAPIResponsePayload ); + cy.log('testDataTitle', testDataTitle) compareWidgetValues( { title, @@ -402,7 +413,7 @@ describe('Integration Tests for Linode Dashboard ', () => { last: parseFloat(actualLast), }, widgetValues, - testData.title + testDataTitle ); }); }); @@ -451,22 +462,35 @@ const compareWidgetValues = ( expectedValues: { max: number; average: number; last: number }, title: string ) => { - expect(actualValues.max).to.equal( - expectedValues.max, - `Expected ${expectedValues.max} for max, but got ${actualValues.max}` + + + + const { title: actualTitle, max: actualMax, + average: actualAverage, last: actualLast, + } = actualValues; + + const { max: expectedMax, + average: expectedAverage, last: expectedLast, + } = expectedValues; + + + expect(actualMax).to.equal( + expectedMax, + `Expected ${expectedMax} for max, but got ${actualMax}` ); - expect(actualValues.average).to.equal( - expectedValues.average, - `Expected ${expectedValues.average} for average, but got ${actualValues.average}` + expect(actualAverage).to.equal( + expectedAverage, + `Expected ${expectedAverage} for average, but got ${actualAverage}` ); - expect(actualValues.last).to.equal( - expectedValues.last, - `Expected ${expectedValues.last} for last, but got ${actualValues.last}` + expect(actualLast).to.equal( + expectedLast, + `Expected ${expectedLast} for last, but got ${actualLast}` ); - const extractedTitle = actualValues.title.substring( + const extractedTitle = actualTitle.substring( 0, - actualValues.title.indexOf(' ', actualValues.title.indexOf(' ') + 1) + actualTitle.indexOf(' ', actualValues.title.indexOf(' ') + 1) ); + expect(extractedTitle).to.equal( title, `Expected ${title} for title ${extractedTitle}` From 878d86babe65f2808ac87a12388469666cb84b40 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Fri, 27 Sep 2024 14:15:19 +0530 Subject: [PATCH 098/474] Updated PR template file --- docs/PULL_REQUEST_TEMPLATE.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/docs/PULL_REQUEST_TEMPLATE.md b/docs/PULL_REQUEST_TEMPLATE.md index 15e72c8495e..486f36b271b 100644 --- a/docs/PULL_REQUEST_TEMPLATE.md +++ b/docs/PULL_REQUEST_TEMPLATE.md @@ -39,18 +39,19 @@ Please specify a release date to guarantee timely review of this PR. If exact da *Check all that apply* -- [ ] 👀 Doing a self review -- [ ] ❔ Our [contribution guidelines](https://github.com/linode/manager/blob/develop/docs/CONTRIBUTING.md) -- [ ] 🤏 Splitting feature into small PRs -- [ ] ➕ Adding a [changeset](https://github.com/linode/manager/blob/develop/docs/CONTRIBUTING.md#writing-a-changeset) -- [ ] 🧪 Providing/Improving test coverage -- [ ] 🔐 Removing all sensitive information from the code and PR description -- [ ] 🚩 Using a feature flag to protect the release -- [ ] 👣 Providing comprehensive reproduction steps -- [ ] 📑 Providing or updating our documentation -- [ ] 🕛 Scheduling a pair reviewing session +- [ ] Use React components instead of HTML Tags +- [ ] Proper naming conventions like cameCase for variables & Function & snake_case for constants +- [ ] Use appropriate types & avoid using "any" +- [ ] No type casting & non-null assertions +- [ ] Adding a [changeset](https://github.com/linode/manager/blob/develop/docs/CONTRIBUTING.md#writing-a-changeset) +- [ ] Providing/Improving test coverage +- [ ] Use sx props to pass styles instead of style prop +- [ ] Add JSDoc comments for interface properties & functions +- [ ] Use strict equality (===) instead of double equal (==) +- [ ] Use of named arguments (interfaces) if function argument list exceeds size 2 +- [ ] Destructure the props +- [ ] Keep component size small & move big computing functions to separate utility - [ ] 📱 Providing mobile support -- [ ] ♿ Providing accessibility support --- ## Commit message and pull request title format standards From fbeed02d2ba64b3ed5668a5a304565a51749f77c Mon Sep 17 00:00:00 2001 From: vmangalr Date: Sun, 29 Sep 2024 18:57:58 +0530 Subject: [PATCH 099/474] upcoming: [DI-20800] - Tooltip and publishing the resource selection onClose from Autocomplete --- .../CloudPulse/Overview/GlobalFilters.tsx | 25 ++++--- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 22 ------ .../CloudPulseAggregateFunction.tsx | 58 +++++++-------- .../components/CloudPulseIntervalSelect.tsx | 71 ++++++++----------- .../Widget/components/CloudPulseLineGraph.tsx | 1 - .../CloudPulse/Widget/components/Zoomer.tsx | 19 ++--- .../shared/CloudPulseResourcesSelect.tsx | 8 ++- .../CloudPulse/shared/CloudPulseTooltip.tsx | 39 ++++++++++ 8 files changed, 119 insertions(+), 124 deletions(-) create mode 100644 packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.tsx diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index b6b290176d7..4dfa47eb125 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -1,5 +1,5 @@ -import { IconButton, useTheme } from '@mui/material'; import { Grid } from '@mui/material'; +import { IconButton, useTheme } from '@mui/material'; import { styled } from '@mui/material/styles'; import * as React from 'react'; @@ -10,6 +10,7 @@ import { CloudPulseDashboardFilterBuilder } from '../shared/CloudPulseDashboardF import { CloudPulseDashboardSelect } from '../shared/CloudPulseDashboardSelect'; import { CloudPulseTimeRangeSelect } from '../shared/CloudPulseTimeRangeSelect'; import { REFRESH } from '../Utils/constants'; +import { CloudPulseTooltip } from '../shared/CloudPulseTooltip'; import type { FilterValueType } from '../Dashboard/CloudPulseDashboardLanding'; import type { Dashboard, TimeDuration } from '@linode/api-v4'; @@ -94,16 +95,18 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { hideLabel label="Select Time Range" /> - handleGlobalRefresh(selectedDashboard)} - size="small" - > - - + + handleGlobalRefresh(selectedDashboard)} + size="small" + > + + + diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index a2350a18849..025c3793d32 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -350,25 +350,3 @@ export const StyledWidgetAutocomplete = styled(Autocomplete, { width: '90px', }, })); - -// popperProps.ts -export const commonPopperProps = { - modifiers: [ - { - name: 'offset', - options: { - offset: [0, -8], // Adjust offset if needed - }, - }, - ], - sx: { - '& .MuiTooltip-tooltip': { - bgcolor: 'black', - color: 'white', - fontSize: '13px', - maxHeight: '28px', - maxWidth: '64px', - padding: '6px', - }, - }, -}; diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx index 9d7f69a0af5..81c9ea3758f 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx @@ -1,11 +1,8 @@ import React from 'react'; -import { Tooltip } from 'src/components/Tooltip'; - -import { - StyledWidgetAutocomplete, - commonPopperProps, -} from '../../Utils/CloudPulseWidgetUtils'; +import { CloudPulseTooltip } from '../../shared/CloudPulseTooltip'; +import { StyledWidgetAutocomplete } from '../../Utils/CloudPulseWidgetUtils'; +import { convertStringToCamelCasesWithSpaces } from '../../Utils/utils'; export interface AggregateFunctionProperties { /** @@ -42,32 +39,29 @@ export const CloudPulseAggregateFunction = React.memo( ) || props.availableAggregateFunctions[0]; return ( - - - { - return option.label == value.label; - }} - onChange={(_: any, selectedAggregateFunc: any) => { - props.onAggregateFuncChange(selectedAggregateFunc.label); - }} - textFieldProps={{ - hideLabel: true, - }} - defaultValue={defaultAggregateFunc} - disableClearable - fullWidth={false} - label="Select an Aggregate Function" - noMarginTop={true} - options={availableAggregateFunc} - sx={{ width: '100%' }} - /> - - + + { + return convertStringToCamelCasesWithSpaces(option.label); // options needed to be display in Caps first + }} + isOptionEqualToValue={(option, value) => { + return option.label == value.label; + }} + onChange={(_: any, selectedAggregateFunc: any) => { + props.onAggregateFuncChange(selectedAggregateFunc.label); + }} + textFieldProps={{ + hideLabel: true, + }} + defaultValue={defaultAggregateFunc} + disableClearable + fullWidth={false} + label="Select an Aggregate Function" + noMarginTop={true} + options={availableAggregateFunc} + sx={{ width: '100%' }} + /> + ); } ); diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx index a665815bac4..21a30295821 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx @@ -1,12 +1,7 @@ import React from 'react'; -import { Box } from 'src/components/Box'; -import { Tooltip } from 'src/components/Tooltip'; - -import { - StyledWidgetAutocomplete, - commonPopperProps, -} from '../../Utils/CloudPulseWidgetUtils'; +import { CloudPulseTooltip } from '../../shared/CloudPulseTooltip'; +import { StyledWidgetAutocomplete } from '../../Utils/CloudPulseWidgetUtils'; import type { TimeGranularity } from '@linode/api-v4'; @@ -121,40 +116,34 @@ export const CloudPulseIntervalSelect = React.memo( } return ( - - - option?.value === value?.value && option?.unit === value?.unit} - onChange={( - _: React.SyntheticEvent, - selectedInterval: IntervalOptions - ) => { - props.onIntervalChange({ - unit: selectedInterval?.unit, - value: selectedInterval?.value, - }); - }} - textFieldProps={{ - hideLabel: true, - }} - defaultValue={{ ...default_interval }} - disableClearable - fullWidth={false} - label="Select an Interval" - noMarginTop={true} - options={[autoIntervalOption, ...availableIntervalOptions]} - sx={{ width: { xs: '100%' } }} - autoHighlight - /> - - + + option?.value === value?.value && option?.unit === value?.unit} + onChange={( + _: React.SyntheticEvent, + selectedInterval: IntervalOptions + ) => { + props.onIntervalChange({ + unit: selectedInterval?.unit, + value: selectedInterval?.value, + }); + }} + textFieldProps={{ + hideLabel: true, + }} + autoHighlight + defaultValue={{ ...default_interval }} + disableClearable + fullWidth={false} + label="Select an Interval" + noMarginTop={true} + options={[autoIntervalOption, ...availableIntervalOptions]} + sx={{ width: { xs: '100%' } }} + /> + ); } ); diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index 4547d306b41..cd62ab3fd80 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -49,7 +49,6 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { border: 0, }, backgroundColor: theme.bg.offWhite, - height: `calc(${theme.spacing(14)} + 3px)`, // 115px maxHeight: `calc(${theme.spacing(14)} + 3px)`, overflow: 'auto', padding: theme.spacing(1), diff --git a/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx b/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx index 028bcd8882e..4ac32e4a335 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx @@ -3,9 +3,8 @@ import * as React from 'react'; import ZoomInMap from 'src/assets/icons/zoomin.svg'; import ZoomOutMap from 'src/assets/icons/zoomout.svg'; -import { Tooltip } from 'src/components/Tooltip'; -import { commonPopperProps } from '../../Utils/CloudPulseWidgetUtils'; +import { CloudPulseTooltip } from '../../shared/CloudPulseTooltip'; export interface ZoomIconProperties { className?: string; @@ -23,11 +22,7 @@ export const ZoomIcon = React.memo((props: ZoomIconProperties) => { const ToggleZoomer = () => { if (props.zoomIn) { return ( - + { > - + ); } return ( - + { > - + ); }; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index adaf971e1ba..800d4be3f3b 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -82,13 +82,15 @@ export const CloudPulseResourcesSelect = React.memo( return ( { + setSelectedResources(resourceSelections); + }} + onClose={() => { updateGlobalFilterPreference({ - [RESOURCES]: resourceSelections.map((resource: { id: string }) => + [RESOURCES]: selectedResources.map((resource: { id: string }) => String(resource.id) ), }); - setSelectedResources(resourceSelections); - handleResourcesSelection(resourceSelections); + handleResourcesSelection(selectedResources); }} placeholder={ selectedResources?.length ? '' : placeholder || 'Select a Resource' diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.tsx new file mode 100644 index 00000000000..e582493ac1f --- /dev/null +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.tsx @@ -0,0 +1,39 @@ +import React from 'react'; + +import { Tooltip } from 'src/components/Tooltip'; + +interface CloudPulseTooltipProps { + children: any; + title: string; +} + +export const CloudPulseTooltip = React.memo((props: CloudPulseTooltipProps) => { + return ( + + {props.children} + + ); +}); From d14737c32ef7d525f44c36e3b59c688d5f662204 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 30 Sep 2024 09:45:25 +0530 Subject: [PATCH 100/474] upcoming: [DI-20800] - Resource Selection close state handling updates --- .../shared/CloudPulseResourcesSelect.tsx | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index 800d4be3f3b..d80dce95da6 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -51,6 +51,8 @@ export const CloudPulseResourcesSelect = React.memo( CloudPulseResources[] >([]); + const isAutocompleteOpen = React.useRef(false); // Ref to track the open state of Autocomplete + const getResourcesList = (): CloudPulseResources[] => { return resources && resources.length > 0 ? resources : []; }; @@ -81,10 +83,23 @@ export const CloudPulseResourcesSelect = React.memo( return ( { + onChange={( + _: React.SyntheticEvent, + resourceSelections: CloudPulseResources[] + ) => { setSelectedResources(resourceSelections); + + if (!isAutocompleteOpen.current) { + updateGlobalFilterPreference({ + [RESOURCES]: resourceSelections.map((resource: { id: string }) => + String(resource.id) + ), + }); + handleResourcesSelection(resourceSelections); + } }} onClose={() => { + isAutocompleteOpen.current = false; updateGlobalFilterPreference({ [RESOURCES]: selectedResources.map((resource: { id: string }) => String(resource.id) @@ -92,6 +107,9 @@ export const CloudPulseResourcesSelect = React.memo( }); handleResourcesSelection(selectedResources); }} + onOpen={() => { + isAutocompleteOpen.current = true; + }} placeholder={ selectedResources?.length ? '' : placeholder || 'Select a Resource' } From b1e43b0a0fa6f05fec0b9f02f6000b6676f4a3dc Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 30 Sep 2024 14:28:07 +0530 Subject: [PATCH 101/474] upcoming: [DI-20800] - Tooltip code refactoring --- .../CloudPulse/Overview/GlobalFilters.tsx | 6 +-- .../CloudPulseAggregateFunction.tsx | 2 +- .../components/CloudPulseIntervalSelect.tsx | 2 +- .../Widget/components/CloudPulseLineGraph.tsx | 3 +- .../CloudPulse/Widget/components/Zoomer.tsx | 4 +- .../CloudPulse/shared/CloudPulseTooltip.tsx | 46 +++++++++++-------- 6 files changed, 36 insertions(+), 27 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index 4dfa47eb125..f09a4de6621 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -1,5 +1,5 @@ -import { Grid } from '@mui/material'; import { IconButton, useTheme } from '@mui/material'; +import { Grid } from '@mui/material'; import { styled } from '@mui/material/styles'; import * as React from 'react'; @@ -9,8 +9,8 @@ import { Divider } from 'src/components/Divider'; import { CloudPulseDashboardFilterBuilder } from '../shared/CloudPulseDashboardFilterBuilder'; import { CloudPulseDashboardSelect } from '../shared/CloudPulseDashboardSelect'; import { CloudPulseTimeRangeSelect } from '../shared/CloudPulseTimeRangeSelect'; -import { REFRESH } from '../Utils/constants'; import { CloudPulseTooltip } from '../shared/CloudPulseTooltip'; +import { REFRESH } from '../Utils/constants'; import type { FilterValueType } from '../Dashboard/CloudPulseDashboardLanding'; import type { Dashboard, TimeDuration } from '@linode/api-v4'; @@ -95,7 +95,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { hideLabel label="Select Time Range" /> - + + { return convertStringToCamelCasesWithSpaces(option.label); // options needed to be display in Caps first diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx index 21a30295821..a609d32bb46 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx @@ -116,7 +116,7 @@ export const CloudPulseIntervalSelect = React.memo( } return ( - + { }, backgroundColor: theme.bg.offWhite, maxHeight: `calc(${theme.spacing(14)} + 3px)`, + minHeight: `calc(${theme.spacing(10)})`, overflow: 'auto', - padding: theme.spacing(1), + paddingLeft: theme.spacing(1), }} ariaLabel={ariaLabel} data={data} diff --git a/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx b/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx index 4ac32e4a335..e4d4a848aeb 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx @@ -22,7 +22,7 @@ export const ZoomIcon = React.memo((props: ZoomIconProperties) => { const ToggleZoomer = () => { if (props.zoomIn) { return ( - + { } return ( - + { + const theme = useTheme(); -export const CloudPulseTooltip = React.memo((props: CloudPulseTooltipProps) => { return ( - {props.children} - + ); }); + +const BootstrapTooltip = styled(({ className, ...props }: TooltipProps) => ( + +))(({ theme }) => ({ + [`& .${tooltipClasses.arrow}`]: { + color: theme.palette.common.black, + }, + [`& .${tooltipClasses.tooltip}`]: { + backgroundColor: theme.palette.common.black, + color: theme.palette.common.white, + fontSize: theme.spacing(1.75), + maxHeight: theme.spacing(3.5), + maxWidth: theme.spacing(30), + padding: theme.spacing(0.75), + }, +})); From f6faf4107d432f031621410c8e789f7bc5a07900 Mon Sep 17 00:00:00 2001 From: Nikhil Agrawal <165884194+nikhagra-akamai@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:53:37 +0530 Subject: [PATCH 102/474] Update CODEOWNERS --- CODEOWNERS | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 8b6b2774004..53b7b942d9d 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,5 +1,2 @@ -# Default code owners -* @linode/frontend - -# Frontend SDET code owners for Cypress tests -/packages/manager/cypress/ @linode/frontend-sdet +@nikhagra-akamai +@venkymano-akamai From 5e2b96b40f7c367d904bc6dc8cd5c2e174e68871 Mon Sep 17 00:00:00 2001 From: Nikhil Agrawal <165884194+nikhagra-akamai@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:59:21 +0530 Subject: [PATCH 103/474] Update CODEOWNERS --- CODEOWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 53b7b942d9d..6143dc6f4a9 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,2 +1,2 @@ -@nikhagra-akamai -@venkymano-akamai +* @nikhagra-akamai +* @venkymano-akamai From 2bacbfbcdfb667ea98c9f5a343c2524c904c8b9e Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 1 Oct 2024 08:20:16 +0530 Subject: [PATCH 104/474] upcoming: [DI-20800] - Tooltip code refactoring --- .../CloudPulse/shared/CloudPulseTooltip.tsx | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.tsx index 035098b9eb6..f6afa0a455f 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.tsx @@ -1,4 +1,4 @@ -import { styled, tooltipClasses, useTheme } from '@mui/material'; +import { styled, tooltipClasses } from '@mui/material'; import React from 'react'; import { Tooltip } from 'src/components/Tooltip'; @@ -6,10 +6,10 @@ import { Tooltip } from 'src/components/Tooltip'; import type { TooltipProps } from '@mui/material'; export const CloudPulseTooltip = React.memo((props: TooltipProps) => { - const theme = useTheme(); + const { children, placement, title } = props; return ( - { }, ], }} - disableHoverListener={props.open !== undefined ? !props.open : false} // Disable hover during operation - open={props.open} - placement={props.placement ?? 'top-start'} - title={props.title} + arrow + data-qa-tooltip={title} + data-test-id={title} + placement={placement ?? 'top-start'} + title={title} > - {props.children} - + {children} + ); }); -const BootstrapTooltip = styled(({ className, ...props }: TooltipProps) => ( - +const StyledTooltip = styled(({ className, ...props }: TooltipProps) => ( + ))(({ theme }) => ({ [`& .${tooltipClasses.arrow}`]: { color: theme.palette.common.black, From a0570fa0431856f6ede533f93ca8fb019867c011 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 1 Oct 2024 08:48:33 +0530 Subject: [PATCH 105/474] upcoming: [DI-20800] - Global Filters --- .../CloudPulse/Overview/GlobalFilters.tsx | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index 5f842956475..157db0a26cc 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -110,17 +110,19 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { label="Select Time Range" savePreferences /> - - - + + + + + From fd70bcd748e3f1282e30a5823a4149a71596c2f4 Mon Sep 17 00:00:00 2001 From: agorthi Date: Tue, 1 Oct 2024 09:10:59 +0530 Subject: [PATCH 106/474] upcoming:[DI-20585]- Added code review comments --- .../linode-widget-verification.spec.ts | 126 +++++++++--------- .../cypress/support/constants/widgets.ts | 5 +- .../cypress/support/intercepts/cloudpulse.ts | 31 ++--- 3 files changed, 78 insertions(+), 84 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index a766357352a..51769da307a 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -95,6 +95,57 @@ const metricsAPIResponsePayload = cloudPulseMetricsResponseFactory.build({ data: generateValues(timeDurationToSelect, '5 min') }); +/** + * Compares actual widget values to the expected values and asserts their equality. + * + * @param actualValues - The actual values retrieved from the widget, consisting of: + * @param actualValues.max - The maximum value shown on the widget. + * @param actualValues.average - The average value shown on the widget. + * @param actualValues.last - The last or most recent value shown on the widget. + * + * @param expectedValues - The expected values that the widget should display, consisting of: + * @param expectedValues.max - The expected maximum value. + * @param expectedValues.average - The expected average value. + * @param expectedValues.last - The expected last or most recent value. + */ + +const compareWidgetValues = ( + actualValues: { title: string; max: number; average: number; last: number }, + expectedValues: { max: number; average: number; last: number }, + title: string +) => { + + const { title: actualTitle, max: actualMax, + average: actualAverage, last: actualLast, + } = actualValues; + + const { max: expectedMax, + average: expectedAverage, last: expectedLast, + } = expectedValues; + + expect(actualMax).to.equal( + expectedMax, + `Expected ${expectedMax} for max, but got ${actualMax}` + ); + expect(actualAverage).to.equal( + expectedAverage, + `Expected ${expectedAverage} for average, but got ${actualAverage}` + ); + expect(actualLast).to.equal( + expectedLast, + `Expected ${expectedLast} for last, but got ${actualLast}` + ); + const extractedTitle = actualTitle.substring( + 0, + actualTitle.indexOf(' ', actualValues.title.indexOf(' ') + 1) + ); + + expect(extractedTitle).to.equal( + title, + `Expected ${title} for title ${extractedTitle}` + ); +}; + describe('Integration Tests for Linode Dashboard ', () => { beforeEach(() => { @@ -147,15 +198,12 @@ describe('Integration Tests for Linode Dashboard ', () => { // Verifies that the expected widgets are loaded on the dashboard. metrics.forEach(({ title, unit }) => { const widgetSelector = `[data-qa-widget-header="${title}"]`; - cy.get(widgetSelector) - .invoke('text') - .then((text) => { - expect(text.trim()).to.equal( - `${title} (${unit.trim()})` - ); - }); - }); + cy.get(widgetSelector).should('have.text', `${title} (${unit.trim()})`).should('be.visible'); + + }); }); + + it('should allow users to select desired granularity and see the most recent data from the API reflected in the graph', () => { // validate the widget level granularity selection and its metrics @@ -167,7 +215,6 @@ describe('Integration Tests for Linode Dashboard ', () => { const widgetSelector = `[data-qa-widget="${testDataTitle}"]`; cy.get(widgetSelector) - .first() .within(() => { // check for all available granularity in popper ui.autocomplete @@ -179,6 +226,11 @@ describe('Integration Tests for Linode Dashboard ', () => { ui.autocompletePopper.findByTitle(option).should('exist'); }); + mockCloudPulseCreateMetrics( + metricsAPIResponsePayload, + serviceType + ).as('getMetrics'); + //find the interval component and select the expected granularity ui.autocomplete .findByLabel('Select an Interval') @@ -236,7 +288,6 @@ describe('Integration Tests for Linode Dashboard ', () => { const widgetSelector = `[data-qa-widget="${testDataTitle}"]`; cy.get(widgetSelector) - .first() .within(() => { // check for all available aggregation in popper ui.autocomplete @@ -358,7 +409,6 @@ describe('Integration Tests for Linode Dashboard ', () => { // validate the widget details cy.findByTestId('linegraph-wrapper') - .as('canvas') .should('be.visible') .find('tbody tr') .each(($tr) => { @@ -392,7 +442,6 @@ describe('Integration Tests for Linode Dashboard ', () => { // validate the widget details cy.findByTestId('linegraph-wrapper') - .as('canvas') .should('be.visible') .find('tbody tr') .each(($tr) => { @@ -443,56 +492,3 @@ const getWidgetLegendRowValuesFromResponse = ( return { average: roundedAverage, last: roundedLast, max: roundedMax }; }; -/** - * Compares actual widget values to the expected values and asserts their equality. - * - * @param actualValues - The actual values retrieved from the widget, consisting of: - * @param actualValues.max - The maximum value shown on the widget. - * @param actualValues.average - The average value shown on the widget. - * @param actualValues.last - The last or most recent value shown on the widget. - * - * @param expectedValues - The expected values that the widget should display, consisting of: - * @param expectedValues.max - The expected maximum value. - * @param expectedValues.average - The expected average value. - * @param expectedValues.last - The expected last or most recent value. - */ - -const compareWidgetValues = ( - actualValues: { title: string; max: number; average: number; last: number }, - expectedValues: { max: number; average: number; last: number }, - title: string -) => { - - - - const { title: actualTitle, max: actualMax, - average: actualAverage, last: actualLast, - } = actualValues; - - const { max: expectedMax, - average: expectedAverage, last: expectedLast, - } = expectedValues; - - - expect(actualMax).to.equal( - expectedMax, - `Expected ${expectedMax} for max, but got ${actualMax}` - ); - expect(actualAverage).to.equal( - expectedAverage, - `Expected ${expectedAverage} for average, but got ${actualAverage}` - ); - expect(actualLast).to.equal( - expectedLast, - `Expected ${expectedLast} for last, but got ${actualLast}` - ); - const extractedTitle = actualTitle.substring( - 0, - actualTitle.indexOf(' ', actualValues.title.indexOf(' ') + 1) - ); - - expect(extractedTitle).to.equal( - title, - `Expected ${title} for title ${extractedTitle}` - ); -}; diff --git a/packages/manager/cypress/support/constants/widgets.ts b/packages/manager/cypress/support/constants/widgets.ts index 39fe8ce5f30..a194244f1b7 100644 --- a/packages/manager/cypress/support/constants/widgets.ts +++ b/packages/manager/cypress/support/constants/widgets.ts @@ -1,7 +1,4 @@ -/** - * Defines the granularity levels used for specifying time intervals in data aggregation or reporting. - * Each property represents a different granularity level. - */ + export const widgetDetails = { dbaas: { diff --git a/packages/manager/cypress/support/intercepts/cloudpulse.ts b/packages/manager/cypress/support/intercepts/cloudpulse.ts index f9edcd78718..d91ca4688db 100644 --- a/packages/manager/cypress/support/intercepts/cloudpulse.ts +++ b/packages/manager/cypress/support/intercepts/cloudpulse.ts @@ -5,6 +5,8 @@ */ import { apiMatcher } from 'support/util/intercepts'; +import { randomString } from 'support/util/random'; +import { makeResponse } from 'support/util/response'; import type { CloudPulseMetricsResponse, @@ -23,11 +25,11 @@ import type { export const mockCloudPulseGetMetricDefinitions = ( metricDefinitions: MetricDefinitions, - service_type: string + serviceType: string ): Cypress.Chainable => { return cy.intercept( 'GET', - apiMatcher(`/monitor/services/${service_type}/metric-definitions`), + apiMatcher(`/monitor/services/${serviceType}/metric-definitions`), metricDefinitions ); }; @@ -59,11 +61,11 @@ export const mockCloudPulseServices = ( export const mockCloudPulseGetDashboards = ( dashboard: Dashboard, - service_type: string + serviceType: string ): Cypress.Chainable => { return cy.intercept( 'GET', - apiMatcher(`/monitor/services/${service_type}/dashboards`), + apiMatcher(`/monitor/services/${serviceType}/dashboards`), { data: [dashboard] } ); }; @@ -78,11 +80,11 @@ export const mockCloudPulseGetDashboards = ( */ export const mockCloudPulseCreateMetrics = ( mockResponse: CloudPulseMetricsResponse, - service_type: string + serviceType: string ): Cypress.Chainable => { return cy.intercept( 'POST', - `**/monitor/services/${service_type}/metrics`, + `**/monitor/services/${serviceType}/metrics`, mockResponse ); }; @@ -110,25 +112,24 @@ export const mockCloudPulseDashboardServicesResponse = ( }; /** - * Mocks the API response for generating a JWT token for a specific service. + * Mocks the API response for generating a JWE token for a specific service. * * This function sets up an interception for POST requests to the endpoint that generates - * JWT tokens for a particular service type. By returning a mock JWT token, you can test + * JWE tokens for a particular service type. By returning a mock JWE token, you can test * how your application handles authentication and authorization without making actual network * requests to the backend service. * - * @param {string} service_type - The type of service for which to mock the JWT token request. + * @param {string} service_type - The type of service for which to mock the JWE token request. * @returns {Cypress.Chainable} - Returns a Cypress chainable object, enabling command chaining in tests. */ -const JWSToken = { - token: 'eyJhbGciOiAiZGlyIiwgImVuYyI6ICJBMTI4Q0JDLUhTMjU2IiwgImtpZCI6ID', -}; export const mockCloudPulseJWSToken = ( - service_type: string + serviceType: string, + token?: string ): Cypress.Chainable => { + const mockToken = token ?? randomString(62); return cy.intercept( 'POST', - apiMatcher(`/monitor/services/${service_type}/token`), - JWSToken + apiMatcher(`/monitor/services/${serviceType}/token`), + makeResponse({ token: mockToken }) ); }; From 30431eb6e9e3d32c16aa7cf460449eb68cf8a53b Mon Sep 17 00:00:00 2001 From: agorthi Date: Tue, 1 Oct 2024 09:28:34 +0530 Subject: [PATCH 107/474] upcoming:[DI-20585]- Added code review comments --- .../core/cloudpulse/linode-widget-verification.spec.ts | 8 +++----- packages/manager/cypress/support/constants/widgets.ts | 2 -- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 51769da307a..bc6b5b9c828 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -195,14 +195,12 @@ describe('Integration Tests for Linode Dashboard ', () => { cy.findByText(resource).should('be.visible'); - // Verifies that the expected widgets are loaded on the dashboard. - metrics.forEach(({ title, unit }) => { + for (const { title, unit } of metrics) { const widgetSelector = `[data-qa-widget-header="${title}"]`; cy.get(widgetSelector).should('have.text', `${title} (${unit.trim()})`).should('be.visible'); - - }); + } }); - + it('should allow users to select desired granularity and see the most recent data from the API reflected in the graph', () => { diff --git a/packages/manager/cypress/support/constants/widgets.ts b/packages/manager/cypress/support/constants/widgets.ts index a194244f1b7..aebf90b1233 100644 --- a/packages/manager/cypress/support/constants/widgets.ts +++ b/packages/manager/cypress/support/constants/widgets.ts @@ -1,5 +1,3 @@ - - export const widgetDetails = { dbaas: { clusterName: 'mysql-cluster', From 042849164181dca10eaee4c9e4036e03365eee75 Mon Sep 17 00:00:00 2001 From: agorthi Date: Tue, 1 Oct 2024 10:42:42 +0530 Subject: [PATCH 108/474] upcoming:[DI-20585]- Added code review comments --- .../linode-widget-verification.spec.ts | 268 +++++------------- .../cypress/support/constants/widgets.ts | 4 +- .../cypress/support/intercepts/cloudpulse.ts | 26 +- 3 files changed, 92 insertions(+), 206 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index bc6b5b9c828..f1a1f28ccb0 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -31,6 +31,7 @@ import { extendRegion } from 'support/util/regions'; import { CloudPulseMetricsResponse } from '@linode/api-v4'; import { transformData } from 'src/features/CloudPulse/Utils/unitConversion'; import { getMetrics } from 'src/utilities/statMetrics'; +import { Interception } from 'cypress/types/net-stubbing'; /** * This test ensures that widget titles are displayed correctly on the dashboard. @@ -96,54 +97,26 @@ const metricsAPIResponsePayload = cloudPulseMetricsResponseFactory.build({ '5 min') }); /** - * Compares actual widget values to the expected values and asserts their equality. + * `verifyWidgetValues` processes and verifies the metric values of a widget from the provided response payload. * - * @param actualValues - The actual values retrieved from the widget, consisting of: - * @param actualValues.max - The maximum value shown on the widget. - * @param actualValues.average - The average value shown on the widget. - * @param actualValues.last - The last or most recent value shown on the widget. + * This method performs the following steps: + * 1. Transforms the raw data from the response payload into a more manageable format using `transformData`. + * 2. Extracts key metrics (average, last, and max) from the transformed data using `getMetrics`. + * 3. Rounds these metrics to two decimal places for accuracy. + * 4. Returns an object containing the rounded average, last, and max values for further verification or comparison. * - * @param expectedValues - The expected values that the widget should display, consisting of: - * @param expectedValues.max - The expected maximum value. - * @param expectedValues.average - The expected average value. - * @param expectedValues.last - The expected last or most recent value. + * @param {CloudPulseMetricsResponse} responsePayload - The response payload containing metric data for a widget. + * @returns {Object} An object with the rounded average, last, and max metric values. */ - -const compareWidgetValues = ( - actualValues: { title: string; max: number; average: number; last: number }, - expectedValues: { max: number; average: number; last: number }, - title: string +const getWidgetLegendRowValuesFromResponse = ( + responsePayload: CloudPulseMetricsResponse ) => { - - const { title: actualTitle, max: actualMax, - average: actualAverage, last: actualLast, - } = actualValues; - - const { max: expectedMax, - average: expectedAverage, last: expectedLast, - } = expectedValues; - - expect(actualMax).to.equal( - expectedMax, - `Expected ${expectedMax} for max, but got ${actualMax}` - ); - expect(actualAverage).to.equal( - expectedAverage, - `Expected ${expectedAverage} for average, but got ${actualAverage}` - ); - expect(actualLast).to.equal( - expectedLast, - `Expected ${expectedLast} for last, but got ${actualLast}` - ); - const extractedTitle = actualTitle.substring( - 0, - actualTitle.indexOf(' ', actualValues.title.indexOf(' ') + 1) - ); - - expect(extractedTitle).to.equal( - title, - `Expected ${title} for title ${extractedTitle}` - ); + const data = transformData(responsePayload.data.result[0].values, 'Bytes'); + const { average, last, max } = getMetrics(data); + const roundedAverage = Math.round(average * 100) / 100; + const roundedLast = Math.round(last * 100) / 100; + const roundedMax = Math.round(max * 100) / 100; + return { average: roundedAverage, last: roundedLast, max: roundedMax }; }; @@ -247,32 +220,15 @@ describe('Integration Tests for Linode Dashboard ', () => { //validate the widget line graph is present and its legend rows cy.findByTestId('linegraph-wrapper') - .should('be.visible') - .find('tbody tr') - .each(($tr) => { - const cells = $tr - .find('td') - .map((_i, el) => { - const text = Cypress.$(el).text().trim(); - return text.replace(/^\s*\([^)]+\)/, ''); - }) - .get(); - const [title, actualMax, actualAvg, actualLast] = cells; // the average, max and last present in the widget - const widgetValues = getWidgetLegendRowValuesFromResponse( - metricsAPIResponsePayload - ); // the average, max and last from the response payload - compareWidgetValues( - // compare both - { - title, - max: parseFloat(actualMax), - average: parseFloat(actualAvg), - last: parseFloat(actualLast), - }, - widgetValues, - testDataTitle + .within(() => { + const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( + metricsAPIResponsePayload ); - }); + cy.findByText(`${testData.title} (${testData.unit})`).should('be.visible'); + cy.findByText(`${expectedWidgetValues.max} ${testData.unit}`).should('be.visible'); + cy.findByText(`${expectedWidgetValues.average} ${testData.unit}`).should('be.visible'); + cy.findByText(`${expectedWidgetValues.last} ${testData.unit}`).should('be.visible'); + }); }); } }); @@ -320,71 +276,45 @@ describe('Integration Tests for Linode Dashboard ', () => { //validate the widget line graph is present and its legend rows cy.findByTestId('linegraph-wrapper') - .should('be.visible') - .find('tbody tr') - .each(($tr) => { - const cells = $tr - .find('td') - .map((_i, el) => { - const text = Cypress.$(el).text().trim(); - return text.replace(/^\s*\([^)]+\)/, ''); - }) - .get(); - const [title, actualMax, actualAvg, actualLast] = cells; // the average, max and last present in the widget - const widgetValues = getWidgetLegendRowValuesFromResponse( - metricsAPIResponsePayload - ); // the average, max and last from the response payload - compareWidgetValues( - // compare both - { - title, - max: parseFloat(actualMax), - average: parseFloat(actualAvg), - last: parseFloat(actualLast), - }, - widgetValues, - testDataTitle + .within(() => { + const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( + metricsAPIResponsePayload ); - }); + cy.findByText(`${testData.title} (${testData.unit})`).should('be.visible'); + cy.findByText(`${expectedWidgetValues.max} ${testData.unit}`).should('be.visible'); + cy.findByText(`${expectedWidgetValues.average} ${testData.unit}`).should('be.visible'); + cy.findByText(`${expectedWidgetValues.last} ${testData.unit}`).should('be.visible'); + }); }); } }); it('should trigger the global refresh button and verify the corresponding network calls', () => { cy.wait(7000); //maintaining the wait since page flicker and rendering - - // click the global refresh button - ui.button - .findByAttribute('aria-label', 'Refresh Dashboard Metrics') - .should('be.visible') - .click(); - - // validate the API calls are going with intended payload - cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']).then( - (interceptions) => { - const interceptionsArray = Array.isArray(interceptions) - ? interceptions - : [interceptions]; - interceptionsArray.forEach((interception) => { - const { body: requestPayload } = interception.request; - const { metric, relative_time_duration: timeRange } = requestPayload; - const metricData = metrics.find(({ name }) => name === metric); - if (!metricData) { - expect.fail( - 'metricData or its expected properties are not defined.' - ); - } - const expectedRelativeTimeDuration = timeRange - ? `Last ${timeRange.value} ${['hour', 'hr'].includes(timeRange.unit.toLowerCase()) - ? 'Hours' - : timeRange.unit - }` - : ''; - expect(metric).to.equal(metricData.name); - expect(expectedRelativeTimeDuration).to.equal(timeDurationToSelect); - }); + mockCloudPulseCreateMetrics(metricsAPIResponsePayload, serviceType).as('refreshMetrics'); + // click the global refresh button + ui.button + .findByAttribute('aria-label', 'Refresh Dashboard Metrics') + .should('be.visible') + .click(); + + // validate the API calls are going with intended payload + cy.get('@refreshMetrics.all') + .should('have.length', 4) + .each((xhr: unknown) => { + const interception = xhr as Interception; + const { body: requestPayload } = interception.request; + const { metric, relative_time_duration: timeRange } = requestPayload; + const metricData = metrics.find(({ name }) => name === metric); + + if (!metricData) { + throw new Error(`Unexpected metric name '${metric}' included in the outgoing refresh API request`); } - ); - }); + expect(metric).to.equal(metricData.name); + expect(timeRange).to.have.property('unit', 'hr'); + expect(timeRange).to.have.property('value', 24); + }); +}); + it('should zoom in and out of all the widgets', () => { // do zoom in and zoom out test on all the widgets @@ -407,28 +337,15 @@ describe('Integration Tests for Linode Dashboard ', () => { // validate the widget details cy.findByTestId('linegraph-wrapper') - .should('be.visible') - .find('tbody tr') - .each(($tr) => { - const cells = $tr - .find('td') - .map((_i, el) => Cypress.$(el).text().trim()) - .get(); - const [title, actualMax, actualAvg, actualLast] = cells; - const widgetValues = getWidgetLegendRowValuesFromResponse( - metricsAPIResponsePayload - ); - compareWidgetValues( - { - title, - max: parseFloat(actualMax), - average: parseFloat(actualAvg), - last: parseFloat(actualLast), - }, - widgetValues, - testDataTitle - ); - }); + .within(() => { + const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( + metricsAPIResponsePayload + ); + cy.findByText(`${testData.title} (${testData.unit})`).should('be.visible'); + cy.findByText(`${expectedWidgetValues.max} ${testData.unit}`).should('be.visible'); + cy.findByText(`${expectedWidgetValues.average} ${testData.unit}`).should('be.visible'); + cy.findByText(`${expectedWidgetValues.last} ${testData.unit}`).should('be.visible'); + }); // click zoom out and validate the same ui.button @@ -440,53 +357,18 @@ describe('Integration Tests for Linode Dashboard ', () => { // validate the widget details cy.findByTestId('linegraph-wrapper') - .should('be.visible') - .find('tbody tr') - .each(($tr) => { - const cells = $tr - .find('td') - .map((i, el) => Cypress.$(el).text().trim()) - .get(); - const [title, actualMax, actualAvg, actualLast] = cells; - const widgetValues = getWidgetLegendRowValuesFromResponse( - metricsAPIResponsePayload - ); - cy.log('testDataTitle', testDataTitle) - compareWidgetValues( - { - title, - max: parseFloat(actualMax), - average: parseFloat(actualAvg), - last: parseFloat(actualLast), - }, - widgetValues, - testDataTitle + .within(() => { + const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( + metricsAPIResponsePayload ); - }); + cy.findByText(`${testData.title} (${testData.unit})`).should('be.visible'); + cy.findByText(`${expectedWidgetValues.max} ${testData.unit}`).should('be.visible'); + cy.findByText(`${expectedWidgetValues.average} ${testData.unit}`).should('be.visible'); + cy.findByText(`${expectedWidgetValues.last} ${testData.unit}`).should('be.visible'); + }); }); }); }); }); -/** - * `verifyWidgetValues` processes and verifies the metric values of a widget from the provided response payload. - * - * This method performs the following steps: - * 1. Transforms the raw data from the response payload into a more manageable format using `transformData`. - * 2. Extracts key metrics (average, last, and max) from the transformed data using `getMetrics`. - * 3. Rounds these metrics to two decimal places for accuracy. - * 4. Returns an object containing the rounded average, last, and max values for further verification or comparison. - * - * @param {CloudPulseMetricsResponse} responsePayload - The response payload containing metric data for a widget. - * @returns {Object} An object with the rounded average, last, and max metric values. - */ -const getWidgetLegendRowValuesFromResponse = ( - responsePayload: CloudPulseMetricsResponse -) => { - const data = transformData(responsePayload.data.result[0].values, 'Bytes'); - const { average, last, max } = getMetrics(data); - const roundedAverage = Math.round(average * 100) / 100; - const roundedLast = Math.round(last * 100) / 100; - const roundedMax = Math.round(max * 100) / 100; - return { average: roundedAverage, last: roundedLast, max: roundedMax }; -}; + diff --git a/packages/manager/cypress/support/constants/widgets.ts b/packages/manager/cypress/support/constants/widgets.ts index aebf90b1233..96c7d4f1720 100644 --- a/packages/manager/cypress/support/constants/widgets.ts +++ b/packages/manager/cypress/support/constants/widgets.ts @@ -66,7 +66,7 @@ export const widgetDetails = { expectedGranularity: '1 hr', name: 'system_memory_usage_by_resource', title: 'Memory Usage', - unit: 'Bytes', + unit: 'B', yLabel: 'system_memory_usage_bytes', }, { @@ -75,7 +75,7 @@ export const widgetDetails = { expectedGranularity: '1 hr', name: 'system_network_io_by_resource', title: 'Network Traffic', - unit: 'Bytes', + unit: 'B', yLabel: 'system_network_io_bytes_total', }, { diff --git a/packages/manager/cypress/support/intercepts/cloudpulse.ts b/packages/manager/cypress/support/intercepts/cloudpulse.ts index d91ca4688db..30d147794fa 100644 --- a/packages/manager/cypress/support/intercepts/cloudpulse.ts +++ b/packages/manager/cypress/support/intercepts/cloudpulse.ts @@ -5,6 +5,7 @@ */ import { apiMatcher } from 'support/util/intercepts'; +import { paginateResponse } from 'support/util/paginate'; import { randomString } from 'support/util/random'; import { makeResponse } from 'support/util/response'; @@ -15,7 +16,7 @@ import type { } from '@linode/api-v4'; /** - * Intercepts HTTP GET requests for metric definitions. + * Intercepts GET requests for metric definitions. * * This function mocks the API response for requests to the endpoint * `dashboardMetricsData`. @@ -35,7 +36,7 @@ export const mockCloudPulseGetMetricDefinitions = ( }; /** - * Intercepts HTTP GET requests for metric definitions. + * Intercepts GET requests for metric definitions. * * This function mocks the API response for requests to the endpoint * `dashboardMetricsData`. @@ -50,23 +51,24 @@ export const mockCloudPulseServices = ( data: [{ service_type }], }); }; + /** - * Intercepts HTTP GET requests for dashboard definitions. - * - * This function mocks the API response for requests to the endpoint - * `dashboardDefinitions`. - * - * @returns {Cypress.Chainable} The chainable Cypress object. - */ ++ * Intercepts GET requests to fetch dashboards and mocks response. ++ * ++ * @param dashboards - Array of Dashboard objects with which to mock response. ++ * @param serviceType - Service type for which to intercept dashboard request. ++ * ++ * @returns The chainable Cypress object. ++ */ export const mockCloudPulseGetDashboards = ( - dashboard: Dashboard, + dashboards: Dashboard[], serviceType: string ): Cypress.Chainable => { return cy.intercept( 'GET', apiMatcher(`/monitor/services/${serviceType}/dashboards`), - { data: [dashboard] } + paginateResponse(dashboards) ); }; @@ -88,6 +90,7 @@ export const mockCloudPulseCreateMetrics = ( mockResponse ); }; + /** * Mocks the API response for fetching a dashboard. * @@ -122,6 +125,7 @@ export const mockCloudPulseDashboardServicesResponse = ( * @param {string} service_type - The type of service for which to mock the JWE token request. * @returns {Cypress.Chainable} - Returns a Cypress chainable object, enabling command chaining in tests. */ + export const mockCloudPulseJWSToken = ( serviceType: string, token?: string From 3aa509525110211e0dd31acbf89d0f309636c1cc Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 1 Oct 2024 10:48:04 +0530 Subject: [PATCH 109/474] tests: [DI-20585] - Removed widget header title --- .../core/cloudpulse/linode-widget-verification.spec.ts | 6 ++++-- .../src/features/CloudPulse/Widget/CloudPulseWidget.tsx | 8 +------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index bc6b5b9c828..882c7911c44 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -196,8 +196,10 @@ describe('Integration Tests for Linode Dashboard ', () => { cy.findByText(resource).should('be.visible'); for (const { title, unit } of metrics) { - const widgetSelector = `[data-qa-widget-header="${title}"]`; - cy.get(widgetSelector).should('have.text', `${title} (${unit.trim()})`).should('be.visible'); + const widgetSelector = `[data-qa-widget="${title}"]`; + cy.get(widgetSelector) + .find('h2') + .should('have.text', `${title} (${unit.trim()})`).should('be.visible'); } }); diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 0c820cd2900..0bfed8b7343 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -304,13 +304,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { marginBottom={1} padding={1} > - + {convertStringToCamelCasesWithSpaces(widget.label)} ({currentUnit} {unit.endsWith('ps') ? '/s' : ''}) From e415b58d4325b45eecd44312fcd231c7383fd085 Mon Sep 17 00:00:00 2001 From: agorthi Date: Tue, 1 Oct 2024 11:06:35 +0530 Subject: [PATCH 110/474] upcoming:[DI-20585]- Added code review comments --- .../e2e/core/cloudpulse/linode-widget-verification.spec.ts | 4 ++-- packages/manager/src/factories/dashboards.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index f1a1f28ccb0..691ad27987b 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -17,7 +17,7 @@ import { cloudPulseMetricsResponseFactory, dashboardFactory, dashboardMetricFactory, - generateValues, + generateRandomMetricsData, kubeLinodeFactory, linodeFactory, regionFactory, @@ -93,7 +93,7 @@ const mockRegion = extendRegion( }) ); const metricsAPIResponsePayload = cloudPulseMetricsResponseFactory.build({ - data: generateValues(timeDurationToSelect, + data: generateRandomMetricsData(timeDurationToSelect, '5 min') }); /** diff --git a/packages/manager/src/factories/dashboards.ts b/packages/manager/src/factories/dashboards.ts index fb607a70e48..aa9e277c9d9 100644 --- a/packages/manager/src/factories/dashboards.ts +++ b/packages/manager/src/factories/dashboards.ts @@ -154,7 +154,7 @@ export const dashboardMetricFactory = Factory.Sync.makeFactory } ); // Function to generate random values based on the number of points -export const generateValues = ( +export const generateRandomMetricsData = ( time: string, granularityData: string ): CloudPulseMetricsResponseData => { From 7daf9d07059dca066a6c998943886d925c6d70b7 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 1 Oct 2024 12:12:39 +0530 Subject: [PATCH 111/474] upcoming: [DI-20800] - As per dev --- package.json | 18 +- packages/api-v4/package.json | 5 +- .../CloudPulse/Utils/UserPreference.ts | 1 - .../shared/CloudPulseTimeRangeSelect.tsx | 10 +- yarn.lock | 5873 ++++++----------- 5 files changed, 2015 insertions(+), 3892 deletions(-) diff --git a/package.json b/package.json index 3892b7c4d14..92048af4679 100644 --- a/package.json +++ b/package.json @@ -37,27 +37,15 @@ "generate-changelogs": "node scripts/changelog/generate-changelogs.mjs", "coverage": "yarn workspace linode-manager coverage", "coverage:summary": "yarn workspace linode-manager coverage:summary", - "junit:summary": "ts-node scripts/junit-summary/index.ts", - "generate-tod": "ts-node scripts/tod-payload/index.ts", + "junit:summary": "tsx scripts/junit-summary/index.ts", + "generate-tod": "tsx scripts/tod-payload/index.ts", "docs": "bunx vitepress@1.0.0-rc.44 dev docs", "prepare": "husky" }, "resolutions": { - "braces": "^3.0.3", - "@babel/traverse": "^7.23.3", - "minimist": "^1.2.3", - "yargs-parser": "^21.1.1", - "kind-of": "^6.0.3", "node-fetch": "^2.6.7", - "ua-parser-js": "^0.7.33", - "immer": "^9.0.6", - "glob-parent": "^5.1.2", - "hosted-git-info": "^5.0.0", "yaml": "^2.3.0", - "word-wrap": "^1.2.4", - "semver": "^7.5.2", - "tough-cookie": "^4.1.3", - "jackspeak": "2.1.1" + "semver": "^7.5.2" }, "workspaces": { "packages": [ diff --git a/packages/api-v4/package.json b/packages/api-v4/package.json index 31e59148235..daea28b7dd8 100644 --- a/packages/api-v4/package.json +++ b/packages/api-v4/package.json @@ -1,6 +1,6 @@ { "name": "@linode/api-v4", - "version": "0.126.0", + "version": "0.127.0", "homepage": "https://github.com/linode/manager/tree/develop/packages/api-v4", "bugs": { "url": "https://github.com/linode/manager/issues" @@ -60,9 +60,8 @@ "@types/node": "^12.7.1", "@types/yup": "^0.29.13", "axios-mock-adapter": "^1.22.0", - "concurrently": "^4.1.1", + "concurrently": "^9.0.1", "eslint": "^6.8.0", - "eslint-plugin-ramda": "^2.5.1", "eslint-plugin-sonarjs": "^0.5.0", "lint-staged": "^15.2.9", "prettier": "~2.2.1", diff --git a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts index 18550ae5f25..3b15045f202 100644 --- a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts +++ b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts @@ -37,7 +37,6 @@ export const useAclpPreference = (): AclpPreferenceObject => { if (keys.includes(DASHBOARD_ID)) { currentPreferences = { ...data, - [TIME_DURATION]: currentPreferences[TIME_DURATION], [WIDGETS]: {}, }; } else { diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx index 8c288622307..5fa8ab4b81a 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx @@ -2,6 +2,8 @@ import * as React from 'react'; import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; +import { DASHBOARD_ID, TIME_DURATION } from '../Utils/constants'; + import type { FilterValue, TimeDuration } from '@linode/api-v4'; import type { BaseSelectProps, @@ -43,7 +45,7 @@ export const CloudPulseTimeRangeSelect = React.memo( return options[0]; } return options.find((o) => o.label === defaultValue) || options[0]; - }, []); + }, [defaultValue]); const [selectedTimeRange, setSelectedTimeRange] = React.useState< Item >(getDefaultValue()); @@ -58,8 +60,12 @@ export const CloudPulseTimeRangeSelect = React.memo( false ); } + + if (item !== selectedTimeRange) { + setSelectedTimeRange(item); + } // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); // need to execute only once, during mounting of this component + }, [defaultValue]); // need to execute only once, during mounting of this component const handleChange = (item: Item) => { setSelectedTimeRange(item); diff --git a/yarn.lock b/yarn.lock index 500b2eb2530..25ba08eb0c2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,129 +2,133 @@ # yarn lockfile v1 -"@aashutoshrathi/word-wrap@^1.2.3": - version "1.2.6" - resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" - integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== - -"@adobe/css-tools@^4.3.2": - version "4.3.3" - resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.3.3.tgz#90749bde8b89cd41764224f5aac29cd4138f75ff" - integrity sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ== - -"@algolia/cache-browser-local-storage@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.22.1.tgz#14b6dc9abc9e3a304a5fffb063d15f30af1032d1" - integrity sha512-Sw6IAmOCvvP6QNgY9j+Hv09mvkvEIDKjYW8ow0UDDAxSXy664RBNQk3i/0nt7gvceOJ6jGmOTimaZoY1THmU7g== - dependencies: - "@algolia/cache-common" "4.22.1" - -"@algolia/cache-common@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.22.1.tgz#c625dff4bc2a74e79f9aed67b4e053b0ef1b3ec1" - integrity sha512-TJMBKqZNKYB9TptRRjSUtevJeQVXRmg6rk9qgFKWvOy8jhCPdyNZV1nB3SKGufzvTVbomAukFR8guu/8NRKBTA== - -"@algolia/cache-in-memory@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.22.1.tgz#858a3d887f521362e87d04f3943e2810226a0d71" - integrity sha512-ve+6Ac2LhwpufuWavM/aHjLoNz/Z/sYSgNIXsinGofWOysPilQZPUetqLj8vbvi+DHZZaYSEP9H5SRVXnpsNNw== - dependencies: - "@algolia/cache-common" "4.22.1" - -"@algolia/client-account@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.22.1.tgz#a7fb8b66b9a4f0a428e1426b2561144267d76d43" - integrity sha512-k8m+oegM2zlns/TwZyi4YgCtyToackkOpE+xCaKCYfBfDtdGOaVZCM5YvGPtK+HGaJMIN/DoTL8asbM3NzHonw== - dependencies: - "@algolia/client-common" "4.22.1" - "@algolia/client-search" "4.22.1" - "@algolia/transporter" "4.22.1" - -"@algolia/client-analytics@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.22.1.tgz#506558740b4d49b1b1e3393861f729a8ce921851" - integrity sha512-1ssi9pyxyQNN4a7Ji9R50nSdISIumMFDwKNuwZipB6TkauJ8J7ha/uO60sPJFqQyqvvI+px7RSNRQT3Zrvzieg== - dependencies: - "@algolia/client-common" "4.22.1" - "@algolia/client-search" "4.22.1" - "@algolia/requester-common" "4.22.1" - "@algolia/transporter" "4.22.1" - -"@algolia/client-common@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.22.1.tgz#042b19c1b6157c485fa1b551349ab313944d2b05" - integrity sha512-IvaL5v9mZtm4k4QHbBGDmU3wa/mKokmqNBqPj0K7lcR8ZDKzUorhcGp/u8PkPC/e0zoHSTvRh7TRkGX3Lm7iOQ== - dependencies: - "@algolia/requester-common" "4.22.1" - "@algolia/transporter" "4.22.1" - -"@algolia/client-personalization@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-4.22.1.tgz#ff088d797648224fb582e9fe5828f8087835fa3d" - integrity sha512-sl+/klQJ93+4yaqZ7ezOttMQ/nczly/3GmgZXJ1xmoewP5jmdP/X/nV5U7EHHH3hCUEHeN7X1nsIhGPVt9E1cQ== - dependencies: - "@algolia/client-common" "4.22.1" - "@algolia/requester-common" "4.22.1" - "@algolia/transporter" "4.22.1" - -"@algolia/client-search@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.22.1.tgz#508cc6ab3d1f4e9c02735a630d4dff6fbb8514a2" - integrity sha512-yb05NA4tNaOgx3+rOxAmFztgMTtGBi97X7PC3jyNeGiwkAjOZc2QrdZBYyIdcDLoI09N0gjtpClcackoTN0gPA== - dependencies: - "@algolia/client-common" "4.22.1" - "@algolia/requester-common" "4.22.1" - "@algolia/transporter" "4.22.1" - -"@algolia/logger-common@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.22.1.tgz#79cf4cd295de0377a94582c6aaac59b1ded731d9" - integrity sha512-OnTFymd2odHSO39r4DSWRFETkBufnY2iGUZNrMXpIhF5cmFE8pGoINNPzwg02QLBlGSaLqdKy0bM8S0GyqPLBg== - -"@algolia/logger-console@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.22.1.tgz#0355345f6940f67aaa78ae9b81c06e44e49f2336" - integrity sha512-O99rcqpVPKN1RlpgD6H3khUWylU24OXlzkavUAMy6QZd1776QAcauE3oP8CmD43nbaTjBexZj2nGsBH9Tc0FVA== - dependencies: - "@algolia/logger-common" "4.22.1" - -"@algolia/requester-browser-xhr@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.22.1.tgz#f04df6fe9690a071b267c77d26b83a3be9280361" - integrity sha512-dtQGYIg6MteqT1Uay3J/0NDqD+UciHy3QgRbk7bNddOJu+p3hzjTRYESqEnoX/DpEkaNYdRHUKNylsqMpgwaEw== - dependencies: - "@algolia/requester-common" "4.22.1" - -"@algolia/requester-common@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.22.1.tgz#27be35f3718aafcb6b388ff9c3aa2defabd559ff" - integrity sha512-dgvhSAtg2MJnR+BxrIFqlLtkLlVVhas9HgYKMk2Uxiy5m6/8HZBL40JVAMb2LovoPFs9I/EWIoFVjOrFwzn5Qg== - -"@algolia/requester-node-http@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.22.1.tgz#589a6fa828ad0f325e727a6fcaf4e1a2343cc62b" - integrity sha512-JfmZ3MVFQkAU+zug8H3s8rZ6h0ahHZL/SpMaSasTCGYR5EEJsCc8SI5UZ6raPN2tjxa5bxS13BRpGSBUens7EA== - dependencies: - "@algolia/requester-common" "4.22.1" - -"@algolia/transporter@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.22.1.tgz#8843841b857dc021668f31647aa557ff19cd9cb1" - integrity sha512-kzWgc2c9IdxMa3YqA6TN0NW5VrKYYW/BELIn7vnLyn+U/RFdZ4lxxt9/8yq3DKV5snvoDzzO4ClyejZRdV3lMQ== - dependencies: - "@algolia/cache-common" "4.22.1" - "@algolia/logger-common" "4.22.1" - "@algolia/requester-common" "4.22.1" - -"@ampproject/remapping@^2.2.0": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" - integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== - dependencies: - "@jridgewell/gen-mapping" "^0.3.0" - "@jridgewell/trace-mapping" "^0.3.9" - -"@ampproject/remapping@^2.3.0": +"@adobe/css-tools@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.4.0.tgz#728c484f4e10df03d5a3acd0d8adcbbebff8ad63" + integrity sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ== + +"@algolia/cache-browser-local-storage@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.24.0.tgz#97bc6d067a9fd932b9c922faa6b7fd6e546e1348" + integrity sha512-t63W9BnoXVrGy9iYHBgObNXqYXM3tYXCjDSHeNwnsc324r4o5UiVKUiAB4THQ5z9U5hTj6qUvwg/Ez43ZD85ww== + dependencies: + "@algolia/cache-common" "4.24.0" + +"@algolia/cache-common@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.24.0.tgz#81a8d3a82ceb75302abb9b150a52eba9960c9744" + integrity sha512-emi+v+DmVLpMGhp0V9q9h5CdkURsNmFC+cOS6uK9ndeJm9J4TiqSvPYVu+THUP8P/S08rxf5x2P+p3CfID0Y4g== + +"@algolia/cache-in-memory@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.24.0.tgz#ffcf8872f3a10cb85c4f4641bdffd307933a6e44" + integrity sha512-gDrt2so19jW26jY3/MkFg5mEypFIPbPoXsQGQWAi6TrCPsNOSEYepBMPlucqWigsmEy/prp5ug2jy/N3PVG/8w== + dependencies: + "@algolia/cache-common" "4.24.0" + +"@algolia/client-account@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.24.0.tgz#eba7a921d828e7c8c40a32d4add21206c7fe12f1" + integrity sha512-adcvyJ3KjPZFDybxlqnf+5KgxJtBjwTPTeyG2aOyoJvx0Y8dUQAEOEVOJ/GBxX0WWNbmaSrhDURMhc+QeevDsA== + dependencies: + "@algolia/client-common" "4.24.0" + "@algolia/client-search" "4.24.0" + "@algolia/transporter" "4.24.0" + +"@algolia/client-analytics@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.24.0.tgz#9d2576c46a9093a14e668833c505ea697a1a3e30" + integrity sha512-y8jOZt1OjwWU4N2qr8G4AxXAzaa8DBvyHTWlHzX/7Me1LX8OayfgHexqrsL4vSBcoMmVw2XnVW9MhL+Y2ZDJXg== + dependencies: + "@algolia/client-common" "4.24.0" + "@algolia/client-search" "4.24.0" + "@algolia/requester-common" "4.24.0" + "@algolia/transporter" "4.24.0" + +"@algolia/client-common@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.24.0.tgz#77c46eee42b9444a1d1c1583a83f7df4398a649d" + integrity sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA== + dependencies: + "@algolia/requester-common" "4.24.0" + "@algolia/transporter" "4.24.0" + +"@algolia/client-personalization@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-4.24.0.tgz#8b47789fb1cb0f8efbea0f79295b7c5a3850f6ae" + integrity sha512-l5FRFm/yngztweU0HdUzz1rC4yoWCFo3IF+dVIVTfEPg906eZg5BOd1k0K6rZx5JzyyoP4LdmOikfkfGsKVE9w== + dependencies: + "@algolia/client-common" "4.24.0" + "@algolia/requester-common" "4.24.0" + "@algolia/transporter" "4.24.0" + +"@algolia/client-search@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.24.0.tgz#75e6c02d33ef3e0f34afd9962c085b856fc4a55f" + integrity sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA== + dependencies: + "@algolia/client-common" "4.24.0" + "@algolia/requester-common" "4.24.0" + "@algolia/transporter" "4.24.0" + +"@algolia/logger-common@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.24.0.tgz#28d439976019ec0a46ba7a1a739ef493d4ef8123" + integrity sha512-LLUNjkahj9KtKYrQhFKCzMx0BY3RnNP4FEtO+sBybCjJ73E8jNdaKJ/Dd8A/VA4imVHP5tADZ8pn5B8Ga/wTMA== + +"@algolia/logger-console@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.24.0.tgz#c6ff486036cd90b81d07a95aaba04461da7e1c65" + integrity sha512-X4C8IoHgHfiUROfoRCV+lzSy+LHMgkoEEU1BbKcsfnV0i0S20zyy0NLww9dwVHUWNfPPxdMU+/wKmLGYf96yTg== + dependencies: + "@algolia/logger-common" "4.24.0" + +"@algolia/recommend@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/recommend/-/recommend-4.24.0.tgz#8a3f78aea471ee0a4836b78fd2aad4e9abcaaf34" + integrity sha512-P9kcgerfVBpfYHDfVZDvvdJv0lEoCvzNlOy2nykyt5bK8TyieYyiD0lguIJdRZZYGre03WIAFf14pgE+V+IBlw== + dependencies: + "@algolia/cache-browser-local-storage" "4.24.0" + "@algolia/cache-common" "4.24.0" + "@algolia/cache-in-memory" "4.24.0" + "@algolia/client-common" "4.24.0" + "@algolia/client-search" "4.24.0" + "@algolia/logger-common" "4.24.0" + "@algolia/logger-console" "4.24.0" + "@algolia/requester-browser-xhr" "4.24.0" + "@algolia/requester-common" "4.24.0" + "@algolia/requester-node-http" "4.24.0" + "@algolia/transporter" "4.24.0" + +"@algolia/requester-browser-xhr@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.24.0.tgz#313c5edab4ed73a052e75803855833b62dd19c16" + integrity sha512-Z2NxZMb6+nVXSjF13YpjYTdvV3032YTBSGm2vnYvYPA6mMxzM3v5rsCiSspndn9rzIW4Qp1lPHBvuoKJV6jnAA== + dependencies: + "@algolia/requester-common" "4.24.0" + +"@algolia/requester-common@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.24.0.tgz#1c60c198031f48fcdb9e34c4057a3ea987b9a436" + integrity sha512-k3CXJ2OVnvgE3HMwcojpvY6d9kgKMPRxs/kVohrwF5WMr2fnqojnycZkxPoEg+bXm8fi5BBfFmOqgYztRtHsQA== + +"@algolia/requester-node-http@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.24.0.tgz#4461593714031d02aa7da221c49df675212f482f" + integrity sha512-JF18yTjNOVYvU/L3UosRcvbPMGT9B+/GQWNWnenIImglzNVGpyzChkXLnrSf6uxwVNO6ESGu6oN8MqcGQcjQJw== + dependencies: + "@algolia/requester-common" "4.24.0" + +"@algolia/transporter@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.24.0.tgz#226bb1f8af62430374c1972b2e5c8580ab275102" + integrity sha512-86nI7w6NzWxd1Zp9q3413dRshDqAzSbsQjhcDhPIatEFiZrL1/TjnHL8S7jVKFePlIMzDsZWXAXwXzcok9c5oA== + dependencies: + "@algolia/cache-common" "4.24.0" + "@algolia/logger-common" "4.24.0" + "@algolia/requester-common" "4.24.0" + +"@ampproject/remapping@^2.2.0", "@ampproject/remapping@^2.3.0": version "2.3.0" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== @@ -139,15 +143,7 @@ dependencies: "@babel/highlight" "^7.10.4" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" - integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== - dependencies: - "@babel/highlight" "^7.23.4" - chalk "^2.4.2" - -"@babel/code-frame@^7.24.7": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== @@ -155,43 +151,33 @@ "@babel/highlight" "^7.24.7" picocolors "^1.0.0" -"@babel/compat-data@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.5.tgz#ffb878728bb6bdcb6f4510aa51b1be9afb8cfd98" - integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw== +"@babel/compat-data@^7.25.2": + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.4.tgz#7d2a80ce229890edcf4cc259d4d696cb4dae2fcb" + integrity sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ== "@babel/core@^7.18.9", "@babel/core@^7.21.3": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.9.tgz#b028820718000f267870822fec434820e9b1e4d1" - integrity sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw== + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.2.tgz#ed8eec275118d7613e77a352894cd12ded8eba77" + integrity sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA== dependencies: "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.23.5" - "@babel/generator" "^7.23.6" - "@babel/helper-compilation-targets" "^7.23.6" - "@babel/helper-module-transforms" "^7.23.3" - "@babel/helpers" "^7.23.9" - "@babel/parser" "^7.23.9" - "@babel/template" "^7.23.9" - "@babel/traverse" "^7.23.9" - "@babel/types" "^7.23.9" + "@babel/code-frame" "^7.24.7" + "@babel/generator" "^7.25.0" + "@babel/helper-compilation-targets" "^7.25.2" + "@babel/helper-module-transforms" "^7.25.2" + "@babel/helpers" "^7.25.0" + "@babel/parser" "^7.25.0" + "@babel/template" "^7.25.0" + "@babel/traverse" "^7.25.2" + "@babel/types" "^7.25.2" convert-source-map "^2.0.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.23.6": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e" - integrity sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw== - dependencies: - "@babel/types" "^7.23.6" - "@jridgewell/gen-mapping" "^0.3.2" - "@jridgewell/trace-mapping" "^0.3.17" - jsesc "^2.5.1" - -"@babel/generator@^7.25.6": +"@babel/generator@^7.25.0", "@babel/generator@^7.25.6": version "7.25.6" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.6.tgz#0df1ad8cb32fe4d2b01d8bf437f153d19342a87c" integrity sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw== @@ -201,87 +187,65 @@ "@jridgewell/trace-mapping" "^0.3.25" jsesc "^2.5.1" -"@babel/helper-compilation-targets@^7.23.6": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz#4d79069b16cbcf1461289eccfbbd81501ae39991" - integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== +"@babel/helper-compilation-targets@^7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz#e1d9410a90974a3a5a66e84ff55ef62e3c02d06c" + integrity sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw== dependencies: - "@babel/compat-data" "^7.23.5" - "@babel/helper-validator-option" "^7.23.5" - browserslist "^4.22.2" + "@babel/compat-data" "^7.25.2" + "@babel/helper-validator-option" "^7.24.8" + browserslist "^4.23.1" lru-cache "^5.1.1" semver "^6.3.1" -"@babel/helper-environment-visitor@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" - integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== - -"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0" - integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== - dependencies: - "@babel/types" "^7.22.15" - -"@babel/helper-module-transforms@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz#d7d12c3c5d30af5b3c0fcab2a6d5217773e2d0f1" - integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ== +"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz#f2f980392de5b84c3328fc71d38bd81bbb83042b" + integrity sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA== dependencies: - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-module-imports" "^7.22.15" - "@babel/helper-simple-access" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/helper-validator-identifier" "^7.22.20" + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" -"@babel/helper-simple-access@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" - integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== +"@babel/helper-module-transforms@^7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz#ee713c29768100f2776edf04d4eb23b8d27a66e6" + integrity sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ== dependencies: - "@babel/types" "^7.22.5" + "@babel/helper-module-imports" "^7.24.7" + "@babel/helper-simple-access" "^7.24.7" + "@babel/helper-validator-identifier" "^7.24.7" + "@babel/traverse" "^7.25.2" -"@babel/helper-split-export-declaration@^7.22.6": - version "7.22.6" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" - integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== +"@babel/helper-simple-access@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz#bcade8da3aec8ed16b9c4953b74e506b51b5edb3" + integrity sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg== dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-string-parser@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" - integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" "@babel/helper-string-parser@^7.24.8": version "7.24.8" resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz#5b3329c9a58803d5df425e5785865881a81ca48d" integrity sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ== -"@babel/helper-validator-identifier@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" - integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== - "@babel/helper-validator-identifier@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== -"@babel/helper-validator-option@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" - integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== +"@babel/helper-validator-option@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz#3725cdeea8b480e86d34df15304806a06975e33d" + integrity sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q== -"@babel/helpers@^7.23.9": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.9.tgz#c3e20bbe7f7a7e10cb9b178384b4affdf5995c7d" - integrity sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ== +"@babel/helpers@^7.25.0": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.6.tgz#57ee60141829ba2e102f30711ffe3afab357cc60" + integrity sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q== dependencies: - "@babel/template" "^7.23.9" - "@babel/traverse" "^7.23.9" - "@babel/types" "^7.23.9" + "@babel/template" "^7.25.0" + "@babel/types" "^7.25.6" "@babel/highlight@^7.10.4", "@babel/highlight@^7.24.7": version "7.24.7" @@ -293,64 +257,20 @@ js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/highlight@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" - integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== - dependencies: - "@babel/helper-validator-identifier" "^7.22.20" - chalk "^2.4.2" - js-tokens "^4.0.0" - -"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.7.0": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.9.tgz#7b903b6149b0f8fa7ad564af646c4c38a77fc44b" - integrity sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA== - -"@babel/parser@^7.25.0": - version "7.25.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.3.tgz#91fb126768d944966263f0657ab222a642b82065" - integrity sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw== - dependencies: - "@babel/types" "^7.25.2" - -"@babel/parser@^7.25.4": - version "7.25.4" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.4.tgz#af4f2df7d02440286b7de57b1c21acfb2a6f257a" - integrity sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA== - dependencies: - "@babel/types" "^7.25.4" - -"@babel/parser@^7.25.6": +"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.25.0", "@babel/parser@^7.25.4", "@babel/parser@^7.25.6", "@babel/parser@^7.7.0": version "7.25.6" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.6.tgz#85660c5ef388cbbf6e3d2a694ee97a38f18afe2f" integrity sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q== dependencies: "@babel/types" "^7.25.6" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.6", "@babel/runtime@^7.15.4", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.9", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.9.tgz#47791a15e4603bb5f905bc0753801cf21d6345f7" - integrity sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw== - dependencies: - regenerator-runtime "^0.14.0" - -"@babel/runtime@^7.25.0": - version "7.25.0" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz#3af9a91c1b739c569d5d80cc917280919c544ecb" - integrity sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw== +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.6", "@babel/runtime@^7.15.4", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.9", "@babel/runtime@^7.25.6", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.6.tgz#9afc3289f7184d8d7f98b099884c26317b9264d2" + integrity sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ== dependencies: regenerator-runtime "^0.14.0" -"@babel/template@^7.23.9": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.23.9.tgz#f881d0487cba2828d3259dcb9ef5005a9731011a" - integrity sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA== - dependencies: - "@babel/code-frame" "^7.23.5" - "@babel/parser" "^7.23.9" - "@babel/types" "^7.23.9" - "@babel/template@^7.25.0": version "7.25.0" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.0.tgz#e733dc3134b4fede528c15bc95e89cb98c52592a" @@ -360,7 +280,7 @@ "@babel/parser" "^7.25.0" "@babel/types" "^7.25.0" -"@babel/traverse@^7.18.9", "@babel/traverse@^7.23.3", "@babel/traverse@^7.23.9", "@babel/traverse@^7.7.0": +"@babel/traverse@^7.18.9", "@babel/traverse@^7.24.7", "@babel/traverse@^7.25.2", "@babel/traverse@^7.7.0": version "7.25.6" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.6.tgz#04fad980e444f182ecf1520504941940a90fea41" integrity sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ== @@ -373,34 +293,7 @@ debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.18.9", "@babel/types@^7.20.7", "@babel/types@^7.21.3", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.6", "@babel/types@^7.23.9", "@babel/types@^7.7.0": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.9.tgz#1dd7b59a9a2b5c87f8b41e52770b5ecbf492e002" - integrity sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q== - dependencies: - "@babel/helper-string-parser" "^7.23.4" - "@babel/helper-validator-identifier" "^7.22.20" - to-fast-properties "^2.0.0" - -"@babel/types@^7.25.0", "@babel/types@^7.25.2": - version "7.25.2" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.2.tgz#55fb231f7dc958cd69ea141a4c2997e819646125" - integrity sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q== - dependencies: - "@babel/helper-string-parser" "^7.24.8" - "@babel/helper-validator-identifier" "^7.24.7" - to-fast-properties "^2.0.0" - -"@babel/types@^7.25.4": - version "7.25.4" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.4.tgz#6bcb46c72fdf1012a209d016c07f769e10adcb5f" - integrity sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ== - dependencies: - "@babel/helper-string-parser" "^7.24.8" - "@babel/helper-validator-identifier" "^7.24.7" - to-fast-properties "^2.0.0" - -"@babel/types@^7.25.6": +"@babel/types@^7.0.0", "@babel/types@^7.18.9", "@babel/types@^7.20.7", "@babel/types@^7.21.3", "@babel/types@^7.24.7", "@babel/types@^7.25.0", "@babel/types@^7.25.2", "@babel/types@^7.25.4", "@babel/types@^7.25.6", "@babel/types@^7.7.0": version "7.25.6" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.6.tgz#893942ddb858f32ae7a004ec9d3a76b3463ef8e6" integrity sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw== @@ -419,17 +312,20 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@braintree/asset-loader@0.4.4": - version "0.4.4" - resolved "https://registry.yarnpkg.com/@braintree/asset-loader/-/asset-loader-0.4.4.tgz#9a5eda24c3627bfd5c7f7483cd48f0e411dd2f09" - integrity sha512-uVhXC5dydmngmNVuDiKgfXSlz4kv4x5ytIJodI8N5SY16mRh13m/UmbQ7yH+o8DQqp50qPZ45MUHIZkXKPg85w== - dependencies: - promise-polyfill "^8.1.3" +"@braintree/asset-loader@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@braintree/asset-loader/-/asset-loader-2.0.0.tgz#4e25ed06379d0bbda101c2157611651157a4df35" + integrity sha512-7Zs3/g3lPTfkdtWr7cKh3tk1pDruXR++TXwGKkx7BPuTjjLNFul2JSfI+ScHzNU4u/gZNPNQagsSTlYxIhBgMA== -"@braintree/browser-detection@1.17.1": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@braintree/browser-detection/-/browser-detection-1.17.1.tgz#d151c409dc7245e9307b05f3a06ede254e0f5d1e" - integrity sha512-Mk7jauyp9pD14BTRS7otoy9dqIJGb3Oy0XtxKM/adGD9i9MAuCjH5uRZMyW2iVmJQTaA/PLlWdG7eSDyMWMc8Q== +"@braintree/asset-loader@2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@braintree/asset-loader/-/asset-loader-2.0.1.tgz#7069b5d54e2827b6c1fb4155c4cdc8dc68e00a33" + integrity sha512-OGAoBA5MRVsr5qg0sXM6NMJbqHnYZhBudtM6WGgpQnoX42fjUYbE6Y6qFuuerD5z3lsOAjnu80DooBs1VBuh5Q== + +"@braintree/browser-detection@2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@braintree/browser-detection/-/browser-detection-2.0.1.tgz#11bc5e1d173c55cd25bda6ad22c6b3ee14ed87a2" + integrity sha512-wpRI7AXEUh6o3ILrJbpNOYE7ItfjX/S8JZP7Z5FF66ULngBGYOqE8SeLlLKXG69Nc07HtlL/6nk/h539iz9hcQ== "@braintree/browser-detection@^1.12.1": version "1.17.2" @@ -441,22 +337,27 @@ resolved "https://registry.yarnpkg.com/@braintree/event-emitter/-/event-emitter-0.4.1.tgz#204eaad8cf84eb7bf81fb288a359d34eda85a396" integrity sha512-X41357O3OXUDlnwMvS1m0GQEn3zB3s3flOBeg2J5OBvLvdJEIAVpPkblABPtsPrlciDSvfv1aSG5ixHPgFH0Zg== -"@braintree/extended-promise@0.4.1": - version "0.4.1" - resolved "https://registry.yarnpkg.com/@braintree/extended-promise/-/extended-promise-0.4.1.tgz#b44f8e6236ddb43434be11924f00fa69f8782a36" - integrity sha512-00n7m4z+swWHoFQLHLvrIBIEoxnGUBsl3ogvX79ITpcn8CHczDwtxYy5+RhMoAraRdfN3oB+8QIpN3KOxs2Q7w== +"@braintree/extended-promise@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@braintree/extended-promise/-/extended-promise-1.0.0.tgz#b9c52cf93b4935c429053b16e1152549df0696a7" + integrity sha512-E9529FJNG4OgeeLJ00vNs3TW67+AeSQobJg0hwfsQk29hgK4bVBsvQHVD4nwDuDD1Czon90K88gfQIFadAMs0w== -"@braintree/iframer@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@braintree/iframer/-/iframer-1.1.0.tgz#7e59b975c2a48bd92616f653367a5214fc2ddd4b" - integrity sha512-tVpr7U6u6bqeQlHreEjYMNtnHX62vLnNWziY2kQLqkWhvusPuY5DfuGEIPpWqsd+V/a1slyTQaxK6HWTlH6A/Q== +"@braintree/iframer@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@braintree/iframer/-/iframer-2.0.0.tgz#bbba9cfd62b701b8cb1f779dffcad6295aed9d23" + integrity sha512-x1kHOyIJNDvi4P1s6pVBZhqhBa1hqDG9+yzcsCR1oNVC0LxH9CAP8bKxioT8/auY1sUyy+D8T4Vp/jv7QqSqLQ== -"@braintree/sanitize-url@6.0.4": - version "6.0.4" - resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-6.0.4.tgz#923ca57e173c6b232bbbb07347b1be982f03e783" - integrity sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A== +"@braintree/sanitize-url@7.0.4": + version "7.0.4" + resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-7.0.4.tgz#a7ddd6d55dfb89e341f5684c9717ee24fef62301" + integrity sha512-hPYRrKFoI+nuckPgDJfyYAkybFvheo4usS0Vw0HNAe+fmGBQA5Az37b/yStO284atBoqqdOUhKJ3d9Zw3PQkcQ== -"@braintree/uuid@0.1.0", "@braintree/uuid@^0.1.0": +"@braintree/uuid@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@braintree/uuid/-/uuid-1.0.0.tgz#4fda394ceae803a8129e673c29ccf6c5e2014360" + integrity sha512-AtI5hfttWSuWAgcwLUZdcZ7Fp/8jCCUf9JTs7+Xow9ditU28zuoBovqq083yph2m3SxPYb84lGjOq+cXlXBvJg== + +"@braintree/uuid@^0.1.0": version "0.1.0" resolved "https://registry.yarnpkg.com/@braintree/uuid/-/uuid-0.1.0.tgz#ab9355015a7fb0e25cf3c2ff9cd32ece8ea304b0" integrity sha512-YvZJdlNcK5EnR+7M8AjgEAf4Qx696+FOSYlPfy5ePn80vODtVAUU0FxHnzKZC0og1VbDNQDDiwhthR65D4Na0g== @@ -473,47 +374,6 @@ dependencies: cookie "^0.5.0" -"@bundled-es-modules/deepmerge@^4.3.1": - version "4.3.1" - resolved "https://registry.yarnpkg.com/@bundled-es-modules/deepmerge/-/deepmerge-4.3.1.tgz#e0ef866494125f64f6fb75adeffacedc25f2f31b" - integrity sha512-Rk453EklPUPC3NRWc3VUNI/SSUjdBaFoaQvFRmNBNtMHVtOFD5AntiWg5kEE1hqcPqedYFDzxE3ZcMYPcA195w== - dependencies: - deepmerge "^4.3.1" - -"@bundled-es-modules/glob@^10.4.2": - version "10.4.2" - resolved "https://registry.yarnpkg.com/@bundled-es-modules/glob/-/glob-10.4.2.tgz#ef8f58b5d33ec8a1d4ca739bb49c09e5d0874bb5" - integrity sha512-740y5ofkzydsFao5EXJrGilcIL6EFEw/cmPf2uhTw9J6G1YOhiIFjNFCHdpgEiiH5VlU3G0SARSjlFlimRRSMA== - dependencies: - buffer "^6.0.3" - events "^3.3.0" - glob "^10.4.2" - patch-package "^8.0.0" - path "^0.12.7" - stream "^0.0.3" - string_decoder "^1.3.0" - url "^0.11.3" - -"@bundled-es-modules/memfs@^4.9.4": - version "4.9.4" - resolved "https://registry.yarnpkg.com/@bundled-es-modules/memfs/-/memfs-4.9.4.tgz#9c68d1ff10f485d59d45778c930aa8d60d0095a2" - integrity sha512-1XyYPUaIHwEOdF19wYVLBtHJRr42Do+3ctht17cZOHwHf67vkmRNPlYDGY2kJps4RgE5+c7nEZmEzxxvb1NZWA== - dependencies: - assert "^2.0.0" - buffer "^6.0.3" - events "^3.3.0" - memfs "^4.9.3" - path "^0.12.7" - stream "^0.0.3" - util "^0.12.5" - -"@bundled-es-modules/postcss-calc-ast-parser@^0.1.6": - version "0.1.6" - resolved "https://registry.yarnpkg.com/@bundled-es-modules/postcss-calc-ast-parser/-/postcss-calc-ast-parser-0.1.6.tgz#c15f422c0300b2daba9cff6a9d07ef6c5e7cc673" - integrity sha512-y65TM5zF+uaxo9OeekJ3rxwTINlQvrkbZLogYvQYVoLtxm4xEiHfZ7e/MyiWbStYyWZVZkVqsaVU6F4SUK5XUA== - dependencies: - postcss-calc-ast-parser "^0.1.4" - "@bundled-es-modules/statuses@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@bundled-es-modules/statuses/-/statuses-1.0.1.tgz#761d10f44e51a94902c4da48675b71a76cc98872" @@ -521,22 +381,23 @@ dependencies: statuses "^2.0.1" +"@bundled-es-modules/tough-cookie@^0.1.6": + version "0.1.6" + resolved "https://registry.yarnpkg.com/@bundled-es-modules/tough-cookie/-/tough-cookie-0.1.6.tgz#fa9cd3cedfeecd6783e8b0d378b4a99e52bde5d3" + integrity sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw== + dependencies: + "@types/tough-cookie" "^4.0.5" + tough-cookie "^4.1.4" + "@colors/colors@1.5.0": version "1.5.0" resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== -"@cspotcode/source-map-support@^0.8.0": - version "0.8.1" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" - integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== - dependencies: - "@jridgewell/trace-mapping" "0.3.9" - "@cypress/request@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@cypress/request/-/request-3.0.1.tgz#72d7d5425236a2413bd3d8bb66d02d9dc3168960" - integrity sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ== + version "3.0.5" + resolved "https://registry.yarnpkg.com/@cypress/request/-/request-3.0.5.tgz#d893a6e68ce2636c085fcd8d7283c3186499ba63" + integrity sha512-v+XHd9XmWbufxF1/bTaVm2yhbxY+TB4YtWRqF2zaXBlDNMkls34KiATz0AVDLavL3iB6bQk9/7n3oY1EoLSWGA== dependencies: aws-sign2 "~0.7.0" aws4 "^1.8.0" @@ -544,14 +405,14 @@ combined-stream "~1.0.6" extend "~3.0.2" forever-agent "~0.6.1" - form-data "~2.3.2" - http-signature "~1.3.6" + form-data "~4.0.0" + http-signature "~1.4.0" is-typedarray "~1.0.0" isstream "~0.1.2" json-stringify-safe "~5.0.1" mime-types "~2.1.19" performance-now "^2.1.0" - qs "6.10.4" + qs "6.13.0" safe-buffer "^5.1.2" tough-cookie "^4.1.3" tunnel-agent "^0.6.0" @@ -565,16 +426,16 @@ debug "^3.1.0" lodash.once "^4.1.1" -"@emotion/babel-plugin@^11.11.0": - version "11.11.0" - resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz#c2d872b6a7767a9d176d007f5b31f7d504bb5d6c" - integrity sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ== +"@emotion/babel-plugin@^11.12.0": + version "11.12.0" + resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz#7b43debb250c313101b3f885eba634f1d723fcc2" + integrity sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw== dependencies: "@babel/helper-module-imports" "^7.16.7" "@babel/runtime" "^7.18.3" - "@emotion/hash" "^0.9.1" - "@emotion/memoize" "^0.8.1" - "@emotion/serialize" "^1.1.2" + "@emotion/hash" "^0.9.2" + "@emotion/memoize" "^0.9.0" + "@emotion/serialize" "^1.2.0" babel-plugin-macros "^3.1.0" convert-source-map "^1.5.0" escape-string-regexp "^4.0.0" @@ -582,15 +443,15 @@ source-map "^0.5.7" stylis "4.2.0" -"@emotion/cache@*", "@emotion/cache@^11.11.0": - version "11.11.0" - resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.11.0.tgz#809b33ee6b1cb1a625fef7a45bc568ccd9b8f3ff" - integrity sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ== +"@emotion/cache@*", "@emotion/cache@^11.11.0", "@emotion/cache@^11.13.0": + version "11.13.1" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.13.1.tgz#fecfc54d51810beebf05bf2a161271a1a91895d7" + integrity sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw== dependencies: - "@emotion/memoize" "^0.8.1" - "@emotion/sheet" "^1.2.2" - "@emotion/utils" "^1.2.1" - "@emotion/weak-memoize" "^0.3.1" + "@emotion/memoize" "^0.9.0" + "@emotion/sheet" "^1.4.0" + "@emotion/utils" "^1.4.0" + "@emotion/weak-memoize" "^0.4.0" stylis "4.2.0" "@emotion/cache@^10.0.27", "@emotion/cache@^10.0.9": @@ -629,51 +490,51 @@ resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== -"@emotion/hash@^0.9.1": - version "0.9.1" - resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.1.tgz#4ffb0055f7ef676ebc3a5a91fb621393294e2f43" - integrity sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ== +"@emotion/hash@^0.9.2": + version "0.9.2" + resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.2.tgz#ff9221b9f58b4dfe61e619a7788734bd63f6898b" + integrity sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g== -"@emotion/is-prop-valid@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz#23116cf1ed18bfeac910ec6436561ecb1a3885cc" - integrity sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw== +"@emotion/is-prop-valid@^1.3.0": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz#8d5cf1132f836d7adbe42cf0b49df7816fc88240" + integrity sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw== dependencies: - "@emotion/memoize" "^0.8.1" + "@emotion/memoize" "^0.9.0" "@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.1": - version "0.8.1" - resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.1.tgz#c1ddb040429c6d21d38cc945fe75c818cfb68e17" - integrity sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA== +"@emotion/memoize@^0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.9.0.tgz#745969d649977776b43fc7648c556aaa462b4102" + integrity sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ== "@emotion/react@^11.11.1": - version "11.11.3" - resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.11.3.tgz#96b855dc40a2a55f52a72f518a41db4f69c31a25" - integrity sha512-Cnn0kuq4DoONOMcnoVsTOR8E+AdnKFf//6kUWc4LCdnxj31pZWn7rIULd6Y7/Js1PiPHzn7SKCM9vB/jBni8eA== + version "11.13.3" + resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.13.3.tgz#a69d0de2a23f5b48e0acf210416638010e4bd2e4" + integrity sha512-lIsdU6JNrmYfJ5EbUCf4xW1ovy5wKQ2CkPRM4xogziOxH1nXxBSjpC9YqbFAP7circxMfYp+6x676BqWcEiixg== dependencies: "@babel/runtime" "^7.18.3" - "@emotion/babel-plugin" "^11.11.0" - "@emotion/cache" "^11.11.0" - "@emotion/serialize" "^1.1.3" - "@emotion/use-insertion-effect-with-fallbacks" "^1.0.1" - "@emotion/utils" "^1.2.1" - "@emotion/weak-memoize" "^0.3.1" + "@emotion/babel-plugin" "^11.12.0" + "@emotion/cache" "^11.13.0" + "@emotion/serialize" "^1.3.1" + "@emotion/use-insertion-effect-with-fallbacks" "^1.1.0" + "@emotion/utils" "^1.4.0" + "@emotion/weak-memoize" "^0.4.0" hoist-non-react-statics "^3.3.1" -"@emotion/serialize@*", "@emotion/serialize@^1.1.2", "@emotion/serialize@^1.1.3": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.3.tgz#84b77bfcfe3b7bb47d326602f640ccfcacd5ffb0" - integrity sha512-iD4D6QVZFDhcbH0RAG1uVu1CwVLMWUkCvAqqlewO/rxf8+87yIBAlt4+AxMiiKPLs5hFc0owNk/sLLAOROw3cA== +"@emotion/serialize@*", "@emotion/serialize@^1.2.0", "@emotion/serialize@^1.3.0", "@emotion/serialize@^1.3.1": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.3.2.tgz#e1c1a2e90708d5d85d81ccaee2dfeb3cc0cccf7a" + integrity sha512-grVnMvVPK9yUVE6rkKfAJlYZgo0cu3l9iMC77V7DW6E1DUIrU68pSEXRmFZFOFB1QFo57TncmOcvcbMDWsL4yA== dependencies: - "@emotion/hash" "^0.9.1" - "@emotion/memoize" "^0.8.1" - "@emotion/unitless" "^0.8.1" - "@emotion/utils" "^1.2.1" + "@emotion/hash" "^0.9.2" + "@emotion/memoize" "^0.9.0" + "@emotion/unitless" "^0.10.0" + "@emotion/utils" "^1.4.1" csstype "^3.0.2" "@emotion/serialize@^0.11.15", "@emotion/serialize@^0.11.16": @@ -692,22 +553,22 @@ resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-0.9.4.tgz#894374bea39ec30f489bbfc3438192b9774d32e5" integrity sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA== -"@emotion/sheet@^1.2.2": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.2.tgz#d58e788ee27267a14342303e1abb3d508b6d0fec" - integrity sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA== +"@emotion/sheet@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.4.0.tgz#c9299c34d248bc26e82563735f78953d2efca83c" + integrity sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg== "@emotion/styled@^11.11.0": - version "11.11.0" - resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.11.0.tgz#26b75e1b5a1b7a629d7c0a8b708fbf5a9cdce346" - integrity sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng== + version "11.13.0" + resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.13.0.tgz#633fd700db701472c7a5dbef54d6f9834e9fb190" + integrity sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA== dependencies: "@babel/runtime" "^7.18.3" - "@emotion/babel-plugin" "^11.11.0" - "@emotion/is-prop-valid" "^1.2.1" - "@emotion/serialize" "^1.1.2" - "@emotion/use-insertion-effect-with-fallbacks" "^1.0.1" - "@emotion/utils" "^1.2.1" + "@emotion/babel-plugin" "^11.12.0" + "@emotion/is-prop-valid" "^1.3.0" + "@emotion/serialize" "^1.3.0" + "@emotion/use-insertion-effect-with-fallbacks" "^1.1.0" + "@emotion/utils" "^1.4.0" "@emotion/stylis@0.8.5": version "0.8.5" @@ -719,20 +580,20 @@ resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== -"@emotion/unitless@^0.8.1": - version "0.8.1" - resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.1.tgz#182b5a4704ef8ad91bde93f7a860a88fd92c79a3" - integrity sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ== +"@emotion/unitless@^0.10.0": + version "0.10.0" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.10.0.tgz#2af2f7c7e5150f497bdabd848ce7b218a27cf745" + integrity sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg== -"@emotion/use-insertion-effect-with-fallbacks@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz#08de79f54eb3406f9daaf77c76e35313da963963" - integrity sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw== +"@emotion/use-insertion-effect-with-fallbacks@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz#1a818a0b2c481efba0cf34e5ab1e0cb2dcb9dfaf" + integrity sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw== -"@emotion/utils@*", "@emotion/utils@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.1.tgz#bbab58465738d31ae4cb3dbb6fc00a5991f755e4" - integrity sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg== +"@emotion/utils@*", "@emotion/utils@^1.4.0", "@emotion/utils@^1.4.1": + version "1.4.1" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.4.1.tgz#b3adbb43de12ee2149541c4f1337d2eb7774f0ad" + integrity sha512-BymCXzCG3r72VKJxaYVwOXATqXIZ85cuvg0YOUDxMGNrKc1DJRZk8MgV5wyXRyEayIMd4FuXJIUgTBXvDNW5cA== "@emotion/utils@0.11.3": version "0.11.3" @@ -744,15 +605,10 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== -"@emotion/weak-memoize@^0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz#d0fce5d07b0620caa282b5131c297bb60f9d87e6" - integrity sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww== - -"@esbuild/aix-ppc64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz#d1bc06aedb6936b3b6d313bf809a5a40387d2b7f" - integrity sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA== +"@emotion/weak-memoize@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz#5e13fac887f08c44f76b0ccaf3370eb00fec9bb6" + integrity sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg== "@esbuild/aix-ppc64@0.21.5": version "0.21.5" @@ -764,11 +620,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz#51299374de171dbd80bb7d838e1cfce9af36f353" integrity sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ== -"@esbuild/android-arm64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz#7ad65a36cfdb7e0d429c353e00f680d737c2aed4" - integrity sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA== - "@esbuild/android-arm64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" @@ -779,11 +630,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz#58565291a1fe548638adb9c584237449e5e14018" integrity sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw== -"@esbuild/android-arm@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.12.tgz#b0c26536f37776162ca8bde25e42040c203f2824" - integrity sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w== - "@esbuild/android-arm@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" @@ -794,11 +640,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.23.1.tgz#5eb8c652d4c82a2421e3395b808e6d9c42c862ee" integrity sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ== -"@esbuild/android-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.12.tgz#cb13e2211282012194d89bf3bfe7721273473b3d" - integrity sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew== - "@esbuild/android-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" @@ -809,11 +650,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.23.1.tgz#ae19d665d2f06f0f48a6ac9a224b3f672e65d517" integrity sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg== -"@esbuild/darwin-arm64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz#cbee41e988020d4b516e9d9e44dd29200996275e" - integrity sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g== - "@esbuild/darwin-arm64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" @@ -824,11 +660,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz#05b17f91a87e557b468a9c75e9d85ab10c121b16" integrity sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q== -"@esbuild/darwin-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz#e37d9633246d52aecf491ee916ece709f9d5f4cd" - integrity sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A== - "@esbuild/darwin-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" @@ -839,11 +670,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz#c58353b982f4e04f0d022284b8ba2733f5ff0931" integrity sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw== -"@esbuild/freebsd-arm64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz#1ee4d8b682ed363b08af74d1ea2b2b4dbba76487" - integrity sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA== - "@esbuild/freebsd-arm64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" @@ -854,11 +680,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz#f9220dc65f80f03635e1ef96cfad5da1f446f3bc" integrity sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA== -"@esbuild/freebsd-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz#37a693553d42ff77cd7126764b535fb6cc28a11c" - integrity sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg== - "@esbuild/freebsd-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" @@ -869,11 +690,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz#69bd8511fa013b59f0226d1609ac43f7ce489730" integrity sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g== -"@esbuild/linux-arm64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz#be9b145985ec6c57470e0e051d887b09dddb2d4b" - integrity sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA== - "@esbuild/linux-arm64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" @@ -884,11 +700,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz#8050af6d51ddb388c75653ef9871f5ccd8f12383" integrity sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g== -"@esbuild/linux-arm@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz#207ecd982a8db95f7b5279207d0ff2331acf5eef" - integrity sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w== - "@esbuild/linux-arm@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" @@ -899,11 +710,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz#ecaabd1c23b701070484990db9a82f382f99e771" integrity sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ== -"@esbuild/linux-ia32@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz#d0d86b5ca1562523dc284a6723293a52d5860601" - integrity sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA== - "@esbuild/linux-ia32@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" @@ -914,11 +720,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz#3ed2273214178109741c09bd0687098a0243b333" integrity sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ== -"@esbuild/linux-loong64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz#9a37f87fec4b8408e682b528391fa22afd952299" - integrity sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA== - "@esbuild/linux-loong64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" @@ -929,11 +730,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz#a0fdf440b5485c81b0fbb316b08933d217f5d3ac" integrity sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw== -"@esbuild/linux-mips64el@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz#4ddebd4e6eeba20b509d8e74c8e30d8ace0b89ec" - integrity sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w== - "@esbuild/linux-mips64el@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" @@ -944,11 +740,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz#e11a2806346db8375b18f5e104c5a9d4e81807f6" integrity sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q== -"@esbuild/linux-ppc64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz#adb67dadb73656849f63cd522f5ecb351dd8dee8" - integrity sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg== - "@esbuild/linux-ppc64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" @@ -959,11 +750,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz#06a2744c5eaf562b1a90937855b4d6cf7c75ec96" integrity sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw== -"@esbuild/linux-riscv64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz#11bc0698bf0a2abf8727f1c7ace2112612c15adf" - integrity sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg== - "@esbuild/linux-riscv64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" @@ -974,11 +760,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz#65b46a2892fc0d1af4ba342af3fe0fa4a8fe08e7" integrity sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA== -"@esbuild/linux-s390x@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz#e86fb8ffba7c5c92ba91fc3b27ed5a70196c3cc8" - integrity sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg== - "@esbuild/linux-s390x@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" @@ -989,11 +770,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz#e71ea18c70c3f604e241d16e4e5ab193a9785d6f" integrity sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw== -"@esbuild/linux-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz#5f37cfdc705aea687dfe5dfbec086a05acfe9c78" - integrity sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg== - "@esbuild/linux-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" @@ -1004,11 +780,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz#d47f97391e80690d4dfe811a2e7d6927ad9eed24" integrity sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ== -"@esbuild/netbsd-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz#29da566a75324e0d0dd7e47519ba2f7ef168657b" - integrity sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA== - "@esbuild/netbsd-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" @@ -1024,11 +795,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz#05c5a1faf67b9881834758c69f3e51b7dee015d7" integrity sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q== -"@esbuild/openbsd-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz#306c0acbdb5a99c95be98bdd1d47c916e7dc3ff0" - integrity sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw== - "@esbuild/openbsd-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" @@ -1039,11 +805,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz#2e58ae511bacf67d19f9f2dcd9e8c5a93f00c273" integrity sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA== -"@esbuild/sunos-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz#0933eaab9af8b9b2c930236f62aae3fc593faf30" - integrity sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA== - "@esbuild/sunos-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" @@ -1054,11 +815,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz#adb022b959d18d3389ac70769cef5a03d3abd403" integrity sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA== -"@esbuild/win32-arm64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz#773bdbaa1971b36db2f6560088639ccd1e6773ae" - integrity sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A== - "@esbuild/win32-arm64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" @@ -1069,11 +825,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz#84906f50c212b72ec360f48461d43202f4c8b9a2" integrity sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A== -"@esbuild/win32-ia32@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz#000516cad06354cc84a73f0943a4aa690ef6fd67" - integrity sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ== - "@esbuild/win32-ia32@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" @@ -1084,11 +835,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz#5e3eacc515820ff729e90d0cb463183128e82fac" integrity sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ== -"@esbuild/win32-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz#c57c8afbb4054a3ab8317591a0b7320360b444ae" - integrity sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA== - "@esbuild/win32-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" @@ -1106,15 +852,24 @@ dependencies: eslint-visitor-keys "^3.3.0" -"@eslint-community/regexpp@^4.5.1": - version "4.10.1" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.1.tgz#361461e5cb3845d874e61731c11cfedd664d83a0" - integrity sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA== +"@eslint-community/regexpp@^4.11.0", "@eslint-community/regexpp@^4.5.1": + version "4.11.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.1.tgz#a547badfc719eb3e5f4b556325e542fbe9d7a18f" + integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q== -"@eslint-community/regexpp@^4.6.1": - version "4.10.0" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" - integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== +"@eslint/config-array@^0.18.0": + version "0.18.0" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.18.0.tgz#37d8fe656e0d5e3dbaea7758ea56540867fd074d" + integrity sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw== + dependencies: + "@eslint/object-schema" "^2.1.4" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/core@^0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.6.0.tgz#9930b5ba24c406d67a1760e94cdbac616a6eb674" + integrity sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg== "@eslint/eslintrc@^0.4.3": version "0.4.3" @@ -1131,67 +886,43 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" -"@eslint/eslintrc@^2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" - integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== +"@eslint/eslintrc@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.1.0.tgz#dbd3482bfd91efa663cbe7aa1f506839868207b6" + integrity sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.6.0" - globals "^13.19.0" + espree "^10.0.1" + globals "^14.0.0" ignore "^5.2.0" import-fresh "^3.2.1" js-yaml "^4.1.0" minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.56.0": - version "8.56.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.56.0.tgz#ef20350fec605a7f7035a01764731b2de0f3782b" - integrity sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A== - -"@floating-ui/core@^1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.0.tgz#fa41b87812a16bf123122bf945946bae3fdf7fc1" - integrity sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g== - dependencies: - "@floating-ui/utils" "^0.2.1" +"@eslint/js@9.11.1": + version "9.11.1" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.11.1.tgz#8bcb37436f9854b3d9a561440daf916acd940986" + integrity sha512-/qu+TWz8WwPWc7/HcIJKi+c+MOm46GdVaSlTTQcaqaL53+GsoA6MxWp5PtTx48qbSP7ylM1Kn7nhvkugfJvRSA== -"@floating-ui/dom@^1.6.1": - version "1.6.1" - resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.1.tgz#d552e8444f77f2d88534372369b3771dc3a2fa5d" - integrity sha512-iA8qE43/H5iGozC3W0YSnVSW42Vh522yyM1gj+BqRwVsTNOyr231PsXDaV04yT39PsO0QL2QpbI/M0ZaLUQgRQ== - dependencies: - "@floating-ui/core" "^1.6.0" - "@floating-ui/utils" "^0.2.1" +"@eslint/object-schema@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.4.tgz#9e69f8bb4031e11df79e03db09f9dbbae1740843" + integrity sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ== -"@floating-ui/react-dom@^2.0.8": - version "2.0.8" - resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.0.8.tgz#afc24f9756d1b433e1fe0d047c24bd4d9cefaa5d" - integrity sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw== +"@eslint/plugin-kit@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz#8712dccae365d24e9eeecb7b346f85e750ba343d" + integrity sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig== dependencies: - "@floating-ui/dom" "^1.6.1" - -"@floating-ui/utils@^0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.1.tgz#16308cea045f0fc777b6ff20a9f25474dd8293d2" - integrity sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q== + levn "^0.4.1" "@hookform/resolvers@2.9.11": version "2.9.11" resolved "https://registry.yarnpkg.com/@hookform/resolvers/-/resolvers-2.9.11.tgz#9ce96e7746625a89239f68ca57c4f654264c17ef" integrity sha512-bA3aZ79UgcHj7tFV7RlgThzwSSHZgvfbt2wprldRkYBcMopdMvHyO17Wwp/twcJasNFischFfS7oz8Katz8DdQ== -"@humanwhocodes/config-array@^0.11.13": - version "0.11.14" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" - integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== - dependencies: - "@humanwhocodes/object-schema" "^2.0.2" - debug "^4.3.1" - minimatch "^3.0.5" - "@humanwhocodes/config-array@^0.5.0": version "0.5.0" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" @@ -1211,69 +942,84 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== -"@humanwhocodes/object-schema@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917" - integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== +"@humanwhocodes/retry@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.0.tgz#6d86b8cb322660f03d3f0aa94b99bdd8e172d570" + integrity sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew== "@inquirer/confirm@^3.0.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@inquirer/confirm/-/confirm-3.1.0.tgz#526cb71ceab28ba827ea287aa81c969e437017b6" - integrity sha512-nH5mxoTEoqk6WpoBz80GMpDSm9jH5V9AF8n+JZAZfMzd9gHeEG9w1o3KawPRR72lfzpP+QxBHLkOKLEApwhDiQ== + version "3.2.0" + resolved "https://registry.yarnpkg.com/@inquirer/confirm/-/confirm-3.2.0.tgz#6af1284670ea7c7d95e3f1253684cfbd7228ad6a" + integrity sha512-oOIwPs0Dvq5220Z8lGL/6LHRTEr9TgLHmiI99Rj1PJ1p1czTys+olrgBqZk4E2qC0YTzeHprxSQmoHioVdJ7Lw== dependencies: - "@inquirer/core" "^7.1.0" - "@inquirer/type" "^1.2.1" + "@inquirer/core" "^9.1.0" + "@inquirer/type" "^1.5.3" -"@inquirer/core@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@inquirer/core/-/core-7.1.0.tgz#fb78738fd6624de50f027c08d6f24298b72a402b" - integrity sha512-FRCiDiU54XHt5B/D8hX4twwZuzSP244ANHbu3R7CAsJfiv1dUOz24ePBgCZjygEjDUi6BWIJuk4eWLKJ7LATUw== +"@inquirer/core@^9.1.0": + version "9.2.1" + resolved "https://registry.yarnpkg.com/@inquirer/core/-/core-9.2.1.tgz#677c49dee399c9063f31e0c93f0f37bddc67add1" + integrity sha512-F2VBt7W/mwqEU4bL0RnHNZmC/OxzNx9cOYxHqnXX3MP6ruYvZUZAW9imgN9+h/uBT/oP8Gh888J2OZSbjSeWcg== dependencies: - "@inquirer/type" "^1.2.1" + "@inquirer/figures" "^1.0.6" + "@inquirer/type" "^2.0.0" "@types/mute-stream" "^0.0.4" - "@types/node" "^20.11.26" + "@types/node" "^22.5.5" "@types/wrap-ansi" "^3.0.0" ansi-escapes "^4.3.2" - chalk "^4.1.2" - cli-spinners "^2.9.2" cli-width "^4.1.0" - figures "^3.2.0" mute-stream "^1.0.0" - run-async "^3.0.0" signal-exit "^4.1.0" strip-ansi "^6.0.1" wrap-ansi "^6.2.0" + yoctocolors-cjs "^2.1.2" -"@inquirer/type@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-1.2.1.tgz#fbc7ab3a2e5050d0c150642d5e8f5e88faa066b8" - integrity sha512-xwMfkPAxeo8Ji/IxfUSqzRi0/+F2GIqJmpc5/thelgMGsjNZcjDDRBO9TLXT1s/hdx/mK5QbVIvgoLIFgXhTMQ== +"@inquirer/figures@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@inquirer/figures/-/figures-1.0.6.tgz#1a562f916da39888c56b65b78259d2261bd7d40b" + integrity sha512-yfZzps3Cso2UbM7WlxKwZQh2Hs6plrbjs1QnzQDZhK2DgyCo6D8AaHps9olkNcUFlcYERMqU3uJSp1gmy3s/qQ== + +"@inquirer/type@^1.5.3": + version "1.5.5" + resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-1.5.5.tgz#303ea04ce7ad2e585b921b662b3be36ef7b4f09b" + integrity sha512-MzICLu4yS7V8AA61sANROZ9vT1H3ooca5dSmI1FjZkzq7o/koMsRfQSzRtFo+F3Ao4Sf1C0bpLKejpKB/+j6MA== + dependencies: + mute-stream "^1.0.0" + +"@inquirer/type@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-2.0.0.tgz#08fa513dca2cb6264fe1b0a2fabade051444e3f6" + integrity sha512-XvJRx+2KR3YXyYtPUUy+qd9i7p+GO9Ko6VIIpWlBrpWwXDv8WLFeHTxz35CfQFUiBMLXlGHhGzys7lqit9gWag== + dependencies: + mute-stream "^1.0.0" + +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" "@istanbuljs/schema@^0.1.2": version "0.1.3" resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== -"@joshwooding/vite-plugin-react-docgen-typescript@0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@joshwooding/vite-plugin-react-docgen-typescript/-/vite-plugin-react-docgen-typescript-0.3.1.tgz#a733e7fc90c00ce694058d3af034b9f63d88cddd" - integrity sha512-pdoMZ9QaPnVlSM+SdU/wgg0nyD/8wQ7y90ttO2CMCyrrm7RxveYIJ5eNfjPaoMFqW41LZra7QO9j+xV4Y18Glw== +"@joshwooding/vite-plugin-react-docgen-typescript@0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@joshwooding/vite-plugin-react-docgen-typescript/-/vite-plugin-react-docgen-typescript-0.3.0.tgz#67599fca260c2eafdaf234a944f9d471e6d53b08" + integrity sha512-2D6y7fNvFmsLmRt6UCOFJPvFoPMJGT0Uh1Wg0RaigUp7kdQPs6yYn8Dmx6GZkOH/NW0yMTwRz/p0SRMMRo50vA== dependencies: glob "^7.2.0" glob-promise "^4.2.0" magic-string "^0.27.0" react-docgen-typescript "^2.2.2" -"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" - integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== - dependencies: - "@jridgewell/set-array" "^1.0.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" - -"@jridgewell/gen-mapping@^0.3.5": +"@jridgewell/gen-mapping@^0.3.2", "@jridgewell/gen-mapping@^0.3.5": version "0.3.5" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== @@ -1282,47 +1028,21 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.24" -"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" - integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== - -"@jridgewell/set-array@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" - integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== "@jridgewell/set-array@^1.2.1": version "1.2.1" resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15": - version "1.4.15" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== - -"@jridgewell/sourcemap-codec@^1.5.0": +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": version "1.5.0" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== -"@jridgewell/trace-mapping@0.3.9": - version "0.3.9" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" - integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" - -"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.22" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz#72a621e5de59f5f1ef792d0793a82ee20f645e4c" - integrity sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - "@jridgewell/trace-mapping@^0.3.23", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" @@ -1331,26 +1051,6 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@jsonjoy.com/base64@^1.1.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@jsonjoy.com/base64/-/base64-1.1.2.tgz#cf8ea9dcb849b81c95f14fc0aaa151c6b54d2578" - integrity sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA== - -"@jsonjoy.com/json-pack@^1.0.3": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@jsonjoy.com/json-pack/-/json-pack-1.0.4.tgz#ab59c642a2e5368e8bcfd815d817143d4f3035d0" - integrity sha512-aOcSN4MeAtFROysrbqG137b7gaDDSmVrl5mpo6sT/w+kcXpWnzhMjmY/Fh/sDx26NBxyIE7MB1seqLeCAzy9Sg== - dependencies: - "@jsonjoy.com/base64" "^1.1.1" - "@jsonjoy.com/util" "^1.1.2" - hyperdyperid "^1.2.0" - thingies "^1.20.0" - -"@jsonjoy.com/util@^1.1.2": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@jsonjoy.com/util/-/util-1.1.3.tgz#75b1c3cf21b70e665789d1ad3eabeff8b7fd1429" - integrity sha512-g//kkF4kOwUjemValCtOc/xiYzmwMRmWq3Bn+YnzOzuZLHq2PpMOxxIayN3cKbo7Ko2Np65t6D9H81IvXbXhqg== - "@kwsites/file-exists@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@kwsites/file-exists/-/file-exists-1.1.1.tgz#ad1efcac13e1987d8dbaf235ef3be5b0d96faa99" @@ -1364,15 +1064,9 @@ integrity sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw== "@linode/design-language-system@^2.6.1": - version "2.6.1" - resolved "https://registry.yarnpkg.com/@linode/design-language-system/-/design-language-system-2.6.1.tgz#dac21f50d5087eaa273f76a3b3542f6160ee6076" - integrity sha512-cnj8X8s5ykxCCrHOwkEkroz/b1od5NTvidDDuyy5147Hqo7V5BWtdS+gLDqdvTKtYO0ybrORXRCD4y9qHf88HA== - dependencies: - "@tokens-studio/sd-transforms" "1.2.0" - react "^17.0.2" - react-copy-to-clipboard "^5.1.0" - react-dom "^17.0.2" - style-dictionary "4.0.1" + version "2.7.1" + resolved "https://registry.yarnpkg.com/@linode/design-language-system/-/design-language-system-2.7.1.tgz#03ee024529a2543249ad986bd7ab85c39e8aa797" + integrity sha512-rrQbFOJD/tG+8Xz7lt3YO6E6sIPSeHGW8nRSqQYLQrw2hJssN1wdGTK92Uluyy+msJQkXSenkTmDf2l1iOGTrQ== "@linode/eslint-plugin-cloud-manager@^0.0.5": version "0.0.5" @@ -1391,97 +1085,60 @@ dependencies: "@types/mdx" "^2.0.0" -"@mswjs/cookies@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@mswjs/cookies/-/cookies-1.1.0.tgz#1528eb43630caf83a1d75d5332b30e75e9bb1b5b" - integrity sha512-0ZcCVQxifZmhwNBoQIrystCb+2sWBY2Zw8lpfJBPCHGCA/HWqehITeCRVIv4VMy8MPlaHo2w2pTHFV2pFfqKPw== - -"@mswjs/interceptors@^0.25.16": - version "0.25.16" - resolved "https://registry.yarnpkg.com/@mswjs/interceptors/-/interceptors-0.25.16.tgz#7955fbb8da479bc691df117dd4c8d889e507ecc2" - integrity sha512-8QC8JyKztvoGAdPgyZy49c9vSHHAZjHagwl4RY9E8carULk8ym3iTaiawrT1YoLF/qb449h48f71XDPgkUSOUg== +"@mswjs/interceptors@^0.35.8": + version "0.35.8" + resolved "https://registry.yarnpkg.com/@mswjs/interceptors/-/interceptors-0.35.8.tgz#f36e5907e05593e33037ef4519aac7815fa3509f" + integrity sha512-PFfqpHplKa7KMdoQdj5td03uG05VK2Ng1dG0sP4pT9h0dGSX2v9txYt/AnrzPb/vAmfyBBC0NQV7VaBEX+efgQ== dependencies: "@open-draft/deferred-promise" "^2.2.0" "@open-draft/logger" "^0.3.0" "@open-draft/until" "^2.0.0" is-node-process "^1.2.0" - outvariant "^1.2.1" + outvariant "^1.4.3" strict-event-emitter "^0.5.1" -"@mui/base@5.0.0-beta.36": - version "5.0.0-beta.36" - resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.36.tgz#29ca2de9d387f6d3943b6f18a84415c43e5f206c" - integrity sha512-6A8fYiXgjqTO6pgj31Hc8wm1M3rFYCxDRh09dBVk0L0W4cb2lnurRJa3cAyic6hHY+we1S58OdGYRbKmOsDpGQ== - dependencies: - "@babel/runtime" "^7.23.9" - "@floating-ui/react-dom" "^2.0.8" - "@mui/types" "^7.2.13" - "@mui/utils" "^5.15.9" - "@popperjs/core" "^2.11.8" - clsx "^2.1.0" - prop-types "^15.8.1" - -"@mui/core-downloads-tracker@^5.15.9": - version "5.15.9" - resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.9.tgz#c29138c70cc0fb49cd909c29beef3fb0647e5af7" - integrity sha512-CSDpVevGaxsvMkiYBZ8ztki1z/eT0mM2MqUT21eCRiMz3DU4zQw5rXG5ML/yTuJF9Z2Wv9SliIeaRAuSR/9Nig== +"@mui/core-downloads-tracker@^5.16.7": + version "5.16.7" + resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.7.tgz#182a325a520f7ebd75de051fceabfc0314cfd004" + integrity sha512-RtsCt4Geed2/v74sbihWzzRs+HsIQCfclHeORh5Ynu2fS4icIKozcSubwuG7vtzq2uW3fOR1zITSP84TNt2GoQ== "@mui/icons-material@^5.14.7": - version "5.15.9" - resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.15.9.tgz#8d11839d35cf3cfd62df40934d8e9485f66be620" - integrity sha512-6tLQoM6RylQuDnHR6qQay0G0pJgKmrhn5MIm0IfrwtmSO8eV5iUFR+nNUTXsWa24gt7ZbIKnJ962UlYaeXa4bg== + version "5.16.7" + resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.16.7.tgz#e27f901af792065efc9f3d75d74a66af7529a10a" + integrity sha512-UrGwDJCXEszbDI7yV047BYU5A28eGJ79keTCP4cc74WyncuVrnurlmIRxaHL8YK+LI1Kzq+/JM52IAkNnv4u+Q== dependencies: "@babel/runtime" "^7.23.9" "@mui/material@^5.14.7": - version "5.15.9" - resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.15.9.tgz#4d6a4aee002c6a2d0e174e08c6d23245c18dd828" - integrity sha512-kbHTZDcFmN8GHKzRpImUEl9AJfFWI/0Kl+DsYVT3kHzQWUuHiKm3uHXR1RCOqr7H8IgHFPdbxItmCSQ/mj7zgg== + version "5.16.7" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.16.7.tgz#6e814e2eefdaf065a769cecf549c3569e107a50b" + integrity sha512-cwwVQxBhK60OIOqZOVLFt55t01zmarKJiJUWbk0+8s/Ix5IaUzAShqlJchxsIQ4mSrWqgcKCCXKtIlG5H+/Jmg== dependencies: "@babel/runtime" "^7.23.9" - "@mui/base" "5.0.0-beta.36" - "@mui/core-downloads-tracker" "^5.15.9" - "@mui/system" "^5.15.9" - "@mui/types" "^7.2.13" - "@mui/utils" "^5.15.9" + "@mui/core-downloads-tracker" "^5.16.7" + "@mui/system" "^5.16.7" + "@mui/types" "^7.2.15" + "@mui/utils" "^5.16.6" + "@popperjs/core" "^2.11.8" "@types/react-transition-group" "^4.4.10" clsx "^2.1.0" csstype "^3.1.3" prop-types "^15.8.1" - react-is "^18.2.0" + react-is "^18.3.1" react-transition-group "^4.4.5" -"@mui/private-theming@^5.15.9": - version "5.15.9" - resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.15.9.tgz#3ea3514ed2f6bf68541dbe9206665a82cd89cb01" - integrity sha512-/aMJlDOxOTAXyp4F2rIukW1O0anodAMCkv1DfBh/z9vaKHY3bd5fFf42wmP+0GRmwMinC5aWPpNfHXOED1fEtg== - dependencies: - "@babel/runtime" "^7.23.9" - "@mui/utils" "^5.15.9" - prop-types "^15.8.1" - "@mui/private-theming@^5.16.6": version "5.16.6" - resolved "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.6.tgz#547671e7ae3f86b68d1289a0b90af04dfcc1c8c9" + resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.16.6.tgz#547671e7ae3f86b68d1289a0b90af04dfcc1c8c9" integrity sha512-rAk+Rh8Clg7Cd7shZhyt2HGTTE5wYKNSJ5sspf28Fqm/PZ69Er9o6KX25g03/FG2dfpg5GCwZh/xOojiTfm3hw== dependencies: "@babel/runtime" "^7.23.9" "@mui/utils" "^5.16.6" prop-types "^15.8.1" -"@mui/styled-engine@^5.15.9": - version "5.15.9" - resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.15.9.tgz#444605039ec3fe456bdd5d5cb94330183be62b91" - integrity sha512-NRKtYkL5PZDH7dEmaLEIiipd3mxNnQSO+Yo8rFNBNptY8wzQnQ+VjayTq39qH7Sast5cwHKYFusUrQyD+SS4Og== - dependencies: - "@babel/runtime" "^7.23.9" - "@emotion/cache" "^11.11.0" - csstype "^3.1.3" - prop-types "^15.8.1" - "@mui/styled-engine@^5.16.6": version "5.16.6" - resolved "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.16.6.tgz#60110c106dd482dfdb7e2aa94fd6490a0a3f8852" + resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.16.6.tgz#60110c106dd482dfdb7e2aa94fd6490a0a3f8852" integrity sha512-zaThmS67ZmtHSWToTiHslbI8jwrmITcN93LQaR2lKArbvS7Z3iLkwRoiikNWutx9MBs8Q6okKvbZq1RQYB3v7g== dependencies: "@babel/runtime" "^7.23.9" @@ -1489,24 +1146,10 @@ csstype "^3.1.3" prop-types "^15.8.1" -"@mui/system@^5.15.9": - version "5.15.9" - resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.15.9.tgz#8a34ac0ab133af2550cc7ab980a35174142fd265" - integrity sha512-SxkaaZ8jsnIJ77bBXttfG//LUf6nTfOcaOuIgItqfHv60ZCQy/Hu7moaob35kBb+guxVJnoSZ+7vQJrA/E7pKg== - dependencies: - "@babel/runtime" "^7.23.9" - "@mui/private-theming" "^5.15.9" - "@mui/styled-engine" "^5.15.9" - "@mui/types" "^7.2.13" - "@mui/utils" "^5.15.9" - clsx "^2.1.0" - csstype "^3.1.3" - prop-types "^15.8.1" - -"@mui/system@^5.16.5": - version "5.16.6" - resolved "https://registry.npmjs.org/@mui/system/-/system-5.16.6.tgz#2dabe63d2e45816ce611c40d6e3f79b9c2ccbcd7" - integrity sha512-5xgyJjBIMPw8HIaZpfbGAaFYPwImQn7Nyh+wwKWhvkoIeDosQ1ZMVrbTclefi7G8hNmqhip04duYwYpbBFnBgw== +"@mui/system@^5.16.7": + version "5.16.7" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.16.7.tgz#4583ca5bf3b38942e02c15a1e622ba869ac51393" + integrity sha512-Jncvs/r/d/itkxh7O7opOunTqbbSSzMTHzZkNLM+FjAOg+cYAZHrPDlYe1ZGKUYORwwb2XexlWnpZp0kZ4AHuA== dependencies: "@babel/runtime" "^7.23.9" "@mui/private-theming" "^5.16.6" @@ -1517,29 +1160,14 @@ csstype "^3.1.3" prop-types "^15.8.1" -"@mui/types@^7.2.13": - version "7.2.13" - resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.13.tgz#d1584912942f9dc042441ecc2d1452be39c666b8" - integrity sha512-qP9OgacN62s+l8rdDhSFRe05HWtLLJ5TGclC9I1+tQngbssu0m2dmFZs+Px53AcOs9fD7TbYd4gc9AXzVqO/+g== - "@mui/types@^7.2.15": - version "7.2.15" - resolved "https://registry.npmjs.org/@mui/types/-/types-7.2.15.tgz#dadd232fe9a70be0d526630675dff3b110f30b53" - integrity sha512-nbo7yPhtKJkdf9kcVOF8JZHPZTmqXjJ/tI0bdWgHg5tp9AnIN4Y7f7wm9T+0SyGYJk76+GYZ8Q5XaTYAsUHN0Q== + version "7.2.17" + resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.17.tgz#329826062d4079de5ea2b97007575cebbba1fdbc" + integrity sha512-oyumoJgB6jDV8JFzRqjBo2daUuHpzDjoO/e3IrRhhHo/FxJlaVhET6mcNrKHUq2E+R+q3ql0qAtvQ4rfWHhAeQ== -"@mui/utils@^5.15.9": - version "5.15.9" - resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.15.9.tgz#2bdf925e274d87cbe90c14eb52d0835318205e86" - integrity sha512-yDYfr61bCYUz1QtwvpqYy/3687Z8/nS4zv7lv/ih/6ZFGMl1iolEvxRmR84v2lOYxlds+kq1IVYbXxDKh8Z9sg== - dependencies: - "@babel/runtime" "^7.23.9" - "@types/prop-types" "^15.7.11" - prop-types "^15.8.1" - react-is "^18.2.0" - -"@mui/utils@^5.16.5", "@mui/utils@^5.16.6": +"@mui/utils@^5.16.6": version "5.16.6" - resolved "https://registry.npmjs.org/@mui/utils/-/utils-5.16.6.tgz#905875bbc58d3dcc24531c3314a6807aba22a711" + resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.16.6.tgz#905875bbc58d3dcc24531c3314a6807aba22a711" integrity sha512-tWiQqlhxAt3KENNiSRL+DIn9H5xNVK6Jjf70x3PnfQPz1MPBdh7yyIcAyVBT9xiw7hP3SomRhPR7hzBMBCjqEA== dependencies: "@babel/runtime" "^7.23.9" @@ -1550,18 +1178,26 @@ react-is "^18.3.1" "@mui/x-date-pickers@^7.12.0": - version "7.12.0" - resolved "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.12.0.tgz#189acc9e3d2a5be260fab9faf5e6add516e59b09" - integrity sha512-WU5C7QNfSpJ9cP8vl2sY7q35NW+0TUMgEy+sl98fcPhLckq3cgV1wnVxoZnQZ3BxVQAtx+7ag/MpefU03vJcVw== + version "7.18.0" + resolved "https://registry.yarnpkg.com/@mui/x-date-pickers/-/x-date-pickers-7.18.0.tgz#264158195aeeaf32a00519718f6c67c165b06711" + integrity sha512-12tXIoMj9vpS8fS/bS3kWPCoVrH38vNGCxgplI0vOnUrN9rJuYJz3agLPJe1S0xciTw+9W8ZSe3soaW+owoz1Q== dependencies: - "@babel/runtime" "^7.25.0" - "@mui/system" "^5.16.5" - "@mui/utils" "^5.16.5" - "@types/react-transition-group" "^4.4.10" + "@babel/runtime" "^7.25.6" + "@mui/utils" "^5.16.6" + "@mui/x-internals" "7.18.0" + "@types/react-transition-group" "^4.4.11" clsx "^2.1.1" prop-types "^15.8.1" react-transition-group "^4.4.5" +"@mui/x-internals@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@mui/x-internals/-/x-internals-7.18.0.tgz#f079968d4f7ea93e63be9faf6ba8558d6f12923b" + integrity sha512-lzCHOWIR0cAIY1bGrWSprYerahbnH5C31ql/2OWCEjcngL2NAV1M6oKI2Vp4HheqzJ822c60UyWyapvyjSzY/A== + dependencies: + "@babel/runtime" "^7.25.6" + "@mui/utils" "^5.16.6" + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -1601,6 +1237,15 @@ resolved "https://registry.yarnpkg.com/@open-draft/until/-/until-2.1.0.tgz#0acf32f470af2ceaf47f095cdecd40d68666efda" integrity sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg== +"@paypal/accelerated-checkout-loader@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@paypal/accelerated-checkout-loader/-/accelerated-checkout-loader-1.1.0.tgz#8e0e939d4b04dfbd2c8a7a22287eb753eedcaf5a" + integrity sha512-S2KkIpq15VnxYyI0tycvfYiNsqdsg2a92El2huYUVLsWnBbubl8toYK8khaP5nnxZ0MGl9mEB9Y9axmfOw2Yvg== + dependencies: + "@braintree/asset-loader" "2.0.0" + envify "^4.1.0" + typescript "^4.6.4" + "@paypal/paypal-js@^5.1.6": version "5.1.6" resolved "https://registry.yarnpkg.com/@paypal/paypal-js/-/paypal-js-5.1.6.tgz#8ec59f4cc016addb3de41511f70950fd0359ffdb" @@ -1617,9 +1262,9 @@ "@paypal/sdk-constants" "^1.0.122" "@paypal/sdk-constants@^1.0.122": - version "1.0.139" - resolved "https://registry.yarnpkg.com/@paypal/sdk-constants/-/sdk-constants-1.0.139.tgz#b8918d26ae0feecf38ba9ad367243165af57818c" - integrity sha512-rCRL2Ys5OAbSCLcJjaFlunJWrgY92UzGNrHb7wYnr//sEXSRJx1n8Na/jxSxiFBmp4GGa/TbgodJvM80fx1iyQ== + version "1.0.149" + resolved "https://registry.yarnpkg.com/@paypal/sdk-constants/-/sdk-constants-1.0.149.tgz#7060213be1c892fb3e9656ba0108a5584cafeac8" + integrity sha512-oHdaRg2fP9LINMDJ8fMTtRvvW2QJVifoEoq7YPOP5Sk50edWX6tyATZTfgSnJmLHHq3OE6OF1aKa7hz09frVxw== dependencies: hi-base32 "^0.5.0" @@ -1636,30 +1281,15 @@ integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== "@polka/url@^1.0.0-next.24": - version "1.0.0-next.24" - resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.24.tgz#58601079e11784d20f82d0585865bb42305c4df3" - integrity sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ== + version "1.0.0-next.28" + resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.28.tgz#d45e01c4a56f143ee69c54dd6b12eade9e270a73" + integrity sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw== "@popperjs/core@^2.11.8": version "2.11.8" resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== -"@radix-ui/react-compose-refs@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz#7ed868b66946aa6030e580b1ffca386dd4d21989" - integrity sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw== - dependencies: - "@babel/runtime" "^7.13.10" - -"@radix-ui/react-slot@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.2.tgz#a9ff4423eade67f501ffb32ec22064bc9d3099ab" - integrity sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/react-compose-refs" "1.0.1" - "@reach/auto-id@0.10.5": version "0.10.5" resolved "https://registry.yarnpkg.com/@reach/auto-id/-/auto-id-0.10.5.tgz#fa78c71ce2f565ebed1ad91a8d9a685176d23c48" @@ -1697,333 +1327,199 @@ warning "^4.0.3" "@rollup/pluginutils@^5.0.2", "@rollup/pluginutils@^5.0.4": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.0.tgz#7e53eddc8c7f483a4ad0b94afb1f7f5fd3c771e0" - integrity sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g== + version "5.1.2" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.2.tgz#d3bc9f0fea4fd4086aaac6aa102f3fa587ce8bd9" + integrity sha512-/FIdS3PyZ39bjZlwqFnWqCOVnW7o963LtKMwQOD0NhQqw22gSr2YY1afu3FxRip4ZCZNsD5jq6Aaz6QV3D/Njw== dependencies: "@types/estree" "^1.0.0" estree-walker "^2.0.2" picomatch "^2.3.1" -"@rollup/rollup-android-arm-eabi@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.0.tgz#d941173f82f9b041c61b0dc1a2a91dcd06e4b31e" - integrity sha512-WTWD8PfoSAJ+qL87lE7votj3syLavxunWhzCnx3XFxFiI/BA/r3X7MUM8dVrH8rb2r4AiO8jJsr3ZjdaftmnfA== - -"@rollup/rollup-android-arm-eabi@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.1.tgz#c3a7938551273a2b72820cf5d22e54cf41dc206e" - integrity sha512-2thheikVEuU7ZxFXubPDOtspKn1x0yqaYQwvALVtEcvFhMifPADBrgRPyHV0TF3b+9BgvgjgagVyvA/UqPZHmg== - -"@rollup/rollup-android-arm-eabi@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.6.tgz#66b8d9cb2b3a474d115500f9ebaf43e2126fe496" - integrity sha512-MVNXSSYN6QXOulbHpLMKYi60ppyO13W9my1qogeiAqtjb2yR4LSmfU2+POvDkLzhjYLXz9Rf9+9a3zFHW1Lecg== - -"@rollup/rollup-android-arm64@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.0.tgz#7e7157c8543215245ceffc445134d9e843ba51c0" - integrity sha512-a1sR2zSK1B4eYkiZu17ZUZhmUQcKjk2/j9Me2IDjk1GHW7LB5Z35LEzj9iJch6gtUfsnvZs1ZNyDW2oZSThrkA== - -"@rollup/rollup-android-arm64@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.1.tgz#fa3693e4674027702c42fcbbb86bbd0c635fd3b9" - integrity sha512-t1lLYn4V9WgnIFHXy1d2Di/7gyzBWS8G5pQSXdZqfrdCGTwi1VasRMSS81DTYb+avDs/Zz4A6dzERki5oRYz1g== - -"@rollup/rollup-android-arm64@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.6.tgz#46327d5b86420d2307946bec1535fdf00356e47d" - integrity sha512-T14aNLpqJ5wzKNf5jEDpv5zgyIqcpn1MlwCrUXLrwoADr2RkWA0vOWP4XxbO9aiO3dvMCQICZdKeDrFl7UMClw== - -"@rollup/rollup-darwin-arm64@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.0.tgz#f0a18a4fc8dc6eb1e94a51fa2adb22876f477947" - integrity sha512-zOnKWLgDld/svhKO5PD9ozmL6roy5OQ5T4ThvdYZLpiOhEGY+dp2NwUmxK0Ld91LrbjrvtNAE0ERBwjqhZTRAA== - -"@rollup/rollup-darwin-arm64@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.1.tgz#e19922f4ac1e4552a230ff8f49d5688c5c07d284" - integrity sha512-AH/wNWSEEHvs6t4iJ3RANxW5ZCK3fUnmf0gyMxWCesY1AlUj8jY7GC+rQE4wd3gwmZ9XDOpL0kcFnCjtN7FXlA== - -"@rollup/rollup-darwin-arm64@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.6.tgz#166987224d2f8b1e2fd28ee90c447d52271d5e90" - integrity sha512-CqNNAyhRkTbo8VVZ5R85X73H3R5NX9ONnKbXuHisGWC0qRbTTxnF1U4V9NafzJbgGM0sHZpdO83pLPzq8uOZFw== - -"@rollup/rollup-darwin-x64@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.0.tgz#34b7867613e5cc42d2b85ddc0424228cc33b43f0" - integrity sha512-7doS8br0xAkg48SKE2QNtMSFPFUlRdw9+votl27MvT46vo44ATBmdZdGysOevNELmZlfd+NEa0UYOA8f01WSrg== - -"@rollup/rollup-darwin-x64@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.1.tgz#897f8d47b115ea84692a29cf2366899499d4d915" - integrity sha512-dO0BIz/+5ZdkLZrVgQrDdW7m2RkrLwYTh2YMFG9IpBtlC1x1NPNSXkfczhZieOlOLEqgXOFH3wYHB7PmBtf+Bg== - -"@rollup/rollup-darwin-x64@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.6.tgz#a2e6e096f74ccea6e2f174454c26aef6bcdd1274" - integrity sha512-zRDtdJuRvA1dc9Mp6BWYqAsU5oeLixdfUvkTHuiYOHwqYuQ4YgSmi6+/lPvSsqc/I0Omw3DdICx4Tfacdzmhog== - -"@rollup/rollup-linux-arm-gnueabihf@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.0.tgz#422b19ff9ae02b05d3395183d1d43b38c7c8be0b" - integrity sha512-pWJsfQjNWNGsoCq53KjMtwdJDmh/6NubwQcz52aEwLEuvx08bzcy6tOUuawAOncPnxz/3siRtd8hiQ32G1y8VA== - -"@rollup/rollup-linux-arm-gnueabihf@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.1.tgz#7d1e2a542f3a5744f5c24320067bd5af99ec9d62" - integrity sha512-sWWgdQ1fq+XKrlda8PsMCfut8caFwZBmhYeoehJ05FdI0YZXk6ZyUjWLrIgbR/VgiGycrFKMMgp7eJ69HOF2pQ== - -"@rollup/rollup-linux-arm-gnueabihf@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.6.tgz#09fcd4c55a2d6160c5865fec708a8e5287f30515" - integrity sha512-oNk8YXDDnNyG4qlNb6is1ojTOGL/tRhbbKeE/YuccItzerEZT68Z9gHrY3ROh7axDc974+zYAPxK5SH0j/G+QQ== - -"@rollup/rollup-linux-arm-musleabihf@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.0.tgz#568aa29195ef6fc57ec6ed3f518923764406a8ee" - integrity sha512-efRIANsz3UHZrnZXuEvxS9LoCOWMGD1rweciD6uJQIx2myN3a8Im1FafZBzh7zk1RJ6oKcR16dU3UPldaKd83w== - -"@rollup/rollup-linux-arm-musleabihf@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.1.tgz#88bec1c9df85fc5e24d49f783e19934717dd69b5" - integrity sha512-9OIiSuj5EsYQlmwhmFRA0LRO0dRRjdCVZA3hnmZe1rEwRk11Jy3ECGGq3a7RrVEZ0/pCsYWx8jG3IvcrJ6RCew== - -"@rollup/rollup-linux-arm64-gnu@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.0.tgz#22309c8bcba9a73114f69165c72bc94b2fbec085" - integrity sha512-ZrPhydkTVhyeGTW94WJ8pnl1uroqVHM3j3hjdquwAcWnmivjAwOYjTEAuEDeJvGX7xv3Z9GAvrBkEzCgHq9U1w== - -"@rollup/rollup-linux-arm64-gnu@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.1.tgz#6dc60f0fe7bd49ed07a2d4d9eab15e671b3bd59d" - integrity sha512-0kuAkRK4MeIUbzQYu63NrJmfoUVicajoRAL1bpwdYIYRcs57iyIV9NLcuyDyDXE2GiZCL4uhKSYAnyWpjZkWow== - -"@rollup/rollup-linux-arm64-gnu@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.6.tgz#19a3c0b6315c747ca9acf86e9b710cc2440f83c9" - integrity sha512-Z3O60yxPtuCYobrtzjo0wlmvDdx2qZfeAWTyfOjEDqd08kthDKexLpV97KfAeUXPosENKd8uyJMRDfFMxcYkDQ== - -"@rollup/rollup-linux-arm64-musl@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.0.tgz#c93c388af6d33f082894b8a60839d7265b2b9bc5" - integrity sha512-cfaupqd+UEFeURmqNP2eEvXqgbSox/LHOyN9/d2pSdV8xTrjdg3NgOFJCtc1vQ/jEke1qD0IejbBfxleBPHnPw== - -"@rollup/rollup-linux-arm64-musl@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.1.tgz#a03b78775c129e8333aca9e1e420e8e217ee99b9" - integrity sha512-/6dYC9fZtfEY0vozpc5bx1RP4VrtEOhNQGb0HwvYNwXD1BBbwQ5cKIbUVVU7G2d5WRE90NfB922elN8ASXAJEA== - -"@rollup/rollup-linux-arm64-musl@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.6.tgz#94aaf95fdaf2ad9335983a4552759f98e6b2e850" - integrity sha512-gpiG0qQJNdYEVad+1iAsGAbgAnZ8j07FapmnIAQgODKcOTjLEWM9sRb+MbQyVsYCnA0Im6M6QIq6ax7liws6eQ== - -"@rollup/rollup-linux-powerpc64le-gnu@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.0.tgz#493c5e19e395cf3c6bd860c7139c8a903dea72b4" - integrity sha512-ZKPan1/RvAhrUylwBXC9t7B2hXdpb/ufeu22pG2psV7RN8roOfGurEghw1ySmX/CmDDHNTDDjY3lo9hRlgtaHg== - -"@rollup/rollup-linux-powerpc64le-gnu@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.1.tgz#ee3810647faf2c105a5a4e71260bb90b96bf87bc" - integrity sha512-ltUWy+sHeAh3YZ91NUsV4Xg3uBXAlscQe8ZOXRCVAKLsivGuJsrkawYPUEyCV3DYa9urgJugMLn8Z3Z/6CeyRQ== - -"@rollup/rollup-linux-riscv64-gnu@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.0.tgz#a2eab4346fbe5909165ce99adb935ba30c9fb444" - integrity sha512-H1eRaCwd5E8eS8leiS+o/NqMdljkcb1d6r2h4fKSsCXQilLKArq6WS7XBLDu80Yz+nMqHVFDquwcVrQmGr28rg== - -"@rollup/rollup-linux-riscv64-gnu@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.1.tgz#385d76a088c27db8054d9f3f28d64d89294f838e" - integrity sha512-BggMndzI7Tlv4/abrgLwa/dxNEMn2gC61DCLrTzw8LkpSKel4o+O+gtjbnkevZ18SKkeN3ihRGPuBxjaetWzWg== - -"@rollup/rollup-linux-riscv64-gnu@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.6.tgz#160510e63f4b12618af4013bddf1761cf9fc9880" - integrity sha512-+uCOcvVmFUYvVDr27aiyun9WgZk0tXe7ThuzoUTAukZJOwS5MrGbmSlNOhx1j80GdpqbOty05XqSl5w4dQvcOA== - -"@rollup/rollup-linux-s390x-gnu@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.0.tgz#0bc49a79db4345d78d757bb1b05e73a1b42fa5c3" - integrity sha512-zJ4hA+3b5tu8u7L58CCSI0A9N1vkfwPhWd/puGXwtZlsB5bTkwDNW/+JCU84+3QYmKpLi+XvHdmrlwUwDA6kqw== - -"@rollup/rollup-linux-s390x-gnu@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.1.tgz#daa2b62a6e6f737ebef6700a12a93c9764e18583" - integrity sha512-z/9rtlGd/OMv+gb1mNSjElasMf9yXusAxnRDrBaYB+eS1shFm6/4/xDH1SAISO5729fFKUkJ88TkGPRUh8WSAA== - -"@rollup/rollup-linux-x64-gnu@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.0.tgz#4fd36a6a41f3406d8693321b13d4f9b7658dd4b9" - integrity sha512-e2hrvElFIh6kW/UNBQK/kzqMNY5mO+67YtEh9OA65RM5IJXYTWiXjX6fjIiPaqOkBthYF1EqgiZ6OXKcQsM0hg== - -"@rollup/rollup-linux-x64-gnu@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.1.tgz#790ae96118cc892464e9f10da358c0c8a6b9acdd" - integrity sha512-kXQVcWqDcDKw0S2E0TmhlTLlUgAmMVqPrJZR+KpH/1ZaZhLSl23GZpQVmawBQGVhyP5WXIsIQ/zqbDBBYmxm5w== - -"@rollup/rollup-linux-x64-gnu@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.6.tgz#5ac5d068ce0726bd0a96ca260d5bd93721c0cb98" - integrity sha512-HUNqM32dGzfBKuaDUBqFB7tP6VMN74eLZ33Q9Y1TBqRDn+qDonkAUyKWwF9BR9unV7QUzffLnz9GrnKvMqC/fw== - -"@rollup/rollup-linux-x64-musl@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.0.tgz#10ebb13bd4469cbad1a5d9b073bd27ec8a886200" - integrity sha512-1vvmgDdUSebVGXWX2lIcgRebqfQSff0hMEkLJyakQ9JQUbLDkEaMsPTLOmyccyC6IJ/l3FZuJbmrBw/u0A0uCQ== - -"@rollup/rollup-linux-x64-musl@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.1.tgz#d613147f7ac15fafe2a0b6249e8484e161ca2847" - integrity sha512-CbFv/WMQsSdl+bpX6rVbzR4kAjSSBuDgCqb1l4J68UYsQNalz5wOqLGYj4ZI0thGpyX5kc+LLZ9CL+kpqDovZA== - -"@rollup/rollup-linux-x64-musl@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.6.tgz#bafa759ab43e8eab9edf242a8259ffb4f2a57a5d" - integrity sha512-ch7M+9Tr5R4FK40FHQk8VnML0Szi2KRujUgHXd/HjuH9ifH72GUmw6lStZBo3c3GB82vHa0ZoUfjfcM7JiiMrQ== - -"@rollup/rollup-win32-arm64-msvc@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.0.tgz#2fef1a90f1402258ef915ae5a94cc91a5a1d5bfc" - integrity sha512-s5oFkZ/hFcrlAyBTONFY1TWndfyre1wOMwU+6KCpm/iatybvrRgmZVM+vCFwxmC5ZhdlgfE0N4XorsDpi7/4XQ== - -"@rollup/rollup-win32-arm64-msvc@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.1.tgz#18349db8250559a5460d59eb3575f9781be4ab98" - integrity sha512-3Q3brDgA86gHXWHklrwdREKIrIbxC0ZgU8lwpj0eEKGBQH+31uPqr0P2v11pn0tSIxHvcdOWxa4j+YvLNx1i6g== - -"@rollup/rollup-win32-arm64-msvc@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.6.tgz#1cc3416682e5a20d8f088f26657e6e47f8db468e" - integrity sha512-VD6qnR99dhmTQ1mJhIzXsRcTBvTjbfbGGwKAHcu+52cVl15AC/kplkhxzW/uT0Xl62Y/meBKDZvoJSJN+vTeGA== - -"@rollup/rollup-win32-ia32-msvc@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.0.tgz#a18ad47a95c5f264defb60acdd8c27569f816fc1" - integrity sha512-G9+TEqRnAA6nbpqyUqgTiopmnfgnMkR3kMukFBDsiyy23LZvUCpiUwjTRx6ezYCjJODXrh52rBR9oXvm+Fp5wg== - -"@rollup/rollup-win32-ia32-msvc@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.1.tgz#199648b68271f7ab9d023f5c077725d51d12d466" - integrity sha512-tNg+jJcKR3Uwe4L0/wY3Ro0H+u3nrb04+tcq1GSYzBEmKLeOQF2emk1whxlzNqb6MMrQ2JOcQEpuuiPLyRcSIw== - -"@rollup/rollup-win32-ia32-msvc@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.6.tgz#7d2251e1aa5e8a1e47c86891fe4547a939503461" - integrity sha512-J9AFDq/xiRI58eR2NIDfyVmTYGyIZmRcvcAoJ48oDld/NTR8wyiPUu2X/v1navJ+N/FGg68LEbX3Ejd6l8B7MQ== - -"@rollup/rollup-win32-x64-msvc@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.0.tgz#20c09cf44dcb082140cc7f439dd679fe4bba3375" - integrity sha512-2jsCDZwtQvRhejHLfZ1JY6w6kEuEtfF9nzYsZxzSlNVKDX+DpsDJ+Rbjkm74nvg2rdx0gwBS+IMdvwJuq3S9pQ== - -"@rollup/rollup-win32-x64-msvc@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.1.tgz#4d3ec02dbf280c20bfeac7e50cd5669b66f9108f" - integrity sha512-xGiIH95H1zU7naUyTKEyOA/I0aexNMUdO9qRv0bLKN3qu25bBdrxZHqA3PTJ24YNN/GdMzG4xkDcd/GvjuhfLg== - -"@rollup/rollup-win32-x64-msvc@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.6.tgz#2c1fb69e02a3f1506f52698cfdc3a8b6386df9a6" - integrity sha512-jqzNLhNDvIZOrt69Ce4UjGRpXJBzhUBzawMwnaDAwyHriki3XollsewxWzOzz+4yOFDkuJHtTsZFwMxhYJWmLQ== - -"@sentry-internal/feedback@7.100.1": - version "7.100.1" - resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-7.100.1.tgz#99585ba6f71eca3e7afe918273dd55b12f3aac8a" - integrity sha512-yqcRVnjf+qS+tC4NxOKLJOaSJ+csHmh/dHUzvCTkf5rLsplwXYRnny2r0tqGTQ4tuXMxwgSMKPYwicg81P+xuw== - dependencies: - "@sentry/core" "7.100.1" - "@sentry/types" "7.100.1" - "@sentry/utils" "7.100.1" - -"@sentry-internal/replay-canvas@7.100.1": - version "7.100.1" - resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-7.100.1.tgz#d37228575931b869d2ad415af46b342d83dd0fd7" - integrity sha512-TnqxqJGhbFhhYRhTG2WLFer+lVieV7mNGeIxFBiw1L4kuj8KGl+C0sknssKyZSRVJFSahhHIosHJGRMkkD//7g== - dependencies: - "@sentry/core" "7.100.1" - "@sentry/replay" "7.100.1" - "@sentry/types" "7.100.1" - "@sentry/utils" "7.100.1" - -"@sentry-internal/tracing@7.100.1": - version "7.100.1" - resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.100.1.tgz#4329492e50c390567197a4acbf7e3672b1db7820" - integrity sha512-+u9RRf5eL3StiyiRyAHZmdkAR7GTSGx4Mt4Lmi5NEtCcWlTGZ1QgW2r8ZbhouVmTiJkjhQgYCyej3cojtazeJg== - dependencies: - "@sentry/core" "7.100.1" - "@sentry/types" "7.100.1" - "@sentry/utils" "7.100.1" - -"@sentry/browser@7.100.1": - version "7.100.1" - resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.100.1.tgz#146ffca94cc187ecbf49915ef3100f6037316110" - integrity sha512-IxHQ08ixf0bmaWpe4yt1J4UUsOpg02fxax9z3tOQYXw5MSzz5pDXn8M8DFUVJB3wWuyXhHXTub9yD3VIP9fnoA== - dependencies: - "@sentry-internal/feedback" "7.100.1" - "@sentry-internal/replay-canvas" "7.100.1" - "@sentry-internal/tracing" "7.100.1" - "@sentry/core" "7.100.1" - "@sentry/replay" "7.100.1" - "@sentry/types" "7.100.1" - "@sentry/utils" "7.100.1" - -"@sentry/core@7.100.1": - version "7.100.1" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.100.1.tgz#7b8e101a931af8e8b3b2449534749f882772df4f" - integrity sha512-f+ItUge/o9AjlveQq0ZUbQauKlPH1FIJbC1TRaYLJ4KNfOdrsh8yZ29RmWv0cFJ/e+FGTr603gWpRPObF5rM8Q== - dependencies: - "@sentry/types" "7.100.1" - "@sentry/utils" "7.100.1" +"@rollup/rollup-android-arm-eabi@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz#8b613b9725e8f9479d142970b106b6ae878610d5" + integrity sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w== + +"@rollup/rollup-android-arm64@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.4.tgz#654ca1049189132ff602bfcf8df14c18da1f15fb" + integrity sha512-VXoK5UMrgECLYaMuGuVTOx5kcuap1Jm8g/M83RnCHBKOqvPPmROFJGQaZhGccnsFtfXQ3XYa4/jMCJvZnbJBdA== + +"@rollup/rollup-darwin-arm64@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.4.tgz#6d241d099d1518ef0c2205d96b3fa52e0fe1954b" + integrity sha512-xMM9ORBqu81jyMKCDP+SZDhnX2QEVQzTcC6G18KlTQEzWK8r/oNZtKuZaCcHhnsa6fEeOBionoyl5JsAbE/36Q== + +"@rollup/rollup-darwin-x64@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.4.tgz#42bd19d292a57ee11734c980c4650de26b457791" + integrity sha512-aJJyYKQwbHuhTUrjWjxEvGnNNBCnmpHDvrb8JFDbeSH3m2XdHcxDd3jthAzvmoI8w/kSjd2y0udT+4okADsZIw== + +"@rollup/rollup-linux-arm-gnueabihf@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.4.tgz#f23555ee3d8fe941c5c5fd458cd22b65eb1c2232" + integrity sha512-j63YtCIRAzbO+gC2L9dWXRh5BFetsv0j0va0Wi9epXDgU/XUi5dJKo4USTttVyK7fGw2nPWK0PbAvyliz50SCQ== + +"@rollup/rollup-linux-arm-musleabihf@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.4.tgz#f3bbd1ae2420f5539d40ac1fde2b38da67779baa" + integrity sha512-dJnWUgwWBX1YBRsuKKMOlXCzh2Wu1mlHzv20TpqEsfdZLb3WoJW2kIEsGwLkroYf24IrPAvOT/ZQ2OYMV6vlrg== + +"@rollup/rollup-linux-arm64-gnu@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.4.tgz#7abe900120113e08a1f90afb84c7c28774054d15" + integrity sha512-AdPRoNi3NKVLolCN/Sp4F4N1d98c4SBnHMKoLuiG6RXgoZ4sllseuGioszumnPGmPM2O7qaAX/IJdeDU8f26Aw== + +"@rollup/rollup-linux-arm64-musl@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.4.tgz#9e655285c8175cd44f57d6a1e8e5dedfbba1d820" + integrity sha512-Gl0AxBtDg8uoAn5CCqQDMqAx22Wx22pjDOjBdmG0VIWX3qUBHzYmOKh8KXHL4UpogfJ14G4wk16EQogF+v8hmA== + +"@rollup/rollup-linux-powerpc64le-gnu@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.4.tgz#9a79ae6c9e9d8fe83d49e2712ecf4302db5bef5e" + integrity sha512-3aVCK9xfWW1oGQpTsYJJPF6bfpWfhbRnhdlyhak2ZiyFLDaayz0EP5j9V1RVLAAxlmWKTDfS9wyRyY3hvhPoOg== + +"@rollup/rollup-linux-riscv64-gnu@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.4.tgz#67ac70eca4ace8e2942fabca95164e8874ab8128" + integrity sha512-ePYIir6VYnhgv2C5Xe9u+ico4t8sZWXschR6fMgoPUK31yQu7hTEJb7bCqivHECwIClJfKgE7zYsh1qTP3WHUA== + +"@rollup/rollup-linux-s390x-gnu@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.4.tgz#9f883a7440f51a22ed7f99e1d070bd84ea5005fc" + integrity sha512-GqFJ9wLlbB9daxhVlrTe61vJtEY99/xB3C8e4ULVsVfflcpmR6c8UZXjtkMA6FhNONhj2eA5Tk9uAVw5orEs4Q== + +"@rollup/rollup-linux-x64-gnu@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.4.tgz#70116ae6c577fe367f58559e2cffb5641a1dd9d0" + integrity sha512-87v0ol2sH9GE3cLQLNEy0K/R0pz1nvg76o8M5nhMR0+Q+BBGLnb35P0fVz4CQxHYXaAOhE8HhlkaZfsdUOlHwg== + +"@rollup/rollup-linux-x64-musl@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.4.tgz#f473f88219feb07b0b98b53a7923be716d1d182f" + integrity sha512-UV6FZMUgePDZrFjrNGIWzDo/vABebuXBhJEqrHxrGiU6HikPy0Z3LfdtciIttEUQfuDdCn8fqh7wiFJjCNwO+g== + +"@rollup/rollup-win32-arm64-msvc@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.4.tgz#4349482d17f5d1c58604d1c8900540d676f420e0" + integrity sha512-BjI+NVVEGAXjGWYHz/vv0pBqfGoUH0IGZ0cICTn7kB9PyjrATSkX+8WkguNjWoj2qSr1im/+tTGRaY+4/PdcQw== + +"@rollup/rollup-win32-ia32-msvc@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.4.tgz#a6fc39a15db618040ec3c2a24c1e26cb5f4d7422" + integrity sha512-SiWG/1TuUdPvYmzmYnmd3IEifzR61Tragkbx9D3+R8mzQqDBz8v+BvZNDlkiTtI9T15KYZhP0ehn3Dld4n9J5g== + +"@rollup/rollup-win32-x64-msvc@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.4.tgz#3dd5d53e900df2a40841882c02e56f866c04d202" + integrity sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q== + +"@sentry-internal/feedback@7.119.0": + version "7.119.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-7.119.0.tgz#429b3ea0fd34e928d2e7de5dcbe9377272a3f221" + integrity sha512-om8TkAU5CQGO8nkmr7qsSBVkP+/vfeS4JgtW3sjoTK0fhj26+DljR6RlfCGWtYQdPSP6XV7atcPTjbSnsmG9FQ== + dependencies: + "@sentry/core" "7.119.0" + "@sentry/types" "7.119.0" + "@sentry/utils" "7.119.0" + +"@sentry-internal/replay-canvas@7.119.0": + version "7.119.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-7.119.0.tgz#85669d184ba79150e64d05de02f5e2b616e68371" + integrity sha512-NL02VQx6ekPxtVRcsdp1bp5Tb5w6vnfBKSIfMKuDRBy5A10Uc3GSoy/c3mPyHjOxB84452A+xZSx6bliEzAnuA== + dependencies: + "@sentry/core" "7.119.0" + "@sentry/replay" "7.119.0" + "@sentry/types" "7.119.0" + "@sentry/utils" "7.119.0" + +"@sentry-internal/tracing@7.119.0": + version "7.119.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.119.0.tgz#201561af2a4ad1837333287c26050a5e688537ca" + integrity sha512-oKdFJnn+56f0DHUADlL8o9l8jTib3VDLbWQBVkjD9EprxfaCwt2m8L5ACRBdQ8hmpxCEo4I8/6traZ7qAdBUqA== + dependencies: + "@sentry/core" "7.119.0" + "@sentry/types" "7.119.0" + "@sentry/utils" "7.119.0" + +"@sentry/browser@7.119.0": + version "7.119.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.119.0.tgz#65004015c107be5d2f49a852ebcffc5d19d90e0d" + integrity sha512-WwmW1Y4D764kVGeKmdsNvQESZiAn9t8LmCWO0ucBksrjL2zw9gBPtOpRcO6l064sCLeSxxzCN+kIxhRm1gDFEA== + dependencies: + "@sentry-internal/feedback" "7.119.0" + "@sentry-internal/replay-canvas" "7.119.0" + "@sentry-internal/tracing" "7.119.0" + "@sentry/core" "7.119.0" + "@sentry/integrations" "7.119.0" + "@sentry/replay" "7.119.0" + "@sentry/types" "7.119.0" + "@sentry/utils" "7.119.0" + +"@sentry/core@7.119.0": + version "7.119.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.119.0.tgz#a6e41119bb03ec27689f9ad04e79d1fba5b7fc37" + integrity sha512-CS2kUv9rAJJEjiRat6wle3JATHypB0SyD7pt4cpX5y0dN5dZ1JrF57oLHRMnga9fxRivydHz7tMTuBhSSwhzjw== + dependencies: + "@sentry/types" "7.119.0" + "@sentry/utils" "7.119.0" + +"@sentry/integrations@7.119.0": + version "7.119.0" + resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.119.0.tgz#5b25c603026dbacfe1ae7bb8d768506a129149fb" + integrity sha512-OHShvtsRW0A+ZL/ZbMnMqDEtJddPasndjq+1aQXw40mN+zeP7At/V1yPZyFaURy86iX7Ucxw5BtmzuNy7hLyTA== + dependencies: + "@sentry/core" "7.119.0" + "@sentry/types" "7.119.0" + "@sentry/utils" "7.119.0" + localforage "^1.8.1" "@sentry/react@^7.57.0": - version "7.100.1" - resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.100.1.tgz#a8621f2124848b6a7bb1fc6279167f5e3cbc44f1" - integrity sha512-EdrBtrXVLK2LSx4Rvz/nQP7HZUZQmr+t3GHV8436RAhF6vs5mntACVMBoQJRWiUvtZ1iRo3rIsIdah7DLiFPgQ== - dependencies: - "@sentry/browser" "7.100.1" - "@sentry/core" "7.100.1" - "@sentry/types" "7.100.1" - "@sentry/utils" "7.100.1" + version "7.119.0" + resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.119.0.tgz#79f2c9d94322a3afbfa8af9f5b872f7c2e9b0820" + integrity sha512-cf8Cei+qdSA26gx+IMAuc/k44PeBImNzIpXi3930SLhUe44ypT5OZ/44L6xTODHZzTIyMSJPduf59vT2+eW9yg== + dependencies: + "@sentry/browser" "7.119.0" + "@sentry/core" "7.119.0" + "@sentry/types" "7.119.0" + "@sentry/utils" "7.119.0" hoist-non-react-statics "^3.3.2" -"@sentry/replay@7.100.1": - version "7.100.1" - resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.100.1.tgz#d9af5f8e92ce0f93cef89f5aef74d91a8d12c3eb" - integrity sha512-B1NFjzGEFaqejxBRdUyEzH8ChXc2kfiqlA/W/Lg0aoWIl2/7nuMk+l4ld9gW5F5bIAXDTVd5vYltb1lWEbpr7w== +"@sentry/replay@7.119.0": + version "7.119.0" + resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.119.0.tgz#50881079d013c77f87a994331d8bcad1d49e0960" + integrity sha512-BnNsYL+X5I4WCH6wOpY6HQtp4MgVt0NVlhLUsEyrvMUiTs0bPkDBrulsgZQBUKJsbOr3l9nHrFoNVB/0i6WNLA== dependencies: - "@sentry-internal/tracing" "7.100.1" - "@sentry/core" "7.100.1" - "@sentry/types" "7.100.1" - "@sentry/utils" "7.100.1" + "@sentry-internal/tracing" "7.119.0" + "@sentry/core" "7.119.0" + "@sentry/types" "7.119.0" + "@sentry/utils" "7.119.0" -"@sentry/types@7.100.1": - version "7.100.1" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.100.1.tgz#1349b77269cecf4e80c087842575bd1a001e9995" - integrity sha512-fLM+LedHuKzOd8IhXBqaQuym+AA519MGjeczBa5kGakes/BbAsUMwsNfjsKQedp7Kh44RgYF99jwoRPK2oDrXw== +"@sentry/types@7.119.0": + version "7.119.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.119.0.tgz#8b3d7a1405c362e75cd900d46089df4e70919d2a" + integrity sha512-27qQbutDBPKGbuJHROxhIWc1i0HJaGLA90tjMu11wt0E4UNxXRX+UQl4Twu68v4EV3CPvQcEpQfgsViYcXmq+w== -"@sentry/utils@7.100.1": - version "7.100.1" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.100.1.tgz#6e26f3b06b1e485a2180f464ab3374ecb8d5e407" - integrity sha512-Ve6dXr1o6xiBe3VCoJgiutmBKrugryI65EZAbYto5XI+t+PjiLLf9wXtEMF24ZrwImo4Lv3E9Uqza+fWkEbw6A== +"@sentry/utils@7.119.0": + version "7.119.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.119.0.tgz#debe29020f6ef3786a5bd855cf1b97116b7be826" + integrity sha512-ZwyXexWn2ZIe2bBoYnXJVPc2esCSbKpdc6+0WJa8eutXfHq3FRKg4ohkfCBpfxljQGEfP1+kfin945lA21Ka+A== dependencies: - "@sentry/types" "7.100.1" + "@sentry/types" "7.119.0" "@storybook/addon-a11y@^8.3.0": - version "8.3.2" - resolved "https://registry.yarnpkg.com/@storybook/addon-a11y/-/addon-a11y-8.3.2.tgz#b8ce0a3f922d86a0283f2249e2b1f47bcc97ddb1" - integrity sha512-i0qyMp+MxzJ3UY3Absqwxhry4JqZo9yk1XLWld7hJpfAzmrulnaIctudQ940/OMFPcEIsOVdg8euz0IGW3HTNw== + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-a11y/-/addon-a11y-8.3.3.tgz#1ab0db4b559f6ba6bb33c928c634b15d21bd5a72" + integrity sha512-TiCbNfKJOBD2b8mMqHOii8ntdt0V4+ifAgzmGku+F1hdf2EhEw1nL6CHpvnx/GBXoGeK4mrPJIKKoPNp+zz0dw== dependencies: - "@storybook/addon-highlight" "8.3.2" + "@storybook/addon-highlight" "8.3.3" axe-core "^4.2.0" "@storybook/addon-actions@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-8.3.0.tgz#0a5c2d7776ae201fa331bcdc48230fc866e854ac" - integrity sha512-HvAc3fW979JVw8CSKXZMouvgrJ2BNLNWaUB8jNokQb3Us00P6igVKLwg/pBV8GBgDr5Ng4pHYqi/ZH+xzEYFFw== + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-8.3.3.tgz#6b3289071fa887eb08aa858aa64a87e93f0bb440" + integrity sha512-cbpksmld7iADwDGXgojZ4r8LGI3YA3NP68duAHg2n1dtnx1oUaFK5wd6dbNuz7GdjyhIOIy3OKU1dAuylYNGOQ== dependencies: "@storybook/global" "^5.0.0" "@types/uuid" "^9.0.1" @@ -2032,9 +1528,9 @@ uuid "^9.0.0" "@storybook/addon-controls@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/addon-controls/-/addon-controls-8.3.0.tgz#692bcdddd1db438a9cc7434ff947ebf215191542" - integrity sha512-Id4j6Neimkdq0OyfQ3qkHpKLisbN08M8pXHDI/A0VeF91xEGBdc1bJgS/EU+ifa24tr5SRYwlAlcBDAWJbZMfA== + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-controls/-/addon-controls-8.3.3.tgz#bad8729f03897f9df0909a11e9181a9d88eb274d" + integrity sha512-78xRtVpY7eX/Lti00JLgwYCBRB6ZcvzY3SWk0uQjEqcTnQGoQkVg2L7oWFDlDoA1LBY18P5ei2vu8MYT9GXU4g== dependencies: "@storybook/global" "^5.0.0" dequal "^2.0.2" @@ -2042,15 +1538,15 @@ ts-dedent "^2.0.0" "@storybook/addon-docs@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/addon-docs/-/addon-docs-8.3.0.tgz#76469c7c24d932296d027407424c8876b06d658a" - integrity sha512-LrvWBDX5Vi//82Q78QRbTsG+9rJU9JJFAVPk1NnLp2Yn0F4FueVzIw8AabAkZFy0LHPMGV+EHpkPtYz4Czkhgw== + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-docs/-/addon-docs-8.3.3.tgz#77869084cbbfaec9d3bbcdf18413de7f627ce81d" + integrity sha512-REUandqq1RnMNOhsocRwx5q2fdlBAYPTDFlKASYfEn4Ln5NgbQRGxOAWl7yXAAFzbDmUDU7K20hkauecF0tyMw== dependencies: "@mdx-js/react" "^3.0.0" - "@storybook/blocks" "8.3.0" - "@storybook/csf-plugin" "8.3.0" + "@storybook/blocks" "8.3.3" + "@storybook/csf-plugin" "8.3.3" "@storybook/global" "^5.0.0" - "@storybook/react-dom-shim" "8.3.0" + "@storybook/react-dom-shim" "8.3.3" "@types/react" "^16.8.0 || ^17.0.0 || ^18.0.0" fs-extra "^11.1.0" react "^16.8.0 || ^17.0.0 || ^18.0.0" @@ -2059,49 +1555,49 @@ rehype-slug "^6.0.0" ts-dedent "^2.0.0" -"@storybook/addon-highlight@8.3.2": - version "8.3.2" - resolved "https://registry.yarnpkg.com/@storybook/addon-highlight/-/addon-highlight-8.3.2.tgz#a23669cadeed5a5bd18ebbbcd6258f9492508b6b" - integrity sha512-JFL/JLBZfa89POgi8lBdt8TzzCS1bgN/X6Qj1MlTq3pxHYqO66eG8DtMLjpuXKOhs8Dhdgs9/uxy5Yd+MFVRmQ== +"@storybook/addon-highlight@8.3.3": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-highlight/-/addon-highlight-8.3.3.tgz#2e1d96bdd8049af7343300cbb43adb4480f3ed7d" + integrity sha512-MB084xJM66rLU+iFFk34kjLUiAWzDiy6Kz4uZRa1CnNqEK0sdI8HaoQGgOxTIa2xgJor05/8/mlYlMkP/0INsQ== dependencies: "@storybook/global" "^5.0.0" "@storybook/addon-mdx-gfm@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/addon-mdx-gfm/-/addon-mdx-gfm-8.3.0.tgz#2a6dadfa76b5f834a2a0f984ddcac0741f2495c8" - integrity sha512-qGaO5/3jd2mcxKiV4Gfloxgw4yvzCsj/ZwqysDIGVJtliguscWYbWE2JMz7zluUyt6nVMhQhDYkF9GnNU4yaoA== + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-mdx-gfm/-/addon-mdx-gfm-8.3.3.tgz#604930985453c4a4bdc3ccbab26ff043a54dc18d" + integrity sha512-jdwVXoBSEdmuw8L4MxUeJ/qIInADfCwdtShnfTQIJBBRucOl8ykgfTKKNjllT79TFiK0gsWoiZmE05P4wuBofw== dependencies: remark-gfm "^4.0.0" ts-dedent "^2.0.0" "@storybook/addon-measure@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/addon-measure/-/addon-measure-8.3.0.tgz#3a79b36ff08259c675ddaf099d14fdee06099484" - integrity sha512-0TZ2ihzX0mRr1rNrFDieDsIKASZ2qUg3eHDkskLKOhxwoUHqsLzXlvS/scKZ+zb8pgjrvsBAsjyPstlrK+z0Zg== + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-measure/-/addon-measure-8.3.3.tgz#9ff6e749ab6c0661252a195ec355f6a6c5bace07" + integrity sha512-R20Z83gnxDRrocES344dw1Of/zDhe3XHSM6TLq80UQTJ9PhnMI+wYHQlK9DsdP3KiRkI+pQA6GCOp0s2ZRy5dg== dependencies: "@storybook/global" "^5.0.0" tiny-invariant "^1.3.1" "@storybook/addon-storysource@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/addon-storysource/-/addon-storysource-8.3.0.tgz#da8087d763fa93fb4ec5a6519786e00515be289d" - integrity sha512-+owWKfUebwccrdboIkCNsqXT25LVwha8XT5UbnHbclKqBkMwtWIyl3HMOkXZ8MGLgDF0dm00iLbO59jVRlhDyQ== + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-storysource/-/addon-storysource-8.3.3.tgz#de1c0db04a927cc6af91aac9b7590cf30058b627" + integrity sha512-yPYQH9NepSNxoSsV9E7OV3/EVFrbU/r2B3E5WP/mCfqTXPg/5noce7iRi+rWqcVM1tsN1qPnSjfQQc7noF0h0Q== dependencies: - "@storybook/source-loader" "8.3.0" + "@storybook/source-loader" "8.3.3" estraverse "^5.2.0" tiny-invariant "^1.3.1" "@storybook/addon-viewport@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/addon-viewport/-/addon-viewport-8.3.0.tgz#30ec8e38ebbe22dfb0886f2b853ea90fa365309e" - integrity sha512-6h/0mKipUG6w2o5IOzyhvC/2ifJlSNIA60hLkJ291g42+ilzkydpby9TBN7FcnrVL3Bv+oLgkDLBWVCqma/fyw== + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-viewport/-/addon-viewport-8.3.3.tgz#53315cb90e013fdee514df86e415747f4be3126d" + integrity sha512-2S+UpbKAL+z1ppzUCkixjaem2UDMkfmm/kyJ1wm3A/ofGLYi4fjMSKNRckk+7NdolXGQJjBo0RcaotUTxFIFwQ== dependencies: memoizerific "^1.11.3" -"@storybook/blocks@8.3.0", "@storybook/blocks@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/blocks/-/blocks-8.3.0.tgz#afb6af3457a8772b3e9b5163f5e591985c1ef179" - integrity sha512-V7D5lv5R+GJya9cCZOCjmOVjhvP5J3KIaclQuuGGJda/ZD/SpwHcFOGSpo6sNR2UKHXXvb61oM8gRQQWDvqPlg== +"@storybook/blocks@8.3.3", "@storybook/blocks@^8.3.0": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/blocks/-/blocks-8.3.3.tgz#a123746b472488d3c6ccc08b1fe831474ec992b0" + integrity sha512-8Vsvxqstop3xfbsx3Dn1nEjyxvQUcOYd8vpxyp2YumxYO8FlXIRuYL6HAkYbcX8JexsKvCZYxor52D2vUGIKZg== dependencies: "@storybook/csf" "^0.1.11" "@storybook/global" "^5.0.0" @@ -2118,12 +1614,12 @@ ts-dedent "^2.0.0" util-deprecate "^1.0.2" -"@storybook/builder-vite@8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/builder-vite/-/builder-vite-8.3.0.tgz#39118813f6938b6544cb635e26c362b35f307c57" - integrity sha512-9qo3zcZkEpy69E7cx9OHHexBe9+25vH0p+4sWZSjl2sjqjhaxLN5eXnODQbDsOKZNRVrLVTGmKxfFJzAJFnY0w== +"@storybook/builder-vite@8.3.3": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/builder-vite/-/builder-vite-8.3.3.tgz#40bc458ac735c0c0dac29d9bded6f4dd05bb9104" + integrity sha512-3yTXCLaB6bzhoPH3PqtacKkcaC1uV4L+IHTf1Zypx1NO1pLZHyhYf0T7dIOxTh2JZfqu1Pm9hTvOmWfR12m+9w== dependencies: - "@storybook/csf-plugin" "8.3.0" + "@storybook/csf-plugin" "8.3.3" "@types/find-cache-dir" "^3.2.1" browser-assert "^1.2.1" es-module-lexer "^1.5.0" @@ -2133,82 +1629,42 @@ magic-string "^0.30.0" ts-dedent "^2.0.0" -"@storybook/channels@8.0.5": - version "8.0.5" - resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-8.0.5.tgz#85744e03c18366b45a5e108c25cd9975d9828bf2" - integrity sha512-UWzjt4STzBgg28Q6FxqyJWwXLWYM6oSz9gGKMUJbn2vRAlEJaG3XwvpT39YFVDUIuiFSHguV5cisXY5Be4nOZw== - dependencies: - "@storybook/client-logger" "8.0.5" - "@storybook/core-events" "8.0.5" - "@storybook/global" "^5.0.0" - telejson "^7.2.0" - tiny-invariant "^1.3.1" - -"@storybook/client-logger@8.0.5": - version "8.0.5" - resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-8.0.5.tgz#8cafa514e9a9af054f926bc179264bef2198c0ce" - integrity sha512-6D7zvPPnLuTVlBNpZSdzEbk5xfWKhEG0gejtPnhjG9R5YzC/dFckdUI0gtvwGWUVMWhL3H/0gjRjhKujUMRY1Q== - dependencies: - "@storybook/global" "^5.0.0" - -"@storybook/components@^8.0.0": - version "8.0.5" - resolved "https://registry.yarnpkg.com/@storybook/components/-/components-8.0.5.tgz#e526b4600b4b8049108a1b63e71fee8d75ff8d3d" - integrity sha512-trBWV9gc4YhFhMKUevkBY9Mdk9WmYmthpBfmF0Y2vgrJQidUqkkQqfAMQThSJ0KLpV8k3fB27s5d93rgrr50Rg== - dependencies: - "@radix-ui/react-slot" "^1.0.2" - "@storybook/client-logger" "8.0.5" - "@storybook/csf" "^0.1.2" - "@storybook/global" "^5.0.0" - "@storybook/icons" "^1.2.5" - "@storybook/theming" "8.0.5" - "@storybook/types" "8.0.5" - memoizerific "^1.11.3" - util-deprecate "^1.0.2" - -"@storybook/components@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/components/-/components-8.3.0.tgz#45c39e5b6768efafe8e7dfd946c01617da59ae1a" - integrity sha512-SO/iTkmWp3aYCIy8DEhRMoOn6K7lcKTPNC/YjTvOFFzwq/CLq86WNqz6aX+wV5n6MvWTs7evSwMoz7lp4Lc4sw== +"@storybook/components@^8.0.0", "@storybook/components@^8.3.3": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/components/-/components-8.3.3.tgz#4b3ac4eedba3bca0884782916c4f6f1e7003b741" + integrity sha512-i2JYtesFGkdu+Hwuj+o9fLuO3yo+LPT1/8o5xBVYtEqsgDtEAyuRUWjSz8d8NPtzloGPOv5kvR6MokWDfbeMfw== -"@storybook/core-events@8.0.5", "@storybook/core-events@^8.0.0": - version "8.0.5" - resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-8.0.5.tgz#fa73281edd7d839439360259a0be48b04cd9a06a" - integrity sha512-26c0m7P7qt9zUKcD1noWLPJmZ+iS6MKXNngUgNBSxTtG20NFV3nxD0/tx9FzNfDVZDF6cHINkWj+FVBAaVuBVQ== - dependencies: - ts-dedent "^2.0.0" +"@storybook/core-events@^8.0.0": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-8.3.3.tgz#0b7cb3b737335a5d4091108a01352720e0e1f965" + integrity sha512-YL+gBuCS81qktzTkvw0MXUJW0bYAXfRzMoiLfDBTrEKZfcJOB4JAlMGmvRRar0+jygK3icD42Rl5BwWoZY6KFQ== -"@storybook/core@8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/core/-/core-8.3.0.tgz#c08ff10405fa935044678c8ae92c7be14dd01bdb" - integrity sha512-UeErpD0xRIP2nFA2TjPYxtEyv24O6VRfq2XXU5ki2QPYnxOxAPBbrMHCADjgBwNS4S2NUWTaVBYxybISVbrj+w== +"@storybook/core@8.3.3": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/core/-/core-8.3.3.tgz#657ce39312ceec5ba03382fe4d4d83ca396bb9ab" + integrity sha512-pmf2bP3fzh45e56gqOuBT8sDX05hGdUKIZ/hcI84d5xmd6MeHiPW8th2v946wCHcxHzxib2/UU9vQUh+mB4VNw== dependencies: "@storybook/csf" "^0.1.11" "@types/express" "^4.17.21" + better-opn "^3.0.2" browser-assert "^1.2.1" esbuild "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0" esbuild-register "^3.5.0" express "^4.19.2" + jsdoc-type-pratt-parser "^4.0.0" process "^0.11.10" recast "^0.23.5" semver "^7.6.2" util "^0.12.5" ws "^8.2.3" -"@storybook/csf-plugin@8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/csf-plugin/-/csf-plugin-8.3.0.tgz#33fbc6799e7e9cdcfbb41219ef2bf863b14096fc" - integrity sha512-sCmeN/OVYj95TKkMqJqxbaztIbdv5jCrtrXuNg4oJaGzNucmMNAbmv2jK2tCNE6Uz2X9IMRcseFX/h9TgjyJ9A== +"@storybook/csf-plugin@8.3.3": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/csf-plugin/-/csf-plugin-8.3.3.tgz#8112d98222f9b3650d5924673d30dfd9bb55457b" + integrity sha512-7AD7ojpXr3THqpTcEI4K7oKUfSwt1hummgL/cASuQvEPOwAZCVZl2gpGtKxcXhtJXTkn3GMCAvlYMoe7O/1YWw== dependencies: unplugin "^1.3.1" -"@storybook/csf@^0.0.1": - version "0.0.1" - resolved "https://registry.yarnpkg.com/@storybook/csf/-/csf-0.0.1.tgz#95901507dc02f0bc6f9ac8ee1983e2fc5bb98ce6" - integrity sha512-USTLkZze5gkel8MYCujSRBVIrUQ3YPBrLOx7GNk/0wttvVtlzWXAq9eLbQ4p/NicGxP+3T7KPEMVV//g+yubpw== - dependencies: - lodash "^4.17.15" - "@storybook/csf@^0.1.11": version "0.1.11" resolved "https://registry.yarnpkg.com/@storybook/csf/-/csf-0.1.11.tgz#ad685a4fe564a47a6b73571c2e7c07b526f4f71b" @@ -2216,90 +1672,57 @@ dependencies: type-fest "^2.19.0" -"@storybook/csf@^0.1.2": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@storybook/csf/-/csf-0.1.2.tgz#8e7452f0097507f5841b5ade3f5da1525bc9afb2" - integrity sha512-ePrvE/pS1vsKR9Xr+o+YwdqNgHUyXvg+1Xjx0h9LrVx7Zq4zNe06pd63F5EvzTbCbJsHj7GHr9tkiaqm7U8WRA== - dependencies: - type-fest "^2.19.0" - "@storybook/global@^5.0.0": version "5.0.0" resolved "https://registry.yarnpkg.com/@storybook/global/-/global-5.0.0.tgz#b793d34b94f572c1d7d9e0f44fac4e0dbc9572ed" integrity sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ== -"@storybook/icons@^1.2.10": - version "1.2.10" - resolved "https://registry.yarnpkg.com/@storybook/icons/-/icons-1.2.10.tgz#d3d44912a3a88f3f04f77ce2c23a7e47e796f766" - integrity sha512-310apKdDcjbbX2VSLWPwhEwAgjxTzVagrwucVZIdGPErwiAppX8KvBuWZgPo+rQLVrtH8S+pw1dbUwjcE6d7og== +"@storybook/icons@^1.2.10", "@storybook/icons@^1.2.5": + version "1.2.12" + resolved "https://registry.yarnpkg.com/@storybook/icons/-/icons-1.2.12.tgz#3e4c939113b67df7ab17b78f805dbb57f4acf0db" + integrity sha512-UxgyK5W3/UV4VrI3dl6ajGfHM4aOqMAkFLWe2KibeQudLf6NJpDrDMSHwZj+3iKC4jFU7dkKbbtH2h/al4sW3Q== -"@storybook/icons@^1.2.5": - version "1.2.9" - resolved "https://registry.yarnpkg.com/@storybook/icons/-/icons-1.2.9.tgz#bb4a51a79e186b62e2dd0e04928b8617ac573838" - integrity sha512-cOmylsz25SYXaJL/gvTk/dl3pyk7yBFRfeXTsHvTA3dfhoU/LWSq0NKL9nM7WBasJyn6XPSGnLS4RtKXLw5EUg== - -"@storybook/manager-api@^8.0.0": - version "8.0.5" - resolved "https://registry.yarnpkg.com/@storybook/manager-api/-/manager-api-8.0.5.tgz#7fdc49803f1507bea97392bfd05760071a19d838" - integrity sha512-2Q+DI9XU1U4EBrihnyfo+kuRK7T3Ce2eSlWEHHkTZ3OYSf+EhFxLUA6AOfMoA1B0nzNEr6SUkW8DBvMrtdTQMA== - dependencies: - "@storybook/channels" "8.0.5" - "@storybook/client-logger" "8.0.5" - "@storybook/core-events" "8.0.5" - "@storybook/csf" "^0.1.2" - "@storybook/global" "^5.0.0" - "@storybook/icons" "^1.2.5" - "@storybook/router" "8.0.5" - "@storybook/theming" "8.0.5" - "@storybook/types" "8.0.5" - dequal "^2.0.2" - lodash "^4.17.21" - memoizerific "^1.11.3" - store2 "^2.14.2" - telejson "^7.2.0" - ts-dedent "^2.0.0" +"@storybook/manager-api@^8.0.0", "@storybook/manager-api@^8.3.0", "@storybook/manager-api@^8.3.3": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/manager-api/-/manager-api-8.3.3.tgz#5518cc761264c9972732fcd9e025a7bc2fee7297" + integrity sha512-Na4U+McOeVUJAR6qzJfQ6y2Qt0kUgEDUriNoAn+curpoKPTmIaZ79RAXBzIqBl31VyQKknKpZbozoRGf861YaQ== -"@storybook/manager-api@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/manager-api/-/manager-api-8.3.0.tgz#0c3e33e3091be2122670b61ba601893c19d5dd47" - integrity sha512-5WBLEFHpe4H+9vZZLjNh7msIkyl9MPt4/C2nI+MXKZyU55xBBgiAy4fcD9aj02PcbhyR4JhLqbqmdeBe5Xafeg== - -"@storybook/preview-api@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/preview-api/-/preview-api-8.3.0.tgz#763126866e9dc8cc2ba6a9506bf84c020987b048" - integrity sha512-pHq/T7oWBfzc9TCIPYyJQUXuiUiFfmdrcYvuZE1kf46i7wXh9Q2/Kd3BUJWSCpBXUMoYfAxg9YysGljMII8LWA== +"@storybook/preview-api@^8.3.0", "@storybook/preview-api@^8.3.3": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/preview-api/-/preview-api-8.3.3.tgz#9f625a2d5e647137c5df7e419eda59e98f88cd44" + integrity sha512-GP2QlaF3BBQGAyo248N7549YkTQjCentsc1hUvqPnFWU4xfjkejbnFk8yLaIw0VbYbL7jfd7npBtjZ+6AnphMQ== -"@storybook/react-dom-shim@8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/react-dom-shim/-/react-dom-shim-8.3.0.tgz#e6c8c75ff725a9a096fb63b46dc4108e51428857" - integrity sha512-87X4cvgwFT1ll5SzXgQq6iGbkVCgxLBpBm58akF/hzpeRkwfJDncGi/A5hElOJrBg63IkznmSJE7tf9RkrboqQ== +"@storybook/react-dom-shim@8.3.3": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/react-dom-shim/-/react-dom-shim-8.3.3.tgz#0a23588f507c5c69b1153e43f16c37dbf38b82f1" + integrity sha512-0dPC9K7+K5+X/bt3GwYmh+pCpisUyKVjWsI+PkzqGnWqaXFakzFakjswowIAIO1rf7wYZR591x3ehUAyL2bJiQ== "@storybook/react-vite@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/react-vite/-/react-vite-8.3.0.tgz#95efa85132b540beeffce15d46a4c2bd6bab4080" - integrity sha512-VcKp/mpO8M+JsyprTGLLvAzwx7PChdWFDBasyQ0MO+YVwci78gPAZnfWNZaaEB2mdDgPPGuoSTwBgzZmP3FsPg== + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/react-vite/-/react-vite-8.3.3.tgz#3ce3d5e25b302ba256c74e1e7871f38eba23cdc6" + integrity sha512-vzOqVaA/rv+X5J17eWKxdZztMKEKfsCSP8pNNmrqXWxK3pSlW0fAPxtn1kw3UNxGtAv71pcqvaCUtTJKqI1PYA== dependencies: - "@joshwooding/vite-plugin-react-docgen-typescript" "0.3.1" + "@joshwooding/vite-plugin-react-docgen-typescript" "0.3.0" "@rollup/pluginutils" "^5.0.2" - "@storybook/builder-vite" "8.3.0" - "@storybook/react" "8.3.0" + "@storybook/builder-vite" "8.3.3" + "@storybook/react" "8.3.3" find-up "^5.0.0" magic-string "^0.30.0" react-docgen "^7.0.0" resolve "^1.22.8" tsconfig-paths "^4.2.0" -"@storybook/react@8.3.0", "@storybook/react@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/react/-/react-8.3.0.tgz#2619341ece6613f81eb1e6e056929525fbcdcf85" - integrity sha512-qd8IKXqaOG9m0VK0QukFMmKpjmm7sy1R3T681dLet8s+AEAimLH/RiBzd+0dxWng2H/Ng6ldUmCtd3Cs6w/EFQ== +"@storybook/react@8.3.3", "@storybook/react@^8.3.0": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/react/-/react-8.3.3.tgz#87d16b3a22f4ace86747f6a382f506a7550a31dc" + integrity sha512-fHOW/mNqI+sZWttGOE32Q+rAIbN7/Oib091cmE8usOM0z0vPNpywUBtqC2cCQH39vp19bhTsQaSsTcoBSweAHw== dependencies: - "@storybook/components" "^8.3.0" + "@storybook/components" "^8.3.3" "@storybook/global" "^5.0.0" - "@storybook/manager-api" "^8.3.0" - "@storybook/preview-api" "^8.3.0" - "@storybook/react-dom-shim" "8.3.0" - "@storybook/theming" "^8.3.0" + "@storybook/manager-api" "^8.3.3" + "@storybook/preview-api" "^8.3.3" + "@storybook/react-dom-shim" "8.3.3" + "@storybook/theming" "^8.3.3" "@types/escodegen" "^0.0.6" "@types/estree" "^0.0.51" "@types/node" "^22.0.0" @@ -2315,48 +1738,20 @@ type-fest "~2.19" util-deprecate "^1.0.2" -"@storybook/router@8.0.5": - version "8.0.5" - resolved "https://registry.yarnpkg.com/@storybook/router/-/router-8.0.5.tgz#b2c3e7fc763003a6d74d0b7061e8cb0a78e5bf66" - integrity sha512-1d4CqNJB5sA25HCd7jZ4eVqMsdlD4r4SuFA/eR6fas0lk7yjVCpG1zWfvSSk5tKoVcNLSptc/TYBiSr2rcGRvw== - dependencies: - "@storybook/client-logger" "8.0.5" - memoizerific "^1.11.3" - qs "^6.10.0" - -"@storybook/source-loader@8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/source-loader/-/source-loader-8.3.0.tgz#eb885c0db12cd851440ef7734a050f763ad211ee" - integrity sha512-WzFTUAuOQfaSYtbj69SG+YfKQkJPqajzL4oHSj653MCQF3V6VGOzE/tW4xBjqK/BiMAclY7bWyl44JWSQO5AjQ== +"@storybook/source-loader@8.3.3": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/source-loader/-/source-loader-8.3.3.tgz#f97db24267f6dc66ff662fa2c6f13362135be040" + integrity sha512-NeP7l53mvnnfwi+91vtRaibZer+UJi6gkoaGRCpphL3L+3qVIXN3p41uXhAy+TahdFI2dbrWvLSNgtsvdXVaFg== dependencies: "@storybook/csf" "^0.1.11" estraverse "^5.2.0" lodash "^4.17.21" prettier "^3.1.1" -"@storybook/theming@8.0.5", "@storybook/theming@^8.0.0": - version "8.0.5" - resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-8.0.5.tgz#e98aa8b761b93c2cff21213770a1bafb971f2c07" - integrity sha512-Hy4hJaKg6UUyivkUM77nCHccv4/lO++ZG9F88qBFVPdBlCwMHHnUrR7Hgje5cCVAy0jK6LyYlD3cWO6nS9OR8w== - dependencies: - "@emotion/use-insertion-effect-with-fallbacks" "^1.0.1" - "@storybook/client-logger" "8.0.5" - "@storybook/global" "^5.0.0" - memoizerific "^1.11.3" - -"@storybook/theming@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-8.3.0.tgz#96edd021c1cffd030974747a5a645bc9ef0f8dbd" - integrity sha512-lJCarAzswZvUgBt/o1LMJp+07Io5G2VI1+Fw+bgn+92kRD8otCFwuMZIy0u7cEjHiEGqGnpzThlIki6vFjEXeA== - -"@storybook/types@8.0.5": - version "8.0.5" - resolved "https://registry.yarnpkg.com/@storybook/types/-/types-8.0.5.tgz#268566058ee2871b13ba42df21abf861e823abf2" - integrity sha512-lYXwYF9qooQhYJkg3HWr6PD/vnQK+iO8fSKS8jtntwgJUKJvTbGZKAhNnS8WzNEI9jIp5QXFsSA367NjIDPaeQ== - dependencies: - "@storybook/channels" "8.0.5" - "@types/express" "^4.7.0" - file-system-cache "2.3.0" +"@storybook/theming@^8.0.0", "@storybook/theming@^8.3.0", "@storybook/theming@^8.3.3": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-8.3.3.tgz#38f2fb24e719f7a97c359a84c93be86ca2c9a20e" + integrity sha512-gWJKetI6XJQgkrvvry4ez10+jLaGNCQKi5ygRPM9N+qrjA3BB8F2LCuFUTBuisa4l64TILDNjfwP/YTWV5+u5A== "@svgr/babel-plugin-add-jsx-attribute@8.0.0": version "8.0.0" @@ -2441,145 +1836,76 @@ "@svgr/hast-util-to-babel-ast" "8.0.0" svg-parser "^2.0.4" -"@swc/core-darwin-arm64@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.4.0.tgz#11abf23b884929a467ba270cf6789b9c50c4248b" - integrity sha512-UTJ/Vz+s7Pagef6HmufWt6Rs0aUu+EJF4Pzuwvr7JQQ5b1DZeAAUeUtkUTFx/PvCbM8Xfw4XdKBUZfrIKCfW8A== - -"@swc/core-darwin-arm64@1.7.26": - version "1.7.26" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.26.tgz#5f4096c00e71771ca1b18c824f0c92a052c70760" - integrity sha512-FF3CRYTg6a7ZVW4yT9mesxoVVZTrcSWtmZhxKCYJX9brH4CS/7PRPjAKNk6kzWgWuRoglP7hkjQcd6EpMcZEAw== - -"@swc/core-darwin-x64@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.4.0.tgz#f044ddaca60c5081e907b148721ad7461f6f6dfe" - integrity sha512-f8v58u2GsGak8EtZFN9guXqE0Ep10Suny6xriaW2d8FGqESPyNrnBzli3aqkSeQk5gGqu2zJ7WiiKp3XoUOidA== - -"@swc/core-darwin-x64@1.7.26": - version "1.7.26" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.7.26.tgz#867b7a4f094e6b64201090ca5fcbf3da7d0f3e22" - integrity sha512-az3cibZdsay2HNKmc4bjf62QVukuiMRh5sfM5kHR/JMTrLyS6vSw7Ihs3UTkZjUxkLTT8ro54LI6sV6sUQUbLQ== - -"@swc/core-linux-arm-gnueabihf@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.4.0.tgz#52ceea673fc76692c0bd6d58e1863125c3e6173b" - integrity sha512-q2KAkBzmPcTnRij/Y1fgHCKAGevUX/H4uUESrw1J5gmUg9Qip6onKV80lTumA1/aooGJ18LOsB31qdbwmZk9OA== - -"@swc/core-linux-arm-gnueabihf@1.7.26": - version "1.7.26" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.7.26.tgz#35bb43894def296d92aaa2cc9372d48042f37777" - integrity sha512-VYPFVJDO5zT5U3RpCdHE5v1gz4mmR8BfHecUZTmD2v1JeFY6fv9KArJUpjrHEEsjK/ucXkQFmJ0jaiWXmpOV9Q== - -"@swc/core-linux-arm64-gnu@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.4.0.tgz#7f3ff1ab824ec48acdb39d231cbcb4096a4f9dd0" - integrity sha512-SknGu96W0mzHtLHWm+62fk5+Omp9fMPFO7AWyGFmz2tr8EgRRXtTSrBUnWhAbgcalnhen48GsvtMdxf1KNputg== - -"@swc/core-linux-arm64-gnu@1.7.26": - version "1.7.26" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.7.26.tgz#8e2321cc4ec84cbfed8f8e16ff1ed7b854450443" - integrity sha512-YKevOV7abpjcAzXrhsl+W48Z9mZvgoVs2eP5nY+uoMAdP2b3GxC0Df1Co0I90o2lkzO4jYBpTMcZlmUXLdXn+Q== - -"@swc/core-linux-arm64-musl@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.4.0.tgz#26c3b1f7947c19ef725997af716f230957d586f8" - integrity sha512-/k3TDvpBRMDNskHooNN1KqwUhcwkfBlIYxRTnJvsfT2C7My4pffR+4KXmt0IKynlTTbCdlU/4jgX4801FSuliw== - -"@swc/core-linux-arm64-musl@1.7.26": - version "1.7.26" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.7.26.tgz#b1c16e4b23ffa9ff19973eda6ffee35d2a7de7b0" - integrity sha512-3w8iZICMkQQON0uIcvz7+Q1MPOW6hJ4O5ETjA0LSP/tuKqx30hIniCGOgPDnv3UTMruLUnQbtBwVCZTBKR3Rkg== - -"@swc/core-linux-x64-gnu@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.4.0.tgz#2c7d03a04a7d045394cfed7d46419ff8816ec22e" - integrity sha512-GYsTMvNt5+WTVlwwQzOOWsPMw6P/F41u5PGHWmfev8Nd4QJ1h3rWPySKk4mV42IJwH9MgQCVSl3ygwNqwl6kFg== - -"@swc/core-linux-x64-gnu@1.7.26": - version "1.7.26" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.7.26.tgz#388e2cc13a010cd28787aead2cecf31eb491836d" - integrity sha512-c+pp9Zkk2lqb06bNGkR2Looxrs7FtGDMA4/aHjZcCqATgp348hOKH5WPvNLBl+yPrISuWjbKDVn3NgAvfvpH4w== - -"@swc/core-linux-x64-musl@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.4.0.tgz#0e76442dfb6d5026d8d6e7db6b2f4922b7692d0f" - integrity sha512-jGVPdM/VwF7kK/uYRW5N6FwzKf/FnDjGIR3RPvQokjYJy7Auk+3Oj21C0Jev7sIT9RYnO/TrFEoEozKeD/z2Qw== - -"@swc/core-linux-x64-musl@1.7.26": - version "1.7.26" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.7.26.tgz#51e0ff30981f26d7a5b97a7a7b5b291bad050d1a" - integrity sha512-PgtyfHBF6xG87dUSSdTJHwZ3/8vWZfNIXQV2GlwEpslrOkGqy+WaiiyE7Of7z9AvDILfBBBcJvJ/r8u980wAfQ== - -"@swc/core-win32-arm64-msvc@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.4.0.tgz#0177bebf312eb251d6749ab76259c0e08088e837" - integrity sha512-biHYm1AronEKlt47O/H8sSOBM2BKXMmWT+ApvlxUw50m1RGNnVnE0bgY7tylFuuSiWyXsQPJbmUV708JqORXVg== - -"@swc/core-win32-arm64-msvc@1.7.26": - version "1.7.26" - resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.7.26.tgz#a7fdcc4074c34ee6a026506b594d00323383c11f" - integrity sha512-9TNXPIJqFynlAOrRD6tUQjMq7KApSklK3R/tXgIxc7Qx+lWu8hlDQ/kVPLpU7PWvMMwC/3hKBW+p5f+Tms1hmA== - -"@swc/core-win32-ia32-msvc@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.4.0.tgz#27fa650280e5651aa42129eaf03e02787b866417" - integrity sha512-TL5L2tFQb19kJwv6+elToGBj74QXCn9j+hZfwQatvZEJRA5rDK16eH6oAE751dGUArhnWlW3Vj65hViPvTuycw== - -"@swc/core-win32-ia32-msvc@1.7.26": - version "1.7.26" - resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.7.26.tgz#ae7be6dde798eebee2000b8fd84e01a439b5bd6a" - integrity sha512-9YngxNcG3177GYdsTum4V98Re+TlCeJEP4kEwEg9EagT5s3YejYdKwVAkAsJszzkXuyRDdnHUpYbTrPG6FiXrQ== - -"@swc/core-win32-x64-msvc@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.4.0.tgz#bd575c599bd6847bddc4863a3babd85e3db5e11e" - integrity sha512-e2xVezU7XZ2Stzn4i7TOQe2Kn84oYdG0M3A7XI7oTdcpsKCcKwgiMoroiAhqCv+iN20KNqhnWwJiUiTj/qN5AA== - -"@swc/core-win32-x64-msvc@1.7.26": - version "1.7.26" - resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.7.26.tgz#310d607004d7319085a4dec20c0c38c3405cc05b" - integrity sha512-VR+hzg9XqucgLjXxA13MtV5O3C0bK0ywtLIBw/+a+O+Oc6mxFWHtdUeXDbIi5AiPbn0fjgVJMqYnyjGyyX8u0w== - -"@swc/core@^1.3.1": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.4.0.tgz#3a0ceeea5b889173f4592955fe1da4d071d86a76" - integrity sha512-wc5DMI5BJftnK0Fyx9SNJKkA0+BZSJQx8430yutWmsILkHMBD3Yd9GhlMaxasab9RhgKqZp7Ht30hUYO5ZDvQg== - dependencies: - "@swc/counter" "^0.1.1" - "@swc/types" "^0.1.5" - optionalDependencies: - "@swc/core-darwin-arm64" "1.4.0" - "@swc/core-darwin-x64" "1.4.0" - "@swc/core-linux-arm-gnueabihf" "1.4.0" - "@swc/core-linux-arm64-gnu" "1.4.0" - "@swc/core-linux-arm64-musl" "1.4.0" - "@swc/core-linux-x64-gnu" "1.4.0" - "@swc/core-linux-x64-musl" "1.4.0" - "@swc/core-win32-arm64-msvc" "1.4.0" - "@swc/core-win32-ia32-msvc" "1.4.0" - "@swc/core-win32-x64-msvc" "1.4.0" - -"@swc/core@^1.5.7": - version "1.7.26" - resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.7.26.tgz#beda9b82063fcec7b56c958804a4d175aecf9a9d" - integrity sha512-f5uYFf+TmMQyYIoxkn/evWhNGuUzC730dFwAKGwBVHHVoPyak1/GvJUm6i1SKl+2Hrj9oN0i3WSoWWZ4pgI8lw== +"@swc/core-darwin-arm64@1.7.28": + version "1.7.28" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.28.tgz#f4ff1c09443a0040a29c7e1e7615f5f5642b6945" + integrity sha512-BNkj6enHo2pdzOpCtQGKZbXT2A/qWIr0CVtbTM4WkJ3MCK/glbFsyO6X59p1r8+gfaZG4bWYnTTu+RuUAcsL5g== + +"@swc/core-darwin-x64@1.7.28": + version "1.7.28" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.7.28.tgz#ce0a6d559084a794517a81457cdadbf61a55c55d" + integrity sha512-96zQ+X5Fd6P/RNPkOyikTJgEc2M4TzznfYvjRd2hye5h22jhxCLL/csoauDgN7lYfd7mwsZ/sVXwJTMKl+vZSA== + +"@swc/core-linux-arm-gnueabihf@1.7.28": + version "1.7.28" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.7.28.tgz#501375ac84c61dc718ed07239c7e44972f6c44e0" + integrity sha512-l2100Wx6LdXMOmOW3+KoHhBhyZrGdz8ylkygcVOC0QHp6YIATfuG+rRHksfyEWCSOdL3anM9MJZJX26KT/s+XQ== + +"@swc/core-linux-arm64-gnu@1.7.28": + version "1.7.28" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.7.28.tgz#75e99da625939627f5b45d3004a6cfd8d6cbf46e" + integrity sha512-03m6iQ5Bv9u2VPnNRyaBmE8eHi056eE39L0gXcqGoo46GAGuoqYHt9pDz8wS6EgoN4t85iBMUZrkCNqFKkN6ZQ== + +"@swc/core-linux-arm64-musl@1.7.28": + version "1.7.28" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.7.28.tgz#c737def355c0bf8db7d8e7bd87a3ae8bb3f9f8fc" + integrity sha512-vqVOpG/jc8mvTKQjaPBLhr7tnWyzuztOHsPnJqMWmg7zGcMeQC/2c5pU4uzRAfXMTp25iId6s4Y4wWfPS1EeDw== + +"@swc/core-linux-x64-gnu@1.7.28": + version "1.7.28" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.7.28.tgz#eb612272ceb1331310eb79ef6094c5a6cc085d23" + integrity sha512-HGwpWuB83Kr+V0E+zT5UwIIY9OxiS8aLd0UVMRVWuO8SrQyKm9HKJ46+zoAb8tfJrpZftfxvbn2ayZWR7gqosA== + +"@swc/core-linux-x64-musl@1.7.28": + version "1.7.28" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.7.28.tgz#a39749a71e690685aabeb7fd60141ccca2e62411" + integrity sha512-q2Y2T8y8EgFtIiRyInnAXNe94aaHX74F0ha1Bl9VdRxE0u1/So+3VLbPvtp4V3Z6pj5pOePfCQJKifnllgAQ9A== + +"@swc/core-win32-arm64-msvc@1.7.28": + version "1.7.28" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.7.28.tgz#93b22667b027e0a5060c91df7e0cc7406d27b01f" + integrity sha512-bCqh4uBT/59h3dWK1v91In6qzz8rKoWoFRxCtNQLIK4jP55K0U231ZK9oN7neZD6bzcOUeFvOGgcyMAgDfFWfA== + +"@swc/core-win32-ia32-msvc@1.7.28": + version "1.7.28" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.7.28.tgz#4d7dbc43a1de79ac0c7cccf35bebf9fe887b2e24" + integrity sha512-XTHbHrksnrqK3JSJ2sbuMWvdJ6/G0roRpgyVTmNDfhTYPOwcVaL/mSrPGLwbksYUbq7ckwoKzrobhdxvQzPsDA== + +"@swc/core-win32-x64-msvc@1.7.28": + version "1.7.28" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.7.28.tgz#d00acea3339a90768279096e6e5f1540c599e6ce" + integrity sha512-jyXeoq6nX8abiCy2EpporsC5ywNENs4ocYuvxo1LSxDktWN1E2MTXq3cdJcEWB2Vydxq0rDcsGyzkRPMzFhkZw== + +"@swc/core@^1.3.1", "@swc/core@^1.5.7": + version "1.7.28" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.7.28.tgz#74aec7a31344da7cfd305a09f14f22420351d495" + integrity sha512-XapcMgsOS0cKh01AFEj+qXOk6KM4NZhp7a5vPicdhkRR8RzvjrCa7DTtijMxfotU8bqaEHguxmiIag2HUlT8QQ== dependencies: "@swc/counter" "^0.1.3" "@swc/types" "^0.1.12" optionalDependencies: - "@swc/core-darwin-arm64" "1.7.26" - "@swc/core-darwin-x64" "1.7.26" - "@swc/core-linux-arm-gnueabihf" "1.7.26" - "@swc/core-linux-arm64-gnu" "1.7.26" - "@swc/core-linux-arm64-musl" "1.7.26" - "@swc/core-linux-x64-gnu" "1.7.26" - "@swc/core-linux-x64-musl" "1.7.26" - "@swc/core-win32-arm64-msvc" "1.7.26" - "@swc/core-win32-ia32-msvc" "1.7.26" - "@swc/core-win32-x64-msvc" "1.7.26" - -"@swc/counter@^0.1.1", "@swc/counter@^0.1.3": + "@swc/core-darwin-arm64" "1.7.28" + "@swc/core-darwin-x64" "1.7.28" + "@swc/core-linux-arm-gnueabihf" "1.7.28" + "@swc/core-linux-arm64-gnu" "1.7.28" + "@swc/core-linux-arm64-musl" "1.7.28" + "@swc/core-linux-x64-gnu" "1.7.28" + "@swc/core-linux-x64-musl" "1.7.28" + "@swc/core-win32-arm64-msvc" "1.7.28" + "@swc/core-win32-ia32-msvc" "1.7.28" + "@swc/core-win32-x64-msvc" "1.7.28" + +"@swc/counter@^0.1.3": version "0.1.3" resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9" integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ== @@ -2591,11 +1917,6 @@ dependencies: "@swc/counter" "^0.1.3" -"@swc/types@^0.1.5": - version "0.1.5" - resolved "https://registry.yarnpkg.com/@swc/types/-/types-0.1.5.tgz#043b731d4f56a79b4897a3de1af35e75d56bc63a" - integrity sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw== - "@tanstack/query-core@5.51.24": version "5.51.24" resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.51.24.tgz#da901637c8652ba5703b92bd07496e7c9ae27836" @@ -2629,9 +1950,9 @@ "@testing-library/dom" "^10.1.0" "@testing-library/dom@^10.1.0": - version "10.1.0" - resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-10.1.0.tgz#2d073e49771ad614da999ca48f199919e5176fb6" - integrity sha512-wdsYKy5zupPyLCW2Je5DLHSxSfbIp6h80WoHOQc+RPtmPGA52O9x5MJEkv92Sjonpq+poOAtUKhh1kBGAXBrNA== + version "10.4.0" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-10.4.0.tgz#82a9d9462f11d240ecadbf406607c6ceeeff43a8" + integrity sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ== dependencies: "@babel/code-frame" "^7.10.4" "@babel/runtime" "^7.12.5" @@ -2643,23 +1964,23 @@ pretty-format "^27.0.2" "@testing-library/jest-dom@~6.4.2": - version "6.4.2" - resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-6.4.2.tgz#38949f6b63722900e2d75ba3c6d9bf8cffb3300e" - integrity sha512-CzqH0AFymEMG48CpzXFriYYkOjk6ZGPCLMhW9e9jg3KMCn5OfJecF8GtGW7yGfR/IgCe3SX8BSwjdzI6BBbZLw== + version "6.4.8" + resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-6.4.8.tgz#9c435742b20c6183d4e7034f2b329d562c079daa" + integrity sha512-JD0G+Zc38f5MBHA4NgxQMR5XtO5Jx9g86jqturNTt2WUfRmLDIY7iKkWHDCCTiDuFMre6nxAD5wHw9W5kI4rGw== dependencies: - "@adobe/css-tools" "^4.3.2" + "@adobe/css-tools" "^4.4.0" "@babel/runtime" "^7.9.2" aria-query "^5.0.0" chalk "^3.0.0" css.escape "^1.5.1" dom-accessibility-api "^0.6.3" - lodash "^4.17.15" + lodash "^4.17.21" redent "^3.0.0" "@testing-library/react@~16.0.0": - version "16.0.0" - resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-16.0.0.tgz#0a1e0c7a3de25841c3591b8cb7fb0cf0c0a27321" - integrity sha512-guuxUKRWQ+FgNX0h0NS0FIq3Q3uLtWVpBzcLOggmfMoUpgBnzBzvLLd4fbm6yS8ydJd94cIfY4yP9qUQjM2KwQ== + version "16.0.1" + resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-16.0.1.tgz#29c0ee878d672703f5e7579f239005e4e0faa875" + integrity sha512-dSmwJVtJXmku+iocRhWOUFbrERC76TX2Mnf0ATODz8brzAZrMBbzLwQixlBSanZxR6LddK3eiwpSFZgDET1URg== dependencies: "@babel/runtime" "^7.12.5" @@ -2668,43 +1989,6 @@ resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.5.2.tgz#db7257d727c891905947bd1c1a99da20e03c2ebd" integrity sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ== -"@tokens-studio/sd-transforms@1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@tokens-studio/sd-transforms/-/sd-transforms-1.2.0.tgz#467ca4adf53cd955d8b6ebb2704ed147f10f1145" - integrity sha512-Ygj0nHiS0b/xMOcCovgrBylKk7EgDM9K3DiWEvdSGQZHAfOshAR7UCYQ5vEIH7NZaIVZqgqu2rB8FCIA9PDxbw== - dependencies: - "@bundled-es-modules/deepmerge" "^4.3.1" - "@bundled-es-modules/postcss-calc-ast-parser" "^0.1.6" - "@tokens-studio/types" "^0.5.1" - colorjs.io "^0.4.3" - expr-eval-fork "^2.0.2" - is-mergeable-object "^1.1.1" - -"@tokens-studio/types@^0.5.1": - version "0.5.1" - resolved "https://registry.yarnpkg.com/@tokens-studio/types/-/types-0.5.1.tgz#5037e58c4b2c306762f12e8d9685e9aeebb21685" - integrity sha512-LdCF9ZH5ej4Gb6n58x5fTkhstxjXDZc1SWteMWY6EiddLQJVONMIgYOrWrf1extlkSLjagX8WS0B63bAqeltnA== - -"@tsconfig/node10@^1.0.7": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" - integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== - -"@tsconfig/node12@^1.0.7": - version "1.0.11" - resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" - integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== - -"@tsconfig/node14@^1.0.0": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" - integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== - -"@tsconfig/node16@^1.0.2": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" - integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== - "@types/aria-query@^5.0.1": version "5.0.4" resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-5.0.4.tgz#1a31c3d378850d2778dabb6374d036dcba4ba708" @@ -2737,9 +2021,9 @@ "@babel/types" "^7.0.0" "@types/babel__traverse@*", "@types/babel__traverse@^7.18.0": - version "7.20.5" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.5.tgz#7b7502be0aa80cc4ef22978846b983edaafcd4dd" - integrity sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ== + version "7.20.6" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.6.tgz#8dc9f0ae0f202c08d8d4dab648912c8d6038e3f7" + integrity sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg== dependencies: "@babel/types" "^7.20.7" @@ -2752,9 +2036,9 @@ "@types/node" "*" "@types/braintree-web@^3.75.23": - version "3.96.10" - resolved "https://registry.yarnpkg.com/@types/braintree-web/-/braintree-web-3.96.10.tgz#c718cd9b6b107748746c04b3d02b0d07af7f951b" - integrity sha512-WB68hhxId8cUxddF9Au8STWULeeT2ZGvSJ+SvJz5ACqV3mYg7rlFkCOY88wHvbWBQAerqdxQ8NLVTe5V05R4/Q== + version "3.96.14" + resolved "https://registry.yarnpkg.com/@types/braintree-web/-/braintree-web-3.96.14.tgz#7303a5439bbc4a3a4b497bbac4bec77921e97cab" + integrity sha512-gRq2BbKUNACKXz6Tiqi4BX1fyMtWXUJZ82ooagwhXpIPQRx/HSRvz/aFzEA48jXr7k9dNchFOs6tMoo3cIgoiA== dependencies: "@types/googlepay" "*" "@types/paypal-checkout-components" "*" @@ -2767,9 +2051,9 @@ "@types/chai" "*" "@types/chai@*": - version "4.3.11" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.11.tgz#e95050bf79a932cb7305dd130254ccdf9bde671c" - integrity sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ== + version "5.0.0" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-5.0.0.tgz#7f981e71e69c9b2d422f58f78de1c59179782133" + integrity sha512-+DwhEHAaFPPdJ2ral3kNHFQXnTfscEEFsUxzD+d7nlcLrFK23JtNjH71RGasTcHb88b4vVi4mTyfpf8u2L8bdA== "@types/chart.js@^2.9.21": version "2.9.41" @@ -2870,7 +2154,7 @@ resolved "https://registry.yarnpkg.com/@types/escodegen/-/escodegen-0.0.6.tgz#5230a9ce796e042cda6f086dbf19f22ea330659c" integrity sha512-AjwI4MvWx3HAOaZqYsjKWyEObT9lcVV0Y0V8nXo6cXzN8ZiMxVhf6F3d/UNvXVGKrEzL/Dluc5p+y9GkzlTWig== -"@types/estree@1.0.5", "@types/estree@^1.0.0": +"@types/estree@1.0.5": version "1.0.5" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== @@ -2880,17 +2164,22 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== +"@types/estree@^1.0.0", "@types/estree@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== + "@types/express-serve-static-core@^4.17.33": - version "4.17.43" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz#10d8444be560cb789c4735aea5eac6e5af45df54" - integrity sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg== + version "4.19.6" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz#e01324c2a024ff367d92c66f48553ced0ab50267" + integrity sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A== dependencies: "@types/node" "*" "@types/qs" "*" "@types/range-parser" "*" "@types/send" "*" -"@types/express@^4.17.21", "@types/express@^4.7.0": +"@types/express@^4.17.21": version "4.17.21" resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.21.tgz#c26d4a151e60efe0084b23dc3369ebc631ed192d" integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ== @@ -2914,9 +2203,9 @@ "@types/node" "*" "@types/googlepay@*": - version "0.7.5" - resolved "https://registry.yarnpkg.com/@types/googlepay/-/googlepay-0.7.5.tgz#b944cd0e4c49f4661c9b966cb45614eb7ae87a26" - integrity sha512-158egcRaqkMSpW6unyGV4uG4FpoCklRf3J5emCzOXSRVAohMfIuZ481JNvp4X6+KxoNjxWiGtMx5vb1YfQADPw== + version "0.7.6" + resolved "https://registry.yarnpkg.com/@types/googlepay/-/googlepay-0.7.6.tgz#ba444ad8b2945e70f873673b8f5371745b8cfe37" + integrity sha512-5003wG+qvf4Ktf1hC9IJuRakNzQov00+Xf09pAWGJLpdOjUrq0SSLCpXX7pwSeTG9r5hrdzq1iFyZcW7WVyr4g== "@types/hast@^3.0.0": version "3.0.4" @@ -2960,16 +2249,7 @@ resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f" integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== -"@types/jsdom@^21.1.4": - version "21.1.6" - resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-21.1.6.tgz#bcbc7b245787ea863f3da1ef19aa1dcfb9271a1b" - integrity sha512-/7kkMsC+/kMs7gAYmmBR9P0vGTnOoLhQhyhQJSlXGI5bzTHp6xdo0TtKWQAsz6pmSAeVqKSbqeyP6hytqr9FDw== - dependencies: - "@types/node" "*" - "@types/tough-cookie" "*" - parse5 "^7.0.0" - -"@types/json-schema@^7.0.12", "@types/json-schema@^7.0.3", "@types/json-schema@^7.0.9": +"@types/json-schema@^7.0.12", "@types/json-schema@^7.0.15", "@types/json-schema@^7.0.3", "@types/json-schema@^7.0.9": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== @@ -2977,36 +2257,17 @@ "@types/jspdf@^1.3.3": version "1.3.3" resolved "https://registry.yarnpkg.com/@types/jspdf/-/jspdf-1.3.3.tgz#6940e892da69fdbe0969b742c6bdd9e4c5da320b" - integrity sha512-DqwyAKpVuv+7DniCp2Deq1xGvfdnKSNgl9Agun2w6dFvR5UKamiv4VfYUgcypd8S9ojUyARFIlZqBrYrBMQlew== - -"@types/linkify-it@*": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-3.0.5.tgz#1e78a3ac2428e6d7e6c05c1665c242023a4601d8" - integrity sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw== - -"@types/lodash.clonedeep@^4.5.9": - version "4.5.9" - resolved "https://registry.yarnpkg.com/@types/lodash.clonedeep/-/lodash.clonedeep-4.5.9.tgz#ea48276c7cc18d080e00bb56cf965bcceb3f0fc1" - integrity sha512-19429mWC+FyaAhOLzsS8kZUsI+/GmBAQ0HFiCPsKGU+7pBXOQWhyrY6xNNDwUSX8SMZMJvuFVMF9O5dQOlQK9Q== - dependencies: - "@types/lodash" "*" - -"@types/lodash.curry@^4.1.9": - version "4.1.9" - resolved "https://registry.yarnpkg.com/@types/lodash.curry/-/lodash.curry-4.1.9.tgz#b9a0f5032747309c3cbe78e1acffc1599fb78d94" - integrity sha512-QV967vSflHEza0d0IMTK7fwbl+baPBXZjcESeAHrA5eSE+EHetaggZjPpkzX1NJh4qa8DLOLScwUR+f7FN85Zg== - dependencies: - "@types/lodash" "*" + integrity sha512-DqwyAKpVuv+7DniCp2Deq1xGvfdnKSNgl9Agun2w6dFvR5UKamiv4VfYUgcypd8S9ojUyARFIlZqBrYrBMQlew== -"@types/lodash@*": - version "4.17.0" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.0.tgz#d774355e41f372d5350a4d0714abb48194a489c3" - integrity sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA== +"@types/linkify-it@*": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-5.0.0.tgz#21413001973106cda1c3a9b91eedd4ccd5469d76" + integrity sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q== "@types/lodash@^4.14.167", "@types/lodash@^4.14.175": - version "4.14.202" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.202.tgz#f09dbd2fb082d507178b2f2a5c7e74bd72ff98f8" - integrity sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ== + version "4.17.9" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.9.tgz#0dc4902c229f6b8e2ac5456522104d7b1a230290" + integrity sha512-w9iWudx1XWOHW5lQRS9iKpK/XuRhnN+0T7HvdCCd802FYkT1AMTnxndJHGrNJwRoRHkslGr4S29tjm1cT7x/7w== "@types/luxon@3.4.2": version "3.4.2" @@ -3029,26 +2290,21 @@ integrity sha512-/i42wjYNgE6wf0j2bcTX6kuowmdL/6PE4IVitMpm2eYKBUuYCprdcWVK+xEF0gcV6ufMCRhtxmReGfc6hIK7Jw== "@types/mdast@^4.0.0": - version "4.0.3" - resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-4.0.3.tgz#1e011ff013566e919a4232d1701ad30d70cab333" - integrity sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg== + version "4.0.4" + resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-4.0.4.tgz#7ccf72edd2f1aa7dd3437e180c64373585804dd6" + integrity sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA== dependencies: "@types/unist" "*" "@types/mdurl@*": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-1.0.5.tgz#3e0d2db570e9fb6ccb2dc8fde0be1d79ac810d39" - integrity sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA== + version "2.0.0" + resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-2.0.0.tgz#d43878b5b20222682163ae6f897b20447233bdfd" + integrity sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg== "@types/mdx@^2.0.0": - version "2.0.11" - resolved "https://registry.yarnpkg.com/@types/mdx/-/mdx-2.0.11.tgz#21f4c166ed0e0a3a733869ba04cd8daea9834b8e" - integrity sha512-HM5bwOaIQJIQbAYfax35HCKxx7a3KrK3nBtIqJgSOitivTD1y3oW9P3rxY9RkXYPUk7y/AjAohfHKmFpGE79zw== - -"@types/mime@*": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.4.tgz#2198ac274de6017b44d941e00261d5bc6a0e0a45" - integrity sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw== + version "2.0.13" + resolved "https://registry.yarnpkg.com/@types/mdx/-/mdx-2.0.13.tgz#68f6877043d377092890ff5b298152b0a21671bd" + integrity sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw== "@types/mime@^1": version "1.3.5" @@ -3061,9 +2317,9 @@ integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== "@types/mocha@^10.0.2": - version "10.0.6" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.6.tgz#818551d39113081048bdddbef96701b4e8bb9d1b" - integrity sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg== + version "10.0.8" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.8.tgz#a7eff5816e070c3b4d803f1d3cd780c4e42934a1" + integrity sha512-HfMcUmy9hTMJh66VNcmeC9iVErIZJli2bszuXc6julh5YGuRb/W5OnkHjwLNYdFlMis0sY3If5SEAp+PktdJjw== "@types/ms@*": version "0.7.34" @@ -3077,32 +2333,18 @@ dependencies: "@types/node" "*" -"@types/node@*": - version "20.11.17" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.17.tgz#cdd642d0e62ef3a861f88ddbc2b61e32578a9292" - integrity sha512-QmgQZGWu1Yw9TDyAP9ZzpFJKynYNeOvwMJmaxABfieQoVoiVOS6MN1WSpqpRcbeA5+RW82kraAVxCCJg+780Qw== +"@types/node@*", "@types/node@^22.0.0", "@types/node@^22.5.5": + version "22.7.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.1.tgz#c6a2628c8a68511ab7b68f3be7c9b38716bdf04f" + integrity sha512-adOMRLVmleuWs/5V/w5/l7o0chDK/az+5ncCsIapTKogsu/3MVWvSgP58qVTXi5IwpfGt8pMobNq9rOWtJyu5Q== dependencies: - undici-types "~5.26.4" + undici-types "~6.19.2" "@types/node@^12.7.1": version "12.20.55" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== -"@types/node@^20.11.26": - version "20.11.27" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.27.tgz#debe5cfc8a507dd60fe2a3b4875b1604f215c2ac" - integrity sha512-qyUZfMnCg1KEz57r7pzFtSGt49f6RPkPBis3Vo4PbS7roQEDn22hiHzl/Lo1q4i4hDEgBJmBF/NTNg2XR0HbFg== - dependencies: - undici-types "~5.26.4" - -"@types/node@^22.0.0": - version "22.5.4" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.4.tgz#83f7d1f65bc2ed223bdbf57c7884f1d5a4fa84e8" - integrity sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg== - dependencies: - undici-types "~6.19.2" - "@types/parse-json@^4.0.0": version "4.0.2" resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239" @@ -3113,15 +2355,10 @@ resolved "https://registry.yarnpkg.com/@types/paypal-checkout-components/-/paypal-checkout-components-4.0.8.tgz#dae11a164fb77fe370b013c0be44951bdc4ebf4d" integrity sha512-Z3IWbFPGdgL3O+Bg+TyVmMT8S3uGBsBjw3a8uRNR4OlYWa9m895djENErJMYU8itoki9rtcQMzoHOSFn8NFb1A== -"@types/prop-types@*", "@types/prop-types@^15.7.11": - version "15.7.11" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.11.tgz#2596fb352ee96a1379c657734d4b913a613ad563" - integrity sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng== - -"@types/prop-types@^15.7.12": - version "15.7.12" - resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6" - integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q== +"@types/prop-types@*", "@types/prop-types@^15.7.12": + version "15.7.13" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.13.tgz#2af91918ee12d9d32914feb13f5326658461b451" + integrity sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA== "@types/qrcode.react@^0.8.0": version "0.8.2" @@ -3131,9 +2368,9 @@ "@types/react" "*" "@types/qs@*": - version "6.9.11" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.11.tgz#208d8a30bc507bd82e03ada29e4732ea46a6bbda" - integrity sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ== + version "6.9.16" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.16.tgz#52bba125a07c0482d26747d5d4947a64daf8f794" + integrity sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A== "@types/raf@^3.4.0": version "3.4.3" @@ -3165,16 +2402,16 @@ "@types/react" "*" "@types/react-dom@*", "@types/react-dom@^18.2.18": - version "18.2.19" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.19.tgz#b84b7c30c635a6c26c6a6dfbb599b2da9788be58" - integrity sha512-aZvQL6uUbIJpjZk4U8JZGbau9KDeAwMfmhyWorxgBkqDIEf6ROjRozcmPIicqsUwPUjbkDfHKgGee1Lq65APcA== + version "18.3.0" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.0.tgz#0cbc818755d87066ab6ca74fbedb2547d74a82b0" + integrity sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg== dependencies: "@types/react" "*" "@types/react-redux@^7.1.20", "@types/react-redux@~7.1.7": - version "7.1.33" - resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.33.tgz#53c5564f03f1ded90904e3c90f77e4bd4dc20b15" - integrity sha512-NF8m5AjWCkert+fosDsN3hAlHzpjSiXlVy9EgQEmLoBhaNXbmyeGs/aj5dQzKuF+/q+S7JQagorGDW8pJ28Hmg== + version "7.1.34" + resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.34.tgz#83613e1957c481521e6776beeac4fd506d11bd0e" + integrity sha512-GdFaVjEbYv4Fthm2ZLvj1VSCedV7TqE5y1kNwnjSdBOTXuRSgowux6J8TAct15T3CKBr63UMk+2CO7ilRhyrAQ== dependencies: "@types/hoist-non-react-statics" "^3.3.0" "@types/react" "*" @@ -3215,35 +2452,27 @@ "@types/react-dom" "*" "@types/react-transition-group" "*" -"@types/react-transition-group@*", "@types/react-transition-group@^4.4.10": - version "4.4.10" - resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.10.tgz#6ee71127bdab1f18f11ad8fb3322c6da27c327ac" - integrity sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q== +"@types/react-transition-group@*", "@types/react-transition-group@^4.4.10", "@types/react-transition-group@^4.4.11": + version "4.4.11" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.11.tgz#d963253a611d757de01ebb241143b1017d5d63d5" + integrity sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA== dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^18.2.55": - version "18.2.55" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.55.tgz#38141821b7084404b5013742bc4ae08e44da7a67" - integrity sha512-Y2Tz5P4yz23brwm2d7jNon39qoAtMMmalOQv6+fEFt1mT+FcM3D841wDpoUvFXhaYenuROCy3FZYqdTjM7qVyA== - dependencies: - "@types/prop-types" "*" - "@types/scheduler" "*" - csstype "^3.0.2" - -"@types/react@^16.8.0 || ^17.0.0 || ^18.0.0": - version "18.2.73" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.73.tgz#0579548ad122660d99e00499d22e33b81e73ed94" - integrity sha512-XcGdod0Jjv84HOC7N5ziY3x+qL0AfmubvKOZ9hJjJ2yd5EE+KYjWhdOjt387e9HPheHkdggF9atTifMRtyAaRA== +"@types/react@*", "@types/react@^16.8.0 || ^17.0.0 || ^18.0.0", "@types/react@^18.2.55": + version "18.3.9" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.9.tgz#2cdf5f425ec8a133d67e9e3673909738b783db20" + integrity sha512-+BpAVyTpJkNWWSSnaLBk6ePpHLOGJKnEQNbINNovPWzvEUyAe3e+/d494QdEh71RekM/qV7lw6jzf1HGrJyAtQ== dependencies: "@types/prop-types" "*" csstype "^3.0.2" "@types/recompose@^0.30.0": - version "0.30.14" - resolved "https://registry.yarnpkg.com/@types/recompose/-/recompose-0.30.14.tgz#06c5b3ff3f1df746ab6e8baecc3e288971936892" - integrity sha512-DDxwOemcQhtXuwIODKz8UVRroNoMkLoHiLJ/kIML3nC4WWE/0sfdrCev4zsazHCuj9BwDTTn/LsNtxwxTRK1WA== + version "0.30.15" + resolved "https://registry.yarnpkg.com/@types/recompose/-/recompose-0.30.15.tgz#29ba4e6ffc7714c9026fd709931125f42c11ed3f" + integrity sha512-glX9JbRTG4WSaWxDrsHlinoRC1YRb0vNr+ocPBgBTJgMawkYx8fqwuduahzy25XBSc3xfG/k9b5XPyW6FuHVkw== dependencies: + "@types/prop-types" "*" "@types/react" "*" "@types/redux-mock-store@^1.0.1": @@ -3258,17 +2487,7 @@ resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.6.tgz#e6e60dad29c2c8c206c026e6dd8d6d1bdda850b8" integrity sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ== -"@types/scheduler@*": - version "0.16.8" - resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.8.tgz#ce5ace04cfeabe7ef87c0091e50752e36707deff" - integrity sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A== - -"@types/semver@^7.3.12": - version "7.5.6" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.6.tgz#c65b2bfce1bec346582c07724e3f8c1017a20339" - integrity sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A== - -"@types/semver@^7.5.0": +"@types/semver@^7.3.12", "@types/semver@^7.5.0": version "7.5.8" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== @@ -3282,13 +2501,13 @@ "@types/node" "*" "@types/serve-static@*": - version "1.15.5" - resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.5.tgz#15e67500ec40789a1e8c9defc2d32a896f05b033" - integrity sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ== + version "1.15.7" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.7.tgz#22174bbd74fb97fe303109738e9b5c2f3064f714" + integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw== dependencies: "@types/http-errors" "*" - "@types/mime" "*" "@types/node" "*" + "@types/send" "*" "@types/sinonjs__fake-timers@8.1.1": version "8.1.1" @@ -3310,7 +2529,7 @@ resolved "https://registry.yarnpkg.com/@types/throttle-debounce/-/throttle-debounce-1.1.1.tgz#4a78636c36a4534b76d85ee244fce238d435f22a" integrity sha512-VhX9p0l8p3TS27XU+CnDfhdnzW7HpVgtKiYDh/lfucSAz8s9uTt0q4aPwcYIr+q+3/NghlU3smXBW6ItvfJKYQ== -"@types/tough-cookie@*": +"@types/tough-cookie@^4.0.5": version "4.0.5" resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.5.tgz#cb6e2a691b70cb177c6e3ae9c1d2e8b2ea8cd304" integrity sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA== @@ -3321,9 +2540,9 @@ integrity sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw== "@types/unist@*", "@types/unist@^3.0.0": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.2.tgz#6dd61e43ef60b34086287f83683a5c1b2dc53d20" - integrity sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ== + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.3.tgz#acaab0f919ce69cce629c2d4ed2eb4adc1b6c20c" + integrity sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q== "@types/uuid@^3.4.3": version "3.4.13" @@ -3365,9 +2584,9 @@ integrity sha512-Ynb/CjHhE/Xp/4bhHmQC4U1Ox+I2OpfRYF3dnNgQqn1cHa6LK3H1wJMNPT02tSVZA6FYuXE2ITORfbnb6zBCSA== "@types/zxcvbn@^4.4.0": - version "4.4.4" - resolved "https://registry.yarnpkg.com/@types/zxcvbn/-/zxcvbn-4.4.4.tgz#987f5fcd87e957097433c476c3a1c91a54f53131" - integrity sha512-Tuk4q7q0DnpzyJDI4aMeghGuFu2iS1QAdKpabn8JfbtfGmVDUgvZv1I7mEjP61Bvnp3ljKCC8BE6YYSTNxmvRQ== + version "4.4.5" + resolved "https://registry.yarnpkg.com/@types/zxcvbn/-/zxcvbn-4.4.5.tgz#8ce8623ed7a36e3a76d1c0b539708dfb2e859bc0" + integrity sha512-FZJgC5Bxuqg7Rhsm/bx6gAruHHhDQ55r+s0JhDh8CQ16fD7NsJJ+p8YMMQDhSQoIrSmjpqqYWA96oQVMNkjRyA== "@typescript-eslint/eslint-plugin@^6.21.0": version "6.21.0" @@ -3540,7 +2759,7 @@ "@typescript-eslint/types" "6.21.0" eslint-visitor-keys "^3.4.1" -"@ungap/structured-clone@^1.0.0", "@ungap/structured-clone@^1.2.0": +"@ungap/structured-clone@^1.0.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== @@ -3647,22 +2866,7 @@ resolved "https://registry.yarnpkg.com/@xterm/xterm/-/xterm-5.5.0.tgz#275fb8f6e14afa6e8a0c05d4ebc94523ff775396" integrity sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A== -"@yarnpkg/lockfile@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" - integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== - -"@zeit/schemas@2.29.0": - version "2.29.0" - resolved "https://registry.yarnpkg.com/@zeit/schemas/-/schemas-2.29.0.tgz#a59ae6ebfdf4ddc66a876872dd736baa58b6696c" - integrity sha512-g5QiLIfbg3pLuYUJPlisNKY+epQJTcMDsOnVNkscrDP1oi7vmJnzOANYJI/1pZcVJ6umUkBv3aFtlg1UvUHGzA== - -"@zip.js/zip.js@^2.7.44": - version "2.7.45" - resolved "https://registry.yarnpkg.com/@zip.js/zip.js/-/zip.js-2.7.45.tgz#823fe2789401d8c1d836ce866578379ec1bd6f0b" - integrity sha512-Mm2EXF33DJQ/3GWWEWeP1UCqzpQ5+fiMvT3QWspsXY05DyqqxWu7a9awSzU4/spHMHVFrTjani1PR0vprgZpow== - -accepts@~1.3.5, accepts@~1.3.8: +accepts@~1.3.8: version "1.3.8" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== @@ -3680,20 +2884,15 @@ acorn-walk@^7.2.0: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== -acorn-walk@^8.1.1: - version "8.3.2" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.2.tgz#7703af9415f1b6db9315d6895503862e231d34aa" - integrity sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A== - acorn@^7.1.1, acorn@^7.4.0, acorn@^7.4.1: version "7.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.11.3, acorn@^8.4.1, acorn@^8.9.0: - version "8.11.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" - integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== +acorn@^8.12.0, acorn@^8.12.1: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== agent-base@^7.0.2, agent-base@^7.1.0: version "7.1.1" @@ -3710,16 +2909,6 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" -ajv@8.11.0: - version "8.11.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" - integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" @@ -3731,41 +2920,35 @@ ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.4: uri-js "^4.2.2" ajv@^8.0.1: - version "8.16.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.16.0.tgz#22e2a92b94f005f7e0f9c9d39652ef0b8f6f0cb4" - integrity sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw== + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== dependencies: fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" json-schema-traverse "^1.0.0" require-from-string "^2.0.2" - uri-js "^4.4.1" algoliasearch@^4.14.3: - version "4.22.1" - resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.22.1.tgz#f10fbecdc7654639ec20d62f109c1b3a46bc6afc" - integrity sha512-jwydKFQJKIx9kIZ8Jm44SdpigFwRGPESaxZBaHSV0XWN2yBJAOT4mT7ppvlrpA4UGzz92pqFnVKr/kaZXrcreg== - dependencies: - "@algolia/cache-browser-local-storage" "4.22.1" - "@algolia/cache-common" "4.22.1" - "@algolia/cache-in-memory" "4.22.1" - "@algolia/client-account" "4.22.1" - "@algolia/client-analytics" "4.22.1" - "@algolia/client-common" "4.22.1" - "@algolia/client-personalization" "4.22.1" - "@algolia/client-search" "4.22.1" - "@algolia/logger-common" "4.22.1" - "@algolia/logger-console" "4.22.1" - "@algolia/requester-browser-xhr" "4.22.1" - "@algolia/requester-common" "4.22.1" - "@algolia/requester-node-http" "4.22.1" - "@algolia/transporter" "4.22.1" - -ansi-align@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59" - integrity sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w== - dependencies: - string-width "^4.1.0" + version "4.24.0" + resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.24.0.tgz#b953b3e2309ef8f25da9de311b95b994ac918275" + integrity sha512-bf0QV/9jVejssFBmz2HQLxUadxk574t4iwjCKp5E7NBzwKkrDEhKPISIIjAU/p6K5qDx3qoeh4+26zWN1jmw3g== + dependencies: + "@algolia/cache-browser-local-storage" "4.24.0" + "@algolia/cache-common" "4.24.0" + "@algolia/cache-in-memory" "4.24.0" + "@algolia/client-account" "4.24.0" + "@algolia/client-analytics" "4.24.0" + "@algolia/client-common" "4.24.0" + "@algolia/client-personalization" "4.24.0" + "@algolia/client-search" "4.24.0" + "@algolia/logger-common" "4.24.0" + "@algolia/logger-console" "4.24.0" + "@algolia/recommend" "4.24.0" + "@algolia/requester-browser-xhr" "4.24.0" + "@algolia/requester-common" "4.24.0" + "@algolia/requester-node-http" "4.24.0" + "@algolia/transporter" "4.24.0" ansi-colors@^4.1.1: version "4.1.3" @@ -3786,16 +2969,6 @@ ansi-escapes@^7.0.0: dependencies: environment "^1.0.0" -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== - -ansi-regex@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1" - integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== - ansi-regex@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" @@ -3807,9 +2980,9 @@ ansi-regex@^5.0.1: integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-regex@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" - integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" @@ -3853,16 +3026,6 @@ arch@^2.2.0: resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== -arg@5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c" - integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg== - -arg@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -3875,13 +3038,25 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -aria-query@5.3.0, aria-query@^5.0.0, aria-query@^5.3.0: +aria-query@5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.0.tgz#650c569e41ad90b51b3d7df5e5eed1c7549c103e" integrity sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A== dependencies: dequal "^2.0.3" +aria-query@^5.0.0: + version "5.3.2" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.2.tgz#93f81a43480e33a338f19163a3d10a50c01dcd59" + integrity sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw== + +aria-query@~5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.1.3.tgz#19db27cd101152773631396f7a95a3b58c22c35e" + integrity sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ== + dependencies: + deep-equal "^2.0.5" + array-buffer-byte-length@^1.0.0, array-buffer-byte-length@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" @@ -3895,15 +3070,16 @@ array-flatten@1.1.1: resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== -array-includes@^3.1.6, array-includes@^3.1.7: - version "3.1.7" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.7.tgz#8cd2e01b26f7a3086cbc87271593fe921c62abda" - integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== +array-includes@^3.1.6, array-includes@^3.1.8: + version "3.1.8" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" + integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" is-string "^1.0.7" array-union@^2.1.0: @@ -3911,6 +3087,18 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== +array.prototype.findlast@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz#3e4fbcb30a15a7f5bf64cf2faae22d139c2e4904" + integrity sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-shim-unscopables "^1.0.2" + array.prototype.flat@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" @@ -3921,7 +3109,7 @@ array.prototype.flat@^1.3.1: es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" -array.prototype.flatmap@^1.3.1, array.prototype.flatmap@^1.3.2: +array.prototype.flatmap@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== @@ -3931,18 +3119,18 @@ array.prototype.flatmap@^1.3.1, array.prototype.flatmap@^1.3.2: es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" -array.prototype.tosorted@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz#c8c89348337e51b8a3c48a9227f9ce93ceedcba8" - integrity sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg== +array.prototype.tosorted@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz#fe954678ff53034e717ea3352a03f0b0b86f7ffc" + integrity sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA== dependencies: - call-bind "^1.0.5" + call-bind "^1.0.7" define-properties "^1.2.1" - es-abstract "^1.22.3" - es-errors "^1.1.0" + es-abstract "^1.23.3" + es-errors "^1.3.0" es-shim-unscopables "^1.0.2" -arraybuffer.prototype.slice@^1.0.2: +arraybuffer.prototype.slice@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== @@ -3973,17 +3161,6 @@ assert-plus@1.0.0, assert-plus@^1.0.0: resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== -assert@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/assert/-/assert-2.1.0.tgz#6d92a238d05dc02e7427c881fb8be81c8448b2dd" - integrity sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw== - dependencies: - call-bind "^1.0.2" - is-nan "^1.3.2" - object-is "^1.1.5" - object.assign "^4.1.4" - util "^0.12.5" - assertion-error@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" @@ -4012,16 +3189,9 @@ astral-regex@^2.0.0: integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== async@^3.2.0: - version "3.2.5" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66" - integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== - -asynciterator.prototype@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz#8c5df0514936cdd133604dfcc9d3fb93f09b2b62" - integrity sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg== - dependencies: - has-symbols "^1.0.3" + version "3.2.6" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" + integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== asynckit@^0.4.0: version "0.4.0" @@ -4043,10 +3213,12 @@ attr-accept@^2.2.1: resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-2.2.2.tgz#646613809660110749e92f2c10833b70968d929b" integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg== -available-typed-arrays@^1.0.5, available-typed-arrays@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.6.tgz#ac812d8ce5a6b976d738e1c45f08d0b00bc7d725" - integrity sha512-j1QzY8iPNPG4o4xmO3ptzpRxTciqD3MgEHtifP/YnJpIo58Xu+ne4BejlbkuaLfXn/nz6HFiw29bLpj2PNMdGg== +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" aws-sign2@~0.7.0: version "0.7.0" @@ -4054,16 +3226,11 @@ aws-sign2@~0.7.0: integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA== aws4@^1.8.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3" - integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg== - -axe-core@=4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf" - integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ== + version "1.13.2" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.13.2.tgz#0aa167216965ac9474ccfa83892cfb6b3e1e52ef" + integrity sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw== -axe-core@^4.2.0: +axe-core@^4.10.0, axe-core@^4.2.0: version "4.10.0" resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.10.0.tgz#d9e56ab0147278272739a000880196cdfe113b59" integrity sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g== @@ -4077,20 +3244,18 @@ axios-mock-adapter@^1.22.0: is-buffer "^2.0.5" axios@~1.7.4: - version "1.7.4" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.4.tgz#4c8ded1b43683c8dd362973c393f3ede24052aa2" - integrity sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw== + version "1.7.7" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" + integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== dependencies: follow-redirects "^1.15.6" form-data "^4.0.0" proxy-from-env "^1.1.0" -axobject-query@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-3.2.1.tgz#39c378a6e3b06ca679f29138151e45b2b32da62a" - integrity sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg== - dependencies: - dequal "^2.0.3" +axobject-query@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-4.1.0.tgz#28768c76d0e3cff21bc62a9e2d0b6ac30042a1ee" + integrity sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ== babel-eslint@>=4.1.1: version "10.1.0" @@ -4170,10 +3335,17 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" +better-opn@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/better-opn/-/better-opn-3.0.2.tgz#f96f35deaaf8f34144a4102651babcf00d1d8817" + integrity sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ== + dependencies: + open "^8.0.4" + binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== blob-util@^2.0.2: version "2.0.2" @@ -4185,10 +3357,10 @@ bluebird@^3.7.2: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== -body-parser@1.20.2: - version "1.20.2" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" - integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== +body-parser@1.20.3: + version "1.20.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" + integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== dependencies: bytes "3.1.2" content-type "~1.0.5" @@ -4198,25 +3370,11 @@ body-parser@1.20.2: http-errors "2.0.0" iconv-lite "0.4.24" on-finished "2.4.1" - qs "6.11.0" + qs "6.13.0" raw-body "2.5.2" type-is "~1.6.18" unpipe "1.0.0" -boxen@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/boxen/-/boxen-7.0.0.tgz#9e5f8c26e716793fc96edcf7cf754cdf5e3fbf32" - integrity sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg== - dependencies: - ansi-align "^3.0.1" - camelcase "^7.0.0" - chalk "^5.0.1" - cli-boxes "^3.0.0" - string-width "^5.1.2" - type-fest "^2.13.0" - widest-line "^4.0.1" - wrap-ansi "^8.0.1" - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -4232,7 +3390,7 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^3.0.2, braces@^3.0.3, braces@~3.0.2: +braces@^3.0.3, braces@~3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== @@ -4240,22 +3398,23 @@ braces@^3.0.2, braces@^3.0.3, braces@~3.0.2: fill-range "^7.1.1" braintree-web@^3.92.2: - version "3.100.0" - resolved "https://registry.yarnpkg.com/braintree-web/-/braintree-web-3.100.0.tgz#e12b3f5aa5b6f8ca3d4c234a9481b611a81306ef" - integrity sha512-+paeD3D5uYUfKKa3dnuIj6sRyivXQMoKmlwH3Iiy4f1e+4BZyirMj8egO4J9srPf+mIInLSYP60RwoymalfMsQ== + version "3.109.0" + resolved "https://registry.yarnpkg.com/braintree-web/-/braintree-web-3.109.0.tgz#366005e6e84ac016f48fd0b2acab962b193ad740" + integrity sha512-89CLzvldYeSD0cxmInE1mq+viMl7sIGkVm74/6cX91pQWrrO+qaA4r2fpgrqPJ7gWJDQp+5YVa0HliwsbFBYTg== dependencies: - "@braintree/asset-loader" "0.4.4" - "@braintree/browser-detection" "1.17.1" + "@braintree/asset-loader" "2.0.1" + "@braintree/browser-detection" "2.0.1" "@braintree/event-emitter" "0.4.1" - "@braintree/extended-promise" "0.4.1" - "@braintree/iframer" "1.1.0" - "@braintree/sanitize-url" "6.0.4" - "@braintree/uuid" "0.1.0" + "@braintree/extended-promise" "1.0.0" + "@braintree/iframer" "2.0.0" + "@braintree/sanitize-url" "7.0.4" + "@braintree/uuid" "1.0.0" "@braintree/wrap-promise" "2.1.0" - card-validator "8.1.1" - credit-card-type "9.1.0" - framebus "5.2.1" - inject-stylesheet "5.0.0" + "@paypal/accelerated-checkout-loader" "1.1.0" + card-validator "10.0.0" + credit-card-type "10.0.1" + framebus "6.0.0" + inject-stylesheet "6.0.1" promise-polyfill "8.2.3" restricted-input "3.0.5" @@ -4264,15 +3423,15 @@ browser-assert@^1.2.1: resolved "https://registry.yarnpkg.com/browser-assert/-/browser-assert-1.2.1.tgz#9aaa5a2a8c74685c2ae05bfe46efd606f068c200" integrity sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ== -browserslist@^4.22.2: - version "4.22.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.3.tgz#299d11b7e947a6b843981392721169e27d60c5a6" - integrity sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A== +browserslist@^4.23.1: + version "4.24.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.0.tgz#a1325fe4bc80b64fda169629fc01b3d6cecd38d4" + integrity sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A== dependencies: - caniuse-lite "^1.0.30001580" - electron-to-chromium "^1.4.648" - node-releases "^2.0.14" - update-browserslist-db "^1.0.13" + caniuse-lite "^1.0.30001663" + electron-to-chromium "^1.5.28" + node-releases "^2.0.18" + update-browserslist-db "^1.1.0" btoa@^1.2.1: version "1.2.1" @@ -4297,14 +3456,6 @@ buffer@^5.7.1: base64-js "^1.3.1" ieee754 "^1.1.13" -buffer@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" - integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - bundle-require@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/bundle-require/-/bundle-require-5.0.0.tgz#071521bdea6534495cf23e92a83f889f91729e93" @@ -4312,11 +3463,6 @@ bundle-require@^5.0.0: dependencies: load-tsconfig "^0.2.3" -bytes@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" - integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== - bytes@3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" @@ -4332,17 +3478,7 @@ cachedir@^2.3.0: resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-2.4.0.tgz#7fef9cf7367233d7c88068fe6e34ed0d355a610d" integrity sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ== -call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.6.tgz#6c46675fc7a5e9de82d75a233d586c8b7ac0d931" - integrity sha512-Mj50FLHtlsoVfRfnHaZvyrooHcrlceNZdL/QBvJJVd9Ta55qCQK0gs4ss2oZDeV9zFCs6ewzYgVE5yfVmfFpVg== - dependencies: - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.3" - set-function-length "^1.2.0" - -call-bind@^1.0.7: +call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== @@ -4363,15 +3499,10 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -camelcase@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-7.0.1.tgz#f02e50af9fd7782bc8b88a3558c32fd3a388f048" - integrity sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw== - -caniuse-lite@^1.0.30001580: - version "1.0.30001653" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001653.tgz" - integrity sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw== +caniuse-lite@^1.0.30001663: + version "1.0.30001663" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001663.tgz#1529a723505e429fdfd49532e9fc42273ba7fed7" + integrity sha512-o9C3X27GLKbLeTYZ6HBOLU1tsAcBZsLis28wrVzddShCS16RujjHp9GDHKZqrB3meE0YjhawvMFsGb/igqiPzA== canvg@^3.0.6: version "3.0.10" @@ -4387,10 +3518,10 @@ canvg@^3.0.6: stackblur-canvas "^2.0.0" svg-pathdata "^6.0.3" -card-validator@8.1.1: - version "8.1.1" - resolved "https://registry.yarnpkg.com/card-validator/-/card-validator-8.1.1.tgz#418f5f32435553fb9ca2a02634ad413bb38697a9" - integrity sha512-cN4FsKwoTfTFnqPwVc7TQLSsH/QMDB3n/gWm0XelcApz4sKipnOQ6k33sa3bWsNnnIpgs7eXOF+mUV2UQAX2Sw== +card-validator@10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/card-validator/-/card-validator-10.0.0.tgz#288a5525cae765566c4ff7d6e841d8e1ae63cd4c" + integrity sha512-2fLyCBOxO7/b56sxoYav8FeJqv9bWpZSyKq8sXKxnpxTGXHnM/0c8WEKG+ZJ+OXFcabnl98pD0EKBtTn+Tql0g== dependencies: credit-card-type "^9.1.0" @@ -4420,18 +3551,6 @@ chai@^5.1.1: loupe "^3.1.0" pathval "^2.0.0" -chalk-template@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/chalk-template/-/chalk-template-0.4.0.tgz#692c034d0ed62436b9062c1707fadcd0f753204b" - integrity sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg== - dependencies: - chalk "^4.1.2" - -chalk@5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.0.1.tgz#ca57d71e82bb534a296df63bbacc4a1c22b2a4b6" - integrity sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w== - chalk@^2.1.0, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -4457,16 +3576,11 @@ chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^5.0.1, chalk@^5.2.0, chalk@^5.3.0, chalk@~5.3.0: +chalk@^5.2.0, chalk@~5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== -change-case@^5.3.0: - version "5.4.4" - resolved "https://registry.yarnpkg.com/change-case/-/change-case-5.4.4.tgz#0d52b507d8fb8f204343432381d1a6d7bff97a02" - integrity sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w== - change-emitter@^0.1.2: version "0.1.6" resolved "https://registry.yarnpkg.com/change-emitter/-/change-emitter-0.1.6.tgz#e8b2fe3d7f1ab7d69a32199aff91ea6931409515" @@ -4535,7 +3649,7 @@ chokidar@^3.5.3, chokidar@^3.6.0: optionalDependencies: fsevents "~2.3.2" -ci-info@^3.2.0, ci-info@^3.7.0: +ci-info@^3.2.0: version "3.9.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== @@ -4545,11 +3659,6 @@ clean-stack@^2.0.0: resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== -cli-boxes@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-3.0.0.tgz#71a10c716feeba005e4504f36329ef0b17cf3145" - integrity sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g== - cli-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" @@ -4564,15 +3673,10 @@ cli-cursor@^5.0.0: dependencies: restore-cursor "^5.0.0" -cli-spinners@^2.9.2: - version "2.9.2" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.2.tgz#1773a8f4b9c4d6ac31563df53b3fc1d79462fe41" - integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg== - cli-table3@~0.6.1: - version "0.6.3" - resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.3.tgz#61ab765aac156b52f222954ffc607a6f01dbeeb2" - integrity sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg== + version "0.6.5" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.5.tgz#013b91351762739c16a9567c21a04632e449bf2f" + integrity sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ== dependencies: string-width "^4.2.0" optionalDependencies: @@ -4604,24 +3708,6 @@ cli-width@^4.1.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-4.1.0.tgz#42daac41d3c254ef38ad8ac037672130173691c5" integrity sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ== -clipboardy@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-3.0.0.tgz#f3876247404d334c9ed01b6f269c11d09a5e3092" - integrity sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg== - dependencies: - arch "^2.2.0" - execa "^5.1.1" - is-wsl "^2.2.0" - -cliui@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" - integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== - dependencies: - string-width "^2.1.1" - strip-ansi "^4.0.0" - wrap-ansi "^2.0.0" - cliui@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" @@ -4645,21 +3731,11 @@ clsx@^1.1.0: resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== -clsx@^2.0.0, clsx@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.0.tgz#e851283bcb5c80ee7608db18487433f7b23f77cb" - integrity sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg== - -clsx@^2.1.1: +clsx@^2.0.0, clsx@^2.1.0, clsx@^2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA== - color-convert@^1.9.0, color-convert@^1.9.3: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -4689,12 +3765,7 @@ colorette@^2.0.16, colorette@^2.0.20: resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== -colorjs.io@^0.4.3: - version "0.4.5" - resolved "https://registry.yarnpkg.com/colorjs.io/-/colorjs.io-0.4.5.tgz#7775f787ff90aca7a38f6edb7b7c0f8cce1e6418" - integrity sha512-yCtUNCmge7llyfd/Wou19PMAcf5yC3XXhgFoAh6zsO2pGswhUPBaaUh8jzgHnXtXuZyFKzXZNAnyF5i+apICow== - -combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: +combined-stream@^1.0.8, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== @@ -4716,11 +3787,6 @@ commander@^6.2.1: resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== -commander@^8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" - integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== - common-tags@^1.8.0: version "1.8.2" resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6" @@ -4731,50 +3797,23 @@ commondir@^1.0.1: resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== -component-emitter@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-2.0.0.tgz#3a137dfe66fcf2efe3eab7cb7d5f51741b3620c6" - integrity sha512-4m5s3Me2xxlVKG9PkZpQqHQR7bgpnN7joDMJ4yvVkVXngjoITG76IaZmzmywSeRTeTpc6N6r3H3+KyUurV8OYw== - -compressible@~2.0.16: - version "2.0.18" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" - integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== - dependencies: - mime-db ">= 1.43.0 < 2" - -compression@1.7.4: - version "1.7.4" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" - integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== - dependencies: - accepts "~1.3.5" - bytes "3.0.0" - compressible "~2.0.16" - debug "2.6.9" - on-headers "~1.0.2" - safe-buffer "5.1.2" - vary "~1.1.2" - concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -concurrently@^4.1.1: - version "4.1.2" - resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-4.1.2.tgz#1a683b2b5c41e9ed324c9002b9f6e4c6e1f3b6d7" - integrity sha512-Kim9SFrNr2jd8/0yNYqDTFALzUX1tvimmwFWxmp/D4mRI+kbqIIwE2RkBDrxS2ic25O1UgQMI5AtBqdtX3ynYg== +concurrently@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-9.0.1.tgz#01e171bf6c7af0c022eb85daef95bff04d8185aa" + integrity sha512-wYKvCd/f54sTXJMSfV6Ln/B8UrfLBKOYa+lzc6CHay3Qek+LorVSBdMVfyewFhRbH0Rbabsk4D+3PL/VjQ5gzg== dependencies: - chalk "^2.4.2" - date-fns "^1.30.1" - lodash "^4.17.15" - read-pkg "^4.0.1" - rxjs "^6.5.2" - spawn-command "^0.0.2-1" - supports-color "^4.5.0" - tree-kill "^1.2.1" - yargs "^12.0.5" + chalk "^4.1.2" + lodash "^4.17.21" + rxjs "^7.8.1" + shell-quote "^1.8.1" + supports-color "^8.1.1" + tree-kill "^1.2.2" + yargs "^17.7.2" consola@^3.2.3: version "3.2.3" @@ -4786,11 +3825,6 @@ consola@^3.2.3: resolved "https://registry.yarnpkg.com/consolidated-events/-/consolidated-events-2.0.2.tgz#da8d8f8c2b232831413d9e190dc11669c79f4a91" integrity sha512-2/uRVMdRypf5z/TW/ncD/66l75P5hH2vM/GR8Jf8HLc2xnfJtmina6F6du8+v4Z2vTrMo7jC+W1tmEEuuELgkQ== -content-disposition@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" - integrity sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA== - content-disposition@0.5.4: version "0.5.4" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" @@ -4828,7 +3862,7 @@ cookie@^0.5.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== -copy-to-clipboard@^3.0.8, copy-to-clipboard@^3.3.1: +copy-to-clipboard@^3.0.8: version "3.3.3" resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz#55ac43a1db8ae639a4bd99511c148cdd1b83a1b0" integrity sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA== @@ -4841,9 +3875,9 @@ core-js@^1.0.0: integrity sha512-ZiPp9pZlgxpWRu0M+YWbm6+aQ84XEfH1JRXvfOc/fILWI0VKhLC2LX13X1NYq4fULzLMq7Hfh43CSo2/aIaUPA== core-js@^3.6.0, core-js@^3.8.3: - version "3.35.1" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.35.1.tgz#9c28f8b7ccee482796f8590cc8d15739eaaf980c" - integrity sha512-IgdsbxNyMskrTFxa9lWHyMwAJU5gXOPP+1yO+K59d50VLVAIDAbs7gIv705KzALModfK3ZrSZTPNpC0PQgIZuw== + version "3.38.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.38.1.tgz#aa375b79a286a670388a1a363363d53677c0383e" + integrity sha512-OP35aUorbU3Zvlx7pjsFdu1rGNnD4pgw/CWoYzRY3t2EzoVT7shKHY1dlAy3f41cGIO7ZDPQimhGFTlEYkG/Hw== core-util-is@1.0.2: version "1.0.2" @@ -4894,17 +3928,17 @@ create-eslint-index@^1.0.0: dependencies: lodash.get "^4.3.0" -create-require@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" - integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== +credit-card-type@10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/credit-card-type/-/credit-card-type-10.0.1.tgz#3464309395a9942f0f9768481645b696f9f7c58a" + integrity sha512-vQOuWmBgsgG1ovGeDi8m6Zeu1JaqH/JncrxKmaqMbv/LunyOQdLiQhPHtOsNlbUI05TocR5nod/Mbs3HYtr6sQ== -credit-card-type@9.1.0, credit-card-type@^9.1.0: +credit-card-type@^9.1.0: version "9.1.0" resolved "https://registry.yarnpkg.com/credit-card-type/-/credit-card-type-9.1.0.tgz#54dd96c93b6579623e9c8656e6798fc2b93f5f05" integrity sha512-CpNFuLxiPFxuZqhSKml3M+t0K/484pMAnfYWH14JoD7OZMnmC0Lmo+P7JX9SobqFpRoo7ifA18kOHdxJywYPEA== -cross-spawn@^6.0.0, cross-spawn@^6.0.5: +cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== @@ -4954,11 +3988,11 @@ css.escape@^1.5.1: integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg== cssstyle@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-4.0.1.tgz#ef29c598a1e90125c870525490ea4f354db0660a" - integrity sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ== + version "4.1.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-4.1.0.tgz#161faee382af1bafadb6d3867a92a19bcb4aea70" + integrity sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA== dependencies: - rrweb-cssom "^0.6.0" + rrweb-cssom "^0.7.1" csstype@^2.5.7: version "2.6.21" @@ -4981,9 +4015,9 @@ cypress-file-upload@^5.0.8: integrity sha512-+8VzNabRk3zG6x8f8BWArF/xA/W0VK4IZNx3MV0jFWrJS/qKn8eHfa5nU73P9fOQAgwHFJx7zjg4lwOnljMO8g== cypress-real-events@^1.12.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/cypress-real-events/-/cypress-real-events-1.12.0.tgz#ffeb2b23686ba5b16ac91dd9bc3b6785d36d38d3" - integrity sha512-oiy+4kGKkzc2PT36k3GGQqkGxNiVypheWjMtfyi89iIk6bYmTzeqxapaLHS3pnhZOX1IEbTDUVxh8T4Nhs1tyQ== + version "1.13.0" + resolved "https://registry.yarnpkg.com/cypress-real-events/-/cypress-real-events-1.13.0.tgz#6b7cd32dcac172db1493608f97a2576c7d0bd5af" + integrity sha512-LoejtK+dyZ1jaT8wGT5oASTPfsNV8/ClRp99ruN60oPj8cBJYod80iJDyNwfPAu4GCxTXOhhAv9FO65Hpwt6Hg== cypress-vite@^1.5.0: version "1.5.0" @@ -5132,15 +4166,37 @@ data-urls@^5.0.0: whatwg-mimetype "^4.0.0" whatwg-url "^14.0.0" -date-fns@^1.30.1: - version "1.30.1" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" - integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw== +data-view-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" + integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" + integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" + integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" dayjs@^1.10.4: - version "1.11.10" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.10.tgz#68acea85317a6e164457d6d6947564029a6a16a0" - integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ== + version "1.11.13" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" + integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== debug@2.6.9: version "2.6.9" @@ -5149,12 +4205,12 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== +debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5, debug@^4.3.6, debug@~4.3.6: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== dependencies: - ms "2.1.2" + ms "^2.1.3" debug@^3.1.0: version "3.2.7" @@ -5163,25 +4219,6 @@ debug@^3.1.0: dependencies: ms "^2.1.1" -debug@^4.3.5, debug@~4.3.6: - version "4.3.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b" - integrity sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg== - dependencies: - ms "2.1.2" - -debug@^4.3.6: - version "4.3.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" - integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== - dependencies: - ms "^2.1.3" - -decamelize@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== - decimal.js-light@^2.4.1: version "2.5.1" resolved "https://registry.yarnpkg.com/decimal.js-light/-/decimal.js-light-2.5.1.tgz#134fd32508f19e208f4fb2f8dac0d2626a867934" @@ -5204,10 +4241,29 @@ deep-eql@^5.0.1: resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-5.0.2.tgz#4b756d8d770a9257300825d52a2c2cff99c3a341" integrity sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q== -deep-extend@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== +deep-equal@^2.0.5: + version "2.2.3" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.2.3.tgz#af89dafb23a396c7da3e862abc0be27cf51d56e1" + integrity sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA== + dependencies: + array-buffer-byte-length "^1.0.0" + call-bind "^1.0.5" + es-get-iterator "^1.1.3" + get-intrinsic "^1.2.2" + is-arguments "^1.1.1" + is-array-buffer "^3.0.2" + is-date-object "^1.0.5" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + isarray "^2.0.5" + object-is "^1.1.5" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.5.1" + side-channel "^1.0.4" + which-boxed-primitive "^1.0.2" + which-collection "^1.0.1" + which-typed-array "^1.1.13" deep-is@^0.1.3, deep-is@~0.1.3: version "0.1.4" @@ -5219,22 +4275,7 @@ deepmerge@^2.1.1: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170" integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA== -deepmerge@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" - integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== - -define-data-property@^1.0.1, define-data-property@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.2.tgz#f3c33b4f0102360cd7c0f5f28700f5678510b63a" - integrity sha512-SRtsSqsDbgpJBbW3pABMCOt6rQyeM8s8RiyeSN8jYG8sYmt/kGJejbydttUsnDs1tadr19tvhT4ShwMyoqAm4g== - dependencies: - es-errors "^1.3.0" - get-intrinsic "^1.2.2" - gopd "^1.0.1" - has-property-descriptors "^1.0.1" - -define-data-property@^1.1.4: +define-data-property@^1.0.1, define-data-property@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== @@ -5243,6 +4284,11 @@ define-data-property@^1.1.4: es-errors "^1.3.0" gopd "^1.0.1" +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" @@ -5279,11 +4325,6 @@ devlop@^1.0.0, devlop@^1.1.0: dependencies: dequal "^2.0.0" -diff@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== - dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -5342,9 +4383,9 @@ dot-case@^3.0.4: tslib "^2.0.3" dotenv@^16.0.3: - version "16.4.1" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.1.tgz#1d9931f1d3e5d2959350d1250efab299561f7f11" - integrity sha512-CjA3y+Dr3FyFDOAMnxZEGtnW9KBR2M0JvvUtXNW+dYJL5ROWxP9DUHCwgFqpMk0OXCc0ljhaNTr2w/kutYIcHQ== + version "16.4.5" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" + integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== eastasianwidth@^0.2.0: version "0.2.0" @@ -5364,15 +4405,15 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== -electron-to-chromium@^1.4.648: - version "1.4.665" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.665.tgz#681700bd590b0e5a3be66e3e2874ce62abcf5da5" - integrity sha512-UpyCWObBoD+nSZgOC2ToaIdZB0r9GhqT2WahPKiSki6ckkSuKhQNso8V2PrFcHBMleI/eqbKgVQgVC4Wni4ilw== +electron-to-chromium@^1.5.28: + version "1.5.28" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.28.tgz#aee074e202c6ee8a0030a9c2ef0b3fe9f967d576" + integrity sha512-VufdJl+rzaKZoYVUijN13QcXVF5dWPZANeFTLNy+OSpHdDL5ynXTF35+60RSBbaQYB1ae723lQXHCrf4pyLsMw== emoji-regex@^10.3.0: - version "10.3.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.3.0.tgz#76998b9268409eb3dae3de989254d456e70cfe23" - integrity sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw== + version "10.4.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.4.0.tgz#03553afea80b3975749cfcb36f776ca268e413d4" + integrity sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw== emoji-regex@^7.0.1: version "7.0.3" @@ -5394,6 +4435,11 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== +encodeurl@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" @@ -5419,6 +4465,14 @@ entities@~2.1.0: resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5" integrity sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w== +envify@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/envify/-/envify-4.1.0.tgz#f39ad3db9d6801b4e6b478b61028d3f0b6819f7e" + integrity sha512-IKRVVoAYr4pIx4yIWNsz9mOsboxlNXiu7TNBnem/K/uTHdkyzXWDzHCK7UTolqBbgaBz0tQHsD3YNls0uIIjiw== + dependencies: + esprima "^4.0.0" + through "~2.3.4" + environment@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/environment/-/environment-1.1.0.tgz#8e86c66b180f363c7ab311787e0259665f45a9f1" @@ -5431,50 +4485,57 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.22.1, es-abstract@^1.22.3: - version "1.22.3" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.3.tgz#48e79f5573198de6dee3589195727f4f74bc4f32" - integrity sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA== +es-abstract@^1.17.5, es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.1, es-abstract@^1.23.2, es-abstract@^1.23.3: + version "1.23.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" + integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== dependencies: - array-buffer-byte-length "^1.0.0" - arraybuffer.prototype.slice "^1.0.2" - available-typed-arrays "^1.0.5" - call-bind "^1.0.5" - es-set-tostringtag "^2.0.1" + array-buffer-byte-length "^1.0.1" + arraybuffer.prototype.slice "^1.0.3" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + data-view-buffer "^1.0.1" + data-view-byte-length "^1.0.1" + data-view-byte-offset "^1.0.0" + es-define-property "^1.0.0" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-set-tostringtag "^2.0.3" es-to-primitive "^1.2.1" function.prototype.name "^1.1.6" - get-intrinsic "^1.2.2" - get-symbol-description "^1.0.0" + get-intrinsic "^1.2.4" + get-symbol-description "^1.0.2" globalthis "^1.0.3" gopd "^1.0.1" - has-property-descriptors "^1.0.0" - has-proto "^1.0.1" + has-property-descriptors "^1.0.2" + has-proto "^1.0.3" has-symbols "^1.0.3" - hasown "^2.0.0" - internal-slot "^1.0.5" - is-array-buffer "^3.0.2" + hasown "^2.0.2" + internal-slot "^1.0.7" + is-array-buffer "^3.0.4" is-callable "^1.2.7" - is-negative-zero "^2.0.2" + is-data-view "^1.0.1" + is-negative-zero "^2.0.3" is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" + is-shared-array-buffer "^1.0.3" is-string "^1.0.7" - is-typed-array "^1.1.12" + is-typed-array "^1.1.13" is-weakref "^1.0.2" object-inspect "^1.13.1" object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.5.1" - safe-array-concat "^1.0.1" - safe-regex-test "^1.0.0" - string.prototype.trim "^1.2.8" - string.prototype.trimend "^1.0.7" - string.prototype.trimstart "^1.0.7" - typed-array-buffer "^1.0.0" - typed-array-byte-length "^1.0.0" - typed-array-byte-offset "^1.0.0" - typed-array-length "^1.0.4" + object.assign "^4.1.5" + regexp.prototype.flags "^1.5.2" + safe-array-concat "^1.1.2" + safe-regex-test "^1.0.3" + string.prototype.trim "^1.2.9" + string.prototype.trimend "^1.0.8" + string.prototype.trimstart "^1.0.8" + typed-array-buffer "^1.0.2" + typed-array-byte-length "^1.0.1" + typed-array-byte-offset "^1.0.2" + typed-array-length "^1.0.6" unbox-primitive "^1.0.2" - which-typed-array "^1.1.13" + which-typed-array "^1.1.15" es-define-property@^1.0.0: version "1.0.0" @@ -5483,44 +4544,66 @@ es-define-property@^1.0.0: dependencies: get-intrinsic "^1.2.4" -es-errors@^1.0.0, es-errors@^1.1.0, es-errors@^1.2.1, es-errors@^1.3.0: +es-errors@^1.2.1, es-errors@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== -es-iterator-helpers@^1.0.12, es-iterator-helpers@^1.0.15: - version "1.0.15" - resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.15.tgz#bd81d275ac766431d19305923707c3efd9f1ae40" - integrity sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g== +es-get-iterator@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.3.tgz#3ef87523c5d464d41084b2c3c9c214f1199763d6" + integrity sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw== dependencies: - asynciterator.prototype "^1.0.0" call-bind "^1.0.2" + get-intrinsic "^1.1.3" + has-symbols "^1.0.3" + is-arguments "^1.1.1" + is-map "^2.0.2" + is-set "^2.0.2" + is-string "^1.0.7" + isarray "^2.0.5" + stop-iteration-iterator "^1.0.0" + +es-iterator-helpers@^1.0.19: + version "1.0.19" + resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz#117003d0e5fec237b4b5c08aded722e0c6d50ca8" + integrity sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw== + dependencies: + call-bind "^1.0.7" define-properties "^1.2.1" - es-abstract "^1.22.1" - es-set-tostringtag "^2.0.1" - function-bind "^1.1.1" - get-intrinsic "^1.2.1" + es-abstract "^1.23.3" + es-errors "^1.3.0" + es-set-tostringtag "^2.0.3" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" globalthis "^1.0.3" - has-property-descriptors "^1.0.0" - has-proto "^1.0.1" + has-property-descriptors "^1.0.2" + has-proto "^1.0.3" has-symbols "^1.0.3" - internal-slot "^1.0.5" + internal-slot "^1.0.7" iterator.prototype "^1.1.2" - safe-array-concat "^1.0.1" + safe-array-concat "^1.1.2" es-module-lexer@^1.5.0: - version "1.5.2" - resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.2.tgz#00b423304f2500ac59359cc9b6844951f372d497" - integrity sha512-l60ETUTmLqbVbVHv1J4/qj+M8nq7AwMzEcg3kmJDt9dCNrTk+yHcYFf/Kw75pMDwd9mPcIGCG5LcS20SxYRzFA== + version "1.5.4" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.4.tgz#a8efec3a3da991e60efa6b633a7cad6ab8d26b78" + integrity sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw== -es-set-tostringtag@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz#11f7cc9f63376930a5f20be4915834f4bc74f9c9" - integrity sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q== +es-object-atoms@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" + integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== dependencies: - get-intrinsic "^1.2.2" - has-tostringtag "^1.0.0" - hasown "^2.0.0" + es-errors "^1.3.0" + +es-set-tostringtag@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" + integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== + dependencies: + get-intrinsic "^1.2.4" + has-tostringtag "^1.0.2" + hasown "^2.0.1" es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2: version "1.0.2" @@ -5539,13 +4622,13 @@ es-to-primitive@^1.2.1: is-symbol "^1.0.2" esbuild-register@^3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/esbuild-register/-/esbuild-register-3.5.0.tgz#449613fb29ab94325c722f560f800dd946dc8ea8" - integrity sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A== + version "3.6.0" + resolved "https://registry.yarnpkg.com/esbuild-register/-/esbuild-register-3.6.0.tgz#cf270cfa677baebbc0010ac024b823cbf723a36d" + integrity sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg== dependencies: debug "^4.3.4" -"esbuild@^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0", esbuild@^0.23.0: +"esbuild@^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0", esbuild@^0.23.0, esbuild@~0.23.0: version "0.23.1" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.23.1.tgz#40fdc3f9265ec0beae6f59824ade1bd3d3d2dab8" integrity sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg== @@ -5575,35 +4658,6 @@ esbuild-register@^3.5.0: "@esbuild/win32-ia32" "0.23.1" "@esbuild/win32-x64" "0.23.1" -esbuild@^0.19.3: - version "0.19.12" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.12.tgz#dc82ee5dc79e82f5a5c3b4323a2a641827db3e04" - integrity sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg== - optionalDependencies: - "@esbuild/aix-ppc64" "0.19.12" - "@esbuild/android-arm" "0.19.12" - "@esbuild/android-arm64" "0.19.12" - "@esbuild/android-x64" "0.19.12" - "@esbuild/darwin-arm64" "0.19.12" - "@esbuild/darwin-x64" "0.19.12" - "@esbuild/freebsd-arm64" "0.19.12" - "@esbuild/freebsd-x64" "0.19.12" - "@esbuild/linux-arm" "0.19.12" - "@esbuild/linux-arm64" "0.19.12" - "@esbuild/linux-ia32" "0.19.12" - "@esbuild/linux-loong64" "0.19.12" - "@esbuild/linux-mips64el" "0.19.12" - "@esbuild/linux-ppc64" "0.19.12" - "@esbuild/linux-riscv64" "0.19.12" - "@esbuild/linux-s390x" "0.19.12" - "@esbuild/linux-x64" "0.19.12" - "@esbuild/netbsd-x64" "0.19.12" - "@esbuild/openbsd-x64" "0.19.12" - "@esbuild/sunos-x64" "0.19.12" - "@esbuild/win32-arm64" "0.19.12" - "@esbuild/win32-ia32" "0.19.12" - "@esbuild/win32-x64" "0.19.12" - esbuild@^0.21.3: version "0.21.5" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d" @@ -5633,10 +4687,10 @@ esbuild@^0.21.3: "@esbuild/win32-ia32" "0.21.5" "@esbuild/win32-x64" "0.21.5" -escalade@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" - integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== +escalade@^3.1.1, escalade@^3.1.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== escape-html@~1.0.3: version "1.0.3" @@ -5675,53 +4729,33 @@ eslint-config-prettier@~8.1.0: integrity sha512-oKMhGv3ihGbCIimCAjqkdzx2Q+jthoqnXSP+d86M9tptwugycmTFdVR4IpLgq2c4SHifbwO90z2fQ8/Aio73yw== eslint-plugin-cypress@^2.11.3: - version "2.15.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-2.15.1.tgz#336afa7e8e27451afaf65aa359c9509e0a4f3a7b" - integrity sha512-eLHLWP5Q+I4j2AWepYq0PgFEei9/s5LvjuSqWrxurkg1YZ8ltxdvMNmdSf0drnsNo57CTgYY/NIHHLRSWejR7w== + version "2.15.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-2.15.2.tgz#f22e12fad4c434edad7b298ef92bac8fa087ffa0" + integrity sha512-CtcFEQTDKyftpI22FVGpx8bkpKyYXBlNge6zSo0pl5/qJvBAnzaD76Vu2AsP16d6mTj478Ldn2mhgrWV+Xr0vQ== dependencies: globals "^13.20.0" -eslint-plugin-es@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz#75a7cdfdccddc0589934aeeb384175f221c57893" - integrity sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ== - dependencies: - eslint-utils "^2.0.0" - regexpp "^3.0.0" - eslint-plugin-jsx-a11y@^6.7.1: - version "6.8.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz#2fa9c701d44fcd722b7c771ec322432857fcbad2" - integrity sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA== + version "6.10.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.0.tgz#36fb9dead91cafd085ddbe3829602fb10ef28339" + integrity sha512-ySOHvXX8eSN6zz8Bywacm7CvGNhUtdjvqfQDVe6020TUK34Cywkw7m0KsCCk1Qtm9G1FayfTN1/7mMYnYO2Bhg== dependencies: - "@babel/runtime" "^7.23.2" - aria-query "^5.3.0" - array-includes "^3.1.7" + aria-query "~5.1.3" + array-includes "^3.1.8" array.prototype.flatmap "^1.3.2" ast-types-flow "^0.0.8" - axe-core "=4.7.0" - axobject-query "^3.2.1" + axe-core "^4.10.0" + axobject-query "^4.1.0" damerau-levenshtein "^1.0.8" emoji-regex "^9.2.2" - es-iterator-helpers "^1.0.15" - hasown "^2.0.0" + es-iterator-helpers "^1.0.19" + hasown "^2.0.2" jsx-ast-utils "^3.3.5" language-tags "^1.0.9" minimatch "^3.1.2" - object.entries "^1.1.7" - object.fromentries "^2.0.7" - -eslint-plugin-node@^11.0.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz#c95544416ee4ada26740a30474eefc5402dc671d" - integrity sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g== - dependencies: - eslint-plugin-es "^3.0.0" - eslint-utils "^2.0.0" - ignore "^5.1.1" - minimatch "^3.0.4" - resolve "^1.10.1" - semver "^6.1.0" + object.fromentries "^2.0.8" + safe-regex-test "^1.0.3" + string.prototype.includes "^2.0.0" eslint-plugin-perfectionist@^1.4.0: version "1.5.1" @@ -5757,26 +4791,28 @@ eslint-plugin-react-hooks@^3.0.0: integrity sha512-EjxTHxjLKIBWFgDJdhKKzLh5q+vjTFrqNZX36uIxWS4OfyXe5DawqPj3U5qeJ1ngLwatjzQnmR0Lz0J0YH3kxw== eslint-plugin-react@^7.19.0: - version "7.33.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz#69ee09443ffc583927eafe86ffebb470ee737608" - integrity sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw== + version "7.36.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.36.1.tgz#f1dabbb11f3d4ebe8b0cf4e54aff4aee81144ee5" + integrity sha512-/qwbqNXZoq+VP30s1d4Nc1C5GTxjJQjk4Jzs4Wq2qzxFM7dSmuG2UkIjg2USMLh3A/aVcUNrK7v0J5U1XEGGwA== dependencies: - array-includes "^3.1.6" - array.prototype.flatmap "^1.3.1" - array.prototype.tosorted "^1.1.1" + array-includes "^3.1.8" + array.prototype.findlast "^1.2.5" + array.prototype.flatmap "^1.3.2" + array.prototype.tosorted "^1.1.4" doctrine "^2.1.0" - es-iterator-helpers "^1.0.12" + es-iterator-helpers "^1.0.19" estraverse "^5.3.0" + hasown "^2.0.2" jsx-ast-utils "^2.4.1 || ^3.0.0" minimatch "^3.1.2" - object.entries "^1.1.6" - object.fromentries "^2.0.6" - object.hasown "^1.1.2" - object.values "^1.1.6" + object.entries "^1.1.8" + object.fromentries "^2.0.8" + object.values "^1.2.0" prop-types "^15.8.1" - resolve "^2.0.0-next.4" + resolve "^2.0.0-next.5" semver "^6.3.1" - string.prototype.matchall "^4.0.8" + string.prototype.matchall "^4.0.11" + string.prototype.repeat "^1.0.0" eslint-plugin-scanjs-rules@^0.2.1: version "0.2.1" @@ -5791,16 +4827,6 @@ eslint-plugin-sonarjs@^0.5.0: resolved "https://registry.yarnpkg.com/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.5.0.tgz#ce17b2daba65a874c2862213a9e38e8986ad7d7d" integrity sha512-XW5MnzlRjhXpIdbULC/qAdJYHWw3rRLws/DyawdlPU/IdVr9AmRK1r2LaCvabwKOAW2XYYSo3kDX58E4MrB7PQ== -eslint-plugin-storybook@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-storybook/-/eslint-plugin-storybook-0.8.0.tgz#23185ecabdc289cae55248c090f0c1d8fbae6c41" - integrity sha512-CZeVO5EzmPY7qghO2t64oaFM+8FTaD4uzOEjHKp516exyTKo+skKAL9GI3QALS2BXhyALJjNtwbmr1XinGE8bA== - dependencies: - "@storybook/csf" "^0.0.1" - "@typescript-eslint/utils" "^5.62.0" - requireindex "^1.2.0" - ts-dedent "^2.2.0" - eslint-plugin-testing-library@^3.1.2: version "3.10.2" resolved "https://registry.yarnpkg.com/eslint-plugin-testing-library/-/eslint-plugin-testing-library-3.10.2.tgz#609ec2b0369da7cf2e6d9edff5da153cc31d87bd" @@ -5823,10 +4849,10 @@ eslint-scope@^5.0.0, eslint-scope@^5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-scope@^7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" - integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== +eslint-scope@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.0.2.tgz#5cbb33d4384c9136083a71190d548158fe128f94" + integrity sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" @@ -5855,48 +4881,52 @@ eslint-visitor-keys@^2.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1: version "3.4.3" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== +eslint-visitor-keys@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz#e3adc021aa038a2a8e0b2f8b0ce8f66b9483b1fb" + integrity sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw== + eslint@>=1.1: - version "8.56.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.56.0.tgz#4957ce8da409dc0809f99ab07a1b94832ab74b15" - integrity sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ== + version "9.11.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.11.1.tgz#701e5fc528990153f9cef696d8427003b5206567" + integrity sha512-MobhYKIoAO1s1e4VUrgx1l1Sk2JBR/Gqjjgw8+mfgoLE2xwsHur4gdfTxyTgShrhvdVFTaJSgMiQBl1jv/AWxg== dependencies: "@eslint-community/eslint-utils" "^4.2.0" - "@eslint-community/regexpp" "^4.6.1" - "@eslint/eslintrc" "^2.1.4" - "@eslint/js" "8.56.0" - "@humanwhocodes/config-array" "^0.11.13" + "@eslint-community/regexpp" "^4.11.0" + "@eslint/config-array" "^0.18.0" + "@eslint/core" "^0.6.0" + "@eslint/eslintrc" "^3.1.0" + "@eslint/js" "9.11.1" + "@eslint/plugin-kit" "^0.2.0" "@humanwhocodes/module-importer" "^1.0.1" + "@humanwhocodes/retry" "^0.3.0" "@nodelib/fs.walk" "^1.2.8" - "@ungap/structured-clone" "^1.2.0" + "@types/estree" "^1.0.6" + "@types/json-schema" "^7.0.15" ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" debug "^4.3.2" - doctrine "^3.0.0" escape-string-regexp "^4.0.0" - eslint-scope "^7.2.2" - eslint-visitor-keys "^3.4.3" - espree "^9.6.1" - esquery "^1.4.2" + eslint-scope "^8.0.2" + eslint-visitor-keys "^4.0.0" + espree "^10.1.0" + esquery "^1.5.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" + file-entry-cache "^8.0.0" find-up "^5.0.0" glob-parent "^6.0.2" - globals "^13.19.0" - graphemer "^1.4.0" ignore "^5.2.0" imurmurhash "^0.1.4" is-glob "^4.0.0" is-path-inside "^3.0.3" - js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" lodash.merge "^4.6.2" minimatch "^3.1.2" natural-compare "^1.4.0" @@ -5993,6 +5023,15 @@ eslint@^7.1.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" +espree@^10.0.1, espree@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.1.0.tgz#8788dae611574c0f070691f522e4116c5a11fc56" + integrity sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA== + dependencies: + acorn "^8.12.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^4.0.0" + espree@^6.1.2: version "6.2.1" resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" @@ -6011,24 +5050,15 @@ espree@^7.3.0, espree@^7.3.1: acorn-jsx "^5.3.1" eslint-visitor-keys "^1.3.0" -espree@^9.6.0, espree@^9.6.1: - version "9.6.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" - integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== - dependencies: - acorn "^8.9.0" - acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.4.1" - esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.0.1, esquery@^1.4.0, esquery@^1.4.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" - integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== +esquery@^1.0.1, esquery@^1.4.0, esquery@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== dependencies: estraverse "^5.1.0" @@ -6086,11 +5116,6 @@ eventemitter3@^5.0.1: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== -events@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" - integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== - execa@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" @@ -6106,19 +5131,6 @@ execa@4.1.0: signal-exit "^3.0.2" strip-final-newline "^2.0.0" -execa@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" - integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== - dependencies: - cross-spawn "^6.0.0" - get-stream "^4.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - execa@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" @@ -6156,42 +5168,37 @@ executable@^4.1.1: dependencies: pify "^2.2.0" -expr-eval-fork@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/expr-eval-fork/-/expr-eval-fork-2.0.2.tgz#97136ac0a8178522055500f55d3d3c5ad54f400d" - integrity sha512-NaAnObPVwHEYrODd7Jzp3zzT9pgTAlUUL4MZiZu9XAYPDpx89cPsfyEImFb2XY0vQNbrqg2CG7CLiI+Rs3seaQ== - express@^4.19.2: - version "4.19.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465" - integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== + version "4.21.0" + resolved "https://registry.yarnpkg.com/express/-/express-4.21.0.tgz#d57cb706d49623d4ac27833f1cbc466b668eb915" + integrity sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng== dependencies: accepts "~1.3.8" array-flatten "1.1.1" - body-parser "1.20.2" + body-parser "1.20.3" content-disposition "0.5.4" content-type "~1.0.4" cookie "0.6.0" cookie-signature "1.0.6" debug "2.6.9" depd "2.0.0" - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" etag "~1.8.1" - finalhandler "1.2.0" + finalhandler "1.3.1" fresh "0.5.2" http-errors "2.0.0" - merge-descriptors "1.0.1" + merge-descriptors "1.0.3" methods "~1.1.2" on-finished "2.4.1" parseurl "~1.3.3" - path-to-regexp "0.1.7" + path-to-regexp "0.1.10" proxy-addr "~2.0.7" - qs "6.11.0" + qs "6.13.0" range-parser "~1.2.1" safe-buffer "5.2.1" - send "0.18.0" - serve-static "1.15.0" + send "0.19.0" + serve-static "1.16.2" setprototypeof "1.2.0" statuses "2.0.1" type-is "~1.6.18" @@ -6282,12 +5289,10 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== -fast-url-parser@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d" - integrity sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ== - dependencies: - punycode "^1.3.2" +fast-uri@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.1.tgz#cddd2eecfc83a71c1be2cc2ef2061331be8a7134" + integrity sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw== fastq@^1.6.0: version "1.17.1" @@ -6347,6 +5352,13 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== + dependencies: + flat-cache "^4.0.0" + file-selector@^0.2.2: version "0.2.4" resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.2.4.tgz#7b98286f9dbb9925f420130ea5ed0a69238d4d80" @@ -6354,14 +5366,6 @@ file-selector@^0.2.2: dependencies: tslib "^2.0.3" -file-system-cache@2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/file-system-cache/-/file-system-cache-2.3.0.tgz#201feaf4c8cd97b9d0d608e96861bb6005f46fe6" - integrity sha512-l4DMNdsIPsVnKrgEXbJwDJsA5mB8rGwHYERMgqQx/xAUtChPJMre1bXBzDEqqVbWv9AIbFezXMxeEkZDSrXUOQ== - dependencies: - fs-extra "11.1.1" - ramda "0.29.0" - fill-range@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" @@ -6369,13 +5373,13 @@ fill-range@^7.1.1: dependencies: to-regex-range "^5.0.1" -finalhandler@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" - integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== +finalhandler@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" + integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== dependencies: debug "2.6.9" - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" on-finished "2.4.1" parseurl "~1.3.3" @@ -6396,13 +5400,6 @@ find-root@^1.1.0: resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== -find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== - dependencies: - locate-path "^3.0.0" - find-up@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" @@ -6419,13 +5416,6 @@ find-up@^5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" -find-yarn-workspace-root@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz#f47fb8d239c900eb78179aa81b66673eac88f7bd" - integrity sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ== - dependencies: - micromatch "^4.0.2" - flag-icons@^6.6.5: version "6.15.0" resolved "https://registry.yarnpkg.com/flag-icons/-/flag-icons-6.15.0.tgz#9b9ea631f408ff41844872d1d7df9bd020d4c76d" @@ -6449,25 +5439,28 @@ flat-cache@^3.0.4: keyv "^4.5.3" rimraf "^3.0.2" +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.4" + flatted@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== -flatted@^3.2.9: - version "3.2.9" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf" - integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== - -flatted@^3.3.1: +flatted@^3.2.9, flatted@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== follow-redirects@^1.15.6: - version "1.15.6" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" - integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== + version "1.15.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== font-logos@^0.18.0: version "0.18.0" @@ -6482,9 +5475,9 @@ for-each@^0.3.3: is-callable "^1.1.3" foreground-child@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" - integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== + version "3.3.0" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" + integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== dependencies: cross-spawn "^7.0.0" signal-exit "^4.0.1" @@ -6494,7 +5487,7 @@ forever-agent@~0.6.1: resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== -form-data@^4.0.0: +form-data@^4.0.0, form-data@~4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== @@ -6503,15 +5496,6 @@ form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - formik@~2.1.3: version "2.1.7" resolved "https://registry.yarnpkg.com/formik/-/formik-2.1.7.tgz#40bd04e59b242176d0a17c701830f1536cd7506b" @@ -6531,10 +5515,10 @@ forwarded@0.2.0: resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== -framebus@5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/framebus/-/framebus-5.2.1.tgz#6b7468191c020e28ee339c15561d4bd12864c636" - integrity sha512-K6pw+M2wNBuOhEoFrmMbf1O+fm7PnNDIfA9y0KpAyQzXRIJ420szGgJ/dI2Ikz0XG+5VfspLqA72M6bXhuyKIQ== +framebus@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/framebus/-/framebus-6.0.0.tgz#4ebafaf4d78441fdb1f6c55cb9a6ea9f72c55cff" + integrity sha512-bL9V68hVaVBCY9rveoWbPFFI9hAXIJtESs51B+9XmzvMt38+wP8b4VdiJsavjMS6NfPZ/afQ/jc2qaHmSGI1kQ== dependencies: "@braintree/uuid" "^0.1.0" @@ -6543,15 +5527,6 @@ fresh@0.5.2: resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== -fs-extra@11.1.1: - version "11.1.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.1.1.tgz#da69f7c39f3b002378b0954bb6ae7efdc0876e2d" - integrity sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - fs-extra@^11.1.0: version "11.2.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.2.0.tgz#e70e17dfad64232287d01929399e0ea7c86b0e5b" @@ -6561,7 +5536,7 @@ fs-extra@^11.1.0: jsonfile "^6.0.1" universalify "^2.0.0" -fs-extra@^9.0.0, fs-extra@^9.1.0: +fs-extra@^9.1.0: version "9.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== @@ -6581,12 +5556,12 @@ fsevents@~2.3.2, fsevents@~2.3.3: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== -function-bind@^1.1.1, function-bind@^1.1.2: +function-bind@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== -function.prototype.name@^1.1.5, function.prototype.name@^1.1.6: +function.prototype.name@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== @@ -6611,11 +5586,6 @@ gensync@^1.0.0-beta.2: resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== -get-caller-file@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" - integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== - get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" @@ -6631,7 +5601,7 @@ get-func-name@^2.0.1: resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== -get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: +get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== @@ -6642,13 +5612,6 @@ get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@ has-symbols "^1.0.3" hasown "^2.0.0" -get-stream@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - dependencies: - pump "^3.0.0" - get-stream@^5.0.0, get-stream@^5.1.0: version "5.2.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" @@ -6666,7 +5629,7 @@ get-stream@^8.0.1: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2" integrity sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA== -get-symbol-description@^1.0.0: +get-symbol-description@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== @@ -6675,6 +5638,13 @@ get-symbol-description@^1.0.0: es-errors "^1.3.0" get-intrinsic "^1.2.4" +get-tsconfig@^4.7.5: + version "4.8.1" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.8.1.tgz#8995eb391ae6e1638d251118c7b56de7eb425471" + integrity sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg== + dependencies: + resolve-pkg-maps "^1.0.0" + getos@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/getos/-/getos-3.2.1.tgz#0134d1f4e00eb46144c5a9c0ac4dc087cbb27dc5" @@ -6694,13 +5664,20 @@ github-slugger@^2.0.0: resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-2.0.0.tgz#52cf2f9279a21eb6c59dd385b410f0c0adda8f1a" integrity sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw== -glob-parent@^5.0.0, glob-parent@^5.1.2, glob-parent@^6.0.2, glob-parent@~5.1.2: +glob-parent@^5.0.0, glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + glob-promise@^4.2.0: version "4.2.2" resolved "https://registry.yarnpkg.com/glob-promise/-/glob-promise-4.2.2.tgz#15f44bcba0e14219cd93af36da6bb905ff007877" @@ -6708,18 +5685,7 @@ glob-promise@^4.2.0: dependencies: "@types/glob" "^7.1.3" -glob@^10.3.1, glob@^10.3.10: - version "10.3.10" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b" - integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== - dependencies: - foreground-child "^3.1.0" - jackspeak "^2.3.5" - minimatch "^9.0.1" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" - path-scurry "^1.10.1" - -glob@^10.4.1, glob@^10.4.2: +glob@^10.3.1, glob@^10.3.10, glob@^10.4.1: version "10.4.5" resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== @@ -6762,19 +5728,25 @@ globals@^12.1.0: dependencies: type-fest "^0.8.1" -globals@^13.19.0, globals@^13.20.0, globals@^13.6.0, globals@^13.9.0: +globals@^13.20.0, globals@^13.6.0, globals@^13.9.0: version "13.24.0" resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== dependencies: type-fest "^0.20.2" +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== + globalthis@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" - integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== + version "1.0.4" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" + integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== dependencies: - define-properties "^1.1.3" + define-properties "^1.2.1" + gopd "^1.0.1" globby@^11.1.0: version "11.1.0" @@ -6800,7 +5772,7 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" -graceful-fs@^4.1.11, graceful-fs@^4.1.6, graceful-fs@^4.2.0: +graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -6811,20 +5783,15 @@ graphemer@^1.4.0: integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== graphql@^16.8.1: - version "16.8.1" - resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.8.1.tgz#1930a965bef1170603702acdb68aedd3f3cf6f07" - integrity sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw== + version "16.9.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.9.0.tgz#1c310e63f16a49ce1fbb230bd0a000e99f6f115f" + integrity sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw== has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== -has-flag@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" - integrity sha512-P+1n3MnwjR/Epg9BBo1KT8qbye2g2Ou4sFumihwt6I4tsUX7jnLcX4BTOSKg/B1ZrIYMN9FcEnG4x5a7NB8Eng== - has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -6835,41 +5802,34 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz#52ba30b6c5ec87fd89fa574bc1c39125c6f65340" - integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg== - dependencies: - get-intrinsic "^1.2.2" - -has-property-descriptors@^1.0.2: +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== dependencies: es-define-property "^1.0.0" -has-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" - integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== +has-proto@^1.0.1, has-proto@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== -has-tostringtag@^1.0.0, has-tostringtag@^1.0.1: +has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== dependencies: has-symbols "^1.0.3" -hasown@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" - integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== +hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== dependencies: function-bind "^1.1.2" @@ -6900,9 +5860,9 @@ he@^1.2.0: integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== headers-polyfill@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/headers-polyfill/-/headers-polyfill-4.0.2.tgz#9115a76eee3ce8fbf95b6e3c6bf82d936785b44a" - integrity sha512-EWGTfnTqAO2L/j5HZgoM/3z82L7necsJ0pO9Tp0X1wil3PDLrkypTBRgVO2ExehEEvUycejZD3FuRaXpZZc3kw== + version "4.0.3" + resolved "https://registry.yarnpkg.com/headers-polyfill/-/headers-polyfill-4.0.3.tgz#922a0155de30ecc1f785bcf04be77844ca95ad07" + integrity sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ== hi-base32@^0.5.0: version "0.5.1" @@ -6910,9 +5870,9 @@ hi-base32@^0.5.0: integrity sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA== highlight.js@*: - version "11.9.0" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.9.0.tgz#04ab9ee43b52a41a047432c8103e2158a1b8b5b0" - integrity sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw== + version "11.10.0" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.10.0.tgz#6e3600dc4b33d6dc23d5bd94fbf72405f5892b92" + integrity sha512-SYVnVFswQER+zu1laSya563s+F8VDGt7o35d4utbamowvUNLLMovFqwCLSocpZTz3MgaSRA1IbqRWZv97dtErQ== highlight.js@^9.7.0: version "9.18.5" @@ -6948,13 +5908,6 @@ hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react- dependencies: react-is "^16.7.0" -hosted-git-info@^2.1.4, hosted-git-info@^5.0.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-5.2.1.tgz#0ba1c97178ef91f3ab30842ae63d6a272341156f" - integrity sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw== - dependencies: - lru-cache "^7.5.1" - html-encoding-sniffer@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz#696df529a7cfd82446369dc5193e590a3735b448" @@ -6999,14 +5952,14 @@ http-proxy-agent@^7.0.2: agent-base "^7.1.0" debug "^4.3.4" -http-signature@~1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.3.6.tgz#cb6fbfdf86d1c974f343be94e87f7fc128662cf9" - integrity sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw== +http-signature@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.4.0.tgz#dee5a9ba2bf49416abc544abd6d967f6a94c8c3f" + integrity sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg== dependencies: assert-plus "^1.0.0" jsprim "^2.0.2" - sshpk "^1.14.1" + sshpk "^1.18.0" https-proxy-agent@^7.0.5: version "7.0.5" @@ -7036,11 +5989,6 @@ husky@^9.1.6: resolved "https://registry.yarnpkg.com/husky/-/husky-9.1.6.tgz#e23aa996b6203ab33534bdc82306b0cf2cb07d6c" integrity sha512-sqbjZKK7kf44hfdE94EoX8MZNk0n7HeW37O4YrVGCF4wzgQjp+akPAkfUK5LZ6KuR/6sqeAVuXHji+RzQgOn5A== -hyperdyperid@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/hyperdyperid/-/hyperdyperid-1.2.0.tgz#59668d323ada92228d2a869d3e474d5a33b69e6b" - integrity sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A== - iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -7055,7 +6003,7 @@ iconv-lite@0.6.3: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -ieee754@^1.1.13, ieee754@^1.2.1: +ieee754@^1.1.13: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -7065,10 +6013,15 @@ ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.1.1, ignore@^5.2.0, ignore@^5.2.4: - version "5.3.1" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" - integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== +ignore@^5.2.0, ignore@^5.2.4: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== immer@^9.0.6: version "9.0.21" @@ -7106,25 +6059,15 @@ inherits@2, inherits@2.0.4, inherits@^2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== - ini@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== -ini@~1.3.0: - version "1.3.8" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" - integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== - -inject-stylesheet@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/inject-stylesheet/-/inject-stylesheet-5.0.0.tgz#bb34acf05ca6ed86e5763d886cd6c9b19f360ab1" - integrity sha512-GzncrJP8E/pavMQzoO93CXoYCfTttwVm2cX2TyXJdgtVE0cCvWSFCn1/uMsM6ZkEg7LUsOcKuamcLiGWlv2p9A== +inject-stylesheet@6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/inject-stylesheet/-/inject-stylesheet-6.0.1.tgz#ab724474ac300684875e8980d1285cb4e99b33ae" + integrity sha512-2fvune1D4+8mvJoLVo95ncY4HrDkIaYIReRzXv8tkWFgdG9iuc5QuX57gtSDPWTWQI/f5BGwwtH85wxHouzucg== inquirer@^7.0.0: version "7.3.3" @@ -7145,7 +6088,7 @@ inquirer@^7.0.0: strip-ansi "^6.0.0" through "^2.3.6" -internal-slot@^1.0.5: +internal-slot@^1.0.4, internal-slot@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== @@ -7166,27 +6109,22 @@ invariant@^2.2.4: dependencies: loose-envify "^1.0.0" -invert-kv@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" - integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== - ipaddr.js@1.9.1, ipaddr.js@^1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== ipaddr.js@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.1.0.tgz#2119bc447ff8c257753b196fc5f1ce08a4cdf39f" - integrity sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ== + version "2.2.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.2.0.tgz#d33fa7bac284f4de7af949638c9d68157c6b92e8" + integrity sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA== is-absolute-url@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-4.0.1.tgz#16e4d487d4fded05cfe0685e53ec86804a5e94dc" integrity sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A== -is-arguments@^1.0.4: +is-arguments@^1.0.4, is-arguments@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== @@ -7259,11 +6197,18 @@ is-ci@^3.0.1: ci-info "^3.2.0" is-core-module@^2.12.1, is-core-module@^2.13.0: - version "2.13.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" - integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + version "2.15.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37" + integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== dependencies: - hasown "^2.0.0" + hasown "^2.0.2" + +is-data-view@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" + integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== + dependencies: + is-typed-array "^1.1.13" is-date-object@^1.0.1, is-date-object@^1.0.5: version "1.0.5" @@ -7272,7 +6217,7 @@ is-date-object@^1.0.1, is-date-object@^1.0.5: dependencies: has-tostringtag "^1.0.0" -is-docker@^2.0.0: +is-docker@^2.0.0, is-docker@^2.1.1: version "2.2.1" resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== @@ -7289,13 +6234,6 @@ is-finalizationregistry@^1.0.2: dependencies: call-bind "^1.0.2" -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw== - dependencies: - number-is-nan "^1.0.0" - is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" @@ -7340,28 +6278,15 @@ is-installed-globally@~0.4.0: global-dirs "^3.0.0" is-path-inside "^3.0.2" -is-map@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" - integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== - -is-mergeable-object@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-mergeable-object/-/is-mergeable-object-1.1.1.tgz#faaa3ed1cfce87d6f7d2f5885e92cc30af3e2ebf" - integrity sha512-CPduJfuGg8h8vW74WOxHtHmtQutyQBzR+3MjQ6iDHIYdbOnm1YC7jv43SqCoU8OPGTJD4nibmiryA4kmogbGrA== - -is-nan@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d" - integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" +is-map@^2.0.2, is-map@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" + integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== -is-negative-zero@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" - integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== +is-negative-zero@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" + integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== is-node-process@^1.2.0: version "1.2.0" @@ -7385,7 +6310,7 @@ is-path-inside@^3.0.2, is-path-inside@^3.0.3: resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== -is-plain-obj@^4.0.0, is-plain-obj@^4.1.0: +is-plain-obj@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0" integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg== @@ -7402,11 +6327,6 @@ is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" -is-port-reachable@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-port-reachable/-/is-port-reachable-4.0.0.tgz#dac044091ef15319c8ab2f34604d8794181f8c2d" - integrity sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig== - is-potential-custom-element-name@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" @@ -7420,22 +6340,17 @@ is-regex@^1.1.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-set@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" - integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== +is-set@^2.0.2, is-set@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d" + integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== -is-shared-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" - integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== +is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" + integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== dependencies: - call-bind "^1.0.2" - -is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ== + call-bind "^1.0.7" is-stream@^2.0.0: version "2.0.1" @@ -7461,7 +6376,7 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" -is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.13, is-typed-array@^1.1.3, is-typed-array@^1.1.9: +is-typed-array@^1.1.13, is-typed-array@^1.1.3: version "1.1.13" resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== @@ -7478,10 +6393,10 @@ is-unicode-supported@^0.1.0: resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -is-weakmap@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" - integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== +is-weakmap@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" + integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w== is-weakref@^1.0.2: version "1.0.2" @@ -7490,15 +6405,15 @@ is-weakref@^1.0.2: dependencies: call-bind "^1.0.2" -is-weakset@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.2.tgz#4569d67a747a1ce5a994dfd4ef6dcea76e7c0a1d" - integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg== +is-weakset@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.3.tgz#e801519df8c0c43e12ff2834eead84ec9e624007" + integrity sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" + call-bind "^1.0.7" + get-intrinsic "^1.2.4" -is-wsl@^2.1.1, is-wsl@^2.2.0: +is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== @@ -7580,12 +6495,12 @@ iterator.prototype@^1.1.2: reflect.getprototypeof "^1.0.4" set-function-name "^2.0.1" -jackspeak@2.1.1, jackspeak@^2.3.5, jackspeak@^3.1.2: - version "2.1.1" - resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.1.1.tgz#2a42db4cfbb7e55433c28b6f75d8b796af9669cd" - integrity sha512-juf9stUEwUaILepraGOWIJTLwg48bUnBmRqd2ln2Os1sW987zeoj/hzhbvRB95oMuS2ZTpjULmdwHNX4rzZIZw== +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== dependencies: - cliui "^8.0.1" + "@isaacs/cliui" "^8.0.2" optionalDependencies: "@pkgjs/parseargs" "^0.11.0" @@ -7619,10 +6534,15 @@ jsbn@~0.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== +jsdoc-type-pratt-parser@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz#ff6b4a3f339c34a6c188cbf50a16087858d22113" + integrity sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg== + jsdom@^24.1.1: - version "24.1.1" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-24.1.1.tgz#f41df8f4f3b2fbfa7e1bdc5df62c9804fd14a9d0" - integrity sha512-5O1wWV99Jhq4DV7rCLIoZ/UIhyQeDR7wHVyZAHAshbrvZsLs+Xzz7gtwnlJTJDjleiTKh54F4dXrX70vJQTyJQ== + version "24.1.3" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-24.1.3.tgz#88e4a07cb9dd21067514a619e9f17b090a394a9f" + integrity sha512-MyL55p3Ut3cXbeBEG7Hcv0mVM8pp8PBNWxRqchZnSfAiES1v1mRnMeFfaHWIPULpwsYfvO+ZmMZz5tGCnjzDUQ== dependencies: cssstyle "^4.0.1" data-urls "^5.0.0" @@ -7656,11 +6576,6 @@ json-buffer@3.0.1: resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== -json-parse-better-errors@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - json-parse-even-better-errors@^2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" @@ -7686,16 +6601,6 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== -json-stable-stringify@^1.0.2: - version "1.1.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.1.1.tgz#52d4361b47d49168bcc4e564189a42e5a7439454" - integrity sha512-SU/971Kt5qVQfJpyDveVhQ/vya+5hvrjClFOcr8c0Fq5aODJjMwutrOfCU+eCnVD5gpx1Q3fEqkyom77zH1iIg== - dependencies: - call-bind "^1.0.5" - isarray "^2.0.5" - jsonify "^0.0.1" - object-keys "^1.1.1" - json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -7715,15 +6620,10 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" -jsonify@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.1.tgz#2aa3111dae3d34a0f151c63f3a45d995d9420978" - integrity sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg== - jspdf-autotable@^3.5.14: - version "3.8.1" - resolved "https://registry.yarnpkg.com/jspdf-autotable/-/jspdf-autotable-3.8.1.tgz#e4d9b62356a412024e8f08e84fdeb5b85e1383b5" - integrity sha512-UjJqo80Z3/WUzDi4JipTGp0pAvNvR3Gsm38inJ5ZnwsJH0Lw4pEbssRSH6zMWAhR1ZkTrsDpQo5p6rZk987/AQ== + version "3.8.3" + resolved "https://registry.yarnpkg.com/jspdf-autotable/-/jspdf-autotable-3.8.3.tgz#b469730c28376a81298d04d18136f1fb464cd4b8" + integrity sha512-PQFdljBt+ijm6ZWXYxhZ54A/awV63UKcipYoA2+YGsz0BXXiXTIL/FIg+V30j7wPdSdzClfbB3qKX9UeuFylPQ== jspdf@^2.5.2: version "2.5.2" @@ -7761,37 +6661,30 @@ jsprim@^2.0.2: object.values "^1.1.6" junit2json@^3.1.4: - version "3.1.5" - resolved "https://registry.yarnpkg.com/junit2json/-/junit2json-3.1.5.tgz#6832ae2c0bd0de9c59b532a92f32721af6cbee5b" - integrity sha512-6fAHN5OMb0VV3+f+8DJ3/8yysRJxajrnUmkBeR+QjQQtUXZ5h4E3RMzF7gFhLnIhFewBUAyQGalgCJrkHieHqQ== + version "3.1.12" + resolved "https://registry.yarnpkg.com/junit2json/-/junit2json-3.1.12.tgz#7abcb34d394662b36f519651d945432b2ae3b1df" + integrity sha512-pVll/UUqeDGA0rao+2x1JyGiXB77+g+vb1TYO/Eq8eFjKxPjcOnilX/cY3YH0xm8Ufl3f6hIbQLgYnH+zI73Uw== dependencies: "@types/xml2js" "0.4.14" xml2js "0.6.2" yargs "17.7.2" -keyv@^4.5.3: +keyv@^4.5.3, keyv@^4.5.4: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== dependencies: json-buffer "3.0.1" -kind-of@^6.0.2, kind-of@^6.0.3: +kind-of@^6.0.2: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== -klaw-sync@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/klaw-sync/-/klaw-sync-6.0.0.tgz#1fd2cfd56ebb6250181114f0a581167099c2b28c" - integrity sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ== - dependencies: - graceful-fs "^4.1.11" - language-subtag-registry@^0.3.20: - version "0.3.22" - resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d" - integrity sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w== + version "0.3.23" + resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz#23529e04d9e3b74679d70142df3fd2eb6ec572e7" + integrity sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ== language-tags@^1.0.9: version "1.0.9" @@ -7801,17 +6694,17 @@ language-tags@^1.0.9: language-subtag-registry "^0.3.20" launchdarkly-js-client-sdk@^3.1.4: - version "3.1.4" - resolved "https://registry.yarnpkg.com/launchdarkly-js-client-sdk/-/launchdarkly-js-client-sdk-3.1.4.tgz#e613cb53412533c07ccf140ae570fc994c59758d" - integrity sha512-yq0FeklpVuHMSRz7jfUAfyM7I/659RvGztqJ0Y9G5eN/ZrG1o2W61ZU0Nrv/gqZCtLXjarh/u1otxSFFBjTpHw== + version "3.4.0" + resolved "https://registry.yarnpkg.com/launchdarkly-js-client-sdk/-/launchdarkly-js-client-sdk-3.4.0.tgz#5b5959b548edac8a0f368eb40b079d942573d37b" + integrity sha512-3v1jKy1RECT0SG/3SGlyRO32vweoNxvWiJuIChRh/Zhk98cHpANuwameXVhwJ4WEDNZJTur73baaKAyatSP46A== dependencies: escape-string-regexp "^4.0.0" - launchdarkly-js-sdk-common "5.0.3" + launchdarkly-js-sdk-common "5.3.0" -launchdarkly-js-sdk-common@5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/launchdarkly-js-sdk-common/-/launchdarkly-js-sdk-common-5.0.3.tgz#345f899f5779be8b03d6599978c855eb838d8b7f" - integrity sha512-wKG8UsVbPVq8+7eavgAm5CVmulQWN6Ddod2ZoA3euZ1zPvJPwIQ2GrOYaCJr3cFrrMIX+nQyBJHBHYxUAPcM+Q== +launchdarkly-js-sdk-common@5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/launchdarkly-js-sdk-common/-/launchdarkly-js-sdk-common-5.3.0.tgz#336a54843f5ba3541632e10014e49dff45d41674" + integrity sha512-NI5wFF8qhjtpRb4KelGdnwNIOf/boLlbLiseV7uf1jxSeoM/L30DAz87RT8VhYCSGCo4LedGILQFednI/MKFkA== dependencies: base64-js "^1.3.0" fast-deep-equal "^2.0.1" @@ -7831,13 +6724,6 @@ lazy-ass@^1.6.0: resolved "https://registry.yarnpkg.com/lazy-ass/-/lazy-ass-1.6.0.tgz#7999655e8646c17f089fdd187d150d3324d54513" integrity sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw== -lcid@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" - integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== - dependencies: - invert-kv "^2.0.0" - levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" @@ -7855,9 +6741,16 @@ levn@^0.4.1: type-check "~0.4.0" libphonenumber-js@^1.10.6: - version "1.10.55" - resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.10.55.tgz#ec864e369bf7babde02021d06b5f2433d7e9c78e" - integrity sha512-MrTg2JFLscgmTY6/oT9vopYETlgUls/FU6OaeeamGwk4LFxjIgOUML/ZSZICgR0LPYXaonVJo40lzMvaaTJlQA== + version "1.11.9" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.11.9.tgz#e653042b11da2b50b7ea3b206fa7ca998436ae99" + integrity sha512-Zs5wf5HaWzW2/inlupe2tstl0I/Tbqo7lH20ZLr6Is58u7Dz2n+gRFGNlj9/gWxFvNfp9+YyDsiegjNhdixB9A== + +lie@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" + integrity sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw== + dependencies: + immediate "~3.0.5" lilconfig@^3.1.1, lilconfig@~3.1.2: version "3.1.2" @@ -7877,9 +6770,9 @@ linkify-it@^3.0.1: uc.micro "^1.0.1" lint-staged@^15.2.9: - version "15.2.9" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-15.2.9.tgz#bf70d40b6b192df6ad756fb89822211615e0f4da" - integrity sha512-BZAt8Lk3sEnxw7tfxM7jeZlPRuT4M68O0/CwZhhaw6eeWu0Lz5eERE3m386InivXB64fp/mDID452h48tvKlRQ== + version "15.2.10" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-15.2.10.tgz#92ac222f802ba911897dcf23671da5bb80643cd2" + integrity sha512-5dY5t743e1byO19P9I4b3x8HJwalIznL5E1FWYnU6OWw33KxNBSLAc6Cy7F2PsFEO8FKnLwjwm5hx7aMF0jzZg== dependencies: chalk "~5.3.0" commander "~12.1.0" @@ -7887,7 +6780,7 @@ lint-staged@^15.2.9: execa "~8.0.1" lilconfig "~3.1.2" listr2 "~8.2.4" - micromatch "~4.0.7" + micromatch "~4.0.8" pidtree "~0.6.0" string-argv "~0.3.2" yaml "~2.5.0" @@ -7923,13 +6816,12 @@ load-tsconfig@^0.2.3: resolved "https://registry.yarnpkg.com/load-tsconfig/-/load-tsconfig-0.2.5.tgz#453b8cd8961bfb912dea77eb6c168fe8cca3d3a1" integrity sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg== -locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== +localforage@^1.8.1: + version "1.10.0" + resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.10.0.tgz#5c465dc5f62b2807c3a84c0c6a1b1b3212781dd4" + integrity sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg== dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" + lie "3.1.1" locate-path@^5.0.0: version "5.0.0" @@ -7955,16 +6847,6 @@ lodash.camelcase@^4.3.0: resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== -lodash.clonedeep@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" - integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ== - -lodash.curry@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.curry/-/lodash.curry-4.1.1.tgz#248e36072ede906501d75966200a86dab8b23170" - integrity sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA== - lodash.get@^4.3.0: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" @@ -8072,16 +6954,6 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" -lru-cache@^7.5.1: - version "7.18.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" - integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== - -"lru-cache@^9.1.1 || ^10.0.0": - version "10.2.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3" - integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q== - luxon@3.4.4: version "3.4.4" resolved "https://registry.yarnpkg.com/luxon/-/luxon-3.4.4.tgz#cf20dc27dc532ba41a169c43fdcc0063601577af" @@ -8099,14 +6971,7 @@ magic-string@^0.27.0: dependencies: "@jridgewell/sourcemap-codec" "^1.4.13" -magic-string@^0.30.0: - version "0.30.7" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.7.tgz#0cecd0527d473298679da95a2d7aeb8c64048505" - integrity sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA== - dependencies: - "@jridgewell/sourcemap-codec" "^1.4.15" - -magic-string@^0.30.11: +magic-string@^0.30.0, magic-string@^0.30.11: version "0.30.11" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.11.tgz#301a6f93b3e8c2cb13ac1a7a673492c0dfd12954" integrity sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A== @@ -8136,18 +7001,6 @@ make-dir@^4.0.0: dependencies: semver "^7.5.3" -make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -map-age-cleaner@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" - integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== - dependencies: - p-defer "^1.0.0" - map-or-similar@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/map-or-similar/-/map-or-similar-1.5.0.tgz#6de2653174adfb5d9edc33c69d3e92a1b76faf08" @@ -8194,9 +7047,9 @@ mdast-util-find-and-replace@^3.0.0: unist-util-visit-parents "^6.0.0" mdast-util-from-markdown@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.0.tgz#52f14815ec291ed061f2922fd14d6689c810cb88" - integrity sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA== + version "2.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.1.tgz#32a6e8f512b416e1f51eb817fc64bd867ebcd9cc" + integrity sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA== dependencies: "@types/mdast" "^4.0.0" "@types/unist" "^3.0.0" @@ -8212,9 +7065,9 @@ mdast-util-from-markdown@^2.0.0: unist-util-stringify-position "^4.0.0" mdast-util-gfm-autolink-literal@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.0.tgz#5baf35407421310a08e68c15e5d8821e8898ba2a" - integrity sha512-FyzMsduZZHSc3i0Px3PQcBT4WJY/X/RCtEJKuybiC6sjPqLv7h1yqAkmILZtuxMSsUyaLUWNp71+vQH2zqp5cg== + version "2.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz#abd557630337bd30a6d5a4bd8252e1c2dc0875d5" + integrity sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ== dependencies: "@types/mdast" "^4.0.0" ccount "^2.0.0" @@ -8315,25 +7168,6 @@ 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== -mem@^4.0.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" - integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w== - dependencies: - map-age-cleaner "^0.1.1" - mimic-fn "^2.0.0" - p-is-promise "^2.0.0" - -memfs@^4.9.3: - version "4.9.4" - resolved "https://registry.yarnpkg.com/memfs/-/memfs-4.9.4.tgz#803eb7f2091d1c6198ec9ba9b582505ad8699c9e" - integrity sha512-Xlj8b2rU11nM6+KU6wC7cuWcHQhVINWCUgdPS4Ar9nPxLaOya3RghqK7ALyDW2QtGebYAYs6uEdEVnwPVT942A== - dependencies: - "@jsonjoy.com/json-pack" "^1.0.3" - "@jsonjoy.com/util" "^1.1.2" - tree-dump "^1.0.1" - tslib "^2.0.0" - memoize-one@^5.0.0, memoize-one@^5.1.1: version "5.2.1" resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" @@ -8346,10 +7180,10 @@ memoizerific@^1.11.3: dependencies: map-or-similar "^1.5.0" -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== +merge-descriptors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" + integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== merge-stream@^2.0.0: version "2.0.0" @@ -8367,9 +7201,9 @@ methods@~1.1.2: integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== micromark-core-commonmark@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-2.0.0.tgz#50740201f0ee78c12a675bf3e68ffebc0bf931a3" - integrity sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz#9a45510557d068605c6e9a80f282b2bb8581e43d" + integrity sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA== dependencies: decode-named-character-reference "^1.0.0" devlop "^1.0.0" @@ -8389,9 +7223,9 @@ micromark-core-commonmark@^2.0.0: micromark-util-types "^2.0.0" micromark-extension-gfm-autolink-literal@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.0.0.tgz#f1e50b42e67d441528f39a67133eddde2bbabfd9" - integrity sha512-rTHfnpt/Q7dEAK1Y5ii0W8bhfJlVJFnJMHIPisfPK3gpVNuOP0VnRl96+YJ3RYWV/P4gFeQoGKNlT3RhuvpqAg== + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz#6286aee9686c4462c1e3552a9d505feddceeb935" + integrity sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw== dependencies: micromark-util-character "^2.0.0" micromark-util-sanitize-uri "^2.0.0" @@ -8399,9 +7233,9 @@ micromark-extension-gfm-autolink-literal@^2.0.0: micromark-util-types "^2.0.0" micromark-extension-gfm-footnote@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.0.0.tgz#91afad310065a94b636ab1e9dab2c60d1aab953c" - integrity sha512-6Rzu0CYRKDv3BfLAUnZsSlzx3ak6HAoI85KTiijuKIz5UxZxbUI+pD6oHgw+6UtQuiRwnGRhzMmPRv4smcz0fg== + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz#4dab56d4e398b9853f6fe4efac4fc9361f3e0750" + integrity sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw== dependencies: devlop "^1.0.0" micromark-core-commonmark "^2.0.0" @@ -8413,9 +7247,9 @@ micromark-extension-gfm-footnote@^2.0.0: micromark-util-types "^2.0.0" micromark-extension-gfm-strikethrough@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.0.0.tgz#6917db8e320da70e39ffbf97abdbff83e6783e61" - integrity sha512-c3BR1ClMp5fxxmwP6AoOY2fXO9U8uFMKs4ADD66ahLTNcwzSCyRVU4k7LPV5Nxo/VJiR4TdzxRQY2v3qIUceCw== + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz#86106df8b3a692b5f6a92280d3879be6be46d923" + integrity sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw== dependencies: devlop "^1.0.0" micromark-util-chunked "^2.0.0" @@ -8425,9 +7259,9 @@ micromark-extension-gfm-strikethrough@^2.0.0: micromark-util-types "^2.0.0" micromark-extension-gfm-table@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.0.0.tgz#2cf3fe352d9e089b7ef5fff003bdfe0da29649b7" - integrity sha512-PoHlhypg1ItIucOaHmKE8fbin3vTLpDOUg8KAr8gRCF1MOZI9Nquq2i/44wFvviM4WuxJzc3demT8Y3dkfvYrw== + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.0.tgz#5cadedfbb29fca7abf752447967003dc3b6583c9" + integrity sha512-Ub2ncQv+fwD70/l4ou27b4YzfNaCJOvyX4HxXU15m7mpYY+rjuWzsLIPZHJL253Z643RpbcP1oeIJlQ/SKW67g== dependencies: devlop "^1.0.0" micromark-factory-space "^2.0.0" @@ -8443,9 +7277,9 @@ micromark-extension-gfm-tagfilter@^2.0.0: micromark-util-types "^2.0.0" micromark-extension-gfm-task-list-item@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.0.1.tgz#ee8b208f1ced1eb9fb11c19a23666e59d86d4838" - integrity sha512-cY5PzGcnULaN5O7T+cOzfMoHjBW7j+T9D2sucA5d/KbsBTPcYdebm9zUd9zzdgJGCwahV+/W78Z3nbulBYVbTw== + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz#bcc34d805639829990ec175c3eea12bb5b781f2c" + integrity sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw== dependencies: devlop "^1.0.0" micromark-factory-space "^2.0.0" @@ -8597,9 +7431,9 @@ micromark-util-sanitize-uri@^2.0.0: micromark-util-symbol "^2.0.0" micromark-util-subtokenize@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.0.tgz#9f412442d77e0c5789ffdf42377fa8a2bcbdf581" - integrity sha512-vc93L1t+gpR3p8jxeVdaYlbV2jTYteDje19rNSS/H5dlhxUYll5Fy6vJ2cDwP8RnsXi818yGty1ayP55y3W6fg== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz#76129c49ac65da6e479c09d0ec4b5f29ec6eace5" + integrity sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q== dependencies: devlop "^1.0.0" micromark-util-chunked "^2.0.0" @@ -8639,15 +7473,7 @@ micromark@^4.0.0: micromark-util-symbol "^2.0.0" micromark-util-types "^2.0.0" -micromatch@^4.0.2, micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== - dependencies: - braces "^3.0.2" - picomatch "^2.3.1" - -micromatch@~4.0.7: +micromatch@^4.0.4, micromatch@~4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== @@ -8655,23 +7481,11 @@ micromatch@~4.0.7: braces "^3.0.3" picomatch "^2.3.1" -mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": +mime-db@1.52.0: version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-db@~1.33.0: - version "1.33.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" - integrity sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ== - -mime-types@2.1.18: - version "2.1.18" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" - integrity sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ== - dependencies: - mime-db "~1.33.0" - mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" @@ -8684,7 +7498,7 @@ mime@1.6.0: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -mimic-fn@^2.0.0, mimic-fn@^2.1.0: +mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== @@ -8704,38 +7518,33 @@ min-indent@^1.0.0, min-indent@^1.0.1: resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== -minimatch@3.1.2, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimatch@9.0.3, minimatch@^9.0.1, minimatch@^9.0.3: +minimatch@9.0.3: version "9.0.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== dependencies: brace-expansion "^2.0.1" -minimatch@^9.0.4: +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" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^9.0.3, minimatch@^9.0.4: version "9.0.5" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== dependencies: brace-expansion "^2.0.1" -minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6, minimist@^1.2.8: +minimist@^1.2.6, minimist@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0": - version "7.0.4" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" - integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== - -minipass@^7.1.2: +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== @@ -8778,26 +7587,21 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - ms@2.1.3, ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== msw@^2.2.3: - version "2.2.3" - resolved "https://registry.yarnpkg.com/msw/-/msw-2.2.3.tgz#d05b46d73e8832cbf2145743938635beaaafa0d7" - integrity sha512-84CoNCkcJ/EvY8Tv0tD/6HKVd4S5HyGowHjM5W12K8Wgryp4fikqS7IaTOceyQgP5dNedxo2icTLDXo7dkpxCg== + version "2.4.9" + resolved "https://registry.yarnpkg.com/msw/-/msw-2.4.9.tgz#350a84cedb90b578a32c7764431e3750900f8407" + integrity sha512-1m8xccT6ipN4PTqLinPwmzhxQREuxaEJYdx4nIbggxP8aM7r1e71vE7RtOUSQoAm1LydjGfZKy7370XD/tsuYg== dependencies: "@bundled-es-modules/cookie" "^2.0.0" "@bundled-es-modules/statuses" "^1.0.1" + "@bundled-es-modules/tough-cookie" "^0.1.6" "@inquirer/confirm" "^3.0.0" - "@mswjs/cookies" "^1.1.0" - "@mswjs/interceptors" "^0.25.16" + "@mswjs/interceptors" "^0.35.8" "@open-draft/until" "^2.1.0" "@types/cookie" "^0.6.0" "@types/statuses" "^2.0.4" @@ -8806,7 +7610,7 @@ msw@^2.2.3: headers-polyfill "^4.0.2" is-node-process "^1.2.0" outvariant "^1.4.2" - path-to-regexp "^6.2.0" + path-to-regexp "^6.3.0" strict-event-emitter "^0.5.1" type-fest "^4.9.0" yargs "^17.7.2" @@ -8875,20 +7679,10 @@ node-fetch@^1.0.1, node-fetch@^2.6.7: dependencies: whatwg-url "^5.0.0" -node-releases@^2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" - integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== - -normalize-package-data@^2.3.2: - version "2.5.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" +node-releases@^2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" @@ -8903,13 +7697,6 @@ notistack@^3.0.1: clsx "^1.1.0" goober "^2.0.33" -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw== - dependencies: - path-key "^2.0.0" - npm-run-path@^4.0.0, npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" @@ -8918,17 +7705,12 @@ npm-run-path@^4.0.0, npm-run-path@^4.0.1: path-key "^3.0.0" npm-run-path@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.2.0.tgz#224cdd22c755560253dd71b83a1ef2f758b2e955" - integrity sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg== + version "5.3.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.3.0.tgz#e23353d0ebb9317f174e93417e4a4d82d0249e9f" + integrity sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ== dependencies: path-key "^4.0.0" -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ== - nwsapi@^2.2.12: version "2.2.12" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.12.tgz#fb6af5c0ec35b27b4581eb3bbad34ec9e5c696f8" @@ -8940,24 +7722,24 @@ object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== object-inspect@^1.13.1: - version "1.13.1" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" - integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== object-is@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" - integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + version "1.1.6" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.6.tgz#1a6a53aed2dd8f7e6775ff870bea58545956ab07" + integrity sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" + call-bind "^1.0.7" + define-properties "^1.2.1" object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object.assign@^4.1.4: +object.assign@^4.1.4, object.assign@^4.1.5: version "4.1.5" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== @@ -8967,40 +7749,33 @@ object.assign@^4.1.4: has-symbols "^1.0.3" object-keys "^1.1.1" -object.entries@^1.1.6, object.entries@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.7.tgz#2b47760e2a2e3a752f39dd874655c61a7f03c131" - integrity sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - -object.fromentries@^2.0.6, object.fromentries@^2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.7.tgz#71e95f441e9a0ea6baf682ecaaf37fa2a8d7e616" - integrity sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA== +object.entries@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.8.tgz#bffe6f282e01f4d17807204a24f8edd823599c41" + integrity sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" -object.hasown@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.3.tgz#6a5f2897bb4d3668b8e79364f98ccf971bda55ae" - integrity sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA== +object.fromentries@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" + integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== dependencies: - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" -object.values@^1.1.6: - version "1.1.7" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.7.tgz#617ed13272e7e1071b43973aa1655d9291b8442a" - integrity sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng== +object.values@^1.1.6, object.values@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b" + integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" on-finished@2.4.1: version "2.4.1" @@ -9009,11 +7784,6 @@ on-finished@2.4.1: dependencies: ee-first "1.1.1" -on-headers@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" - integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== - once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -9042,13 +7812,14 @@ onetime@^7.0.0: dependencies: mimic-function "^5.0.0" -open@^7.4.2: - version "7.4.2" - resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" - integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== +open@^8.0.4: + version "8.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" + integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== dependencies: - is-docker "^2.0.0" - is-wsl "^2.1.1" + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" optionator@^0.8.3: version "0.8.3" @@ -9062,7 +7833,7 @@ optionator@^0.8.3: type-check "~0.3.2" word-wrap "~1.2.3" -optionator@^0.9.1: +optionator@^0.9.1, optionator@^0.9.3: version "0.9.4" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== @@ -9074,27 +7845,6 @@ optionator@^0.9.1: type-check "^0.4.0" word-wrap "^1.2.5" -optionator@^0.9.3: - version "0.9.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" - integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== - dependencies: - "@aashutoshrathi/word-wrap" "^1.2.3" - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - -os-locale@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" - integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== - dependencies: - execa "^1.0.0" - lcid "^2.0.0" - mem "^4.0.0" - os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -9105,27 +7855,12 @@ ospath@^1.2.2: resolved "https://registry.yarnpkg.com/ospath/-/ospath-1.2.2.tgz#1276639774a3f8ef2572f7fe4280e0ea4550c07b" integrity sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA== -outvariant@^1.2.1, outvariant@^1.4.0, outvariant@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/outvariant/-/outvariant-1.4.2.tgz#f54f19240eeb7f15b28263d5147405752d8e2066" - integrity sha512-Ou3dJ6bA/UJ5GVHxah4LnqDwZRwAmWxrG3wtrHrbGnP4RnLCtA64A4F+ae7Y8ww660JaddSoArUR5HjipWSHAQ== - -p-defer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" - integrity sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw== - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== - -p-is-promise@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" - integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== +outvariant@^1.4.0, outvariant@^1.4.2, outvariant@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/outvariant/-/outvariant-1.4.3.tgz#221c1bfc093e8fec7075497e7799fdbf43d14873" + integrity sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA== -p-limit@^2.0.0, p-limit@^2.2.0: +p-limit@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== @@ -9139,13 +7874,6 @@ p-limit@^3.0.2: dependencies: yocto-queue "^0.1.0" -p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== - dependencies: - p-limit "^2.0.0" - p-locate@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" @@ -9184,14 +7912,6 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw== - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - 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" @@ -9202,7 +7922,7 @@ parse-json@^5.0.0, parse-json@^5.2.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" -parse5@^7.0.0, parse5@^7.1.2: +parse5@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== @@ -9214,32 +7934,6 @@ parseurl@~1.3.3: resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== -patch-package@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-8.0.0.tgz#d191e2f1b6e06a4624a0116bcb88edd6714ede61" - integrity sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA== - dependencies: - "@yarnpkg/lockfile" "^1.1.0" - chalk "^4.1.2" - ci-info "^3.7.0" - cross-spawn "^7.0.3" - find-yarn-workspace-root "^2.0.0" - fs-extra "^9.0.0" - json-stable-stringify "^1.0.2" - klaw-sync "^6.0.0" - minimist "^1.2.6" - open "^7.4.2" - rimraf "^2.6.3" - semver "^7.5.3" - slash "^2.0.0" - tmp "^0.0.33" - yaml "^2.2.2" - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== - path-exists@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" @@ -9250,12 +7944,7 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -path-is-inside@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - integrity sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w== - -path-key@^2.0.0, path-key@^2.0.1: +path-key@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== @@ -9275,14 +7964,6 @@ 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-scurry@^1.10.1: - version "1.10.1" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698" - integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ== - dependencies: - lru-cache "^9.1.1 || ^10.0.0" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" - path-scurry@^1.11.1: version "1.11.1" resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" @@ -9291,46 +7972,28 @@ path-scurry@^1.11.1: lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== - -path-to-regexp@2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.2.1.tgz#90b617025a16381a879bc82a38d4e8bdeb2bcf45" - integrity sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ== +path-to-regexp@0.1.10: + version "0.1.10" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b" + integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w== 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== + version "1.9.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.9.0.tgz#5dc0753acbf8521ca2e0f137b4578b917b10cf24" + integrity sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g== dependencies: isarray "0.0.1" -path-to-regexp@^6.2.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.1.tgz#d54934d6798eb9e5ef14e7af7962c945906918e5" - integrity sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw== +path-to-regexp@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.3.0.tgz#2b6a26a337737a8e1416f9272ed0766b1c0389f4" + integrity sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ== 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== -path-unified@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/path-unified/-/path-unified-0.1.0.tgz#fd751e787ab019a88cdf5cecbd7e5e4711c66c7d" - integrity sha512-/Oaz9ZJforrkmFrwkR/AcvjVsCAwGSJHO0X6O6ISj8YeFbATjIEBXLDcZfnK3MO4uvCBrJTdVIxdOc79PMqSdg== - -path@^0.12.7: - version "0.12.7" - resolved "https://registry.yarnpkg.com/path/-/path-0.12.7.tgz#d4dc2a506c4ce2197eb481ebfcd5b36c0140b10f" - integrity sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q== - dependencies: - process "^0.11.1" - util "^0.10.3" - pathe@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec" @@ -9360,17 +8023,7 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== -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== - -picocolors@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" - integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== - -picocolors@^1.1.0: +picocolors@^1.0.0, picocolors@^1.0.1, picocolors@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== @@ -9395,11 +8048,6 @@ pify@^2.2.0: resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg== - pirates@^4.0.1: version "4.0.6" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" @@ -9419,12 +8067,10 @@ polished@^4.2.2: dependencies: "@babel/runtime" "^7.17.8" -postcss-calc-ast-parser@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/postcss-calc-ast-parser/-/postcss-calc-ast-parser-0.1.4.tgz#9aeee3650a91c0b2902789689bc044c9f83bc447" - integrity sha512-CebpbHc96zgFjGgdQ6BqBy6XIUgRx1xXWCAAk6oke02RZ5nxwo9KQejTg8y7uYEeI9kv8jKQPYjoe6REsY23vw== - dependencies: - postcss-value-parser "^3.3.1" +possible-typed-array-names@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" + integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== postcss-load-config@^6.0.1: version "6.0.1" @@ -9433,20 +8079,6 @@ postcss-load-config@^6.0.1: dependencies: lilconfig "^3.1.1" -postcss-value-parser@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" - integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== - -postcss@^8.4.35: - version "8.4.35" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.35.tgz#60997775689ce09011edf083a549cea44aabe2f7" - integrity sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA== - dependencies: - nanoid "^3.3.7" - picocolors "^1.0.0" - source-map-js "^1.0.2" - postcss@^8.4.43: version "8.4.47" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.47.tgz#5bf6c9a010f3e724c503bf03ef7947dcb0fea365" @@ -9474,9 +8106,9 @@ prettier-linter-helpers@^1.0.0: fast-diff "^1.1.2" prettier@^3.1.1: - version "3.2.5" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368" - integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A== + version "3.3.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105" + integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== prettier@~2.2.1: version "2.2.1" @@ -9497,7 +8129,7 @@ pretty-format@^27.0.2: ansi-styles "^5.0.0" react-is "^17.0.1" -process@^0.11.1, process@^0.11.10: +process@^0.11.10: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== @@ -9512,7 +8144,7 @@ promise-polyfill@8.2.3: resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-8.2.3.tgz#2edc7e4b81aff781c88a0d577e5fe9da822107c6" integrity sha512-Og0+jCRQetV84U8wVjMNccfGCnMQ9mGs9Hv78QFe+pSDD3gWTpz0y+1QCuxy5d/vBFuZ3iwP2eycAkvqIMPmWg== -promise-polyfill@^8.1.3, promise-polyfill@^8.3.0: +promise-polyfill@^8.3.0: version "8.3.0" resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-8.3.0.tgz#9284810268138d103807b11f4e23d5e945a4db63" integrity sha512-H5oELycFml5yto/atYqmjyigJoAo3+OXwolYiH7OfQuYlAqhxNvTfiNMbV9hsC6Yp83yE5r2KTVmtrG6R9i6Pg== @@ -9562,18 +8194,13 @@ psl@^1.1.33: integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + version "3.0.2" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.2.tgz#836f3edd6bc2ee599256c924ffe0d88573ddcbf8" + integrity sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw== dependencies: end-of-stream "^1.1.0" once "^1.3.1" -punycode@^1.3.2, punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== - punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" @@ -9592,31 +8219,10 @@ qrcode.react@^0.8.0: prop-types "^15.6.0" qr.js "0.0.0" -qs@6.10.4: - version "6.10.4" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.4.tgz#6a3003755add91c0ec9eacdc5f878b034e73f9e7" - integrity sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g== - dependencies: - side-channel "^1.0.4" - -qs@6.11.0: - version "6.11.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" - integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== - dependencies: - side-channel "^1.0.4" - -qs@^6.10.0: - version "6.11.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" - integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== - dependencies: - side-channel "^1.0.4" - -qs@^6.11.2: - version "6.12.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.12.1.tgz#39422111ca7cbdb70425541cba20c7d7b216599a" - integrity sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ== +qs@6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" + integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== dependencies: side-channel "^1.0.6" @@ -9647,16 +8253,6 @@ ramda@0.25.0, ramda@~0.25.0: resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.25.0.tgz#8fdf68231cffa90bc2f9460390a0cb74a29b29a9" integrity sha512-GXpfrYVPwx3K7RQ6aYT8KPS8XViSXUVJT1ONhoKPE9VAleW42YE+U+8VEyGWt41EnEQW7gwecYJriTI0pKoecQ== -ramda@0.29.0: - version "0.29.0" - resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.29.0.tgz#fbbb67a740a754c8a4cbb41e2a6e0eb8507f55fb" - integrity sha512-BBea6L67bYLtdbOqfp8f58fPMqEwx0doL+pAi8TZyp2YWz8R9G8z9x75CZI8W+ftqhFHCpEX2cRnUUXK130iKA== - -range-parser@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" - integrity sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A== - range-parser@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" @@ -9672,16 +8268,6 @@ raw-body@2.5.2: iconv-lite "0.4.24" unpipe "1.0.0" -rc@^1.0.1, rc@^1.1.6: - version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== - dependencies: - deep-extend "^0.6.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - react-beautiful-dnd@^13.0.0: version "13.1.1" resolved "https://registry.yarnpkg.com/react-beautiful-dnd/-/react-beautiful-dnd-13.1.1.tgz#b0f3087a5840920abf8bb2325f1ffa46d8c4d0a2" @@ -9700,14 +8286,6 @@ react-colorful@^5.1.2: resolved "https://registry.yarnpkg.com/react-colorful/-/react-colorful-5.6.1.tgz#7dc2aed2d7c72fac89694e834d179e32f3da563b" integrity sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw== -react-copy-to-clipboard@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz#09aae5ec4c62750ccb2e6421a58725eabc41255c" - integrity sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A== - dependencies: - copy-to-clipboard "^3.3.1" - prop-types "^15.8.1" - react-csv@^2.0.3: version "2.2.2" resolved "https://registry.yarnpkg.com/react-csv/-/react-csv-2.2.2.tgz#5bbf0d72a846412221a14880f294da9d6def9bfb" @@ -9735,21 +8313,12 @@ react-docgen@^7.0.0: strip-indent "^4.0.0" "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0", react-dom@^18.2.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" - integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== - dependencies: - loose-envify "^1.1.0" - scheduler "^0.23.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== + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" + integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== dependencies: loose-envify "^1.1.0" - object-assign "^4.1.1" - scheduler "^0.20.2" + scheduler "^0.23.2" react-dropzone@~11.2.0: version "11.2.4" @@ -9775,9 +8344,9 @@ react-fast-compare@^2.0.1: integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== react-hook-form@^7.51.0: - version "7.51.0" - resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.51.0.tgz#757ae71b37c26e00590bd3788508287dcc5ecdaf" - integrity sha512-BggOy5j58RdhdMzzRUHGOYhSz1oeylFAv6jUSG86OvCIvlAvS7KvnRY7yoAf2pfEiPN7BesnR0xx73nEk3qIiw== + version "7.53.0" + resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.53.0.tgz#3cf70951bf41fa95207b34486203ebefbd3a05ab" + integrity sha512-M1n3HhqCww6S2hxLxciEXy2oISPnAzxY7gvwVPrtlczTM/1dDadXgUxDpHMrMTblDOcm/AXtXxHwZ3jpg1mqKQ== react-input-autosize@^2.2.2: version "2.2.2" @@ -9791,7 +8360,7 @@ react-is@18.1.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.1.0.tgz#61aaed3096d30eacf2a2127118b5b41387d32a67" integrity sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg== -react-is@^16.10.2, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.6, react-is@^16.9.0: +react-is@^16.10.2, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.9.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== @@ -9801,14 +8370,9 @@ react-is@^17.0.1, react-is@^17.0.2: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -"react-is@^17.0.1 || ^18.0.0", react-is@^18.2.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" - integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== - -react-is@^18.3.1: +"react-is@^17.0.1 || ^18.0.0", react-is@^18.3.1: version "18.3.1" - resolved "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== react-lifecycles-compat@^3.0.2: @@ -9897,24 +8461,14 @@ react-select@~3.1.0: react-transition-group "^4.3.0" react-smooth@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/react-smooth/-/react-smooth-4.0.0.tgz#69e560ab69b69a066187d70cb92c1a664f7f046a" - integrity sha512-2NMXOBY1uVUQx1jBeENGA497HK20y6CPGYL1ZnJLeoQ8rrc3UfmOM82sRxtzpcoCkUMy4CS0RGylfuVhuFjBgg== + version "4.0.1" + resolved "https://registry.yarnpkg.com/react-smooth/-/react-smooth-4.0.1.tgz#6200d8699bfe051ae40ba187988323b1449eab1a" + integrity sha512-OE4hm7XqR0jNOq3Qmk9mFLyd6p2+j6bvbPJ7qlB7+oo0eNcL2l7WQzG6MBnT3EXY6xzkLMUBec3AfewJdA0J8w== dependencies: fast-equals "^5.0.1" prop-types "^15.8.1" react-transition-group "^4.4.5" -react-test-renderer@16.14.0: - version "16.14.0" - resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.14.0.tgz#e98360087348e260c56d4fe2315e970480c228ae" - integrity sha512-L8yPjqPE5CZO6rKsKXRO/rVPiaCOy0tQQJbC+UjPNlobl5mad59lvPjwFsQHTvL03caVDIVr9x9/OSgDe6I5Eg== - dependencies: - object-assign "^4.1.1" - prop-types "^15.6.2" - react-is "^16.8.6" - scheduler "^0.19.1" - react-transition-group@^4.3.0, react-transition-group@^4.4.5: version "4.4.5" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1" @@ -9941,28 +8495,11 @@ react-waypoint@^10.3.0: react-is "^17.0.1 || ^18.0.0" "react@^16.8.0 || ^17.0.0 || ^18.0.0", react@^18.2.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" - integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== - dependencies: - loose-envify "^1.1.0" - -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== + version "18.3.1" + resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" + integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== dependencies: loose-envify "^1.1.0" - object-assign "^4.1.1" - -read-pkg@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-4.0.1.tgz#963625378f3e1c4d48c85872b5a6ec7d5d093237" - integrity sha512-+UBirHHDm5J+3WDmLBZYSklRYg82nMlz+enn+GMZ22nSR2f4bzxmhso6rzQW/3mT2PVzpzDTiYIZahk8UmZ44w== - dependencies: - normalize-package-data "^2.3.2" - parse-json "^4.0.0" - pify "^3.0.0" readdirp@~3.6.0: version "3.6.0" @@ -9972,9 +8509,9 @@ readdirp@~3.6.0: picomatch "^2.2.1" recast@^0.23.5: - version "0.23.6" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.23.6.tgz#198fba74f66143a30acc81929302d214ce4e3bfa" - integrity sha512-9FHoNjX1yjuesMwuthAmPKabxYQdOgihFYmT5ebXfYGBcnqXZf3WOVz+5foEZ8Y83P4ZY6yQD5GMmtV+pgCCAQ== + version "0.23.9" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.23.9.tgz#587c5d3a77c2cfcb0c18ccce6da4361528c2587b" + integrity sha512-Hx/BGIbwj+Des3+xy5uAtAbdCyqK9y9wbBcDFDYanLS9JnMqf7OeF87HQwUimE87OEc72mr6tkKUKMBBL+hF9Q== dependencies: ast-types "^0.16.1" esprima "~4.0.0" @@ -9990,13 +8527,13 @@ recharts-scale@^0.4.4: decimal.js-light "^2.4.1" recharts@^2.9.3: - version "2.12.0" - resolved "https://registry.yarnpkg.com/recharts/-/recharts-2.12.0.tgz#e731e2733359d7942d5807c34c70f67673096d25" - integrity sha512-rVNcdNQ5b7+40Ue7mcEKZJyEv+3SUk2bDEVvOyXPDXXVE7TU3lrvnJUgAvO36hSzhRP2DnAamKXvHLFIFOU0Ww== + version "2.12.7" + resolved "https://registry.yarnpkg.com/recharts/-/recharts-2.12.7.tgz#c7f42f473a257ff88b43d88a92530930b5f9e773" + integrity sha512-hlLJMhPQfv4/3NBSAyq3gzGg4h2v69RJh6KU7b3pXYNNAELs9kEoXOjbkxdXpALqKBoVmVptGfLpxdaVYqjmXQ== dependencies: clsx "^2.0.0" eventemitter3 "^4.0.1" - lodash "^4.17.19" + lodash "^4.17.21" react-is "^16.10.2" react-smooth "^4.0.0" recharts-scale "^0.4.4" @@ -10043,15 +8580,15 @@ redux@^4.0.0, redux@^4.0.4, redux@^4.0.5: "@babel/runtime" "^7.9.2" reflect.getprototypeof@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.5.tgz#e0bd28b597518f16edaf9c0e292c631eb13e0674" - integrity sha512-62wgfC8dJWrmxv44CA36pLDnP6KKl3Vhxb7PL+8+qrrFMMoJij4vgiMP8zV4O8+CBMXY1mHxI5fITGHXFHVmQQ== + version "1.0.6" + resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz#3ab04c32a8390b770712b7a8633972702d278859" + integrity sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg== dependencies: - call-bind "^1.0.5" + call-bind "^1.0.7" define-properties "^1.2.1" - es-abstract "^1.22.3" - es-errors "^1.0.0" - get-intrinsic "^1.2.3" + es-abstract "^1.23.1" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" globalthis "^1.0.3" which-builtin-type "^1.1.3" @@ -10065,40 +8602,26 @@ regenerator-runtime@^0.14.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== -regexp.prototype.flags@^1.5.0, regexp.prototype.flags@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz#90ce989138db209f81492edd734183ce99f9677e" - integrity sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg== +regexp.prototype.flags@^1.5.1, regexp.prototype.flags@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" + integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - set-function-name "^2.0.0" + call-bind "^1.0.6" + define-properties "^1.2.1" + es-errors "^1.3.0" + set-function-name "^2.0.1" regexpp@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== -regexpp@^3.0.0, regexpp@^3.1.0: +regexpp@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== -registry-auth-token@3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20" - integrity sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ== - dependencies: - rc "^1.1.6" - safe-buffer "^5.0.1" - -registry-url@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" - integrity sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA== - dependencies: - rc "^1.0.1" - rehype-external-links@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/rehype-external-links/-/rehype-external-links-3.0.0.tgz#2b28b5cda1932f83f045b6f80a3e1b15f168c6f6" @@ -10175,16 +8698,6 @@ require-from-string@^2.0.2: resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== -require-main-filename@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" - integrity sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug== - -requireindex@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/requireindex/-/requireindex-1.2.0.tgz#3463cdb22ee151902635aa6c9535d4de9c2ef1ef" - integrity sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww== - requireindex@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/requireindex/-/requireindex-1.1.0.tgz#e5404b81557ef75db6e49c5a72004893fe03e162" @@ -10195,18 +8708,6 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== -reselect-tools@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/reselect-tools/-/reselect-tools-0.0.7.tgz#bff19df422ebebd1a7c322262db94a554f6b44ed" - integrity sha512-+RGguS8ph21y04l6YwQwL+VfJ/c0qyZKCkhCd5ZwbNJ/lklsJml3CIim+uaG/t+7jYZQcwDW4bk5+VzTeuzwtw== - dependencies: - reselect "4.0.0" - -reselect@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.0.0.tgz#f2529830e5d3d0e021408b246a206ef4ea4437f7" - integrity sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA== - reselect@^4.0.0: version "4.1.8" resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.8.tgz#3f5dc671ea168dccdeb3e141236f69f02eaec524" @@ -10227,7 +8728,12 @@ resolve-pathname@^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@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.19.0, resolve@^1.22.1, resolve@^1.22.8: +resolve-pkg-maps@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" + integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== + +resolve@^1.12.0, resolve@^1.19.0, resolve@^1.22.1, resolve@^1.22.8: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -10236,7 +8742,7 @@ resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.19.0, resolve@^1.2 path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@^2.0.0-next.4: +resolve@^2.0.0-next.5: version "2.0.0-next.5" resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c" integrity sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA== @@ -10273,12 +8779,7 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rfdc@^1.3.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.1.tgz#2b6d4df52dffe8bb346992a10ea9451f24373a8f" - integrity sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg== - -rfdc@^1.4.1: +rfdc@^1.3.0, rfdc@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.4.1.tgz#778f76c4fb731d93414e8f925fbecf64cce7f6ca" integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== @@ -10295,97 +8796,38 @@ rimraf@2.6.3: dependencies: glob "^7.1.3" -rimraf@^2.6.3: - version "2.7.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== - dependencies: - glob "^7.1.3" - -rimraf@^3.0.0, rimraf@^3.0.2: +rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: glob "^7.1.3" -rollup@^4.19.0: - version "4.21.0" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.21.0.tgz#28db5f5c556a5180361d35009979ccc749560b9d" - integrity sha512-vo+S/lfA2lMS7rZ2Qoubi6I5hwZwzXeUIctILZLbHI+laNtvhhOIon2S1JksA5UEDQ7l3vberd0fxK44lTYjbQ== - dependencies: - "@types/estree" "1.0.5" - optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.21.0" - "@rollup/rollup-android-arm64" "4.21.0" - "@rollup/rollup-darwin-arm64" "4.21.0" - "@rollup/rollup-darwin-x64" "4.21.0" - "@rollup/rollup-linux-arm-gnueabihf" "4.21.0" - "@rollup/rollup-linux-arm-musleabihf" "4.21.0" - "@rollup/rollup-linux-arm64-gnu" "4.21.0" - "@rollup/rollup-linux-arm64-musl" "4.21.0" - "@rollup/rollup-linux-powerpc64le-gnu" "4.21.0" - "@rollup/rollup-linux-riscv64-gnu" "4.21.0" - "@rollup/rollup-linux-s390x-gnu" "4.21.0" - "@rollup/rollup-linux-x64-gnu" "4.21.0" - "@rollup/rollup-linux-x64-musl" "4.21.0" - "@rollup/rollup-win32-arm64-msvc" "4.21.0" - "@rollup/rollup-win32-ia32-msvc" "4.21.0" - "@rollup/rollup-win32-x64-msvc" "4.21.0" - fsevents "~2.3.2" - -rollup@^4.2.0: - version "4.9.6" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.9.6.tgz#4515facb0318ecca254a2ee1315e22e09efc50a0" - integrity sha512-05lzkCS2uASX0CiLFybYfVkwNbKZG5NFQ6Go0VWyogFTXXbR039UVsegViTntkk4OglHBdF54ccApXRRuXRbsg== - dependencies: - "@types/estree" "1.0.5" - optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.9.6" - "@rollup/rollup-android-arm64" "4.9.6" - "@rollup/rollup-darwin-arm64" "4.9.6" - "@rollup/rollup-darwin-x64" "4.9.6" - "@rollup/rollup-linux-arm-gnueabihf" "4.9.6" - "@rollup/rollup-linux-arm64-gnu" "4.9.6" - "@rollup/rollup-linux-arm64-musl" "4.9.6" - "@rollup/rollup-linux-riscv64-gnu" "4.9.6" - "@rollup/rollup-linux-x64-gnu" "4.9.6" - "@rollup/rollup-linux-x64-musl" "4.9.6" - "@rollup/rollup-win32-arm64-msvc" "4.9.6" - "@rollup/rollup-win32-ia32-msvc" "4.9.6" - "@rollup/rollup-win32-x64-msvc" "4.9.6" - fsevents "~2.3.2" - -rollup@^4.20.0: - version "4.21.1" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.21.1.tgz#65b9b9e9de9a64604fab083fb127f3e9eac2935d" - integrity sha512-ZnYyKvscThhgd3M5+Qt3pmhO4jIRR5RGzaSovB6Q7rGNrK5cUncrtLmcTTJVSdcKXyZjW8X8MB0JMSuH9bcAJg== +rollup@^4.19.0, rollup@^4.20.0: + version "4.22.4" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.22.4.tgz#4135a6446671cd2a2453e1ad42a45d5973ec3a0f" + integrity sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A== dependencies: "@types/estree" "1.0.5" optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.21.1" - "@rollup/rollup-android-arm64" "4.21.1" - "@rollup/rollup-darwin-arm64" "4.21.1" - "@rollup/rollup-darwin-x64" "4.21.1" - "@rollup/rollup-linux-arm-gnueabihf" "4.21.1" - "@rollup/rollup-linux-arm-musleabihf" "4.21.1" - "@rollup/rollup-linux-arm64-gnu" "4.21.1" - "@rollup/rollup-linux-arm64-musl" "4.21.1" - "@rollup/rollup-linux-powerpc64le-gnu" "4.21.1" - "@rollup/rollup-linux-riscv64-gnu" "4.21.1" - "@rollup/rollup-linux-s390x-gnu" "4.21.1" - "@rollup/rollup-linux-x64-gnu" "4.21.1" - "@rollup/rollup-linux-x64-musl" "4.21.1" - "@rollup/rollup-win32-arm64-msvc" "4.21.1" - "@rollup/rollup-win32-ia32-msvc" "4.21.1" - "@rollup/rollup-win32-x64-msvc" "4.21.1" + "@rollup/rollup-android-arm-eabi" "4.22.4" + "@rollup/rollup-android-arm64" "4.22.4" + "@rollup/rollup-darwin-arm64" "4.22.4" + "@rollup/rollup-darwin-x64" "4.22.4" + "@rollup/rollup-linux-arm-gnueabihf" "4.22.4" + "@rollup/rollup-linux-arm-musleabihf" "4.22.4" + "@rollup/rollup-linux-arm64-gnu" "4.22.4" + "@rollup/rollup-linux-arm64-musl" "4.22.4" + "@rollup/rollup-linux-powerpc64le-gnu" "4.22.4" + "@rollup/rollup-linux-riscv64-gnu" "4.22.4" + "@rollup/rollup-linux-s390x-gnu" "4.22.4" + "@rollup/rollup-linux-x64-gnu" "4.22.4" + "@rollup/rollup-linux-x64-musl" "4.22.4" + "@rollup/rollup-win32-arm64-msvc" "4.22.4" + "@rollup/rollup-win32-ia32-msvc" "4.22.4" + "@rollup/rollup-win32-x64-msvc" "4.22.4" fsevents "~2.3.2" -rrweb-cssom@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz#ed298055b97cbddcdeb278f904857629dec5e0e1" - integrity sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw== - rrweb-cssom@^0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz#c73451a484b86dd7cfb1e0b2898df4b703183e4b" @@ -10396,11 +8838,6 @@ run-async@^2.4.0: resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== -run-async@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-3.0.0.tgz#42a432f6d76c689522058984384df28be379daad" - integrity sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q== - run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -10408,41 +8845,36 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rxjs@^6.5.2, rxjs@^6.6.0: +rxjs@^6.6.0: version "6.6.7" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== dependencies: tslib "^1.9.0" -rxjs@^7.5.1: +rxjs@^7.5.1, rxjs@^7.8.1: version "7.8.1" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== dependencies: tslib "^2.1.0" -safe-array-concat@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.0.tgz#8d0cae9cb806d6d1c06e08ab13d847293ebe0692" - integrity sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg== +safe-array-concat@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" + integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== dependencies: - call-bind "^1.0.5" - get-intrinsic "^1.2.2" + call-bind "^1.0.7" + get-intrinsic "^1.2.4" has-symbols "^1.0.3" isarray "^2.0.5" -safe-buffer@5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.2: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -safe-regex-test@^1.0.0: +safe-regex-test@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== @@ -10457,9 +8889,9 @@ safe-regex-test@^1.0.0: integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== sax@>=0.6.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.3.0.tgz#a5dbe77db3be05c9d1ee7785dbd3ea9de51593d0" - integrity sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA== + version "1.4.1" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f" + integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg== saxes@^6.0.0: version "6.0.0" @@ -10476,26 +8908,10 @@ scheduler@^0.18.0: loose-envify "^1.1.0" object-assign "^4.1.1" -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" - -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" - -scheduler@^0.23.0: - version "0.23.0" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" - integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw== +scheduler@^0.23.2: + version "0.23.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" + integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== dependencies: loose-envify "^1.1.0" @@ -10504,15 +8920,15 @@ search-string@^3.1.0: resolved "https://registry.yarnpkg.com/search-string/-/search-string-3.1.0.tgz#3f111c6919a33de33a8e304fd5f8395c3d806ffb" integrity sha512-yY3b0VlaXfKi2B//34PN5AFF+GQvwme6Kj4FjggmoSBOa7B8AHfS1nYZbsrYu+IyGeYOAkF8ywL9LN9dkrOo6g== -"semver@2 || 3 || 4 || 5", semver@7.6.0, semver@^5.5.0, semver@^6.0.0, semver@^6.1.0, semver@^6.1.2, semver@^6.3.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.7, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.6.2: +semver@7.6.0, semver@^5.5.0, semver@^6.0.0, semver@^6.1.2, semver@^6.3.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.7, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.6.2: version "7.6.3" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== -send@0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" - integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== +send@0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" + integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== dependencies: debug "2.6.9" depd "2.0.0" @@ -10528,63 +8944,15 @@ send@0.18.0: range-parser "~1.2.1" statuses "2.0.1" -serve-handler@6.1.5: - version "6.1.5" - resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.5.tgz#a4a0964f5c55c7e37a02a633232b6f0d6f068375" - integrity sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg== - dependencies: - bytes "3.0.0" - content-disposition "0.5.2" - fast-url-parser "1.1.3" - mime-types "2.1.18" - minimatch "3.1.2" - path-is-inside "1.0.2" - path-to-regexp "2.2.1" - range-parser "1.2.0" - -serve-static@1.15.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" - integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== +serve-static@1.16.2: + version "1.16.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" + integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== dependencies: - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" parseurl "~1.3.3" - send "0.18.0" - -serve@^14.0.1: - version "14.2.1" - resolved "https://registry.yarnpkg.com/serve/-/serve-14.2.1.tgz#3f078d292ed5e7b2c5a64f957af2765b0459798b" - integrity sha512-48er5fzHh7GCShLnNyPBRPEjs2I6QBozeGr02gaacROiyS/8ARADlj595j39iZXAqBbJHH/ivJJyPRWY9sQWZA== - dependencies: - "@zeit/schemas" "2.29.0" - ajv "8.11.0" - arg "5.0.2" - boxen "7.0.0" - chalk "5.0.1" - chalk-template "0.4.0" - clipboardy "3.0.0" - compression "1.7.4" - is-port-reachable "4.0.0" - serve-handler "6.1.5" - update-check "1.5.4" - -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== - -set-function-length@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.1.tgz#47cc5945f2c771e2cf261c6737cf9684a2a5e425" - integrity sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g== - dependencies: - define-data-property "^1.1.2" - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.3" - gopd "^1.0.1" - has-property-descriptors "^1.0.1" + send "0.19.0" set-function-length@^1.2.1: version "1.2.2" @@ -10598,14 +8966,15 @@ set-function-length@^1.2.1: gopd "^1.0.1" has-property-descriptors "^1.0.2" -set-function-name@^2.0.0, set-function-name@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.1.tgz#12ce38b7954310b9f61faa12701620a0c882793a" - integrity sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA== +set-function-name@^2.0.1, set-function-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== dependencies: - define-data-property "^1.0.1" + define-data-property "^1.1.4" + es-errors "^1.3.0" functions-have-names "^1.2.3" - has-property-descriptors "^1.0.0" + has-property-descriptors "^1.0.2" setimmediate@^1.0.5: version "1.0.5" @@ -10648,17 +9017,12 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -side-channel@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.5.tgz#9a84546599b48909fb6af1211708d23b1946221b" - integrity sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ== - dependencies: - call-bind "^1.0.6" - es-errors "^1.3.0" - get-intrinsic "^1.2.4" - object-inspect "^1.13.1" +shell-quote@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" + integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== -side-channel@^1.0.6: +side-channel@^1.0.4, side-channel@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== @@ -10673,7 +9037,7 @@ siginfo@^2.0.0: resolved "https://registry.yarnpkg.com/siginfo/-/siginfo-2.0.0.tgz#32e76c70b79724e3bb567cb9d543eb858ccfaf30" integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g== -signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: +signal-exit@^3.0.2, signal-exit@^3.0.3: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -10684,13 +9048,13 @@ signal-exit@^4.0.1, signal-exit@^4.1.0: integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== simple-git@^3.19.0: - version "3.22.0" - resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-3.22.0.tgz#616d41c661e30f9c65778956317d422b1729a242" - integrity sha512-6JujwSs0ac82jkGjMHiCnTifvf1crOiY/+tfs/Pqih6iow7VrpNKRRNdWm6RtaXpvvv/JGNYhlUtLhGFqHF+Yw== + version "3.27.0" + resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-3.27.0.tgz#f4b09e807bda56a4a3968f635c0e4888d3decbd5" + integrity sha512-ivHoFS9Yi9GY49ogc6/YAi3Fl9ROnF4VyubNylgCkA+RVqLaKWnDSzXOVzya8csELIaWaYNutsEuAhZrtOjozA== dependencies: "@kwsites/file-exists" "^1.1.1" "@kwsites/promise-deferred" "^1.1.1" - debug "^4.3.4" + debug "^4.3.5" sirv@^2.0.4: version "2.0.4" @@ -10701,11 +9065,6 @@ sirv@^2.0.4: mrmime "^2.0.0" totalist "^3.0.0" -slash@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" - integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== - slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" @@ -10767,17 +9126,7 @@ source-map-generator@0.8.0: resolved "https://registry.yarnpkg.com/source-map-generator/-/source-map-generator-0.8.0.tgz#10d5ca0651e2c9302ea338739cbd4408849c5d00" integrity sha512-psgxdGMwl5MZM9S3FWee4EgsEaIjahYV5AzGnwUvPhWeITz/j6rKpysQHlQ4USdxvINlb8lKfWGIXwfkrgtqkA== -source-map-js@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" - integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== - -source-map-js@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" - integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== - -source-map-js@^1.2.1: +source-map-js@^1.2.0, source-map-js@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== @@ -10812,43 +9161,12 @@ space-separated-tokens@^2.0.0: resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz#1ecd9d2350a3844572c3f4a312bceb018348859f" integrity sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q== -spawn-command@^0.0.2-1: - version "0.0.2-1" - resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2-1.tgz#62f5e9466981c1b796dc5929937e11c9c6921bd0" - integrity sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg== - -spdx-correct@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" - integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.4.0.tgz#c07a4ede25b16e4f78e6707bbd84b15a45c19c1b" - integrity sha512-hcjppoJ68fhxA/cjbN4T8N6uCUejN8yFw69ttpqtBeCbF3u13n7mb31NB9jKwGTTWWnt9IbRA/mf1FprYS8wfw== - -spdx-expression-parse@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" - integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.17" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz#887da8aa73218e51a1d917502d79863161a93f9c" - integrity sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg== - sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== -sshpk@^1.14.1: +sshpk@^1.18.0: version "1.18.0" resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.18.0.tgz#1663e55cddf4d688b86a46b77f0d5fe363aba028" integrity sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ== @@ -10883,12 +9201,14 @@ std-env@^3.7.0: resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.7.0.tgz#c9f7386ced6ecf13360b6c6c55b8aaa4ef7481d2" integrity sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg== -store2@^2.14.2: - version "2.14.2" - resolved "https://registry.yarnpkg.com/store2/-/store2-2.14.2.tgz#56138d200f9fe5f582ad63bc2704dbc0e4a45068" - integrity sha512-siT1RiqlfQnGqgT/YzXVUNsom9S0H1OX+dpdGN1xkyYATo4I6sep5NmsRD/40s3IIOvlCq6akxkqG82urIZW1w== +stop-iteration-iterator@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz#6a60be0b4ee757d1ed5254858ec66b10c49285e4" + integrity sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ== + dependencies: + internal-slot "^1.0.4" -storybook-dark-mode@^4.0.1: +storybook-dark-mode@4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/storybook-dark-mode/-/storybook-dark-mode-4.0.1.tgz#899cedb527f43aec1a1a782b767ba2ac32a113da" integrity sha512-9l3qY8NdgwZnY+NlO1XHB3eUb6FmZo9GazJeUSeFkjRqwA5FmnMSeq0YVqEOqfwniM/TvQwOiTYd5g/hC2wugA== @@ -10903,18 +9223,11 @@ storybook-dark-mode@^4.0.1: memoizerific "^1.11.3" storybook@^8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/storybook/-/storybook-8.3.0.tgz#172a5d5e415b83bcb08a3a670a2e6f34383dfea1" - integrity sha512-XKU+nem9OKX/juvJPwka1Q7DTpSbOe0IMp8ZyLQWorhFKpquJdUjryl7Z9GiFZyyTykCqH4ItQ7h8PaOmqVMOw== - dependencies: - "@storybook/core" "8.3.0" - -stream@^0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/stream/-/stream-0.0.3.tgz#3f3934a900a561ce3e2b9ffbd2819cead32699d9" - integrity sha512-aMsbn7VKrl4A2T7QAQQbzgN7NVc70vgF5INQrBXqn4dCXN1zy3L9HGgLO5s7PExmdrzTJ8uR/27aviW8or8/+A== + version "8.3.3" + resolved "https://registry.yarnpkg.com/storybook/-/storybook-8.3.3.tgz#3de9be589815403539660653d2ec810348e7dafb" + integrity sha512-FG2KAVQN54T9R6voudiEftehtkXtLO+YVGP2gBPfacEdDQjY++ld7kTbHzpTT/bpCDx7Yq3dqOegLm9arVJfYw== dependencies: - component-emitter "^2.0.0" + "@storybook/core" "8.3.3" strict-event-emitter@^0.5.1: version "0.5.1" @@ -10926,22 +9239,14 @@ string-argv@~0.3.2: resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw== - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -string-width@^2.0.0, string-width@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" string-width@^3.0.0: version "3.1.0" @@ -10952,15 +9257,6 @@ string-width@^3.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" @@ -10979,68 +9275,74 @@ string-width@^7.0.0: get-east-asian-width "^1.0.0" strip-ansi "^7.1.0" -string.prototype.matchall@^4.0.8: - version "4.0.10" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz#a1553eb532221d4180c51581d6072cd65d1ee100" - integrity sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ== +string.prototype.includes@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string.prototype.includes/-/string.prototype.includes-2.0.0.tgz#8986d57aee66d5460c144620a6d873778ad7289f" + integrity sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" - has-symbols "^1.0.3" - internal-slot "^1.0.5" - regexp.prototype.flags "^1.5.0" - set-function-name "^2.0.0" - side-channel "^1.0.4" + define-properties "^1.1.3" + es-abstract "^1.17.5" -string.prototype.trim@^1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz#f9ac6f8af4bd55ddfa8895e6aea92a96395393bd" - integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== +string.prototype.matchall@^4.0.11: + version "4.0.11" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz#1092a72c59268d2abaad76582dccc687c0297e0a" + integrity sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-symbols "^1.0.3" + internal-slot "^1.0.7" + regexp.prototype.flags "^1.5.2" + set-function-name "^2.0.2" + side-channel "^1.0.6" -string.prototype.trimend@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz#1bb3afc5008661d73e2dc015cd4853732d6c471e" - integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA== +string.prototype.repeat@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz#e90872ee0308b29435aa26275f6e1b762daee01a" + integrity sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + define-properties "^1.1.3" + es-abstract "^1.17.5" -string.prototype.trimstart@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz#d4cdb44b83a4737ffbac2d406e405d43d0184298" - integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== +string.prototype.trim@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" + integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.0" + es-object-atoms "^1.0.0" -string_decoder@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== +string.prototype.trimend@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" + integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== dependencies: - safe-buffer "~5.2.0" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg== +string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== dependencies: - ansi-regex "^2.0.0" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow== +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: - ansi-regex "^3.0.0" + ansi-regex "^5.0.1" strip-ansi@^5.1.0, strip-ansi@^5.2.0: version "5.2.0" @@ -11049,13 +9351,6 @@ strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.0.1, strip-ansi@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -11068,11 +9363,6 @@ strip-bom@^3.0.0: resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q== - strip-final-newline@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" @@ -11102,29 +9392,6 @@ strip-json-comments@^3.0.1, strip-json-comments@^3.1.0, strip-json-comments@^3.1 resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== - -style-dictionary@4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/style-dictionary/-/style-dictionary-4.0.1.tgz#d8347d18874e7dff3f4a6faed0ddcb30c797cff0" - integrity sha512-aZ2iouI0i0DIXk3QhCkwOeo5rQeuk5Ja0PhHo32/EXCNuay4jK4CZ+hQJW0Er0J74VWniR+qaeoWgjklcULxOQ== - dependencies: - "@bundled-es-modules/deepmerge" "^4.3.1" - "@bundled-es-modules/glob" "^10.4.2" - "@bundled-es-modules/memfs" "^4.9.4" - "@zip.js/zip.js" "^2.7.44" - chalk "^5.3.0" - change-case "^5.3.0" - commander "^8.3.0" - is-plain-obj "^4.1.0" - json5 "^2.2.2" - patch-package "^8.0.0" - path-unified "^0.1.0" - tinycolor2 "^1.6.0" - stylis@4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51" @@ -11143,13 +9410,6 @@ sucrase@^3.35.0: pirates "^4.0.1" ts-interface-checker "^0.1.9" -supports-color@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b" - integrity sha512-ycQR/UbvI9xIlEdQT1TQqwoXtEldExbCEAJgRo5YXlmSKjv6ThHnP9/vwGa1gr19Gfw+LkFd7KqYMhzrRC5JYw== - dependencies: - has-flag "^2.0.0" - supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -11259,11 +9519,6 @@ thenify-all@^1.0.0: dependencies: any-promise "^1.0.0" -thingies@^1.20.0: - version "1.21.0" - resolved "https://registry.yarnpkg.com/thingies/-/thingies-1.21.0.tgz#e80fbe58fd6fdaaab8fad9b67bd0a5c943c445c1" - integrity sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g== - throttle-debounce@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-2.3.0.tgz#fd31865e66502071e411817e241465b3e9c372e2" @@ -11274,17 +9529,12 @@ throttleit@^1.0.0: resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.1.tgz#304ec51631c3b770c65c6c6f76938b384000f4d5" integrity sha512-vDZpf9Chs9mAdfY046mcPt8fg5QSZr37hEH4TXYBnDF+izxgrbRGUAAaBvIk/fJm9aOFCGFd1EsNg5AZCbnQCQ== -through@^2.3.6, through@^2.3.8: +through@^2.3.6, through@^2.3.8, through@~2.3.4: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== -tiny-invariant@^1.0.2, tiny-invariant@^1.0.6, tiny-invariant@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642" - integrity sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw== - -tiny-invariant@^1.3.3: +tiny-invariant@^1.0.2, tiny-invariant@^1.0.6, tiny-invariant@^1.3.1, tiny-invariant@^1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127" integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg== @@ -11299,17 +9549,12 @@ tinybench@^2.9.0: resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.9.0.tgz#103c9f8ba6d7237a47ab6dd1dcff77251863426b" integrity sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg== -tinycolor2@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.6.0.tgz#f98007460169b0263b97072c5ae92484ce02d09e" - integrity sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw== - tinyexec@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-0.3.0.tgz#ed60cfce19c17799d4a241e06b31b0ec2bee69e6" integrity sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg== -tinyglobby@^0.2.6: +tinyglobby@^0.2.1, tinyglobby@^0.2.6: version "0.2.6" resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.6.tgz#950baf1462d0c0b443bc3d754d0d39c2e589aaae" integrity sha512-NbBoFBpqfcgd1tCiO8Lkfdk+xrA7mlLR9zgvZcZWQQwU63XAfUePyd6wZBaU93Hqw347lHnwFzttAkemHzzz4g== @@ -11328,9 +9573,9 @@ tinyrainbow@^1.2.0: integrity sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ== tinyspy@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-3.0.0.tgz#cb61644f2713cd84dee184863f4642e06ddf0585" - integrity sha512-q5nmENpTHgiPVd1cJDDc9cVoYN5x4vCvwT3FMilvKPKneCBZAxn2YWQjDF0UMcE9k0Cay1gBiDfTMU0g+mPMQA== + version "3.0.2" + resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-3.0.2.tgz#86dd3cf3d737b15adcf17d7887c84a75201df20a" + integrity sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q== tmp@^0.0.33: version "0.0.33" @@ -11340,11 +9585,9 @@ tmp@^0.0.33: os-tmpdir "~1.0.2" tmp@~0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" - integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== - dependencies: - rimraf "^3.0.0" + version "0.2.3" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae" + integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w== to-fast-properties@^2.0.0: version "2.0.0" @@ -11379,9 +9622,9 @@ totalist@^3.0.0: integrity sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ== tough-cookie@^4.1.3, tough-cookie@^4.1.4: - version "4.1.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" - integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== + version "4.1.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36" + integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag== dependencies: psl "^1.1.33" punycode "^2.1.1" @@ -11407,12 +9650,7 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== -tree-dump@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/tree-dump/-/tree-dump-1.0.2.tgz#c460d5921caeb197bde71d0e9a7b479848c5b8ac" - integrity sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ== - -tree-kill@^1.2.1, tree-kill@^1.2.2: +tree-kill@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== @@ -11427,7 +9665,7 @@ ts-api-utils@^1.0.1: resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== -ts-dedent@^2.0.0, ts-dedent@^2.2.0: +ts-dedent@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5" integrity sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ== @@ -11437,25 +9675,6 @@ ts-interface-checker@^0.1.9: resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== -ts-node@^10.9.2: - version "10.9.2" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" - integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== - dependencies: - "@cspotcode/source-map-support" "^0.8.0" - "@tsconfig/node10" "^1.0.7" - "@tsconfig/node12" "^1.0.7" - "@tsconfig/node14" "^1.0.0" - "@tsconfig/node16" "^1.0.2" - acorn "^8.4.1" - acorn-walk "^8.1.1" - arg "^4.1.0" - create-require "^1.1.0" - diff "^4.0.1" - make-error "^1.1.1" - v8-compile-cache-lib "^3.0.1" - yn "3.1.1" - tsconfig-paths@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz#ef78e19039133446d244beac0fd6a1632e2d107c" @@ -11471,23 +9690,23 @@ tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0: integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0: - version "2.6.2" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" - integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + version "2.7.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" + integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== tss-react@^4.8.2: - version "4.9.4" - resolved "https://registry.yarnpkg.com/tss-react/-/tss-react-4.9.4.tgz#037603ed2f8765c2f208ac1c75e9293753aa18cd" - integrity sha512-4o+XFdaTcraNEIsCRxKiEX7g6xhcsdSxfHRjos3Kg9GbYIpzfK4M2MHMETTuXT54nUrldtnkipNC003v/q5KVg== + version "4.9.13" + resolved "https://registry.yarnpkg.com/tss-react/-/tss-react-4.9.13.tgz#e6ac0bfea3977e58b5ef5a261cd0b035e6bd8254" + integrity sha512-Gu19qqPH8/SAyKVIgDE5qHygirEDnNIQcXhiEc+l4Q9T7C1sfvUnbVWs+yBpmN26/wyk4FTOupjYS2wq4vH0yA== dependencies: "@emotion/cache" "*" "@emotion/serialize" "*" "@emotion/utils" "*" tsup@^8.2.4: - version "8.2.4" - resolved "https://registry.yarnpkg.com/tsup/-/tsup-8.2.4.tgz#5e31790c1e66392cee384ad746ed51c106614beb" - integrity sha512-akpCPePnBnC/CXgRrcy72ZSntgIEUa1jN0oJbbvpALWKNOz1B7aM+UVDWGRGIO/T/PZugAESWDJUAb5FD48o8Q== + version "8.3.0" + resolved "https://registry.yarnpkg.com/tsup/-/tsup-8.3.0.tgz#c7dae40b13d11d81fb144c0f90077a99102a572a" + integrity sha512-ALscEeyS03IomcuNdFdc0YWGVIkwH1Ws7nfTbAPuoILvEV2hpGQAY72LIOjglGo4ShWpZfpBqP/jpQVCzqYQag== dependencies: bundle-require "^5.0.0" cac "^6.7.14" @@ -11496,7 +9715,6 @@ tsup@^8.2.4: debug "^4.3.5" esbuild "^0.23.0" execa "^5.1.1" - globby "^11.1.0" joycon "^3.1.1" picocolors "^1.0.1" postcss-load-config "^6.0.1" @@ -11504,6 +9722,7 @@ tsup@^8.2.4: rollup "^4.19.0" source-map "0.8.0-beta.0" sucrase "^3.35.0" + tinyglobby "^0.2.1" tree-kill "^1.2.2" tsutils@^3.17.1, tsutils@^3.21.0: @@ -11513,6 +9732,16 @@ tsutils@^3.17.1, tsutils@^3.21.0: dependencies: tslib "^1.8.1" +tsx@^4.19.1: + version "4.19.1" + resolved "https://registry.yarnpkg.com/tsx/-/tsx-4.19.1.tgz#b7bffdf4b565813e4dea14b90872af279cd0090b" + integrity sha512-0flMz1lh74BR4wOvBjuh9olbnwqCPc35OOlfyzHba0Dc+QNUeWX/Gq2YTbnwcWPO3BMd8fkzRVrHcsR+a7z7rA== + dependencies: + esbuild "~0.23.0" + get-tsconfig "^4.7.5" + optionalDependencies: + fsevents "~2.3.3" + tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" @@ -11554,15 +9783,15 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== -type-fest@^2.13.0, type-fest@^2.19.0, type-fest@~2.19: +type-fest@^2.19.0, type-fest@~2.19: version "2.19.0" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== type-fest@^4.9.0: - version "4.12.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.12.0.tgz#00ae70d02161b81ecd095158143c4bb8c879760d" - integrity sha512-5Y2/pp2wtJk8o08G0CMkuFPCO354FGwk/vbidxrdhRGZfd0tFnb4Qb8anp9XxXriwBgVPjdWbKpGl4J9lJY2jQ== + version "4.26.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.26.1.tgz#a4a17fa314f976dd3e6d6675ef6c775c16d7955e" + integrity sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg== type-is@~1.6.18: version "1.6.18" @@ -11572,44 +9801,49 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typed-array-buffer@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.1.tgz#0608ffe6bca71bf15a45bff0ca2604107a1325f5" - integrity sha512-RSqu1UEuSlrBhHTWC8O9FnPjOduNs4M7rJ4pRKoEjtx1zUNOPN2sSXHLDX+Y2WPbHIxbvg4JFo2DNAEfPIKWoQ== +typed-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" + integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== dependencies: - call-bind "^1.0.6" + call-bind "^1.0.7" es-errors "^1.3.0" is-typed-array "^1.1.13" -typed-array-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz#d787a24a995711611fb2b87a4052799517b230d0" - integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== +typed-array-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" + integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== dependencies: - call-bind "^1.0.2" + call-bind "^1.0.7" for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" -typed-array-byte-offset@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz#cbbe89b51fdef9cd6aaf07ad4707340abbc4ea0b" - integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== +typed-array-byte-offset@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" + integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" -typed-array-length@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" - integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== +typed-array-length@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" + integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== dependencies: - call-bind "^1.0.2" + call-bind "^1.0.7" for-each "^0.3.3" - is-typed-array "^1.1.9" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + possible-typed-array-names "^1.0.0" typescript-fsa-reducers@^1.2.0: version "1.2.2" @@ -11621,12 +9855,17 @@ typescript-fsa@^3.0.0: resolved "https://registry.yarnpkg.com/typescript-fsa/-/typescript-fsa-3.0.0.tgz#3ad1cb915a67338e013fc21f67c9b3e0e110c912" integrity sha512-xiXAib35i0QHl/+wMobzPibjAH5TJLDj+qGq5jwVLG9qR4FUswZURBw2qihBm0m06tHoyb3FzpnJs1GRhRwVag== +typescript@^4.6.4: + version "4.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== + typescript@^5.5.4: - version "5.5.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba" - integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== + version "5.6.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.2.tgz#d1de67b6bef77c41823f822df8f0b3bcff60a5a0" + integrity sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw== -ua-parser-js@^0.7.30, ua-parser-js@^0.7.33: +ua-parser-js@^0.7.30: version "0.7.39" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.39.tgz#c71efb46ebeabc461c4612d22d54f88880fabe7e" integrity sha512-IZ6acm6RhQHNibSt7+c09hhvsKy9WUr4DVbeq9U8o71qxyYtJpQeDxQnMrVqnIFMLcQjHO0I9wgfO2vIahht4w== @@ -11646,20 +9885,15 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" -undici-types@~5.26.4: - version "5.26.5" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" - integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== - undici-types@~6.19.2: version "6.19.8" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== unified@^11.0.0: - version "11.0.4" - resolved "https://registry.yarnpkg.com/unified/-/unified-11.0.4.tgz#f4be0ac0fe4c88cb873687c07c64c49ed5969015" - integrity sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ== + version "11.0.5" + resolved "https://registry.yarnpkg.com/unified/-/unified-11.0.5.tgz#f66677610a5c0a9ee90cab2b8d4d66037026d9e1" + integrity sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA== dependencies: "@types/unist" "^3.0.0" bail "^2.0.0" @@ -11716,37 +9950,27 @@ unpipe@1.0.0, unpipe@~1.0.0: integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== unplugin@^1.3.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-1.7.1.tgz#009571e3128640f4e327f33680d2db27afaf1e11" - integrity sha512-JqzORDAPxxs8ErLV4x+LL7bk5pk3YlcWqpSNsIkAZj972KzFZLClc/ekppahKkOczGkwIG6ElFgdOgOlK4tXZw== + version "1.14.1" + resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-1.14.1.tgz#c76d6155a661e43e6a897bce6b767a1ecc344c1a" + integrity sha512-lBlHbfSFPToDYp9pjXlUEFVxYLaue9f9T1HC+4OHlmj+HnMDdz9oZY+erXfoCe/5V/7gKUSY2jpXPb9S7f0f/w== dependencies: - acorn "^8.11.3" - chokidar "^3.5.3" - webpack-sources "^3.2.3" - webpack-virtual-modules "^0.6.1" + acorn "^8.12.1" + webpack-virtual-modules "^0.6.2" untildify@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== -update-browserslist-db@^1.0.13: - version "1.0.13" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" - integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== - dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" - -update-check@1.5.4: - version "1.5.4" - resolved "https://registry.yarnpkg.com/update-check/-/update-check-1.5.4.tgz#5b508e259558f1ad7dbc8b4b0457d4c9d28c8743" - integrity sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ== +update-browserslist-db@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" + integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== dependencies: - registry-auth-token "3.3.2" - registry-url "3.1.0" + escalade "^3.1.2" + picocolors "^1.0.1" -uri-js@^4.2.2, uri-js@^4.4.1: +uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== @@ -11761,14 +9985,6 @@ url-parse@^1.5.3: querystringify "^2.1.1" requires-port "^1.0.0" -url@^0.11.3: - version "0.11.3" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.3.tgz#6f495f4b935de40ce4a0a52faee8954244f3d3ad" - integrity sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw== - dependencies: - punycode "^1.4.1" - qs "^6.11.2" - use-memo-one@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/use-memo-one/-/use-memo-one-1.1.3.tgz#2fd2e43a2169eabc7496960ace8c79efef975e99" @@ -11779,13 +9995,6 @@ util-deprecate@^1.0.2: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== -util@^0.10.3: - version "0.10.4" - resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" - integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A== - dependencies: - inherits "2.0.3" - util@^0.12.5: version "0.12.5" resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc" @@ -11819,24 +10028,11 @@ uuid@^9.0.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== -v8-compile-cache-lib@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" - integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== - v8-compile-cache@^2.0.3: version "2.4.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz#cdada8bec61e15865f05d097c5f4fd30e94dc128" integrity sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw== -validate-npm-package-license@^3.0.1: - version "3.0.4" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - value-equal@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" @@ -11865,18 +10061,17 @@ vfile-message@^4.0.0: unist-util-stringify-position "^4.0.0" vfile@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/vfile/-/vfile-6.0.1.tgz#1e8327f41eac91947d4fe9d237a2dd9209762536" - integrity sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw== + version "6.0.3" + resolved "https://registry.yarnpkg.com/vfile/-/vfile-6.0.3.tgz#3652ab1c496531852bf55a6bac57af981ebc38ab" + integrity sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q== dependencies: "@types/unist" "^3.0.0" - unist-util-stringify-position "^4.0.0" vfile-message "^4.0.0" victory-vendor@^36.6.8: - version "36.9.1" - resolved "https://registry.yarnpkg.com/victory-vendor/-/victory-vendor-36.9.1.tgz#a7536766ca9725711c7dc1a36dd1d1d248cfa22d" - integrity sha512-+pZIP+U3pEJdDCeFmsXwHzV7vNHQC/eIbHklfe2ZCZqayYRH7lQbHcVgsJ0XOOv27hWs4jH4MONgXxHMObTMSA== + version "36.9.2" + resolved "https://registry.yarnpkg.com/victory-vendor/-/victory-vendor-36.9.2.tgz#668b02a448fa4ea0f788dbf4228b7e64669ff801" + integrity sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ== dependencies: "@types/d3-array" "^3.0.3" "@types/d3-ease" "^3.0.0" @@ -11912,21 +10107,10 @@ vite-plugin-svgr@^3.2.0: "@svgr/core" "^8.1.0" "@svgr/plugin-jsx" "^8.1.0" -vite@^5.0.0: - version "5.1.7" - resolved "https://registry.yarnpkg.com/vite/-/vite-5.1.7.tgz#9f685a2c4c70707fef6d37341b0e809c366da619" - integrity sha512-sgnEEFTZYMui/sTlH1/XEnVNHMujOahPLGMxn1+5sIT45Xjng1Ec1K78jRP15dSmVgg5WBin9yO81j3o9OxofA== - dependencies: - esbuild "^0.19.3" - postcss "^8.4.35" - rollup "^4.2.0" - optionalDependencies: - fsevents "~2.3.3" - -vite@^5.4.6: - version "5.4.6" - resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.6.tgz#85a93a1228a7fb5a723ca1743e337a2588ed008f" - integrity sha512-IeL5f8OO5nylsgzd9tq4qD2QqI0k2CQLGrWD0rCN0EQJZpBK5vJAx0I+GDkMOXxQX/OfFHMuLIx6ddAxGX/k+Q== +vite@^5.0.0, vite@^5.4.6: + version "5.4.8" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.8.tgz#af548ce1c211b2785478d3ba3e8da51e39a287e8" + integrity sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ== dependencies: esbuild "^0.21.3" postcss "^8.4.43" @@ -11988,15 +10172,10 @@ webidl-conversions@^7.0.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== -webpack-sources@^3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" - integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== - -webpack-virtual-modules@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.1.tgz#ac6fdb9c5adb8caecd82ec241c9631b7a3681b6f" - integrity sha512-poXpCylU7ExuvZK8z+On3kX+S8o/2dQ/SVYueKA0D4WEMXROXgY8Ez50/bQEUmvoSMMrWcrJqCHuhAbsiwg7Dg== +webpack-virtual-modules@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz#057faa9065c8acf48f24cb57ac0e77739ab9a7e8" + integrity sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ== whatwg-encoding@^3.1.1: version "3.1.1" @@ -12052,12 +10231,12 @@ which-boxed-primitive@^1.0.2: is-symbol "^1.0.3" which-builtin-type@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.1.3.tgz#b1b8443707cc58b6e9bf98d32110ff0c2cbd029b" - integrity sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw== + version "1.1.4" + resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.1.4.tgz#592796260602fc3514a1b5ee7fa29319b72380c3" + integrity sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w== dependencies: - function.prototype.name "^1.1.5" - has-tostringtag "^1.0.0" + function.prototype.name "^1.1.6" + has-tostringtag "^1.0.2" is-async-function "^2.0.0" is-date-object "^1.0.5" is-finalizationregistry "^1.0.2" @@ -12066,34 +10245,29 @@ which-builtin-type@^1.1.3: is-weakref "^1.0.2" isarray "^2.0.5" which-boxed-primitive "^1.0.2" - which-collection "^1.0.1" - which-typed-array "^1.1.9" + which-collection "^1.0.2" + which-typed-array "^1.1.15" -which-collection@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" - integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== +which-collection@^1.0.1, which-collection@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0" + integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw== dependencies: - is-map "^2.0.1" - is-set "^2.0.1" - is-weakmap "^2.0.1" - is-weakset "^2.0.1" - -which-module@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" - integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== + is-map "^2.0.3" + is-set "^2.0.3" + is-weakmap "^2.0.2" + is-weakset "^2.0.3" -which-typed-array@^1.1.13, which-typed-array@^1.1.14, which-typed-array@^1.1.2, which-typed-array@^1.1.9: - version "1.1.14" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.14.tgz#1f78a111aee1e131ca66164d8bdc3ab062c95a06" - integrity sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg== +which-typed-array@^1.1.13, which-typed-array@^1.1.14, which-typed-array@^1.1.15, which-typed-array@^1.1.2: + version "1.1.15" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" + integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== dependencies: - available-typed-arrays "^1.0.6" - call-bind "^1.0.5" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" for-each "^0.3.3" gopd "^1.0.1" - has-tostringtag "^1.0.1" + has-tostringtag "^1.0.2" which@^1.2.9: version "1.3.1" @@ -12117,25 +10291,19 @@ why-is-node-running@^2.3.0: siginfo "^2.0.0" stackback "0.0.2" -widest-line@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-4.0.1.tgz#a0fc673aaba1ea6f0a0d35b3c2795c9a9cc2ebf2" - integrity sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig== - dependencies: - string-width "^5.0.1" - -word-wrap@^1.2.4, word-wrap@^1.2.5, word-wrap@~1.2.3: +word-wrap@^1.2.5, word-wrap@~1.2.3: version "1.2.5" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== -wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - integrity sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw== +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" wrap-ansi@^6.2.0: version "6.2.0" @@ -12146,16 +10314,7 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^8.0.1: +wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== @@ -12185,16 +10344,11 @@ write@1.0.3: dependencies: mkdirp "^0.5.1" -ws@^8.18.0: +ws@^8.18.0, ws@^8.2.3: version "8.18.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== -ws@^8.2.3: - version "8.16.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.16.0.tgz#d1cd774f36fbc07165066a60e40323eab6446fd4" - integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ== - xml-name-validator@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-5.0.0.tgz#82be9b957f7afdacf961e5980f1bf227c0bf7673" @@ -12223,11 +10377,6 @@ xmlchars@^2.2.0: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== -"y18n@^3.2.1 || ^4.0.0": - version "4.0.3" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" - integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== - y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" @@ -12238,12 +10387,12 @@ yallist@^3.0.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== -yaml@^1.10.0, yaml@^1.7.2, yaml@^2.2.2, yaml@^2.3.0, yaml@~2.5.0: +yaml@^1.10.0, yaml@^1.7.2, yaml@^2.3.0, yaml@~2.5.0: version "2.5.1" resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.5.1.tgz#c9772aacf62cb7494a95b0c4f1fb065b563db130" integrity sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q== -yargs-parser@^11.1.1, yargs-parser@^21.1.1: +yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== @@ -12261,24 +10410,6 @@ yargs@17.7.2, yargs@^17.7.2: y18n "^5.0.5" yargs-parser "^21.1.1" -yargs@^12.0.5: - version "12.0.5" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" - integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== - dependencies: - cliui "^4.0.0" - decamelize "^1.2.0" - find-up "^3.0.0" - get-caller-file "^1.0.1" - os-locale "^3.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1 || ^4.0.0" - yargs-parser "^11.1.1" - yauzl@^2.10.0: version "2.10.0" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" @@ -12287,16 +10418,16 @@ yauzl@^2.10.0: buffer-crc32 "~0.2.3" fd-slicer "~1.1.0" -yn@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" - integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== - yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== +yoctocolors-cjs@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz#f4b905a840a37506813a7acaa28febe97767a242" + integrity sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA== + yup@^0.32.9: version "0.32.11" resolved "https://registry.yarnpkg.com/yup/-/yup-0.32.11.tgz#d67fb83eefa4698607982e63f7ca4c5ed3cf18c5" From 70857be4ff57d99cd7d6db73994cf94f0b78ed0c Mon Sep 17 00:00:00 2001 From: agorthi Date: Tue, 1 Oct 2024 12:38:48 +0530 Subject: [PATCH 112/474] upcoming:[DI-20585]- Added code review comments --- .../core/cloudpulse/linode-widget-verification.spec.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index bcb5d1d1d48..508cb3d5f18 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -128,7 +128,7 @@ describe('Integration Tests for Linode Dashboard ', () => { mockGetAccount(mockAccount); // Enables the account to have capability for Akamai Cloud Pulse mockGetLinodes([mockLinode]); mockCloudPulseGetMetricDefinitions(metricDefinitions, serviceType); - mockCloudPulseGetDashboards(dashboard, serviceType); + mockCloudPulseGetDashboards([dashboard], serviceType); mockCloudPulseServices(serviceType); mockCloudPulseDashboardServicesResponse(dashboard, id); mockCloudPulseJWSToken(serviceType); @@ -183,8 +183,6 @@ describe('Integration Tests for Linode Dashboard ', () => { for (const testData of metrics) { const { title: testDataTitle, expectedGranularity } = testData; - - cy.wait(7000); //maintaining the wait since page flicker and rendering const widgetSelector = `[data-qa-widget="${testDataTitle}"]`; cy.get(widgetSelector) @@ -240,7 +238,6 @@ describe('Integration Tests for Linode Dashboard ', () => { const { title: testDataTitle, expectedAggregation, expectedAggregationArray } = testData; - cy.wait(7000); //maintaining the wait since page flicker and rendering const widgetSelector = `[data-qa-widget="${testDataTitle}"]`; cy.get(widgetSelector) @@ -291,7 +288,6 @@ describe('Integration Tests for Linode Dashboard ', () => { } }); it('should trigger the global refresh button and verify the corresponding network calls', () => { - cy.wait(7000); //maintaining the wait since page flicker and rendering mockCloudPulseCreateMetrics(metricsAPIResponsePayload, serviceType).as('refreshMetrics'); // click the global refresh button ui.button @@ -323,9 +319,7 @@ describe('Integration Tests for Linode Dashboard ', () => { metrics.forEach((testData) => { const { title: testDataTitle } = testData; - - cy.wait(7000); //maintaining the wait since page flicker and rendering - + cy.get(`[data-qa-widget="${testDataTitle}"]`).as('widget'); cy.get('@widget') .should('be.visible') From b8e5c4e4b896b5433bf1327e5583939379eb2778 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 1 Oct 2024 13:05:22 +0530 Subject: [PATCH 113/474] upcoming: [DI-20800] - Code clean up and refactoring --- .../src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts | 1 - .../manager/src/features/CloudPulse/Utils/UserPreference.ts | 2 +- .../features/CloudPulse/shared/CloudPulseResourcesSelect.tsx | 4 ++-- .../features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx | 2 -- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index 025c3793d32..29eabd3a7a9 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -26,7 +26,6 @@ import type { } from '@linode/api-v4'; import type { DataSet } from 'src/components/LineGraph/LineGraph'; import type { CloudPulseResourceTypeMapFlag, FlagSet } from 'src/featureFlags'; -import { Tooltip } from 'src/components/Tooltip'; interface LabelNameOptionsProps { /** diff --git a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts index 3b15045f202..69d193c87e8 100644 --- a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts +++ b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts @@ -5,7 +5,7 @@ import { usePreferences, } from 'src/queries/profile/preferences'; -import { DASHBOARD_ID, TIME_DURATION, WIDGETS } from './constants'; +import { DASHBOARD_ID, WIDGETS } from './constants'; import type { AclpConfig, AclpWidget } from '@linode/api-v4'; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index 4dd2c23bb50..52fb36b03be 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -88,12 +88,12 @@ export const CloudPulseResourcesSelect = React.memo( setSelectedResources(resourceSelections); if (!isAutocompleteOpen.current) { - handleResourcesSelection(resourceSelections); + handleResourcesSelection(resourceSelections, savePreferences); } }} onClose={() => { isAutocompleteOpen.current = false; - handleResourcesSelection(selectedResources ?? []); + handleResourcesSelection(selectedResources ?? [], savePreferences); }} onOpen={() => { isAutocompleteOpen.current = true; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx index 5fa8ab4b81a..1b22edcdc7d 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx @@ -2,8 +2,6 @@ import * as React from 'react'; import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; -import { DASHBOARD_ID, TIME_DURATION } from '../Utils/constants'; - import type { FilterValue, TimeDuration } from '@linode/api-v4'; import type { BaseSelectProps, From 70dba3c25599b5eb406c00eab614b63f64730376 Mon Sep 17 00:00:00 2001 From: agorthi Date: Tue, 1 Oct 2024 13:40:57 +0530 Subject: [PATCH 114/474] yarn file reverting --- yarn.lock | 6004 ++++++++++++++++++----------------------------------- 1 file changed, 2012 insertions(+), 3992 deletions(-) diff --git a/yarn.lock b/yarn.lock index 6423caaf392..25ba08eb0c2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,129 +2,133 @@ # yarn lockfile v1 -"@aashutoshrathi/word-wrap@^1.2.3": - version "1.2.6" - resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" - integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== - -"@adobe/css-tools@^4.3.2": - version "4.3.3" - resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.3.3.tgz#90749bde8b89cd41764224f5aac29cd4138f75ff" - integrity sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ== - -"@algolia/cache-browser-local-storage@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.22.1.tgz#14b6dc9abc9e3a304a5fffb063d15f30af1032d1" - integrity sha512-Sw6IAmOCvvP6QNgY9j+Hv09mvkvEIDKjYW8ow0UDDAxSXy664RBNQk3i/0nt7gvceOJ6jGmOTimaZoY1THmU7g== - dependencies: - "@algolia/cache-common" "4.22.1" - -"@algolia/cache-common@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.22.1.tgz#c625dff4bc2a74e79f9aed67b4e053b0ef1b3ec1" - integrity sha512-TJMBKqZNKYB9TptRRjSUtevJeQVXRmg6rk9qgFKWvOy8jhCPdyNZV1nB3SKGufzvTVbomAukFR8guu/8NRKBTA== - -"@algolia/cache-in-memory@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.22.1.tgz#858a3d887f521362e87d04f3943e2810226a0d71" - integrity sha512-ve+6Ac2LhwpufuWavM/aHjLoNz/Z/sYSgNIXsinGofWOysPilQZPUetqLj8vbvi+DHZZaYSEP9H5SRVXnpsNNw== - dependencies: - "@algolia/cache-common" "4.22.1" - -"@algolia/client-account@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.22.1.tgz#a7fb8b66b9a4f0a428e1426b2561144267d76d43" - integrity sha512-k8m+oegM2zlns/TwZyi4YgCtyToackkOpE+xCaKCYfBfDtdGOaVZCM5YvGPtK+HGaJMIN/DoTL8asbM3NzHonw== - dependencies: - "@algolia/client-common" "4.22.1" - "@algolia/client-search" "4.22.1" - "@algolia/transporter" "4.22.1" - -"@algolia/client-analytics@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.22.1.tgz#506558740b4d49b1b1e3393861f729a8ce921851" - integrity sha512-1ssi9pyxyQNN4a7Ji9R50nSdISIumMFDwKNuwZipB6TkauJ8J7ha/uO60sPJFqQyqvvI+px7RSNRQT3Zrvzieg== - dependencies: - "@algolia/client-common" "4.22.1" - "@algolia/client-search" "4.22.1" - "@algolia/requester-common" "4.22.1" - "@algolia/transporter" "4.22.1" - -"@algolia/client-common@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.22.1.tgz#042b19c1b6157c485fa1b551349ab313944d2b05" - integrity sha512-IvaL5v9mZtm4k4QHbBGDmU3wa/mKokmqNBqPj0K7lcR8ZDKzUorhcGp/u8PkPC/e0zoHSTvRh7TRkGX3Lm7iOQ== - dependencies: - "@algolia/requester-common" "4.22.1" - "@algolia/transporter" "4.22.1" - -"@algolia/client-personalization@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-4.22.1.tgz#ff088d797648224fb582e9fe5828f8087835fa3d" - integrity sha512-sl+/klQJ93+4yaqZ7ezOttMQ/nczly/3GmgZXJ1xmoewP5jmdP/X/nV5U7EHHH3hCUEHeN7X1nsIhGPVt9E1cQ== - dependencies: - "@algolia/client-common" "4.22.1" - "@algolia/requester-common" "4.22.1" - "@algolia/transporter" "4.22.1" - -"@algolia/client-search@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.22.1.tgz#508cc6ab3d1f4e9c02735a630d4dff6fbb8514a2" - integrity sha512-yb05NA4tNaOgx3+rOxAmFztgMTtGBi97X7PC3jyNeGiwkAjOZc2QrdZBYyIdcDLoI09N0gjtpClcackoTN0gPA== - dependencies: - "@algolia/client-common" "4.22.1" - "@algolia/requester-common" "4.22.1" - "@algolia/transporter" "4.22.1" - -"@algolia/logger-common@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.22.1.tgz#79cf4cd295de0377a94582c6aaac59b1ded731d9" - integrity sha512-OnTFymd2odHSO39r4DSWRFETkBufnY2iGUZNrMXpIhF5cmFE8pGoINNPzwg02QLBlGSaLqdKy0bM8S0GyqPLBg== - -"@algolia/logger-console@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.22.1.tgz#0355345f6940f67aaa78ae9b81c06e44e49f2336" - integrity sha512-O99rcqpVPKN1RlpgD6H3khUWylU24OXlzkavUAMy6QZd1776QAcauE3oP8CmD43nbaTjBexZj2nGsBH9Tc0FVA== - dependencies: - "@algolia/logger-common" "4.22.1" - -"@algolia/requester-browser-xhr@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.22.1.tgz#f04df6fe9690a071b267c77d26b83a3be9280361" - integrity sha512-dtQGYIg6MteqT1Uay3J/0NDqD+UciHy3QgRbk7bNddOJu+p3hzjTRYESqEnoX/DpEkaNYdRHUKNylsqMpgwaEw== - dependencies: - "@algolia/requester-common" "4.22.1" - -"@algolia/requester-common@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.22.1.tgz#27be35f3718aafcb6b388ff9c3aa2defabd559ff" - integrity sha512-dgvhSAtg2MJnR+BxrIFqlLtkLlVVhas9HgYKMk2Uxiy5m6/8HZBL40JVAMb2LovoPFs9I/EWIoFVjOrFwzn5Qg== - -"@algolia/requester-node-http@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.22.1.tgz#589a6fa828ad0f325e727a6fcaf4e1a2343cc62b" - integrity sha512-JfmZ3MVFQkAU+zug8H3s8rZ6h0ahHZL/SpMaSasTCGYR5EEJsCc8SI5UZ6raPN2tjxa5bxS13BRpGSBUens7EA== - dependencies: - "@algolia/requester-common" "4.22.1" - -"@algolia/transporter@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.22.1.tgz#8843841b857dc021668f31647aa557ff19cd9cb1" - integrity sha512-kzWgc2c9IdxMa3YqA6TN0NW5VrKYYW/BELIn7vnLyn+U/RFdZ4lxxt9/8yq3DKV5snvoDzzO4ClyejZRdV3lMQ== - dependencies: - "@algolia/cache-common" "4.22.1" - "@algolia/logger-common" "4.22.1" - "@algolia/requester-common" "4.22.1" - -"@ampproject/remapping@^2.2.0": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" - integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== - dependencies: - "@jridgewell/gen-mapping" "^0.3.0" - "@jridgewell/trace-mapping" "^0.3.9" - -"@ampproject/remapping@^2.3.0": +"@adobe/css-tools@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.4.0.tgz#728c484f4e10df03d5a3acd0d8adcbbebff8ad63" + integrity sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ== + +"@algolia/cache-browser-local-storage@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.24.0.tgz#97bc6d067a9fd932b9c922faa6b7fd6e546e1348" + integrity sha512-t63W9BnoXVrGy9iYHBgObNXqYXM3tYXCjDSHeNwnsc324r4o5UiVKUiAB4THQ5z9U5hTj6qUvwg/Ez43ZD85ww== + dependencies: + "@algolia/cache-common" "4.24.0" + +"@algolia/cache-common@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.24.0.tgz#81a8d3a82ceb75302abb9b150a52eba9960c9744" + integrity sha512-emi+v+DmVLpMGhp0V9q9h5CdkURsNmFC+cOS6uK9ndeJm9J4TiqSvPYVu+THUP8P/S08rxf5x2P+p3CfID0Y4g== + +"@algolia/cache-in-memory@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.24.0.tgz#ffcf8872f3a10cb85c4f4641bdffd307933a6e44" + integrity sha512-gDrt2so19jW26jY3/MkFg5mEypFIPbPoXsQGQWAi6TrCPsNOSEYepBMPlucqWigsmEy/prp5ug2jy/N3PVG/8w== + dependencies: + "@algolia/cache-common" "4.24.0" + +"@algolia/client-account@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.24.0.tgz#eba7a921d828e7c8c40a32d4add21206c7fe12f1" + integrity sha512-adcvyJ3KjPZFDybxlqnf+5KgxJtBjwTPTeyG2aOyoJvx0Y8dUQAEOEVOJ/GBxX0WWNbmaSrhDURMhc+QeevDsA== + dependencies: + "@algolia/client-common" "4.24.0" + "@algolia/client-search" "4.24.0" + "@algolia/transporter" "4.24.0" + +"@algolia/client-analytics@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.24.0.tgz#9d2576c46a9093a14e668833c505ea697a1a3e30" + integrity sha512-y8jOZt1OjwWU4N2qr8G4AxXAzaa8DBvyHTWlHzX/7Me1LX8OayfgHexqrsL4vSBcoMmVw2XnVW9MhL+Y2ZDJXg== + dependencies: + "@algolia/client-common" "4.24.0" + "@algolia/client-search" "4.24.0" + "@algolia/requester-common" "4.24.0" + "@algolia/transporter" "4.24.0" + +"@algolia/client-common@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.24.0.tgz#77c46eee42b9444a1d1c1583a83f7df4398a649d" + integrity sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA== + dependencies: + "@algolia/requester-common" "4.24.0" + "@algolia/transporter" "4.24.0" + +"@algolia/client-personalization@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-4.24.0.tgz#8b47789fb1cb0f8efbea0f79295b7c5a3850f6ae" + integrity sha512-l5FRFm/yngztweU0HdUzz1rC4yoWCFo3IF+dVIVTfEPg906eZg5BOd1k0K6rZx5JzyyoP4LdmOikfkfGsKVE9w== + dependencies: + "@algolia/client-common" "4.24.0" + "@algolia/requester-common" "4.24.0" + "@algolia/transporter" "4.24.0" + +"@algolia/client-search@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.24.0.tgz#75e6c02d33ef3e0f34afd9962c085b856fc4a55f" + integrity sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA== + dependencies: + "@algolia/client-common" "4.24.0" + "@algolia/requester-common" "4.24.0" + "@algolia/transporter" "4.24.0" + +"@algolia/logger-common@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.24.0.tgz#28d439976019ec0a46ba7a1a739ef493d4ef8123" + integrity sha512-LLUNjkahj9KtKYrQhFKCzMx0BY3RnNP4FEtO+sBybCjJ73E8jNdaKJ/Dd8A/VA4imVHP5tADZ8pn5B8Ga/wTMA== + +"@algolia/logger-console@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.24.0.tgz#c6ff486036cd90b81d07a95aaba04461da7e1c65" + integrity sha512-X4C8IoHgHfiUROfoRCV+lzSy+LHMgkoEEU1BbKcsfnV0i0S20zyy0NLww9dwVHUWNfPPxdMU+/wKmLGYf96yTg== + dependencies: + "@algolia/logger-common" "4.24.0" + +"@algolia/recommend@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/recommend/-/recommend-4.24.0.tgz#8a3f78aea471ee0a4836b78fd2aad4e9abcaaf34" + integrity sha512-P9kcgerfVBpfYHDfVZDvvdJv0lEoCvzNlOy2nykyt5bK8TyieYyiD0lguIJdRZZYGre03WIAFf14pgE+V+IBlw== + dependencies: + "@algolia/cache-browser-local-storage" "4.24.0" + "@algolia/cache-common" "4.24.0" + "@algolia/cache-in-memory" "4.24.0" + "@algolia/client-common" "4.24.0" + "@algolia/client-search" "4.24.0" + "@algolia/logger-common" "4.24.0" + "@algolia/logger-console" "4.24.0" + "@algolia/requester-browser-xhr" "4.24.0" + "@algolia/requester-common" "4.24.0" + "@algolia/requester-node-http" "4.24.0" + "@algolia/transporter" "4.24.0" + +"@algolia/requester-browser-xhr@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.24.0.tgz#313c5edab4ed73a052e75803855833b62dd19c16" + integrity sha512-Z2NxZMb6+nVXSjF13YpjYTdvV3032YTBSGm2vnYvYPA6mMxzM3v5rsCiSspndn9rzIW4Qp1lPHBvuoKJV6jnAA== + dependencies: + "@algolia/requester-common" "4.24.0" + +"@algolia/requester-common@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.24.0.tgz#1c60c198031f48fcdb9e34c4057a3ea987b9a436" + integrity sha512-k3CXJ2OVnvgE3HMwcojpvY6d9kgKMPRxs/kVohrwF5WMr2fnqojnycZkxPoEg+bXm8fi5BBfFmOqgYztRtHsQA== + +"@algolia/requester-node-http@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.24.0.tgz#4461593714031d02aa7da221c49df675212f482f" + integrity sha512-JF18yTjNOVYvU/L3UosRcvbPMGT9B+/GQWNWnenIImglzNVGpyzChkXLnrSf6uxwVNO6ESGu6oN8MqcGQcjQJw== + dependencies: + "@algolia/requester-common" "4.24.0" + +"@algolia/transporter@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.24.0.tgz#226bb1f8af62430374c1972b2e5c8580ab275102" + integrity sha512-86nI7w6NzWxd1Zp9q3413dRshDqAzSbsQjhcDhPIatEFiZrL1/TjnHL8S7jVKFePlIMzDsZWXAXwXzcok9c5oA== + dependencies: + "@algolia/cache-common" "4.24.0" + "@algolia/logger-common" "4.24.0" + "@algolia/requester-common" "4.24.0" + +"@ampproject/remapping@^2.2.0", "@ampproject/remapping@^2.3.0": version "2.3.0" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== @@ -139,15 +143,7 @@ dependencies: "@babel/highlight" "^7.10.4" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" - integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== - dependencies: - "@babel/highlight" "^7.23.4" - chalk "^2.4.2" - -"@babel/code-frame@^7.24.7": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== @@ -155,43 +151,33 @@ "@babel/highlight" "^7.24.7" picocolors "^1.0.0" -"@babel/compat-data@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.5.tgz#ffb878728bb6bdcb6f4510aa51b1be9afb8cfd98" - integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw== +"@babel/compat-data@^7.25.2": + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.4.tgz#7d2a80ce229890edcf4cc259d4d696cb4dae2fcb" + integrity sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ== "@babel/core@^7.18.9", "@babel/core@^7.21.3": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.9.tgz#b028820718000f267870822fec434820e9b1e4d1" - integrity sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw== + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.2.tgz#ed8eec275118d7613e77a352894cd12ded8eba77" + integrity sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA== dependencies: "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.23.5" - "@babel/generator" "^7.23.6" - "@babel/helper-compilation-targets" "^7.23.6" - "@babel/helper-module-transforms" "^7.23.3" - "@babel/helpers" "^7.23.9" - "@babel/parser" "^7.23.9" - "@babel/template" "^7.23.9" - "@babel/traverse" "^7.23.9" - "@babel/types" "^7.23.9" + "@babel/code-frame" "^7.24.7" + "@babel/generator" "^7.25.0" + "@babel/helper-compilation-targets" "^7.25.2" + "@babel/helper-module-transforms" "^7.25.2" + "@babel/helpers" "^7.25.0" + "@babel/parser" "^7.25.0" + "@babel/template" "^7.25.0" + "@babel/traverse" "^7.25.2" + "@babel/types" "^7.25.2" convert-source-map "^2.0.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.23.6": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e" - integrity sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw== - dependencies: - "@babel/types" "^7.23.6" - "@jridgewell/gen-mapping" "^0.3.2" - "@jridgewell/trace-mapping" "^0.3.17" - jsesc "^2.5.1" - -"@babel/generator@^7.25.6": +"@babel/generator@^7.25.0", "@babel/generator@^7.25.6": version "7.25.6" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.6.tgz#0df1ad8cb32fe4d2b01d8bf437f153d19342a87c" integrity sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw== @@ -201,87 +187,65 @@ "@jridgewell/trace-mapping" "^0.3.25" jsesc "^2.5.1" -"@babel/helper-compilation-targets@^7.23.6": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz#4d79069b16cbcf1461289eccfbbd81501ae39991" - integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== +"@babel/helper-compilation-targets@^7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz#e1d9410a90974a3a5a66e84ff55ef62e3c02d06c" + integrity sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw== dependencies: - "@babel/compat-data" "^7.23.5" - "@babel/helper-validator-option" "^7.23.5" - browserslist "^4.22.2" + "@babel/compat-data" "^7.25.2" + "@babel/helper-validator-option" "^7.24.8" + browserslist "^4.23.1" lru-cache "^5.1.1" semver "^6.3.1" -"@babel/helper-environment-visitor@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" - integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== - -"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0" - integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== - dependencies: - "@babel/types" "^7.22.15" - -"@babel/helper-module-transforms@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz#d7d12c3c5d30af5b3c0fcab2a6d5217773e2d0f1" - integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ== +"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz#f2f980392de5b84c3328fc71d38bd81bbb83042b" + integrity sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA== dependencies: - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-module-imports" "^7.22.15" - "@babel/helper-simple-access" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/helper-validator-identifier" "^7.22.20" + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" -"@babel/helper-simple-access@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" - integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== +"@babel/helper-module-transforms@^7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz#ee713c29768100f2776edf04d4eb23b8d27a66e6" + integrity sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ== dependencies: - "@babel/types" "^7.22.5" + "@babel/helper-module-imports" "^7.24.7" + "@babel/helper-simple-access" "^7.24.7" + "@babel/helper-validator-identifier" "^7.24.7" + "@babel/traverse" "^7.25.2" -"@babel/helper-split-export-declaration@^7.22.6": - version "7.22.6" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" - integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== +"@babel/helper-simple-access@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz#bcade8da3aec8ed16b9c4953b74e506b51b5edb3" + integrity sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg== dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-string-parser@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" - integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" "@babel/helper-string-parser@^7.24.8": version "7.24.8" resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz#5b3329c9a58803d5df425e5785865881a81ca48d" integrity sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ== -"@babel/helper-validator-identifier@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" - integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== - "@babel/helper-validator-identifier@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== -"@babel/helper-validator-option@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" - integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== +"@babel/helper-validator-option@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz#3725cdeea8b480e86d34df15304806a06975e33d" + integrity sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q== -"@babel/helpers@^7.23.9": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.9.tgz#c3e20bbe7f7a7e10cb9b178384b4affdf5995c7d" - integrity sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ== +"@babel/helpers@^7.25.0": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.6.tgz#57ee60141829ba2e102f30711ffe3afab357cc60" + integrity sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q== dependencies: - "@babel/template" "^7.23.9" - "@babel/traverse" "^7.23.9" - "@babel/types" "^7.23.9" + "@babel/template" "^7.25.0" + "@babel/types" "^7.25.6" "@babel/highlight@^7.10.4", "@babel/highlight@^7.24.7": version "7.24.7" @@ -293,64 +257,20 @@ js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/highlight@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" - integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== - dependencies: - "@babel/helper-validator-identifier" "^7.22.20" - chalk "^2.4.2" - js-tokens "^4.0.0" - -"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.7.0": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.9.tgz#7b903b6149b0f8fa7ad564af646c4c38a77fc44b" - integrity sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA== - -"@babel/parser@^7.25.0": - version "7.25.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.3.tgz#91fb126768d944966263f0657ab222a642b82065" - integrity sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw== - dependencies: - "@babel/types" "^7.25.2" - -"@babel/parser@^7.25.4": - version "7.25.4" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.4.tgz#af4f2df7d02440286b7de57b1c21acfb2a6f257a" - integrity sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA== - dependencies: - "@babel/types" "^7.25.4" - -"@babel/parser@^7.25.6": +"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.25.0", "@babel/parser@^7.25.4", "@babel/parser@^7.25.6", "@babel/parser@^7.7.0": version "7.25.6" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.6.tgz#85660c5ef388cbbf6e3d2a694ee97a38f18afe2f" integrity sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q== dependencies: "@babel/types" "^7.25.6" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.6", "@babel/runtime@^7.15.4", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.9", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.9.tgz#47791a15e4603bb5f905bc0753801cf21d6345f7" - integrity sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw== - dependencies: - regenerator-runtime "^0.14.0" - -"@babel/runtime@^7.25.0": - version "7.25.0" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz#3af9a91c1b739c569d5d80cc917280919c544ecb" - integrity sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw== +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.6", "@babel/runtime@^7.15.4", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.9", "@babel/runtime@^7.25.6", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.6.tgz#9afc3289f7184d8d7f98b099884c26317b9264d2" + integrity sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ== dependencies: regenerator-runtime "^0.14.0" -"@babel/template@^7.23.9": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.23.9.tgz#f881d0487cba2828d3259dcb9ef5005a9731011a" - integrity sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA== - dependencies: - "@babel/code-frame" "^7.23.5" - "@babel/parser" "^7.23.9" - "@babel/types" "^7.23.9" - "@babel/template@^7.25.0": version "7.25.0" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.0.tgz#e733dc3134b4fede528c15bc95e89cb98c52592a" @@ -360,7 +280,7 @@ "@babel/parser" "^7.25.0" "@babel/types" "^7.25.0" -"@babel/traverse@^7.18.9", "@babel/traverse@^7.23.3", "@babel/traverse@^7.23.9", "@babel/traverse@^7.7.0": +"@babel/traverse@^7.18.9", "@babel/traverse@^7.24.7", "@babel/traverse@^7.25.2", "@babel/traverse@^7.7.0": version "7.25.6" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.6.tgz#04fad980e444f182ecf1520504941940a90fea41" integrity sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ== @@ -373,34 +293,7 @@ debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.18.9", "@babel/types@^7.20.7", "@babel/types@^7.21.3", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.6", "@babel/types@^7.23.9", "@babel/types@^7.7.0": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.9.tgz#1dd7b59a9a2b5c87f8b41e52770b5ecbf492e002" - integrity sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q== - dependencies: - "@babel/helper-string-parser" "^7.23.4" - "@babel/helper-validator-identifier" "^7.22.20" - to-fast-properties "^2.0.0" - -"@babel/types@^7.25.0", "@babel/types@^7.25.2": - version "7.25.2" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.2.tgz#55fb231f7dc958cd69ea141a4c2997e819646125" - integrity sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q== - dependencies: - "@babel/helper-string-parser" "^7.24.8" - "@babel/helper-validator-identifier" "^7.24.7" - to-fast-properties "^2.0.0" - -"@babel/types@^7.25.4": - version "7.25.4" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.4.tgz#6bcb46c72fdf1012a209d016c07f769e10adcb5f" - integrity sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ== - dependencies: - "@babel/helper-string-parser" "^7.24.8" - "@babel/helper-validator-identifier" "^7.24.7" - to-fast-properties "^2.0.0" - -"@babel/types@^7.25.6": +"@babel/types@^7.0.0", "@babel/types@^7.18.9", "@babel/types@^7.20.7", "@babel/types@^7.21.3", "@babel/types@^7.24.7", "@babel/types@^7.25.0", "@babel/types@^7.25.2", "@babel/types@^7.25.4", "@babel/types@^7.25.6", "@babel/types@^7.7.0": version "7.25.6" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.6.tgz#893942ddb858f32ae7a004ec9d3a76b3463ef8e6" integrity sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw== @@ -419,17 +312,20 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@braintree/asset-loader@0.4.4": - version "0.4.4" - resolved "https://registry.yarnpkg.com/@braintree/asset-loader/-/asset-loader-0.4.4.tgz#9a5eda24c3627bfd5c7f7483cd48f0e411dd2f09" - integrity sha512-uVhXC5dydmngmNVuDiKgfXSlz4kv4x5ytIJodI8N5SY16mRh13m/UmbQ7yH+o8DQqp50qPZ45MUHIZkXKPg85w== - dependencies: - promise-polyfill "^8.1.3" +"@braintree/asset-loader@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@braintree/asset-loader/-/asset-loader-2.0.0.tgz#4e25ed06379d0bbda101c2157611651157a4df35" + integrity sha512-7Zs3/g3lPTfkdtWr7cKh3tk1pDruXR++TXwGKkx7BPuTjjLNFul2JSfI+ScHzNU4u/gZNPNQagsSTlYxIhBgMA== -"@braintree/browser-detection@1.17.1": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@braintree/browser-detection/-/browser-detection-1.17.1.tgz#d151c409dc7245e9307b05f3a06ede254e0f5d1e" - integrity sha512-Mk7jauyp9pD14BTRS7otoy9dqIJGb3Oy0XtxKM/adGD9i9MAuCjH5uRZMyW2iVmJQTaA/PLlWdG7eSDyMWMc8Q== +"@braintree/asset-loader@2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@braintree/asset-loader/-/asset-loader-2.0.1.tgz#7069b5d54e2827b6c1fb4155c4cdc8dc68e00a33" + integrity sha512-OGAoBA5MRVsr5qg0sXM6NMJbqHnYZhBudtM6WGgpQnoX42fjUYbE6Y6qFuuerD5z3lsOAjnu80DooBs1VBuh5Q== + +"@braintree/browser-detection@2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@braintree/browser-detection/-/browser-detection-2.0.1.tgz#11bc5e1d173c55cd25bda6ad22c6b3ee14ed87a2" + integrity sha512-wpRI7AXEUh6o3ILrJbpNOYE7ItfjX/S8JZP7Z5FF66ULngBGYOqE8SeLlLKXG69Nc07HtlL/6nk/h539iz9hcQ== "@braintree/browser-detection@^1.12.1": version "1.17.2" @@ -441,22 +337,27 @@ resolved "https://registry.yarnpkg.com/@braintree/event-emitter/-/event-emitter-0.4.1.tgz#204eaad8cf84eb7bf81fb288a359d34eda85a396" integrity sha512-X41357O3OXUDlnwMvS1m0GQEn3zB3s3flOBeg2J5OBvLvdJEIAVpPkblABPtsPrlciDSvfv1aSG5ixHPgFH0Zg== -"@braintree/extended-promise@0.4.1": - version "0.4.1" - resolved "https://registry.yarnpkg.com/@braintree/extended-promise/-/extended-promise-0.4.1.tgz#b44f8e6236ddb43434be11924f00fa69f8782a36" - integrity sha512-00n7m4z+swWHoFQLHLvrIBIEoxnGUBsl3ogvX79ITpcn8CHczDwtxYy5+RhMoAraRdfN3oB+8QIpN3KOxs2Q7w== +"@braintree/extended-promise@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@braintree/extended-promise/-/extended-promise-1.0.0.tgz#b9c52cf93b4935c429053b16e1152549df0696a7" + integrity sha512-E9529FJNG4OgeeLJ00vNs3TW67+AeSQobJg0hwfsQk29hgK4bVBsvQHVD4nwDuDD1Czon90K88gfQIFadAMs0w== -"@braintree/iframer@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@braintree/iframer/-/iframer-1.1.0.tgz#7e59b975c2a48bd92616f653367a5214fc2ddd4b" - integrity sha512-tVpr7U6u6bqeQlHreEjYMNtnHX62vLnNWziY2kQLqkWhvusPuY5DfuGEIPpWqsd+V/a1slyTQaxK6HWTlH6A/Q== +"@braintree/iframer@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@braintree/iframer/-/iframer-2.0.0.tgz#bbba9cfd62b701b8cb1f779dffcad6295aed9d23" + integrity sha512-x1kHOyIJNDvi4P1s6pVBZhqhBa1hqDG9+yzcsCR1oNVC0LxH9CAP8bKxioT8/auY1sUyy+D8T4Vp/jv7QqSqLQ== -"@braintree/sanitize-url@6.0.4": - version "6.0.4" - resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-6.0.4.tgz#923ca57e173c6b232bbbb07347b1be982f03e783" - integrity sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A== +"@braintree/sanitize-url@7.0.4": + version "7.0.4" + resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-7.0.4.tgz#a7ddd6d55dfb89e341f5684c9717ee24fef62301" + integrity sha512-hPYRrKFoI+nuckPgDJfyYAkybFvheo4usS0Vw0HNAe+fmGBQA5Az37b/yStO284atBoqqdOUhKJ3d9Zw3PQkcQ== + +"@braintree/uuid@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@braintree/uuid/-/uuid-1.0.0.tgz#4fda394ceae803a8129e673c29ccf6c5e2014360" + integrity sha512-AtI5hfttWSuWAgcwLUZdcZ7Fp/8jCCUf9JTs7+Xow9ditU28zuoBovqq083yph2m3SxPYb84lGjOq+cXlXBvJg== -"@braintree/uuid@0.1.0", "@braintree/uuid@^0.1.0": +"@braintree/uuid@^0.1.0": version "0.1.0" resolved "https://registry.yarnpkg.com/@braintree/uuid/-/uuid-0.1.0.tgz#ab9355015a7fb0e25cf3c2ff9cd32ece8ea304b0" integrity sha512-YvZJdlNcK5EnR+7M8AjgEAf4Qx696+FOSYlPfy5ePn80vODtVAUU0FxHnzKZC0og1VbDNQDDiwhthR65D4Na0g== @@ -473,47 +374,6 @@ dependencies: cookie "^0.5.0" -"@bundled-es-modules/deepmerge@^4.3.1": - version "4.3.1" - resolved "https://registry.yarnpkg.com/@bundled-es-modules/deepmerge/-/deepmerge-4.3.1.tgz#e0ef866494125f64f6fb75adeffacedc25f2f31b" - integrity sha512-Rk453EklPUPC3NRWc3VUNI/SSUjdBaFoaQvFRmNBNtMHVtOFD5AntiWg5kEE1hqcPqedYFDzxE3ZcMYPcA195w== - dependencies: - deepmerge "^4.3.1" - -"@bundled-es-modules/glob@^10.4.2": - version "10.4.2" - resolved "https://registry.yarnpkg.com/@bundled-es-modules/glob/-/glob-10.4.2.tgz#ef8f58b5d33ec8a1d4ca739bb49c09e5d0874bb5" - integrity sha512-740y5ofkzydsFao5EXJrGilcIL6EFEw/cmPf2uhTw9J6G1YOhiIFjNFCHdpgEiiH5VlU3G0SARSjlFlimRRSMA== - dependencies: - buffer "^6.0.3" - events "^3.3.0" - glob "^10.4.2" - patch-package "^8.0.0" - path "^0.12.7" - stream "^0.0.3" - string_decoder "^1.3.0" - url "^0.11.3" - -"@bundled-es-modules/memfs@^4.9.4": - version "4.9.4" - resolved "https://registry.yarnpkg.com/@bundled-es-modules/memfs/-/memfs-4.9.4.tgz#9c68d1ff10f485d59d45778c930aa8d60d0095a2" - integrity sha512-1XyYPUaIHwEOdF19wYVLBtHJRr42Do+3ctht17cZOHwHf67vkmRNPlYDGY2kJps4RgE5+c7nEZmEzxxvb1NZWA== - dependencies: - assert "^2.0.0" - buffer "^6.0.3" - events "^3.3.0" - memfs "^4.9.3" - path "^0.12.7" - stream "^0.0.3" - util "^0.12.5" - -"@bundled-es-modules/postcss-calc-ast-parser@^0.1.6": - version "0.1.6" - resolved "https://registry.yarnpkg.com/@bundled-es-modules/postcss-calc-ast-parser/-/postcss-calc-ast-parser-0.1.6.tgz#c15f422c0300b2daba9cff6a9d07ef6c5e7cc673" - integrity sha512-y65TM5zF+uaxo9OeekJ3rxwTINlQvrkbZLogYvQYVoLtxm4xEiHfZ7e/MyiWbStYyWZVZkVqsaVU6F4SUK5XUA== - dependencies: - postcss-calc-ast-parser "^0.1.4" - "@bundled-es-modules/statuses@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@bundled-es-modules/statuses/-/statuses-1.0.1.tgz#761d10f44e51a94902c4da48675b71a76cc98872" @@ -521,22 +381,23 @@ dependencies: statuses "^2.0.1" +"@bundled-es-modules/tough-cookie@^0.1.6": + version "0.1.6" + resolved "https://registry.yarnpkg.com/@bundled-es-modules/tough-cookie/-/tough-cookie-0.1.6.tgz#fa9cd3cedfeecd6783e8b0d378b4a99e52bde5d3" + integrity sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw== + dependencies: + "@types/tough-cookie" "^4.0.5" + tough-cookie "^4.1.4" + "@colors/colors@1.5.0": version "1.5.0" resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== -"@cspotcode/source-map-support@^0.8.0": - version "0.8.1" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" - integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== - dependencies: - "@jridgewell/trace-mapping" "0.3.9" - "@cypress/request@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@cypress/request/-/request-3.0.1.tgz#72d7d5425236a2413bd3d8bb66d02d9dc3168960" - integrity sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ== + version "3.0.5" + resolved "https://registry.yarnpkg.com/@cypress/request/-/request-3.0.5.tgz#d893a6e68ce2636c085fcd8d7283c3186499ba63" + integrity sha512-v+XHd9XmWbufxF1/bTaVm2yhbxY+TB4YtWRqF2zaXBlDNMkls34KiATz0AVDLavL3iB6bQk9/7n3oY1EoLSWGA== dependencies: aws-sign2 "~0.7.0" aws4 "^1.8.0" @@ -544,14 +405,14 @@ combined-stream "~1.0.6" extend "~3.0.2" forever-agent "~0.6.1" - form-data "~2.3.2" - http-signature "~1.3.6" + form-data "~4.0.0" + http-signature "~1.4.0" is-typedarray "~1.0.0" isstream "~0.1.2" json-stringify-safe "~5.0.1" mime-types "~2.1.19" performance-now "^2.1.0" - qs "6.10.4" + qs "6.13.0" safe-buffer "^5.1.2" tough-cookie "^4.1.3" tunnel-agent "^0.6.0" @@ -565,16 +426,16 @@ debug "^3.1.0" lodash.once "^4.1.1" -"@emotion/babel-plugin@^11.11.0": - version "11.11.0" - resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz#c2d872b6a7767a9d176d007f5b31f7d504bb5d6c" - integrity sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ== +"@emotion/babel-plugin@^11.12.0": + version "11.12.0" + resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz#7b43debb250c313101b3f885eba634f1d723fcc2" + integrity sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw== dependencies: "@babel/helper-module-imports" "^7.16.7" "@babel/runtime" "^7.18.3" - "@emotion/hash" "^0.9.1" - "@emotion/memoize" "^0.8.1" - "@emotion/serialize" "^1.1.2" + "@emotion/hash" "^0.9.2" + "@emotion/memoize" "^0.9.0" + "@emotion/serialize" "^1.2.0" babel-plugin-macros "^3.1.0" convert-source-map "^1.5.0" escape-string-regexp "^4.0.0" @@ -582,15 +443,15 @@ source-map "^0.5.7" stylis "4.2.0" -"@emotion/cache@*", "@emotion/cache@^11.11.0": - version "11.11.0" - resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.11.0.tgz#809b33ee6b1cb1a625fef7a45bc568ccd9b8f3ff" - integrity sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ== +"@emotion/cache@*", "@emotion/cache@^11.11.0", "@emotion/cache@^11.13.0": + version "11.13.1" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.13.1.tgz#fecfc54d51810beebf05bf2a161271a1a91895d7" + integrity sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw== dependencies: - "@emotion/memoize" "^0.8.1" - "@emotion/sheet" "^1.2.2" - "@emotion/utils" "^1.2.1" - "@emotion/weak-memoize" "^0.3.1" + "@emotion/memoize" "^0.9.0" + "@emotion/sheet" "^1.4.0" + "@emotion/utils" "^1.4.0" + "@emotion/weak-memoize" "^0.4.0" stylis "4.2.0" "@emotion/cache@^10.0.27", "@emotion/cache@^10.0.9": @@ -629,51 +490,51 @@ resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== -"@emotion/hash@^0.9.1": - version "0.9.1" - resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.1.tgz#4ffb0055f7ef676ebc3a5a91fb621393294e2f43" - integrity sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ== +"@emotion/hash@^0.9.2": + version "0.9.2" + resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.2.tgz#ff9221b9f58b4dfe61e619a7788734bd63f6898b" + integrity sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g== -"@emotion/is-prop-valid@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz#23116cf1ed18bfeac910ec6436561ecb1a3885cc" - integrity sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw== +"@emotion/is-prop-valid@^1.3.0": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz#8d5cf1132f836d7adbe42cf0b49df7816fc88240" + integrity sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw== dependencies: - "@emotion/memoize" "^0.8.1" + "@emotion/memoize" "^0.9.0" "@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.1": - version "0.8.1" - resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.1.tgz#c1ddb040429c6d21d38cc945fe75c818cfb68e17" - integrity sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA== +"@emotion/memoize@^0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.9.0.tgz#745969d649977776b43fc7648c556aaa462b4102" + integrity sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ== "@emotion/react@^11.11.1": - version "11.11.3" - resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.11.3.tgz#96b855dc40a2a55f52a72f518a41db4f69c31a25" - integrity sha512-Cnn0kuq4DoONOMcnoVsTOR8E+AdnKFf//6kUWc4LCdnxj31pZWn7rIULd6Y7/Js1PiPHzn7SKCM9vB/jBni8eA== + version "11.13.3" + resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.13.3.tgz#a69d0de2a23f5b48e0acf210416638010e4bd2e4" + integrity sha512-lIsdU6JNrmYfJ5EbUCf4xW1ovy5wKQ2CkPRM4xogziOxH1nXxBSjpC9YqbFAP7circxMfYp+6x676BqWcEiixg== dependencies: "@babel/runtime" "^7.18.3" - "@emotion/babel-plugin" "^11.11.0" - "@emotion/cache" "^11.11.0" - "@emotion/serialize" "^1.1.3" - "@emotion/use-insertion-effect-with-fallbacks" "^1.0.1" - "@emotion/utils" "^1.2.1" - "@emotion/weak-memoize" "^0.3.1" + "@emotion/babel-plugin" "^11.12.0" + "@emotion/cache" "^11.13.0" + "@emotion/serialize" "^1.3.1" + "@emotion/use-insertion-effect-with-fallbacks" "^1.1.0" + "@emotion/utils" "^1.4.0" + "@emotion/weak-memoize" "^0.4.0" hoist-non-react-statics "^3.3.1" -"@emotion/serialize@*", "@emotion/serialize@^1.1.2", "@emotion/serialize@^1.1.3": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.3.tgz#84b77bfcfe3b7bb47d326602f640ccfcacd5ffb0" - integrity sha512-iD4D6QVZFDhcbH0RAG1uVu1CwVLMWUkCvAqqlewO/rxf8+87yIBAlt4+AxMiiKPLs5hFc0owNk/sLLAOROw3cA== +"@emotion/serialize@*", "@emotion/serialize@^1.2.0", "@emotion/serialize@^1.3.0", "@emotion/serialize@^1.3.1": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.3.2.tgz#e1c1a2e90708d5d85d81ccaee2dfeb3cc0cccf7a" + integrity sha512-grVnMvVPK9yUVE6rkKfAJlYZgo0cu3l9iMC77V7DW6E1DUIrU68pSEXRmFZFOFB1QFo57TncmOcvcbMDWsL4yA== dependencies: - "@emotion/hash" "^0.9.1" - "@emotion/memoize" "^0.8.1" - "@emotion/unitless" "^0.8.1" - "@emotion/utils" "^1.2.1" + "@emotion/hash" "^0.9.2" + "@emotion/memoize" "^0.9.0" + "@emotion/unitless" "^0.10.0" + "@emotion/utils" "^1.4.1" csstype "^3.0.2" "@emotion/serialize@^0.11.15", "@emotion/serialize@^0.11.16": @@ -692,22 +553,22 @@ resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-0.9.4.tgz#894374bea39ec30f489bbfc3438192b9774d32e5" integrity sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA== -"@emotion/sheet@^1.2.2": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.2.tgz#d58e788ee27267a14342303e1abb3d508b6d0fec" - integrity sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA== +"@emotion/sheet@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.4.0.tgz#c9299c34d248bc26e82563735f78953d2efca83c" + integrity sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg== "@emotion/styled@^11.11.0": - version "11.11.0" - resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.11.0.tgz#26b75e1b5a1b7a629d7c0a8b708fbf5a9cdce346" - integrity sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng== + version "11.13.0" + resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.13.0.tgz#633fd700db701472c7a5dbef54d6f9834e9fb190" + integrity sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA== dependencies: "@babel/runtime" "^7.18.3" - "@emotion/babel-plugin" "^11.11.0" - "@emotion/is-prop-valid" "^1.2.1" - "@emotion/serialize" "^1.1.2" - "@emotion/use-insertion-effect-with-fallbacks" "^1.0.1" - "@emotion/utils" "^1.2.1" + "@emotion/babel-plugin" "^11.12.0" + "@emotion/is-prop-valid" "^1.3.0" + "@emotion/serialize" "^1.3.0" + "@emotion/use-insertion-effect-with-fallbacks" "^1.1.0" + "@emotion/utils" "^1.4.0" "@emotion/stylis@0.8.5": version "0.8.5" @@ -719,20 +580,20 @@ resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== -"@emotion/unitless@^0.8.1": - version "0.8.1" - resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.1.tgz#182b5a4704ef8ad91bde93f7a860a88fd92c79a3" - integrity sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ== +"@emotion/unitless@^0.10.0": + version "0.10.0" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.10.0.tgz#2af2f7c7e5150f497bdabd848ce7b218a27cf745" + integrity sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg== -"@emotion/use-insertion-effect-with-fallbacks@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz#08de79f54eb3406f9daaf77c76e35313da963963" - integrity sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw== +"@emotion/use-insertion-effect-with-fallbacks@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz#1a818a0b2c481efba0cf34e5ab1e0cb2dcb9dfaf" + integrity sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw== -"@emotion/utils@*", "@emotion/utils@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.1.tgz#bbab58465738d31ae4cb3dbb6fc00a5991f755e4" - integrity sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg== +"@emotion/utils@*", "@emotion/utils@^1.4.0", "@emotion/utils@^1.4.1": + version "1.4.1" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.4.1.tgz#b3adbb43de12ee2149541c4f1337d2eb7774f0ad" + integrity sha512-BymCXzCG3r72VKJxaYVwOXATqXIZ85cuvg0YOUDxMGNrKc1DJRZk8MgV5wyXRyEayIMd4FuXJIUgTBXvDNW5cA== "@emotion/utils@0.11.3": version "0.11.3" @@ -744,15 +605,10 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== -"@emotion/weak-memoize@^0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz#d0fce5d07b0620caa282b5131c297bb60f9d87e6" - integrity sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww== - -"@esbuild/aix-ppc64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz#d1bc06aedb6936b3b6d313bf809a5a40387d2b7f" - integrity sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA== +"@emotion/weak-memoize@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz#5e13fac887f08c44f76b0ccaf3370eb00fec9bb6" + integrity sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg== "@esbuild/aix-ppc64@0.21.5": version "0.21.5" @@ -764,11 +620,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz#51299374de171dbd80bb7d838e1cfce9af36f353" integrity sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ== -"@esbuild/android-arm64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz#7ad65a36cfdb7e0d429c353e00f680d737c2aed4" - integrity sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA== - "@esbuild/android-arm64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" @@ -779,11 +630,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz#58565291a1fe548638adb9c584237449e5e14018" integrity sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw== -"@esbuild/android-arm@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.12.tgz#b0c26536f37776162ca8bde25e42040c203f2824" - integrity sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w== - "@esbuild/android-arm@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" @@ -794,11 +640,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.23.1.tgz#5eb8c652d4c82a2421e3395b808e6d9c42c862ee" integrity sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ== -"@esbuild/android-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.12.tgz#cb13e2211282012194d89bf3bfe7721273473b3d" - integrity sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew== - "@esbuild/android-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" @@ -809,11 +650,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.23.1.tgz#ae19d665d2f06f0f48a6ac9a224b3f672e65d517" integrity sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg== -"@esbuild/darwin-arm64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz#cbee41e988020d4b516e9d9e44dd29200996275e" - integrity sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g== - "@esbuild/darwin-arm64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" @@ -824,11 +660,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz#05b17f91a87e557b468a9c75e9d85ab10c121b16" integrity sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q== -"@esbuild/darwin-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz#e37d9633246d52aecf491ee916ece709f9d5f4cd" - integrity sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A== - "@esbuild/darwin-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" @@ -839,11 +670,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz#c58353b982f4e04f0d022284b8ba2733f5ff0931" integrity sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw== -"@esbuild/freebsd-arm64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz#1ee4d8b682ed363b08af74d1ea2b2b4dbba76487" - integrity sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA== - "@esbuild/freebsd-arm64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" @@ -854,11 +680,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz#f9220dc65f80f03635e1ef96cfad5da1f446f3bc" integrity sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA== -"@esbuild/freebsd-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz#37a693553d42ff77cd7126764b535fb6cc28a11c" - integrity sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg== - "@esbuild/freebsd-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" @@ -869,11 +690,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz#69bd8511fa013b59f0226d1609ac43f7ce489730" integrity sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g== -"@esbuild/linux-arm64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz#be9b145985ec6c57470e0e051d887b09dddb2d4b" - integrity sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA== - "@esbuild/linux-arm64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" @@ -884,11 +700,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz#8050af6d51ddb388c75653ef9871f5ccd8f12383" integrity sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g== -"@esbuild/linux-arm@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz#207ecd982a8db95f7b5279207d0ff2331acf5eef" - integrity sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w== - "@esbuild/linux-arm@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" @@ -899,11 +710,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz#ecaabd1c23b701070484990db9a82f382f99e771" integrity sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ== -"@esbuild/linux-ia32@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz#d0d86b5ca1562523dc284a6723293a52d5860601" - integrity sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA== - "@esbuild/linux-ia32@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" @@ -914,11 +720,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz#3ed2273214178109741c09bd0687098a0243b333" integrity sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ== -"@esbuild/linux-loong64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz#9a37f87fec4b8408e682b528391fa22afd952299" - integrity sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA== - "@esbuild/linux-loong64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" @@ -929,11 +730,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz#a0fdf440b5485c81b0fbb316b08933d217f5d3ac" integrity sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw== -"@esbuild/linux-mips64el@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz#4ddebd4e6eeba20b509d8e74c8e30d8ace0b89ec" - integrity sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w== - "@esbuild/linux-mips64el@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" @@ -944,11 +740,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz#e11a2806346db8375b18f5e104c5a9d4e81807f6" integrity sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q== -"@esbuild/linux-ppc64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz#adb67dadb73656849f63cd522f5ecb351dd8dee8" - integrity sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg== - "@esbuild/linux-ppc64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" @@ -959,11 +750,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz#06a2744c5eaf562b1a90937855b4d6cf7c75ec96" integrity sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw== -"@esbuild/linux-riscv64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz#11bc0698bf0a2abf8727f1c7ace2112612c15adf" - integrity sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg== - "@esbuild/linux-riscv64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" @@ -974,11 +760,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz#65b46a2892fc0d1af4ba342af3fe0fa4a8fe08e7" integrity sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA== -"@esbuild/linux-s390x@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz#e86fb8ffba7c5c92ba91fc3b27ed5a70196c3cc8" - integrity sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg== - "@esbuild/linux-s390x@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" @@ -989,11 +770,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz#e71ea18c70c3f604e241d16e4e5ab193a9785d6f" integrity sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw== -"@esbuild/linux-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz#5f37cfdc705aea687dfe5dfbec086a05acfe9c78" - integrity sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg== - "@esbuild/linux-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" @@ -1004,11 +780,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz#d47f97391e80690d4dfe811a2e7d6927ad9eed24" integrity sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ== -"@esbuild/netbsd-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz#29da566a75324e0d0dd7e47519ba2f7ef168657b" - integrity sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA== - "@esbuild/netbsd-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" @@ -1024,11 +795,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz#05c5a1faf67b9881834758c69f3e51b7dee015d7" integrity sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q== -"@esbuild/openbsd-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz#306c0acbdb5a99c95be98bdd1d47c916e7dc3ff0" - integrity sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw== - "@esbuild/openbsd-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" @@ -1039,11 +805,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz#2e58ae511bacf67d19f9f2dcd9e8c5a93f00c273" integrity sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA== -"@esbuild/sunos-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz#0933eaab9af8b9b2c930236f62aae3fc593faf30" - integrity sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA== - "@esbuild/sunos-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" @@ -1054,11 +815,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz#adb022b959d18d3389ac70769cef5a03d3abd403" integrity sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA== -"@esbuild/win32-arm64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz#773bdbaa1971b36db2f6560088639ccd1e6773ae" - integrity sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A== - "@esbuild/win32-arm64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" @@ -1069,11 +825,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz#84906f50c212b72ec360f48461d43202f4c8b9a2" integrity sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A== -"@esbuild/win32-ia32@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz#000516cad06354cc84a73f0943a4aa690ef6fd67" - integrity sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ== - "@esbuild/win32-ia32@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" @@ -1084,11 +835,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz#5e3eacc515820ff729e90d0cb463183128e82fac" integrity sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ== -"@esbuild/win32-x64@0.19.12": - version "0.19.12" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz#c57c8afbb4054a3ab8317591a0b7320360b444ae" - integrity sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA== - "@esbuild/win32-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" @@ -1106,15 +852,24 @@ dependencies: eslint-visitor-keys "^3.3.0" -"@eslint-community/regexpp@^4.5.1": - version "4.10.1" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.1.tgz#361461e5cb3845d874e61731c11cfedd664d83a0" - integrity sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA== +"@eslint-community/regexpp@^4.11.0", "@eslint-community/regexpp@^4.5.1": + version "4.11.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.1.tgz#a547badfc719eb3e5f4b556325e542fbe9d7a18f" + integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q== -"@eslint-community/regexpp@^4.6.1": - version "4.10.0" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" - integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== +"@eslint/config-array@^0.18.0": + version "0.18.0" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.18.0.tgz#37d8fe656e0d5e3dbaea7758ea56540867fd074d" + integrity sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw== + dependencies: + "@eslint/object-schema" "^2.1.4" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/core@^0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.6.0.tgz#9930b5ba24c406d67a1760e94cdbac616a6eb674" + integrity sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg== "@eslint/eslintrc@^0.4.3": version "0.4.3" @@ -1131,67 +886,43 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" -"@eslint/eslintrc@^2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" - integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== +"@eslint/eslintrc@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.1.0.tgz#dbd3482bfd91efa663cbe7aa1f506839868207b6" + integrity sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.6.0" - globals "^13.19.0" + espree "^10.0.1" + globals "^14.0.0" ignore "^5.2.0" import-fresh "^3.2.1" js-yaml "^4.1.0" minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.56.0": - version "8.56.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.56.0.tgz#ef20350fec605a7f7035a01764731b2de0f3782b" - integrity sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A== - -"@floating-ui/core@^1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.0.tgz#fa41b87812a16bf123122bf945946bae3fdf7fc1" - integrity sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g== - dependencies: - "@floating-ui/utils" "^0.2.1" +"@eslint/js@9.11.1": + version "9.11.1" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.11.1.tgz#8bcb37436f9854b3d9a561440daf916acd940986" + integrity sha512-/qu+TWz8WwPWc7/HcIJKi+c+MOm46GdVaSlTTQcaqaL53+GsoA6MxWp5PtTx48qbSP7ylM1Kn7nhvkugfJvRSA== -"@floating-ui/dom@^1.6.1": - version "1.6.1" - resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.1.tgz#d552e8444f77f2d88534372369b3771dc3a2fa5d" - integrity sha512-iA8qE43/H5iGozC3W0YSnVSW42Vh522yyM1gj+BqRwVsTNOyr231PsXDaV04yT39PsO0QL2QpbI/M0ZaLUQgRQ== - dependencies: - "@floating-ui/core" "^1.6.0" - "@floating-ui/utils" "^0.2.1" +"@eslint/object-schema@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.4.tgz#9e69f8bb4031e11df79e03db09f9dbbae1740843" + integrity sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ== -"@floating-ui/react-dom@^2.0.8": - version "2.0.8" - resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.0.8.tgz#afc24f9756d1b433e1fe0d047c24bd4d9cefaa5d" - integrity sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw== +"@eslint/plugin-kit@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz#8712dccae365d24e9eeecb7b346f85e750ba343d" + integrity sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig== dependencies: - "@floating-ui/dom" "^1.6.1" - -"@floating-ui/utils@^0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.1.tgz#16308cea045f0fc777b6ff20a9f25474dd8293d2" - integrity sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q== + levn "^0.4.1" "@hookform/resolvers@2.9.11": version "2.9.11" resolved "https://registry.yarnpkg.com/@hookform/resolvers/-/resolvers-2.9.11.tgz#9ce96e7746625a89239f68ca57c4f654264c17ef" integrity sha512-bA3aZ79UgcHj7tFV7RlgThzwSSHZgvfbt2wprldRkYBcMopdMvHyO17Wwp/twcJasNFischFfS7oz8Katz8DdQ== -"@humanwhocodes/config-array@^0.11.13": - version "0.11.14" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" - integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== - dependencies: - "@humanwhocodes/object-schema" "^2.0.2" - debug "^4.3.1" - minimatch "^3.0.5" - "@humanwhocodes/config-array@^0.5.0": version "0.5.0" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" @@ -1211,69 +942,84 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== -"@humanwhocodes/object-schema@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917" - integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== +"@humanwhocodes/retry@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.0.tgz#6d86b8cb322660f03d3f0aa94b99bdd8e172d570" + integrity sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew== "@inquirer/confirm@^3.0.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@inquirer/confirm/-/confirm-3.1.0.tgz#526cb71ceab28ba827ea287aa81c969e437017b6" - integrity sha512-nH5mxoTEoqk6WpoBz80GMpDSm9jH5V9AF8n+JZAZfMzd9gHeEG9w1o3KawPRR72lfzpP+QxBHLkOKLEApwhDiQ== + version "3.2.0" + resolved "https://registry.yarnpkg.com/@inquirer/confirm/-/confirm-3.2.0.tgz#6af1284670ea7c7d95e3f1253684cfbd7228ad6a" + integrity sha512-oOIwPs0Dvq5220Z8lGL/6LHRTEr9TgLHmiI99Rj1PJ1p1czTys+olrgBqZk4E2qC0YTzeHprxSQmoHioVdJ7Lw== dependencies: - "@inquirer/core" "^7.1.0" - "@inquirer/type" "^1.2.1" + "@inquirer/core" "^9.1.0" + "@inquirer/type" "^1.5.3" -"@inquirer/core@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@inquirer/core/-/core-7.1.0.tgz#fb78738fd6624de50f027c08d6f24298b72a402b" - integrity sha512-FRCiDiU54XHt5B/D8hX4twwZuzSP244ANHbu3R7CAsJfiv1dUOz24ePBgCZjygEjDUi6BWIJuk4eWLKJ7LATUw== +"@inquirer/core@^9.1.0": + version "9.2.1" + resolved "https://registry.yarnpkg.com/@inquirer/core/-/core-9.2.1.tgz#677c49dee399c9063f31e0c93f0f37bddc67add1" + integrity sha512-F2VBt7W/mwqEU4bL0RnHNZmC/OxzNx9cOYxHqnXX3MP6ruYvZUZAW9imgN9+h/uBT/oP8Gh888J2OZSbjSeWcg== dependencies: - "@inquirer/type" "^1.2.1" + "@inquirer/figures" "^1.0.6" + "@inquirer/type" "^2.0.0" "@types/mute-stream" "^0.0.4" - "@types/node" "^20.11.26" + "@types/node" "^22.5.5" "@types/wrap-ansi" "^3.0.0" ansi-escapes "^4.3.2" - chalk "^4.1.2" - cli-spinners "^2.9.2" cli-width "^4.1.0" - figures "^3.2.0" mute-stream "^1.0.0" - run-async "^3.0.0" signal-exit "^4.1.0" strip-ansi "^6.0.1" wrap-ansi "^6.2.0" + yoctocolors-cjs "^2.1.2" -"@inquirer/type@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-1.2.1.tgz#fbc7ab3a2e5050d0c150642d5e8f5e88faa066b8" - integrity sha512-xwMfkPAxeo8Ji/IxfUSqzRi0/+F2GIqJmpc5/thelgMGsjNZcjDDRBO9TLXT1s/hdx/mK5QbVIvgoLIFgXhTMQ== +"@inquirer/figures@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@inquirer/figures/-/figures-1.0.6.tgz#1a562f916da39888c56b65b78259d2261bd7d40b" + integrity sha512-yfZzps3Cso2UbM7WlxKwZQh2Hs6plrbjs1QnzQDZhK2DgyCo6D8AaHps9olkNcUFlcYERMqU3uJSp1gmy3s/qQ== + +"@inquirer/type@^1.5.3": + version "1.5.5" + resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-1.5.5.tgz#303ea04ce7ad2e585b921b662b3be36ef7b4f09b" + integrity sha512-MzICLu4yS7V8AA61sANROZ9vT1H3ooca5dSmI1FjZkzq7o/koMsRfQSzRtFo+F3Ao4Sf1C0bpLKejpKB/+j6MA== + dependencies: + mute-stream "^1.0.0" + +"@inquirer/type@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-2.0.0.tgz#08fa513dca2cb6264fe1b0a2fabade051444e3f6" + integrity sha512-XvJRx+2KR3YXyYtPUUy+qd9i7p+GO9Ko6VIIpWlBrpWwXDv8WLFeHTxz35CfQFUiBMLXlGHhGzys7lqit9gWag== + dependencies: + mute-stream "^1.0.0" + +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" "@istanbuljs/schema@^0.1.2": version "0.1.3" resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== -"@joshwooding/vite-plugin-react-docgen-typescript@0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@joshwooding/vite-plugin-react-docgen-typescript/-/vite-plugin-react-docgen-typescript-0.3.1.tgz#a733e7fc90c00ce694058d3af034b9f63d88cddd" - integrity sha512-pdoMZ9QaPnVlSM+SdU/wgg0nyD/8wQ7y90ttO2CMCyrrm7RxveYIJ5eNfjPaoMFqW41LZra7QO9j+xV4Y18Glw== +"@joshwooding/vite-plugin-react-docgen-typescript@0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@joshwooding/vite-plugin-react-docgen-typescript/-/vite-plugin-react-docgen-typescript-0.3.0.tgz#67599fca260c2eafdaf234a944f9d471e6d53b08" + integrity sha512-2D6y7fNvFmsLmRt6UCOFJPvFoPMJGT0Uh1Wg0RaigUp7kdQPs6yYn8Dmx6GZkOH/NW0yMTwRz/p0SRMMRo50vA== dependencies: glob "^7.2.0" glob-promise "^4.2.0" magic-string "^0.27.0" react-docgen-typescript "^2.2.2" -"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" - integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== - dependencies: - "@jridgewell/set-array" "^1.0.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" - -"@jridgewell/gen-mapping@^0.3.5": +"@jridgewell/gen-mapping@^0.3.2", "@jridgewell/gen-mapping@^0.3.5": version "0.3.5" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== @@ -1282,47 +1028,21 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.24" -"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" - integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== - -"@jridgewell/set-array@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" - integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== "@jridgewell/set-array@^1.2.1": version "1.2.1" resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15": - version "1.4.15" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== - -"@jridgewell/sourcemap-codec@^1.5.0": +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": version "1.5.0" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== -"@jridgewell/trace-mapping@0.3.9": - version "0.3.9" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" - integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" - -"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.22" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz#72a621e5de59f5f1ef792d0793a82ee20f645e4c" - integrity sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - "@jridgewell/trace-mapping@^0.3.23", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" @@ -1331,26 +1051,6 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@jsonjoy.com/base64@^1.1.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@jsonjoy.com/base64/-/base64-1.1.2.tgz#cf8ea9dcb849b81c95f14fc0aaa151c6b54d2578" - integrity sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA== - -"@jsonjoy.com/json-pack@^1.0.3": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@jsonjoy.com/json-pack/-/json-pack-1.0.4.tgz#ab59c642a2e5368e8bcfd815d817143d4f3035d0" - integrity sha512-aOcSN4MeAtFROysrbqG137b7gaDDSmVrl5mpo6sT/w+kcXpWnzhMjmY/Fh/sDx26NBxyIE7MB1seqLeCAzy9Sg== - dependencies: - "@jsonjoy.com/base64" "^1.1.1" - "@jsonjoy.com/util" "^1.1.2" - hyperdyperid "^1.2.0" - thingies "^1.20.0" - -"@jsonjoy.com/util@^1.1.2": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@jsonjoy.com/util/-/util-1.1.3.tgz#75b1c3cf21b70e665789d1ad3eabeff8b7fd1429" - integrity sha512-g//kkF4kOwUjemValCtOc/xiYzmwMRmWq3Bn+YnzOzuZLHq2PpMOxxIayN3cKbo7Ko2Np65t6D9H81IvXbXhqg== - "@kwsites/file-exists@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@kwsites/file-exists/-/file-exists-1.1.1.tgz#ad1efcac13e1987d8dbaf235ef3be5b0d96faa99" @@ -1364,15 +1064,9 @@ integrity sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw== "@linode/design-language-system@^2.6.1": - version "2.6.1" - resolved "https://registry.yarnpkg.com/@linode/design-language-system/-/design-language-system-2.6.1.tgz#dac21f50d5087eaa273f76a3b3542f6160ee6076" - integrity sha512-cnj8X8s5ykxCCrHOwkEkroz/b1od5NTvidDDuyy5147Hqo7V5BWtdS+gLDqdvTKtYO0ybrORXRCD4y9qHf88HA== - dependencies: - "@tokens-studio/sd-transforms" "1.2.0" - react "^17.0.2" - react-copy-to-clipboard "^5.1.0" - react-dom "^17.0.2" - style-dictionary "4.0.1" + version "2.7.1" + resolved "https://registry.yarnpkg.com/@linode/design-language-system/-/design-language-system-2.7.1.tgz#03ee024529a2543249ad986bd7ab85c39e8aa797" + integrity sha512-rrQbFOJD/tG+8Xz7lt3YO6E6sIPSeHGW8nRSqQYLQrw2hJssN1wdGTK92Uluyy+msJQkXSenkTmDf2l1iOGTrQ== "@linode/eslint-plugin-cloud-manager@^0.0.5": version "0.0.5" @@ -1391,97 +1085,60 @@ dependencies: "@types/mdx" "^2.0.0" -"@mswjs/cookies@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@mswjs/cookies/-/cookies-1.1.0.tgz#1528eb43630caf83a1d75d5332b30e75e9bb1b5b" - integrity sha512-0ZcCVQxifZmhwNBoQIrystCb+2sWBY2Zw8lpfJBPCHGCA/HWqehITeCRVIv4VMy8MPlaHo2w2pTHFV2pFfqKPw== - -"@mswjs/interceptors@^0.25.16": - version "0.25.16" - resolved "https://registry.yarnpkg.com/@mswjs/interceptors/-/interceptors-0.25.16.tgz#7955fbb8da479bc691df117dd4c8d889e507ecc2" - integrity sha512-8QC8JyKztvoGAdPgyZy49c9vSHHAZjHagwl4RY9E8carULk8ym3iTaiawrT1YoLF/qb449h48f71XDPgkUSOUg== +"@mswjs/interceptors@^0.35.8": + version "0.35.8" + resolved "https://registry.yarnpkg.com/@mswjs/interceptors/-/interceptors-0.35.8.tgz#f36e5907e05593e33037ef4519aac7815fa3509f" + integrity sha512-PFfqpHplKa7KMdoQdj5td03uG05VK2Ng1dG0sP4pT9h0dGSX2v9txYt/AnrzPb/vAmfyBBC0NQV7VaBEX+efgQ== dependencies: "@open-draft/deferred-promise" "^2.2.0" "@open-draft/logger" "^0.3.0" "@open-draft/until" "^2.0.0" is-node-process "^1.2.0" - outvariant "^1.2.1" + outvariant "^1.4.3" strict-event-emitter "^0.5.1" -"@mui/base@5.0.0-beta.36": - version "5.0.0-beta.36" - resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.36.tgz#29ca2de9d387f6d3943b6f18a84415c43e5f206c" - integrity sha512-6A8fYiXgjqTO6pgj31Hc8wm1M3rFYCxDRh09dBVk0L0W4cb2lnurRJa3cAyic6hHY+we1S58OdGYRbKmOsDpGQ== - dependencies: - "@babel/runtime" "^7.23.9" - "@floating-ui/react-dom" "^2.0.8" - "@mui/types" "^7.2.13" - "@mui/utils" "^5.15.9" - "@popperjs/core" "^2.11.8" - clsx "^2.1.0" - prop-types "^15.8.1" - -"@mui/core-downloads-tracker@^5.15.9": - version "5.15.9" - resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.9.tgz#c29138c70cc0fb49cd909c29beef3fb0647e5af7" - integrity sha512-CSDpVevGaxsvMkiYBZ8ztki1z/eT0mM2MqUT21eCRiMz3DU4zQw5rXG5ML/yTuJF9Z2Wv9SliIeaRAuSR/9Nig== +"@mui/core-downloads-tracker@^5.16.7": + version "5.16.7" + resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.7.tgz#182a325a520f7ebd75de051fceabfc0314cfd004" + integrity sha512-RtsCt4Geed2/v74sbihWzzRs+HsIQCfclHeORh5Ynu2fS4icIKozcSubwuG7vtzq2uW3fOR1zITSP84TNt2GoQ== "@mui/icons-material@^5.14.7": - version "5.15.9" - resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.15.9.tgz#8d11839d35cf3cfd62df40934d8e9485f66be620" - integrity sha512-6tLQoM6RylQuDnHR6qQay0G0pJgKmrhn5MIm0IfrwtmSO8eV5iUFR+nNUTXsWa24gt7ZbIKnJ962UlYaeXa4bg== + version "5.16.7" + resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.16.7.tgz#e27f901af792065efc9f3d75d74a66af7529a10a" + integrity sha512-UrGwDJCXEszbDI7yV047BYU5A28eGJ79keTCP4cc74WyncuVrnurlmIRxaHL8YK+LI1Kzq+/JM52IAkNnv4u+Q== dependencies: "@babel/runtime" "^7.23.9" "@mui/material@^5.14.7": - version "5.15.9" - resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.15.9.tgz#4d6a4aee002c6a2d0e174e08c6d23245c18dd828" - integrity sha512-kbHTZDcFmN8GHKzRpImUEl9AJfFWI/0Kl+DsYVT3kHzQWUuHiKm3uHXR1RCOqr7H8IgHFPdbxItmCSQ/mj7zgg== + version "5.16.7" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.16.7.tgz#6e814e2eefdaf065a769cecf549c3569e107a50b" + integrity sha512-cwwVQxBhK60OIOqZOVLFt55t01zmarKJiJUWbk0+8s/Ix5IaUzAShqlJchxsIQ4mSrWqgcKCCXKtIlG5H+/Jmg== dependencies: "@babel/runtime" "^7.23.9" - "@mui/base" "5.0.0-beta.36" - "@mui/core-downloads-tracker" "^5.15.9" - "@mui/system" "^5.15.9" - "@mui/types" "^7.2.13" - "@mui/utils" "^5.15.9" + "@mui/core-downloads-tracker" "^5.16.7" + "@mui/system" "^5.16.7" + "@mui/types" "^7.2.15" + "@mui/utils" "^5.16.6" + "@popperjs/core" "^2.11.8" "@types/react-transition-group" "^4.4.10" clsx "^2.1.0" csstype "^3.1.3" prop-types "^15.8.1" - react-is "^18.2.0" + react-is "^18.3.1" react-transition-group "^4.4.5" -"@mui/private-theming@^5.15.9": - version "5.15.9" - resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.15.9.tgz#3ea3514ed2f6bf68541dbe9206665a82cd89cb01" - integrity sha512-/aMJlDOxOTAXyp4F2rIukW1O0anodAMCkv1DfBh/z9vaKHY3bd5fFf42wmP+0GRmwMinC5aWPpNfHXOED1fEtg== - dependencies: - "@babel/runtime" "^7.23.9" - "@mui/utils" "^5.15.9" - prop-types "^15.8.1" - "@mui/private-theming@^5.16.6": version "5.16.6" - resolved "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.6.tgz#547671e7ae3f86b68d1289a0b90af04dfcc1c8c9" + resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.16.6.tgz#547671e7ae3f86b68d1289a0b90af04dfcc1c8c9" integrity sha512-rAk+Rh8Clg7Cd7shZhyt2HGTTE5wYKNSJ5sspf28Fqm/PZ69Er9o6KX25g03/FG2dfpg5GCwZh/xOojiTfm3hw== dependencies: "@babel/runtime" "^7.23.9" "@mui/utils" "^5.16.6" prop-types "^15.8.1" -"@mui/styled-engine@^5.15.9": - version "5.15.9" - resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.15.9.tgz#444605039ec3fe456bdd5d5cb94330183be62b91" - integrity sha512-NRKtYkL5PZDH7dEmaLEIiipd3mxNnQSO+Yo8rFNBNptY8wzQnQ+VjayTq39qH7Sast5cwHKYFusUrQyD+SS4Og== - dependencies: - "@babel/runtime" "^7.23.9" - "@emotion/cache" "^11.11.0" - csstype "^3.1.3" - prop-types "^15.8.1" - "@mui/styled-engine@^5.16.6": version "5.16.6" - resolved "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.16.6.tgz#60110c106dd482dfdb7e2aa94fd6490a0a3f8852" + resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.16.6.tgz#60110c106dd482dfdb7e2aa94fd6490a0a3f8852" integrity sha512-zaThmS67ZmtHSWToTiHslbI8jwrmITcN93LQaR2lKArbvS7Z3iLkwRoiikNWutx9MBs8Q6okKvbZq1RQYB3v7g== dependencies: "@babel/runtime" "^7.23.9" @@ -1489,24 +1146,10 @@ csstype "^3.1.3" prop-types "^15.8.1" -"@mui/system@^5.15.9": - version "5.15.9" - resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.15.9.tgz#8a34ac0ab133af2550cc7ab980a35174142fd265" - integrity sha512-SxkaaZ8jsnIJ77bBXttfG//LUf6nTfOcaOuIgItqfHv60ZCQy/Hu7moaob35kBb+guxVJnoSZ+7vQJrA/E7pKg== - dependencies: - "@babel/runtime" "^7.23.9" - "@mui/private-theming" "^5.15.9" - "@mui/styled-engine" "^5.15.9" - "@mui/types" "^7.2.13" - "@mui/utils" "^5.15.9" - clsx "^2.1.0" - csstype "^3.1.3" - prop-types "^15.8.1" - -"@mui/system@^5.16.5": - version "5.16.6" - resolved "https://registry.npmjs.org/@mui/system/-/system-5.16.6.tgz#2dabe63d2e45816ce611c40d6e3f79b9c2ccbcd7" - integrity sha512-5xgyJjBIMPw8HIaZpfbGAaFYPwImQn7Nyh+wwKWhvkoIeDosQ1ZMVrbTclefi7G8hNmqhip04duYwYpbBFnBgw== +"@mui/system@^5.16.7": + version "5.16.7" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.16.7.tgz#4583ca5bf3b38942e02c15a1e622ba869ac51393" + integrity sha512-Jncvs/r/d/itkxh7O7opOunTqbbSSzMTHzZkNLM+FjAOg+cYAZHrPDlYe1ZGKUYORwwb2XexlWnpZp0kZ4AHuA== dependencies: "@babel/runtime" "^7.23.9" "@mui/private-theming" "^5.16.6" @@ -1517,29 +1160,14 @@ csstype "^3.1.3" prop-types "^15.8.1" -"@mui/types@^7.2.13": - version "7.2.13" - resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.13.tgz#d1584912942f9dc042441ecc2d1452be39c666b8" - integrity sha512-qP9OgacN62s+l8rdDhSFRe05HWtLLJ5TGclC9I1+tQngbssu0m2dmFZs+Px53AcOs9fD7TbYd4gc9AXzVqO/+g== - "@mui/types@^7.2.15": - version "7.2.15" - resolved "https://registry.npmjs.org/@mui/types/-/types-7.2.15.tgz#dadd232fe9a70be0d526630675dff3b110f30b53" - integrity sha512-nbo7yPhtKJkdf9kcVOF8JZHPZTmqXjJ/tI0bdWgHg5tp9AnIN4Y7f7wm9T+0SyGYJk76+GYZ8Q5XaTYAsUHN0Q== - -"@mui/utils@^5.15.9": - version "5.15.9" - resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.15.9.tgz#2bdf925e274d87cbe90c14eb52d0835318205e86" - integrity sha512-yDYfr61bCYUz1QtwvpqYy/3687Z8/nS4zv7lv/ih/6ZFGMl1iolEvxRmR84v2lOYxlds+kq1IVYbXxDKh8Z9sg== - dependencies: - "@babel/runtime" "^7.23.9" - "@types/prop-types" "^15.7.11" - prop-types "^15.8.1" - react-is "^18.2.0" + version "7.2.17" + resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.17.tgz#329826062d4079de5ea2b97007575cebbba1fdbc" + integrity sha512-oyumoJgB6jDV8JFzRqjBo2daUuHpzDjoO/e3IrRhhHo/FxJlaVhET6mcNrKHUq2E+R+q3ql0qAtvQ4rfWHhAeQ== -"@mui/utils@^5.16.5", "@mui/utils@^5.16.6": +"@mui/utils@^5.16.6": version "5.16.6" - resolved "https://registry.npmjs.org/@mui/utils/-/utils-5.16.6.tgz#905875bbc58d3dcc24531c3314a6807aba22a711" + resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.16.6.tgz#905875bbc58d3dcc24531c3314a6807aba22a711" integrity sha512-tWiQqlhxAt3KENNiSRL+DIn9H5xNVK6Jjf70x3PnfQPz1MPBdh7yyIcAyVBT9xiw7hP3SomRhPR7hzBMBCjqEA== dependencies: "@babel/runtime" "^7.23.9" @@ -1550,18 +1178,26 @@ react-is "^18.3.1" "@mui/x-date-pickers@^7.12.0": - version "7.12.0" - resolved "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.12.0.tgz#189acc9e3d2a5be260fab9faf5e6add516e59b09" - integrity sha512-WU5C7QNfSpJ9cP8vl2sY7q35NW+0TUMgEy+sl98fcPhLckq3cgV1wnVxoZnQZ3BxVQAtx+7ag/MpefU03vJcVw== + version "7.18.0" + resolved "https://registry.yarnpkg.com/@mui/x-date-pickers/-/x-date-pickers-7.18.0.tgz#264158195aeeaf32a00519718f6c67c165b06711" + integrity sha512-12tXIoMj9vpS8fS/bS3kWPCoVrH38vNGCxgplI0vOnUrN9rJuYJz3agLPJe1S0xciTw+9W8ZSe3soaW+owoz1Q== dependencies: - "@babel/runtime" "^7.25.0" - "@mui/system" "^5.16.5" - "@mui/utils" "^5.16.5" - "@types/react-transition-group" "^4.4.10" + "@babel/runtime" "^7.25.6" + "@mui/utils" "^5.16.6" + "@mui/x-internals" "7.18.0" + "@types/react-transition-group" "^4.4.11" clsx "^2.1.1" prop-types "^15.8.1" react-transition-group "^4.4.5" +"@mui/x-internals@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@mui/x-internals/-/x-internals-7.18.0.tgz#f079968d4f7ea93e63be9faf6ba8558d6f12923b" + integrity sha512-lzCHOWIR0cAIY1bGrWSprYerahbnH5C31ql/2OWCEjcngL2NAV1M6oKI2Vp4HheqzJ822c60UyWyapvyjSzY/A== + dependencies: + "@babel/runtime" "^7.25.6" + "@mui/utils" "^5.16.6" + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -1601,6 +1237,15 @@ resolved "https://registry.yarnpkg.com/@open-draft/until/-/until-2.1.0.tgz#0acf32f470af2ceaf47f095cdecd40d68666efda" integrity sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg== +"@paypal/accelerated-checkout-loader@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@paypal/accelerated-checkout-loader/-/accelerated-checkout-loader-1.1.0.tgz#8e0e939d4b04dfbd2c8a7a22287eb753eedcaf5a" + integrity sha512-S2KkIpq15VnxYyI0tycvfYiNsqdsg2a92El2huYUVLsWnBbubl8toYK8khaP5nnxZ0MGl9mEB9Y9axmfOw2Yvg== + dependencies: + "@braintree/asset-loader" "2.0.0" + envify "^4.1.0" + typescript "^4.6.4" + "@paypal/paypal-js@^5.1.6": version "5.1.6" resolved "https://registry.yarnpkg.com/@paypal/paypal-js/-/paypal-js-5.1.6.tgz#8ec59f4cc016addb3de41511f70950fd0359ffdb" @@ -1617,9 +1262,9 @@ "@paypal/sdk-constants" "^1.0.122" "@paypal/sdk-constants@^1.0.122": - version "1.0.139" - resolved "https://registry.yarnpkg.com/@paypal/sdk-constants/-/sdk-constants-1.0.139.tgz#b8918d26ae0feecf38ba9ad367243165af57818c" - integrity sha512-rCRL2Ys5OAbSCLcJjaFlunJWrgY92UzGNrHb7wYnr//sEXSRJx1n8Na/jxSxiFBmp4GGa/TbgodJvM80fx1iyQ== + version "1.0.149" + resolved "https://registry.yarnpkg.com/@paypal/sdk-constants/-/sdk-constants-1.0.149.tgz#7060213be1c892fb3e9656ba0108a5584cafeac8" + integrity sha512-oHdaRg2fP9LINMDJ8fMTtRvvW2QJVifoEoq7YPOP5Sk50edWX6tyATZTfgSnJmLHHq3OE6OF1aKa7hz09frVxw== dependencies: hi-base32 "^0.5.0" @@ -1636,30 +1281,15 @@ integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== "@polka/url@^1.0.0-next.24": - version "1.0.0-next.24" - resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.24.tgz#58601079e11784d20f82d0585865bb42305c4df3" - integrity sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ== + version "1.0.0-next.28" + resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.28.tgz#d45e01c4a56f143ee69c54dd6b12eade9e270a73" + integrity sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw== "@popperjs/core@^2.11.8": version "2.11.8" resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== -"@radix-ui/react-compose-refs@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz#7ed868b66946aa6030e580b1ffca386dd4d21989" - integrity sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw== - dependencies: - "@babel/runtime" "^7.13.10" - -"@radix-ui/react-slot@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.2.tgz#a9ff4423eade67f501ffb32ec22064bc9d3099ab" - integrity sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/react-compose-refs" "1.0.1" - "@reach/auto-id@0.10.5": version "0.10.5" resolved "https://registry.yarnpkg.com/@reach/auto-id/-/auto-id-0.10.5.tgz#fa78c71ce2f565ebed1ad91a8d9a685176d23c48" @@ -1697,333 +1327,199 @@ warning "^4.0.3" "@rollup/pluginutils@^5.0.2", "@rollup/pluginutils@^5.0.4": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.0.tgz#7e53eddc8c7f483a4ad0b94afb1f7f5fd3c771e0" - integrity sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g== + version "5.1.2" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.2.tgz#d3bc9f0fea4fd4086aaac6aa102f3fa587ce8bd9" + integrity sha512-/FIdS3PyZ39bjZlwqFnWqCOVnW7o963LtKMwQOD0NhQqw22gSr2YY1afu3FxRip4ZCZNsD5jq6Aaz6QV3D/Njw== dependencies: "@types/estree" "^1.0.0" estree-walker "^2.0.2" picomatch "^2.3.1" -"@rollup/rollup-android-arm-eabi@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.0.tgz#d941173f82f9b041c61b0dc1a2a91dcd06e4b31e" - integrity sha512-WTWD8PfoSAJ+qL87lE7votj3syLavxunWhzCnx3XFxFiI/BA/r3X7MUM8dVrH8rb2r4AiO8jJsr3ZjdaftmnfA== - -"@rollup/rollup-android-arm-eabi@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.1.tgz#c3a7938551273a2b72820cf5d22e54cf41dc206e" - integrity sha512-2thheikVEuU7ZxFXubPDOtspKn1x0yqaYQwvALVtEcvFhMifPADBrgRPyHV0TF3b+9BgvgjgagVyvA/UqPZHmg== - -"@rollup/rollup-android-arm-eabi@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.6.tgz#66b8d9cb2b3a474d115500f9ebaf43e2126fe496" - integrity sha512-MVNXSSYN6QXOulbHpLMKYi60ppyO13W9my1qogeiAqtjb2yR4LSmfU2+POvDkLzhjYLXz9Rf9+9a3zFHW1Lecg== - -"@rollup/rollup-android-arm64@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.0.tgz#7e7157c8543215245ceffc445134d9e843ba51c0" - integrity sha512-a1sR2zSK1B4eYkiZu17ZUZhmUQcKjk2/j9Me2IDjk1GHW7LB5Z35LEzj9iJch6gtUfsnvZs1ZNyDW2oZSThrkA== - -"@rollup/rollup-android-arm64@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.1.tgz#fa3693e4674027702c42fcbbb86bbd0c635fd3b9" - integrity sha512-t1lLYn4V9WgnIFHXy1d2Di/7gyzBWS8G5pQSXdZqfrdCGTwi1VasRMSS81DTYb+avDs/Zz4A6dzERki5oRYz1g== - -"@rollup/rollup-android-arm64@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.6.tgz#46327d5b86420d2307946bec1535fdf00356e47d" - integrity sha512-T14aNLpqJ5wzKNf5jEDpv5zgyIqcpn1MlwCrUXLrwoADr2RkWA0vOWP4XxbO9aiO3dvMCQICZdKeDrFl7UMClw== - -"@rollup/rollup-darwin-arm64@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.0.tgz#f0a18a4fc8dc6eb1e94a51fa2adb22876f477947" - integrity sha512-zOnKWLgDld/svhKO5PD9ozmL6roy5OQ5T4ThvdYZLpiOhEGY+dp2NwUmxK0Ld91LrbjrvtNAE0ERBwjqhZTRAA== - -"@rollup/rollup-darwin-arm64@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.1.tgz#e19922f4ac1e4552a230ff8f49d5688c5c07d284" - integrity sha512-AH/wNWSEEHvs6t4iJ3RANxW5ZCK3fUnmf0gyMxWCesY1AlUj8jY7GC+rQE4wd3gwmZ9XDOpL0kcFnCjtN7FXlA== - -"@rollup/rollup-darwin-arm64@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.6.tgz#166987224d2f8b1e2fd28ee90c447d52271d5e90" - integrity sha512-CqNNAyhRkTbo8VVZ5R85X73H3R5NX9ONnKbXuHisGWC0qRbTTxnF1U4V9NafzJbgGM0sHZpdO83pLPzq8uOZFw== - -"@rollup/rollup-darwin-x64@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.0.tgz#34b7867613e5cc42d2b85ddc0424228cc33b43f0" - integrity sha512-7doS8br0xAkg48SKE2QNtMSFPFUlRdw9+votl27MvT46vo44ATBmdZdGysOevNELmZlfd+NEa0UYOA8f01WSrg== - -"@rollup/rollup-darwin-x64@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.1.tgz#897f8d47b115ea84692a29cf2366899499d4d915" - integrity sha512-dO0BIz/+5ZdkLZrVgQrDdW7m2RkrLwYTh2YMFG9IpBtlC1x1NPNSXkfczhZieOlOLEqgXOFH3wYHB7PmBtf+Bg== - -"@rollup/rollup-darwin-x64@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.6.tgz#a2e6e096f74ccea6e2f174454c26aef6bcdd1274" - integrity sha512-zRDtdJuRvA1dc9Mp6BWYqAsU5oeLixdfUvkTHuiYOHwqYuQ4YgSmi6+/lPvSsqc/I0Omw3DdICx4Tfacdzmhog== - -"@rollup/rollup-linux-arm-gnueabihf@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.0.tgz#422b19ff9ae02b05d3395183d1d43b38c7c8be0b" - integrity sha512-pWJsfQjNWNGsoCq53KjMtwdJDmh/6NubwQcz52aEwLEuvx08bzcy6tOUuawAOncPnxz/3siRtd8hiQ32G1y8VA== - -"@rollup/rollup-linux-arm-gnueabihf@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.1.tgz#7d1e2a542f3a5744f5c24320067bd5af99ec9d62" - integrity sha512-sWWgdQ1fq+XKrlda8PsMCfut8caFwZBmhYeoehJ05FdI0YZXk6ZyUjWLrIgbR/VgiGycrFKMMgp7eJ69HOF2pQ== - -"@rollup/rollup-linux-arm-gnueabihf@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.6.tgz#09fcd4c55a2d6160c5865fec708a8e5287f30515" - integrity sha512-oNk8YXDDnNyG4qlNb6is1ojTOGL/tRhbbKeE/YuccItzerEZT68Z9gHrY3ROh7axDc974+zYAPxK5SH0j/G+QQ== - -"@rollup/rollup-linux-arm-musleabihf@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.0.tgz#568aa29195ef6fc57ec6ed3f518923764406a8ee" - integrity sha512-efRIANsz3UHZrnZXuEvxS9LoCOWMGD1rweciD6uJQIx2myN3a8Im1FafZBzh7zk1RJ6oKcR16dU3UPldaKd83w== - -"@rollup/rollup-linux-arm-musleabihf@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.1.tgz#88bec1c9df85fc5e24d49f783e19934717dd69b5" - integrity sha512-9OIiSuj5EsYQlmwhmFRA0LRO0dRRjdCVZA3hnmZe1rEwRk11Jy3ECGGq3a7RrVEZ0/pCsYWx8jG3IvcrJ6RCew== - -"@rollup/rollup-linux-arm64-gnu@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.0.tgz#22309c8bcba9a73114f69165c72bc94b2fbec085" - integrity sha512-ZrPhydkTVhyeGTW94WJ8pnl1uroqVHM3j3hjdquwAcWnmivjAwOYjTEAuEDeJvGX7xv3Z9GAvrBkEzCgHq9U1w== - -"@rollup/rollup-linux-arm64-gnu@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.1.tgz#6dc60f0fe7bd49ed07a2d4d9eab15e671b3bd59d" - integrity sha512-0kuAkRK4MeIUbzQYu63NrJmfoUVicajoRAL1bpwdYIYRcs57iyIV9NLcuyDyDXE2GiZCL4uhKSYAnyWpjZkWow== - -"@rollup/rollup-linux-arm64-gnu@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.6.tgz#19a3c0b6315c747ca9acf86e9b710cc2440f83c9" - integrity sha512-Z3O60yxPtuCYobrtzjo0wlmvDdx2qZfeAWTyfOjEDqd08kthDKexLpV97KfAeUXPosENKd8uyJMRDfFMxcYkDQ== - -"@rollup/rollup-linux-arm64-musl@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.0.tgz#c93c388af6d33f082894b8a60839d7265b2b9bc5" - integrity sha512-cfaupqd+UEFeURmqNP2eEvXqgbSox/LHOyN9/d2pSdV8xTrjdg3NgOFJCtc1vQ/jEke1qD0IejbBfxleBPHnPw== - -"@rollup/rollup-linux-arm64-musl@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.1.tgz#a03b78775c129e8333aca9e1e420e8e217ee99b9" - integrity sha512-/6dYC9fZtfEY0vozpc5bx1RP4VrtEOhNQGb0HwvYNwXD1BBbwQ5cKIbUVVU7G2d5WRE90NfB922elN8ASXAJEA== - -"@rollup/rollup-linux-arm64-musl@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.6.tgz#94aaf95fdaf2ad9335983a4552759f98e6b2e850" - integrity sha512-gpiG0qQJNdYEVad+1iAsGAbgAnZ8j07FapmnIAQgODKcOTjLEWM9sRb+MbQyVsYCnA0Im6M6QIq6ax7liws6eQ== - -"@rollup/rollup-linux-powerpc64le-gnu@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.0.tgz#493c5e19e395cf3c6bd860c7139c8a903dea72b4" - integrity sha512-ZKPan1/RvAhrUylwBXC9t7B2hXdpb/ufeu22pG2psV7RN8roOfGurEghw1ySmX/CmDDHNTDDjY3lo9hRlgtaHg== - -"@rollup/rollup-linux-powerpc64le-gnu@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.1.tgz#ee3810647faf2c105a5a4e71260bb90b96bf87bc" - integrity sha512-ltUWy+sHeAh3YZ91NUsV4Xg3uBXAlscQe8ZOXRCVAKLsivGuJsrkawYPUEyCV3DYa9urgJugMLn8Z3Z/6CeyRQ== - -"@rollup/rollup-linux-riscv64-gnu@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.0.tgz#a2eab4346fbe5909165ce99adb935ba30c9fb444" - integrity sha512-H1eRaCwd5E8eS8leiS+o/NqMdljkcb1d6r2h4fKSsCXQilLKArq6WS7XBLDu80Yz+nMqHVFDquwcVrQmGr28rg== - -"@rollup/rollup-linux-riscv64-gnu@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.1.tgz#385d76a088c27db8054d9f3f28d64d89294f838e" - integrity sha512-BggMndzI7Tlv4/abrgLwa/dxNEMn2gC61DCLrTzw8LkpSKel4o+O+gtjbnkevZ18SKkeN3ihRGPuBxjaetWzWg== - -"@rollup/rollup-linux-riscv64-gnu@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.6.tgz#160510e63f4b12618af4013bddf1761cf9fc9880" - integrity sha512-+uCOcvVmFUYvVDr27aiyun9WgZk0tXe7ThuzoUTAukZJOwS5MrGbmSlNOhx1j80GdpqbOty05XqSl5w4dQvcOA== - -"@rollup/rollup-linux-s390x-gnu@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.0.tgz#0bc49a79db4345d78d757bb1b05e73a1b42fa5c3" - integrity sha512-zJ4hA+3b5tu8u7L58CCSI0A9N1vkfwPhWd/puGXwtZlsB5bTkwDNW/+JCU84+3QYmKpLi+XvHdmrlwUwDA6kqw== - -"@rollup/rollup-linux-s390x-gnu@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.1.tgz#daa2b62a6e6f737ebef6700a12a93c9764e18583" - integrity sha512-z/9rtlGd/OMv+gb1mNSjElasMf9yXusAxnRDrBaYB+eS1shFm6/4/xDH1SAISO5729fFKUkJ88TkGPRUh8WSAA== - -"@rollup/rollup-linux-x64-gnu@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.0.tgz#4fd36a6a41f3406d8693321b13d4f9b7658dd4b9" - integrity sha512-e2hrvElFIh6kW/UNBQK/kzqMNY5mO+67YtEh9OA65RM5IJXYTWiXjX6fjIiPaqOkBthYF1EqgiZ6OXKcQsM0hg== - -"@rollup/rollup-linux-x64-gnu@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.1.tgz#790ae96118cc892464e9f10da358c0c8a6b9acdd" - integrity sha512-kXQVcWqDcDKw0S2E0TmhlTLlUgAmMVqPrJZR+KpH/1ZaZhLSl23GZpQVmawBQGVhyP5WXIsIQ/zqbDBBYmxm5w== - -"@rollup/rollup-linux-x64-gnu@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.6.tgz#5ac5d068ce0726bd0a96ca260d5bd93721c0cb98" - integrity sha512-HUNqM32dGzfBKuaDUBqFB7tP6VMN74eLZ33Q9Y1TBqRDn+qDonkAUyKWwF9BR9unV7QUzffLnz9GrnKvMqC/fw== - -"@rollup/rollup-linux-x64-musl@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.0.tgz#10ebb13bd4469cbad1a5d9b073bd27ec8a886200" - integrity sha512-1vvmgDdUSebVGXWX2lIcgRebqfQSff0hMEkLJyakQ9JQUbLDkEaMsPTLOmyccyC6IJ/l3FZuJbmrBw/u0A0uCQ== - -"@rollup/rollup-linux-x64-musl@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.1.tgz#d613147f7ac15fafe2a0b6249e8484e161ca2847" - integrity sha512-CbFv/WMQsSdl+bpX6rVbzR4kAjSSBuDgCqb1l4J68UYsQNalz5wOqLGYj4ZI0thGpyX5kc+LLZ9CL+kpqDovZA== - -"@rollup/rollup-linux-x64-musl@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.6.tgz#bafa759ab43e8eab9edf242a8259ffb4f2a57a5d" - integrity sha512-ch7M+9Tr5R4FK40FHQk8VnML0Szi2KRujUgHXd/HjuH9ifH72GUmw6lStZBo3c3GB82vHa0ZoUfjfcM7JiiMrQ== - -"@rollup/rollup-win32-arm64-msvc@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.0.tgz#2fef1a90f1402258ef915ae5a94cc91a5a1d5bfc" - integrity sha512-s5oFkZ/hFcrlAyBTONFY1TWndfyre1wOMwU+6KCpm/iatybvrRgmZVM+vCFwxmC5ZhdlgfE0N4XorsDpi7/4XQ== - -"@rollup/rollup-win32-arm64-msvc@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.1.tgz#18349db8250559a5460d59eb3575f9781be4ab98" - integrity sha512-3Q3brDgA86gHXWHklrwdREKIrIbxC0ZgU8lwpj0eEKGBQH+31uPqr0P2v11pn0tSIxHvcdOWxa4j+YvLNx1i6g== - -"@rollup/rollup-win32-arm64-msvc@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.6.tgz#1cc3416682e5a20d8f088f26657e6e47f8db468e" - integrity sha512-VD6qnR99dhmTQ1mJhIzXsRcTBvTjbfbGGwKAHcu+52cVl15AC/kplkhxzW/uT0Xl62Y/meBKDZvoJSJN+vTeGA== - -"@rollup/rollup-win32-ia32-msvc@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.0.tgz#a18ad47a95c5f264defb60acdd8c27569f816fc1" - integrity sha512-G9+TEqRnAA6nbpqyUqgTiopmnfgnMkR3kMukFBDsiyy23LZvUCpiUwjTRx6ezYCjJODXrh52rBR9oXvm+Fp5wg== - -"@rollup/rollup-win32-ia32-msvc@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.1.tgz#199648b68271f7ab9d023f5c077725d51d12d466" - integrity sha512-tNg+jJcKR3Uwe4L0/wY3Ro0H+u3nrb04+tcq1GSYzBEmKLeOQF2emk1whxlzNqb6MMrQ2JOcQEpuuiPLyRcSIw== - -"@rollup/rollup-win32-ia32-msvc@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.6.tgz#7d2251e1aa5e8a1e47c86891fe4547a939503461" - integrity sha512-J9AFDq/xiRI58eR2NIDfyVmTYGyIZmRcvcAoJ48oDld/NTR8wyiPUu2X/v1navJ+N/FGg68LEbX3Ejd6l8B7MQ== - -"@rollup/rollup-win32-x64-msvc@4.21.0": - version "4.21.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.0.tgz#20c09cf44dcb082140cc7f439dd679fe4bba3375" - integrity sha512-2jsCDZwtQvRhejHLfZ1JY6w6kEuEtfF9nzYsZxzSlNVKDX+DpsDJ+Rbjkm74nvg2rdx0gwBS+IMdvwJuq3S9pQ== - -"@rollup/rollup-win32-x64-msvc@4.21.1": - version "4.21.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.1.tgz#4d3ec02dbf280c20bfeac7e50cd5669b66f9108f" - integrity sha512-xGiIH95H1zU7naUyTKEyOA/I0aexNMUdO9qRv0bLKN3qu25bBdrxZHqA3PTJ24YNN/GdMzG4xkDcd/GvjuhfLg== - -"@rollup/rollup-win32-x64-msvc@4.9.6": - version "4.9.6" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.6.tgz#2c1fb69e02a3f1506f52698cfdc3a8b6386df9a6" - integrity sha512-jqzNLhNDvIZOrt69Ce4UjGRpXJBzhUBzawMwnaDAwyHriki3XollsewxWzOzz+4yOFDkuJHtTsZFwMxhYJWmLQ== - -"@sentry-internal/feedback@7.100.1": - version "7.100.1" - resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-7.100.1.tgz#99585ba6f71eca3e7afe918273dd55b12f3aac8a" - integrity sha512-yqcRVnjf+qS+tC4NxOKLJOaSJ+csHmh/dHUzvCTkf5rLsplwXYRnny2r0tqGTQ4tuXMxwgSMKPYwicg81P+xuw== - dependencies: - "@sentry/core" "7.100.1" - "@sentry/types" "7.100.1" - "@sentry/utils" "7.100.1" - -"@sentry-internal/replay-canvas@7.100.1": - version "7.100.1" - resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-7.100.1.tgz#d37228575931b869d2ad415af46b342d83dd0fd7" - integrity sha512-TnqxqJGhbFhhYRhTG2WLFer+lVieV7mNGeIxFBiw1L4kuj8KGl+C0sknssKyZSRVJFSahhHIosHJGRMkkD//7g== - dependencies: - "@sentry/core" "7.100.1" - "@sentry/replay" "7.100.1" - "@sentry/types" "7.100.1" - "@sentry/utils" "7.100.1" - -"@sentry-internal/tracing@7.100.1": - version "7.100.1" - resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.100.1.tgz#4329492e50c390567197a4acbf7e3672b1db7820" - integrity sha512-+u9RRf5eL3StiyiRyAHZmdkAR7GTSGx4Mt4Lmi5NEtCcWlTGZ1QgW2r8ZbhouVmTiJkjhQgYCyej3cojtazeJg== - dependencies: - "@sentry/core" "7.100.1" - "@sentry/types" "7.100.1" - "@sentry/utils" "7.100.1" - -"@sentry/browser@7.100.1": - version "7.100.1" - resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.100.1.tgz#146ffca94cc187ecbf49915ef3100f6037316110" - integrity sha512-IxHQ08ixf0bmaWpe4yt1J4UUsOpg02fxax9z3tOQYXw5MSzz5pDXn8M8DFUVJB3wWuyXhHXTub9yD3VIP9fnoA== - dependencies: - "@sentry-internal/feedback" "7.100.1" - "@sentry-internal/replay-canvas" "7.100.1" - "@sentry-internal/tracing" "7.100.1" - "@sentry/core" "7.100.1" - "@sentry/replay" "7.100.1" - "@sentry/types" "7.100.1" - "@sentry/utils" "7.100.1" - -"@sentry/core@7.100.1": - version "7.100.1" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.100.1.tgz#7b8e101a931af8e8b3b2449534749f882772df4f" - integrity sha512-f+ItUge/o9AjlveQq0ZUbQauKlPH1FIJbC1TRaYLJ4KNfOdrsh8yZ29RmWv0cFJ/e+FGTr603gWpRPObF5rM8Q== - dependencies: - "@sentry/types" "7.100.1" - "@sentry/utils" "7.100.1" +"@rollup/rollup-android-arm-eabi@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz#8b613b9725e8f9479d142970b106b6ae878610d5" + integrity sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w== + +"@rollup/rollup-android-arm64@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.4.tgz#654ca1049189132ff602bfcf8df14c18da1f15fb" + integrity sha512-VXoK5UMrgECLYaMuGuVTOx5kcuap1Jm8g/M83RnCHBKOqvPPmROFJGQaZhGccnsFtfXQ3XYa4/jMCJvZnbJBdA== + +"@rollup/rollup-darwin-arm64@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.4.tgz#6d241d099d1518ef0c2205d96b3fa52e0fe1954b" + integrity sha512-xMM9ORBqu81jyMKCDP+SZDhnX2QEVQzTcC6G18KlTQEzWK8r/oNZtKuZaCcHhnsa6fEeOBionoyl5JsAbE/36Q== + +"@rollup/rollup-darwin-x64@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.4.tgz#42bd19d292a57ee11734c980c4650de26b457791" + integrity sha512-aJJyYKQwbHuhTUrjWjxEvGnNNBCnmpHDvrb8JFDbeSH3m2XdHcxDd3jthAzvmoI8w/kSjd2y0udT+4okADsZIw== + +"@rollup/rollup-linux-arm-gnueabihf@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.4.tgz#f23555ee3d8fe941c5c5fd458cd22b65eb1c2232" + integrity sha512-j63YtCIRAzbO+gC2L9dWXRh5BFetsv0j0va0Wi9epXDgU/XUi5dJKo4USTttVyK7fGw2nPWK0PbAvyliz50SCQ== + +"@rollup/rollup-linux-arm-musleabihf@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.4.tgz#f3bbd1ae2420f5539d40ac1fde2b38da67779baa" + integrity sha512-dJnWUgwWBX1YBRsuKKMOlXCzh2Wu1mlHzv20TpqEsfdZLb3WoJW2kIEsGwLkroYf24IrPAvOT/ZQ2OYMV6vlrg== + +"@rollup/rollup-linux-arm64-gnu@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.4.tgz#7abe900120113e08a1f90afb84c7c28774054d15" + integrity sha512-AdPRoNi3NKVLolCN/Sp4F4N1d98c4SBnHMKoLuiG6RXgoZ4sllseuGioszumnPGmPM2O7qaAX/IJdeDU8f26Aw== + +"@rollup/rollup-linux-arm64-musl@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.4.tgz#9e655285c8175cd44f57d6a1e8e5dedfbba1d820" + integrity sha512-Gl0AxBtDg8uoAn5CCqQDMqAx22Wx22pjDOjBdmG0VIWX3qUBHzYmOKh8KXHL4UpogfJ14G4wk16EQogF+v8hmA== + +"@rollup/rollup-linux-powerpc64le-gnu@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.4.tgz#9a79ae6c9e9d8fe83d49e2712ecf4302db5bef5e" + integrity sha512-3aVCK9xfWW1oGQpTsYJJPF6bfpWfhbRnhdlyhak2ZiyFLDaayz0EP5j9V1RVLAAxlmWKTDfS9wyRyY3hvhPoOg== + +"@rollup/rollup-linux-riscv64-gnu@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.4.tgz#67ac70eca4ace8e2942fabca95164e8874ab8128" + integrity sha512-ePYIir6VYnhgv2C5Xe9u+ico4t8sZWXschR6fMgoPUK31yQu7hTEJb7bCqivHECwIClJfKgE7zYsh1qTP3WHUA== + +"@rollup/rollup-linux-s390x-gnu@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.4.tgz#9f883a7440f51a22ed7f99e1d070bd84ea5005fc" + integrity sha512-GqFJ9wLlbB9daxhVlrTe61vJtEY99/xB3C8e4ULVsVfflcpmR6c8UZXjtkMA6FhNONhj2eA5Tk9uAVw5orEs4Q== + +"@rollup/rollup-linux-x64-gnu@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.4.tgz#70116ae6c577fe367f58559e2cffb5641a1dd9d0" + integrity sha512-87v0ol2sH9GE3cLQLNEy0K/R0pz1nvg76o8M5nhMR0+Q+BBGLnb35P0fVz4CQxHYXaAOhE8HhlkaZfsdUOlHwg== + +"@rollup/rollup-linux-x64-musl@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.4.tgz#f473f88219feb07b0b98b53a7923be716d1d182f" + integrity sha512-UV6FZMUgePDZrFjrNGIWzDo/vABebuXBhJEqrHxrGiU6HikPy0Z3LfdtciIttEUQfuDdCn8fqh7wiFJjCNwO+g== + +"@rollup/rollup-win32-arm64-msvc@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.4.tgz#4349482d17f5d1c58604d1c8900540d676f420e0" + integrity sha512-BjI+NVVEGAXjGWYHz/vv0pBqfGoUH0IGZ0cICTn7kB9PyjrATSkX+8WkguNjWoj2qSr1im/+tTGRaY+4/PdcQw== + +"@rollup/rollup-win32-ia32-msvc@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.4.tgz#a6fc39a15db618040ec3c2a24c1e26cb5f4d7422" + integrity sha512-SiWG/1TuUdPvYmzmYnmd3IEifzR61Tragkbx9D3+R8mzQqDBz8v+BvZNDlkiTtI9T15KYZhP0ehn3Dld4n9J5g== + +"@rollup/rollup-win32-x64-msvc@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.4.tgz#3dd5d53e900df2a40841882c02e56f866c04d202" + integrity sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q== + +"@sentry-internal/feedback@7.119.0": + version "7.119.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-7.119.0.tgz#429b3ea0fd34e928d2e7de5dcbe9377272a3f221" + integrity sha512-om8TkAU5CQGO8nkmr7qsSBVkP+/vfeS4JgtW3sjoTK0fhj26+DljR6RlfCGWtYQdPSP6XV7atcPTjbSnsmG9FQ== + dependencies: + "@sentry/core" "7.119.0" + "@sentry/types" "7.119.0" + "@sentry/utils" "7.119.0" + +"@sentry-internal/replay-canvas@7.119.0": + version "7.119.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-7.119.0.tgz#85669d184ba79150e64d05de02f5e2b616e68371" + integrity sha512-NL02VQx6ekPxtVRcsdp1bp5Tb5w6vnfBKSIfMKuDRBy5A10Uc3GSoy/c3mPyHjOxB84452A+xZSx6bliEzAnuA== + dependencies: + "@sentry/core" "7.119.0" + "@sentry/replay" "7.119.0" + "@sentry/types" "7.119.0" + "@sentry/utils" "7.119.0" + +"@sentry-internal/tracing@7.119.0": + version "7.119.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.119.0.tgz#201561af2a4ad1837333287c26050a5e688537ca" + integrity sha512-oKdFJnn+56f0DHUADlL8o9l8jTib3VDLbWQBVkjD9EprxfaCwt2m8L5ACRBdQ8hmpxCEo4I8/6traZ7qAdBUqA== + dependencies: + "@sentry/core" "7.119.0" + "@sentry/types" "7.119.0" + "@sentry/utils" "7.119.0" + +"@sentry/browser@7.119.0": + version "7.119.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.119.0.tgz#65004015c107be5d2f49a852ebcffc5d19d90e0d" + integrity sha512-WwmW1Y4D764kVGeKmdsNvQESZiAn9t8LmCWO0ucBksrjL2zw9gBPtOpRcO6l064sCLeSxxzCN+kIxhRm1gDFEA== + dependencies: + "@sentry-internal/feedback" "7.119.0" + "@sentry-internal/replay-canvas" "7.119.0" + "@sentry-internal/tracing" "7.119.0" + "@sentry/core" "7.119.0" + "@sentry/integrations" "7.119.0" + "@sentry/replay" "7.119.0" + "@sentry/types" "7.119.0" + "@sentry/utils" "7.119.0" + +"@sentry/core@7.119.0": + version "7.119.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.119.0.tgz#a6e41119bb03ec27689f9ad04e79d1fba5b7fc37" + integrity sha512-CS2kUv9rAJJEjiRat6wle3JATHypB0SyD7pt4cpX5y0dN5dZ1JrF57oLHRMnga9fxRivydHz7tMTuBhSSwhzjw== + dependencies: + "@sentry/types" "7.119.0" + "@sentry/utils" "7.119.0" + +"@sentry/integrations@7.119.0": + version "7.119.0" + resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.119.0.tgz#5b25c603026dbacfe1ae7bb8d768506a129149fb" + integrity sha512-OHShvtsRW0A+ZL/ZbMnMqDEtJddPasndjq+1aQXw40mN+zeP7At/V1yPZyFaURy86iX7Ucxw5BtmzuNy7hLyTA== + dependencies: + "@sentry/core" "7.119.0" + "@sentry/types" "7.119.0" + "@sentry/utils" "7.119.0" + localforage "^1.8.1" "@sentry/react@^7.57.0": - version "7.100.1" - resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.100.1.tgz#a8621f2124848b6a7bb1fc6279167f5e3cbc44f1" - integrity sha512-EdrBtrXVLK2LSx4Rvz/nQP7HZUZQmr+t3GHV8436RAhF6vs5mntACVMBoQJRWiUvtZ1iRo3rIsIdah7DLiFPgQ== - dependencies: - "@sentry/browser" "7.100.1" - "@sentry/core" "7.100.1" - "@sentry/types" "7.100.1" - "@sentry/utils" "7.100.1" + version "7.119.0" + resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.119.0.tgz#79f2c9d94322a3afbfa8af9f5b872f7c2e9b0820" + integrity sha512-cf8Cei+qdSA26gx+IMAuc/k44PeBImNzIpXi3930SLhUe44ypT5OZ/44L6xTODHZzTIyMSJPduf59vT2+eW9yg== + dependencies: + "@sentry/browser" "7.119.0" + "@sentry/core" "7.119.0" + "@sentry/types" "7.119.0" + "@sentry/utils" "7.119.0" hoist-non-react-statics "^3.3.2" -"@sentry/replay@7.100.1": - version "7.100.1" - resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.100.1.tgz#d9af5f8e92ce0f93cef89f5aef74d91a8d12c3eb" - integrity sha512-B1NFjzGEFaqejxBRdUyEzH8ChXc2kfiqlA/W/Lg0aoWIl2/7nuMk+l4ld9gW5F5bIAXDTVd5vYltb1lWEbpr7w== +"@sentry/replay@7.119.0": + version "7.119.0" + resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.119.0.tgz#50881079d013c77f87a994331d8bcad1d49e0960" + integrity sha512-BnNsYL+X5I4WCH6wOpY6HQtp4MgVt0NVlhLUsEyrvMUiTs0bPkDBrulsgZQBUKJsbOr3l9nHrFoNVB/0i6WNLA== dependencies: - "@sentry-internal/tracing" "7.100.1" - "@sentry/core" "7.100.1" - "@sentry/types" "7.100.1" - "@sentry/utils" "7.100.1" + "@sentry-internal/tracing" "7.119.0" + "@sentry/core" "7.119.0" + "@sentry/types" "7.119.0" + "@sentry/utils" "7.119.0" -"@sentry/types@7.100.1": - version "7.100.1" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.100.1.tgz#1349b77269cecf4e80c087842575bd1a001e9995" - integrity sha512-fLM+LedHuKzOd8IhXBqaQuym+AA519MGjeczBa5kGakes/BbAsUMwsNfjsKQedp7Kh44RgYF99jwoRPK2oDrXw== +"@sentry/types@7.119.0": + version "7.119.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.119.0.tgz#8b3d7a1405c362e75cd900d46089df4e70919d2a" + integrity sha512-27qQbutDBPKGbuJHROxhIWc1i0HJaGLA90tjMu11wt0E4UNxXRX+UQl4Twu68v4EV3CPvQcEpQfgsViYcXmq+w== -"@sentry/utils@7.100.1": - version "7.100.1" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.100.1.tgz#6e26f3b06b1e485a2180f464ab3374ecb8d5e407" - integrity sha512-Ve6dXr1o6xiBe3VCoJgiutmBKrugryI65EZAbYto5XI+t+PjiLLf9wXtEMF24ZrwImo4Lv3E9Uqza+fWkEbw6A== +"@sentry/utils@7.119.0": + version "7.119.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.119.0.tgz#debe29020f6ef3786a5bd855cf1b97116b7be826" + integrity sha512-ZwyXexWn2ZIe2bBoYnXJVPc2esCSbKpdc6+0WJa8eutXfHq3FRKg4ohkfCBpfxljQGEfP1+kfin945lA21Ka+A== dependencies: - "@sentry/types" "7.100.1" + "@sentry/types" "7.119.0" "@storybook/addon-a11y@^8.3.0": - version "8.3.2" - resolved "https://registry.yarnpkg.com/@storybook/addon-a11y/-/addon-a11y-8.3.2.tgz#b8ce0a3f922d86a0283f2249e2b1f47bcc97ddb1" - integrity sha512-i0qyMp+MxzJ3UY3Absqwxhry4JqZo9yk1XLWld7hJpfAzmrulnaIctudQ940/OMFPcEIsOVdg8euz0IGW3HTNw== + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-a11y/-/addon-a11y-8.3.3.tgz#1ab0db4b559f6ba6bb33c928c634b15d21bd5a72" + integrity sha512-TiCbNfKJOBD2b8mMqHOii8ntdt0V4+ifAgzmGku+F1hdf2EhEw1nL6CHpvnx/GBXoGeK4mrPJIKKoPNp+zz0dw== dependencies: - "@storybook/addon-highlight" "8.3.2" + "@storybook/addon-highlight" "8.3.3" axe-core "^4.2.0" "@storybook/addon-actions@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-8.3.0.tgz#0a5c2d7776ae201fa331bcdc48230fc866e854ac" - integrity sha512-HvAc3fW979JVw8CSKXZMouvgrJ2BNLNWaUB8jNokQb3Us00P6igVKLwg/pBV8GBgDr5Ng4pHYqi/ZH+xzEYFFw== + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-8.3.3.tgz#6b3289071fa887eb08aa858aa64a87e93f0bb440" + integrity sha512-cbpksmld7iADwDGXgojZ4r8LGI3YA3NP68duAHg2n1dtnx1oUaFK5wd6dbNuz7GdjyhIOIy3OKU1dAuylYNGOQ== dependencies: "@storybook/global" "^5.0.0" "@types/uuid" "^9.0.1" @@ -2032,9 +1528,9 @@ uuid "^9.0.0" "@storybook/addon-controls@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/addon-controls/-/addon-controls-8.3.0.tgz#692bcdddd1db438a9cc7434ff947ebf215191542" - integrity sha512-Id4j6Neimkdq0OyfQ3qkHpKLisbN08M8pXHDI/A0VeF91xEGBdc1bJgS/EU+ifa24tr5SRYwlAlcBDAWJbZMfA== + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-controls/-/addon-controls-8.3.3.tgz#bad8729f03897f9df0909a11e9181a9d88eb274d" + integrity sha512-78xRtVpY7eX/Lti00JLgwYCBRB6ZcvzY3SWk0uQjEqcTnQGoQkVg2L7oWFDlDoA1LBY18P5ei2vu8MYT9GXU4g== dependencies: "@storybook/global" "^5.0.0" dequal "^2.0.2" @@ -2042,15 +1538,15 @@ ts-dedent "^2.0.0" "@storybook/addon-docs@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/addon-docs/-/addon-docs-8.3.0.tgz#76469c7c24d932296d027407424c8876b06d658a" - integrity sha512-LrvWBDX5Vi//82Q78QRbTsG+9rJU9JJFAVPk1NnLp2Yn0F4FueVzIw8AabAkZFy0LHPMGV+EHpkPtYz4Czkhgw== + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-docs/-/addon-docs-8.3.3.tgz#77869084cbbfaec9d3bbcdf18413de7f627ce81d" + integrity sha512-REUandqq1RnMNOhsocRwx5q2fdlBAYPTDFlKASYfEn4Ln5NgbQRGxOAWl7yXAAFzbDmUDU7K20hkauecF0tyMw== dependencies: "@mdx-js/react" "^3.0.0" - "@storybook/blocks" "8.3.0" - "@storybook/csf-plugin" "8.3.0" + "@storybook/blocks" "8.3.3" + "@storybook/csf-plugin" "8.3.3" "@storybook/global" "^5.0.0" - "@storybook/react-dom-shim" "8.3.0" + "@storybook/react-dom-shim" "8.3.3" "@types/react" "^16.8.0 || ^17.0.0 || ^18.0.0" fs-extra "^11.1.0" react "^16.8.0 || ^17.0.0 || ^18.0.0" @@ -2059,49 +1555,49 @@ rehype-slug "^6.0.0" ts-dedent "^2.0.0" -"@storybook/addon-highlight@8.3.2": - version "8.3.2" - resolved "https://registry.yarnpkg.com/@storybook/addon-highlight/-/addon-highlight-8.3.2.tgz#a23669cadeed5a5bd18ebbbcd6258f9492508b6b" - integrity sha512-JFL/JLBZfa89POgi8lBdt8TzzCS1bgN/X6Qj1MlTq3pxHYqO66eG8DtMLjpuXKOhs8Dhdgs9/uxy5Yd+MFVRmQ== +"@storybook/addon-highlight@8.3.3": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-highlight/-/addon-highlight-8.3.3.tgz#2e1d96bdd8049af7343300cbb43adb4480f3ed7d" + integrity sha512-MB084xJM66rLU+iFFk34kjLUiAWzDiy6Kz4uZRa1CnNqEK0sdI8HaoQGgOxTIa2xgJor05/8/mlYlMkP/0INsQ== dependencies: "@storybook/global" "^5.0.0" "@storybook/addon-mdx-gfm@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/addon-mdx-gfm/-/addon-mdx-gfm-8.3.0.tgz#2a6dadfa76b5f834a2a0f984ddcac0741f2495c8" - integrity sha512-qGaO5/3jd2mcxKiV4Gfloxgw4yvzCsj/ZwqysDIGVJtliguscWYbWE2JMz7zluUyt6nVMhQhDYkF9GnNU4yaoA== + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-mdx-gfm/-/addon-mdx-gfm-8.3.3.tgz#604930985453c4a4bdc3ccbab26ff043a54dc18d" + integrity sha512-jdwVXoBSEdmuw8L4MxUeJ/qIInADfCwdtShnfTQIJBBRucOl8ykgfTKKNjllT79TFiK0gsWoiZmE05P4wuBofw== dependencies: remark-gfm "^4.0.0" ts-dedent "^2.0.0" "@storybook/addon-measure@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/addon-measure/-/addon-measure-8.3.0.tgz#3a79b36ff08259c675ddaf099d14fdee06099484" - integrity sha512-0TZ2ihzX0mRr1rNrFDieDsIKASZ2qUg3eHDkskLKOhxwoUHqsLzXlvS/scKZ+zb8pgjrvsBAsjyPstlrK+z0Zg== + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-measure/-/addon-measure-8.3.3.tgz#9ff6e749ab6c0661252a195ec355f6a6c5bace07" + integrity sha512-R20Z83gnxDRrocES344dw1Of/zDhe3XHSM6TLq80UQTJ9PhnMI+wYHQlK9DsdP3KiRkI+pQA6GCOp0s2ZRy5dg== dependencies: "@storybook/global" "^5.0.0" tiny-invariant "^1.3.1" "@storybook/addon-storysource@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/addon-storysource/-/addon-storysource-8.3.0.tgz#da8087d763fa93fb4ec5a6519786e00515be289d" - integrity sha512-+owWKfUebwccrdboIkCNsqXT25LVwha8XT5UbnHbclKqBkMwtWIyl3HMOkXZ8MGLgDF0dm00iLbO59jVRlhDyQ== + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-storysource/-/addon-storysource-8.3.3.tgz#de1c0db04a927cc6af91aac9b7590cf30058b627" + integrity sha512-yPYQH9NepSNxoSsV9E7OV3/EVFrbU/r2B3E5WP/mCfqTXPg/5noce7iRi+rWqcVM1tsN1qPnSjfQQc7noF0h0Q== dependencies: - "@storybook/source-loader" "8.3.0" + "@storybook/source-loader" "8.3.3" estraverse "^5.2.0" tiny-invariant "^1.3.1" "@storybook/addon-viewport@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/addon-viewport/-/addon-viewport-8.3.0.tgz#30ec8e38ebbe22dfb0886f2b853ea90fa365309e" - integrity sha512-6h/0mKipUG6w2o5IOzyhvC/2ifJlSNIA60hLkJ291g42+ilzkydpby9TBN7FcnrVL3Bv+oLgkDLBWVCqma/fyw== + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/addon-viewport/-/addon-viewport-8.3.3.tgz#53315cb90e013fdee514df86e415747f4be3126d" + integrity sha512-2S+UpbKAL+z1ppzUCkixjaem2UDMkfmm/kyJ1wm3A/ofGLYi4fjMSKNRckk+7NdolXGQJjBo0RcaotUTxFIFwQ== dependencies: memoizerific "^1.11.3" -"@storybook/blocks@8.3.0", "@storybook/blocks@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/blocks/-/blocks-8.3.0.tgz#afb6af3457a8772b3e9b5163f5e591985c1ef179" - integrity sha512-V7D5lv5R+GJya9cCZOCjmOVjhvP5J3KIaclQuuGGJda/ZD/SpwHcFOGSpo6sNR2UKHXXvb61oM8gRQQWDvqPlg== +"@storybook/blocks@8.3.3", "@storybook/blocks@^8.3.0": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/blocks/-/blocks-8.3.3.tgz#a123746b472488d3c6ccc08b1fe831474ec992b0" + integrity sha512-8Vsvxqstop3xfbsx3Dn1nEjyxvQUcOYd8vpxyp2YumxYO8FlXIRuYL6HAkYbcX8JexsKvCZYxor52D2vUGIKZg== dependencies: "@storybook/csf" "^0.1.11" "@storybook/global" "^5.0.0" @@ -2118,12 +1614,12 @@ ts-dedent "^2.0.0" util-deprecate "^1.0.2" -"@storybook/builder-vite@8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/builder-vite/-/builder-vite-8.3.0.tgz#39118813f6938b6544cb635e26c362b35f307c57" - integrity sha512-9qo3zcZkEpy69E7cx9OHHexBe9+25vH0p+4sWZSjl2sjqjhaxLN5eXnODQbDsOKZNRVrLVTGmKxfFJzAJFnY0w== +"@storybook/builder-vite@8.3.3": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/builder-vite/-/builder-vite-8.3.3.tgz#40bc458ac735c0c0dac29d9bded6f4dd05bb9104" + integrity sha512-3yTXCLaB6bzhoPH3PqtacKkcaC1uV4L+IHTf1Zypx1NO1pLZHyhYf0T7dIOxTh2JZfqu1Pm9hTvOmWfR12m+9w== dependencies: - "@storybook/csf-plugin" "8.3.0" + "@storybook/csf-plugin" "8.3.3" "@types/find-cache-dir" "^3.2.1" browser-assert "^1.2.1" es-module-lexer "^1.5.0" @@ -2133,82 +1629,42 @@ magic-string "^0.30.0" ts-dedent "^2.0.0" -"@storybook/channels@8.0.5": - version "8.0.5" - resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-8.0.5.tgz#85744e03c18366b45a5e108c25cd9975d9828bf2" - integrity sha512-UWzjt4STzBgg28Q6FxqyJWwXLWYM6oSz9gGKMUJbn2vRAlEJaG3XwvpT39YFVDUIuiFSHguV5cisXY5Be4nOZw== - dependencies: - "@storybook/client-logger" "8.0.5" - "@storybook/core-events" "8.0.5" - "@storybook/global" "^5.0.0" - telejson "^7.2.0" - tiny-invariant "^1.3.1" +"@storybook/components@^8.0.0", "@storybook/components@^8.3.3": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/components/-/components-8.3.3.tgz#4b3ac4eedba3bca0884782916c4f6f1e7003b741" + integrity sha512-i2JYtesFGkdu+Hwuj+o9fLuO3yo+LPT1/8o5xBVYtEqsgDtEAyuRUWjSz8d8NPtzloGPOv5kvR6MokWDfbeMfw== -"@storybook/client-logger@8.0.5": - version "8.0.5" - resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-8.0.5.tgz#8cafa514e9a9af054f926bc179264bef2198c0ce" - integrity sha512-6D7zvPPnLuTVlBNpZSdzEbk5xfWKhEG0gejtPnhjG9R5YzC/dFckdUI0gtvwGWUVMWhL3H/0gjRjhKujUMRY1Q== - dependencies: - "@storybook/global" "^5.0.0" +"@storybook/core-events@^8.0.0": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-8.3.3.tgz#0b7cb3b737335a5d4091108a01352720e0e1f965" + integrity sha512-YL+gBuCS81qktzTkvw0MXUJW0bYAXfRzMoiLfDBTrEKZfcJOB4JAlMGmvRRar0+jygK3icD42Rl5BwWoZY6KFQ== -"@storybook/components@^8.0.0": - version "8.0.5" - resolved "https://registry.yarnpkg.com/@storybook/components/-/components-8.0.5.tgz#e526b4600b4b8049108a1b63e71fee8d75ff8d3d" - integrity sha512-trBWV9gc4YhFhMKUevkBY9Mdk9WmYmthpBfmF0Y2vgrJQidUqkkQqfAMQThSJ0KLpV8k3fB27s5d93rgrr50Rg== - dependencies: - "@radix-ui/react-slot" "^1.0.2" - "@storybook/client-logger" "8.0.5" - "@storybook/csf" "^0.1.2" - "@storybook/global" "^5.0.0" - "@storybook/icons" "^1.2.5" - "@storybook/theming" "8.0.5" - "@storybook/types" "8.0.5" - memoizerific "^1.11.3" - util-deprecate "^1.0.2" - -"@storybook/components@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/components/-/components-8.3.0.tgz#45c39e5b6768efafe8e7dfd946c01617da59ae1a" - integrity sha512-SO/iTkmWp3aYCIy8DEhRMoOn6K7lcKTPNC/YjTvOFFzwq/CLq86WNqz6aX+wV5n6MvWTs7evSwMoz7lp4Lc4sw== - -"@storybook/core-events@8.0.5", "@storybook/core-events@^8.0.0": - version "8.0.5" - resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-8.0.5.tgz#fa73281edd7d839439360259a0be48b04cd9a06a" - integrity sha512-26c0m7P7qt9zUKcD1noWLPJmZ+iS6MKXNngUgNBSxTtG20NFV3nxD0/tx9FzNfDVZDF6cHINkWj+FVBAaVuBVQ== - dependencies: - ts-dedent "^2.0.0" - -"@storybook/core@8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/core/-/core-8.3.0.tgz#c08ff10405fa935044678c8ae92c7be14dd01bdb" - integrity sha512-UeErpD0xRIP2nFA2TjPYxtEyv24O6VRfq2XXU5ki2QPYnxOxAPBbrMHCADjgBwNS4S2NUWTaVBYxybISVbrj+w== +"@storybook/core@8.3.3": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/core/-/core-8.3.3.tgz#657ce39312ceec5ba03382fe4d4d83ca396bb9ab" + integrity sha512-pmf2bP3fzh45e56gqOuBT8sDX05hGdUKIZ/hcI84d5xmd6MeHiPW8th2v946wCHcxHzxib2/UU9vQUh+mB4VNw== dependencies: "@storybook/csf" "^0.1.11" "@types/express" "^4.17.21" + better-opn "^3.0.2" browser-assert "^1.2.1" esbuild "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0" esbuild-register "^3.5.0" express "^4.19.2" + jsdoc-type-pratt-parser "^4.0.0" process "^0.11.10" recast "^0.23.5" semver "^7.6.2" util "^0.12.5" ws "^8.2.3" -"@storybook/csf-plugin@8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/csf-plugin/-/csf-plugin-8.3.0.tgz#33fbc6799e7e9cdcfbb41219ef2bf863b14096fc" - integrity sha512-sCmeN/OVYj95TKkMqJqxbaztIbdv5jCrtrXuNg4oJaGzNucmMNAbmv2jK2tCNE6Uz2X9IMRcseFX/h9TgjyJ9A== +"@storybook/csf-plugin@8.3.3": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/csf-plugin/-/csf-plugin-8.3.3.tgz#8112d98222f9b3650d5924673d30dfd9bb55457b" + integrity sha512-7AD7ojpXr3THqpTcEI4K7oKUfSwt1hummgL/cASuQvEPOwAZCVZl2gpGtKxcXhtJXTkn3GMCAvlYMoe7O/1YWw== dependencies: unplugin "^1.3.1" -"@storybook/csf@^0.0.1": - version "0.0.1" - resolved "https://registry.yarnpkg.com/@storybook/csf/-/csf-0.0.1.tgz#95901507dc02f0bc6f9ac8ee1983e2fc5bb98ce6" - integrity sha512-USTLkZze5gkel8MYCujSRBVIrUQ3YPBrLOx7GNk/0wttvVtlzWXAq9eLbQ4p/NicGxP+3T7KPEMVV//g+yubpw== - dependencies: - lodash "^4.17.15" - "@storybook/csf@^0.1.11": version "0.1.11" resolved "https://registry.yarnpkg.com/@storybook/csf/-/csf-0.1.11.tgz#ad685a4fe564a47a6b73571c2e7c07b526f4f71b" @@ -2216,90 +1672,57 @@ dependencies: type-fest "^2.19.0" -"@storybook/csf@^0.1.2": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@storybook/csf/-/csf-0.1.2.tgz#8e7452f0097507f5841b5ade3f5da1525bc9afb2" - integrity sha512-ePrvE/pS1vsKR9Xr+o+YwdqNgHUyXvg+1Xjx0h9LrVx7Zq4zNe06pd63F5EvzTbCbJsHj7GHr9tkiaqm7U8WRA== - dependencies: - type-fest "^2.19.0" - "@storybook/global@^5.0.0": version "5.0.0" resolved "https://registry.yarnpkg.com/@storybook/global/-/global-5.0.0.tgz#b793d34b94f572c1d7d9e0f44fac4e0dbc9572ed" integrity sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ== -"@storybook/icons@^1.2.10": - version "1.2.10" - resolved "https://registry.yarnpkg.com/@storybook/icons/-/icons-1.2.10.tgz#d3d44912a3a88f3f04f77ce2c23a7e47e796f766" - integrity sha512-310apKdDcjbbX2VSLWPwhEwAgjxTzVagrwucVZIdGPErwiAppX8KvBuWZgPo+rQLVrtH8S+pw1dbUwjcE6d7og== - -"@storybook/icons@^1.2.5": - version "1.2.9" - resolved "https://registry.yarnpkg.com/@storybook/icons/-/icons-1.2.9.tgz#bb4a51a79e186b62e2dd0e04928b8617ac573838" - integrity sha512-cOmylsz25SYXaJL/gvTk/dl3pyk7yBFRfeXTsHvTA3dfhoU/LWSq0NKL9nM7WBasJyn6XPSGnLS4RtKXLw5EUg== - -"@storybook/manager-api@^8.0.0": - version "8.0.5" - resolved "https://registry.yarnpkg.com/@storybook/manager-api/-/manager-api-8.0.5.tgz#7fdc49803f1507bea97392bfd05760071a19d838" - integrity sha512-2Q+DI9XU1U4EBrihnyfo+kuRK7T3Ce2eSlWEHHkTZ3OYSf+EhFxLUA6AOfMoA1B0nzNEr6SUkW8DBvMrtdTQMA== - dependencies: - "@storybook/channels" "8.0.5" - "@storybook/client-logger" "8.0.5" - "@storybook/core-events" "8.0.5" - "@storybook/csf" "^0.1.2" - "@storybook/global" "^5.0.0" - "@storybook/icons" "^1.2.5" - "@storybook/router" "8.0.5" - "@storybook/theming" "8.0.5" - "@storybook/types" "8.0.5" - dequal "^2.0.2" - lodash "^4.17.21" - memoizerific "^1.11.3" - store2 "^2.14.2" - telejson "^7.2.0" - ts-dedent "^2.0.0" +"@storybook/icons@^1.2.10", "@storybook/icons@^1.2.5": + version "1.2.12" + resolved "https://registry.yarnpkg.com/@storybook/icons/-/icons-1.2.12.tgz#3e4c939113b67df7ab17b78f805dbb57f4acf0db" + integrity sha512-UxgyK5W3/UV4VrI3dl6ajGfHM4aOqMAkFLWe2KibeQudLf6NJpDrDMSHwZj+3iKC4jFU7dkKbbtH2h/al4sW3Q== -"@storybook/manager-api@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/manager-api/-/manager-api-8.3.0.tgz#0c3e33e3091be2122670b61ba601893c19d5dd47" - integrity sha512-5WBLEFHpe4H+9vZZLjNh7msIkyl9MPt4/C2nI+MXKZyU55xBBgiAy4fcD9aj02PcbhyR4JhLqbqmdeBe5Xafeg== +"@storybook/manager-api@^8.0.0", "@storybook/manager-api@^8.3.0", "@storybook/manager-api@^8.3.3": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/manager-api/-/manager-api-8.3.3.tgz#5518cc761264c9972732fcd9e025a7bc2fee7297" + integrity sha512-Na4U+McOeVUJAR6qzJfQ6y2Qt0kUgEDUriNoAn+curpoKPTmIaZ79RAXBzIqBl31VyQKknKpZbozoRGf861YaQ== -"@storybook/preview-api@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/preview-api/-/preview-api-8.3.0.tgz#763126866e9dc8cc2ba6a9506bf84c020987b048" - integrity sha512-pHq/T7oWBfzc9TCIPYyJQUXuiUiFfmdrcYvuZE1kf46i7wXh9Q2/Kd3BUJWSCpBXUMoYfAxg9YysGljMII8LWA== +"@storybook/preview-api@^8.3.0", "@storybook/preview-api@^8.3.3": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/preview-api/-/preview-api-8.3.3.tgz#9f625a2d5e647137c5df7e419eda59e98f88cd44" + integrity sha512-GP2QlaF3BBQGAyo248N7549YkTQjCentsc1hUvqPnFWU4xfjkejbnFk8yLaIw0VbYbL7jfd7npBtjZ+6AnphMQ== -"@storybook/react-dom-shim@8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/react-dom-shim/-/react-dom-shim-8.3.0.tgz#e6c8c75ff725a9a096fb63b46dc4108e51428857" - integrity sha512-87X4cvgwFT1ll5SzXgQq6iGbkVCgxLBpBm58akF/hzpeRkwfJDncGi/A5hElOJrBg63IkznmSJE7tf9RkrboqQ== +"@storybook/react-dom-shim@8.3.3": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/react-dom-shim/-/react-dom-shim-8.3.3.tgz#0a23588f507c5c69b1153e43f16c37dbf38b82f1" + integrity sha512-0dPC9K7+K5+X/bt3GwYmh+pCpisUyKVjWsI+PkzqGnWqaXFakzFakjswowIAIO1rf7wYZR591x3ehUAyL2bJiQ== "@storybook/react-vite@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/react-vite/-/react-vite-8.3.0.tgz#95efa85132b540beeffce15d46a4c2bd6bab4080" - integrity sha512-VcKp/mpO8M+JsyprTGLLvAzwx7PChdWFDBasyQ0MO+YVwci78gPAZnfWNZaaEB2mdDgPPGuoSTwBgzZmP3FsPg== + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/react-vite/-/react-vite-8.3.3.tgz#3ce3d5e25b302ba256c74e1e7871f38eba23cdc6" + integrity sha512-vzOqVaA/rv+X5J17eWKxdZztMKEKfsCSP8pNNmrqXWxK3pSlW0fAPxtn1kw3UNxGtAv71pcqvaCUtTJKqI1PYA== dependencies: - "@joshwooding/vite-plugin-react-docgen-typescript" "0.3.1" + "@joshwooding/vite-plugin-react-docgen-typescript" "0.3.0" "@rollup/pluginutils" "^5.0.2" - "@storybook/builder-vite" "8.3.0" - "@storybook/react" "8.3.0" + "@storybook/builder-vite" "8.3.3" + "@storybook/react" "8.3.3" find-up "^5.0.0" magic-string "^0.30.0" react-docgen "^7.0.0" resolve "^1.22.8" tsconfig-paths "^4.2.0" -"@storybook/react@8.3.0", "@storybook/react@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/react/-/react-8.3.0.tgz#2619341ece6613f81eb1e6e056929525fbcdcf85" - integrity sha512-qd8IKXqaOG9m0VK0QukFMmKpjmm7sy1R3T681dLet8s+AEAimLH/RiBzd+0dxWng2H/Ng6ldUmCtd3Cs6w/EFQ== +"@storybook/react@8.3.3", "@storybook/react@^8.3.0": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/react/-/react-8.3.3.tgz#87d16b3a22f4ace86747f6a382f506a7550a31dc" + integrity sha512-fHOW/mNqI+sZWttGOE32Q+rAIbN7/Oib091cmE8usOM0z0vPNpywUBtqC2cCQH39vp19bhTsQaSsTcoBSweAHw== dependencies: - "@storybook/components" "^8.3.0" + "@storybook/components" "^8.3.3" "@storybook/global" "^5.0.0" - "@storybook/manager-api" "^8.3.0" - "@storybook/preview-api" "^8.3.0" - "@storybook/react-dom-shim" "8.3.0" - "@storybook/theming" "^8.3.0" + "@storybook/manager-api" "^8.3.3" + "@storybook/preview-api" "^8.3.3" + "@storybook/react-dom-shim" "8.3.3" + "@storybook/theming" "^8.3.3" "@types/escodegen" "^0.0.6" "@types/estree" "^0.0.51" "@types/node" "^22.0.0" @@ -2315,48 +1738,20 @@ type-fest "~2.19" util-deprecate "^1.0.2" -"@storybook/router@8.0.5": - version "8.0.5" - resolved "https://registry.yarnpkg.com/@storybook/router/-/router-8.0.5.tgz#b2c3e7fc763003a6d74d0b7061e8cb0a78e5bf66" - integrity sha512-1d4CqNJB5sA25HCd7jZ4eVqMsdlD4r4SuFA/eR6fas0lk7yjVCpG1zWfvSSk5tKoVcNLSptc/TYBiSr2rcGRvw== - dependencies: - "@storybook/client-logger" "8.0.5" - memoizerific "^1.11.3" - qs "^6.10.0" - -"@storybook/source-loader@8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/source-loader/-/source-loader-8.3.0.tgz#eb885c0db12cd851440ef7734a050f763ad211ee" - integrity sha512-WzFTUAuOQfaSYtbj69SG+YfKQkJPqajzL4oHSj653MCQF3V6VGOzE/tW4xBjqK/BiMAclY7bWyl44JWSQO5AjQ== +"@storybook/source-loader@8.3.3": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/source-loader/-/source-loader-8.3.3.tgz#f97db24267f6dc66ff662fa2c6f13362135be040" + integrity sha512-NeP7l53mvnnfwi+91vtRaibZer+UJi6gkoaGRCpphL3L+3qVIXN3p41uXhAy+TahdFI2dbrWvLSNgtsvdXVaFg== dependencies: "@storybook/csf" "^0.1.11" estraverse "^5.2.0" lodash "^4.17.21" prettier "^3.1.1" -"@storybook/theming@8.0.5", "@storybook/theming@^8.0.0": - version "8.0.5" - resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-8.0.5.tgz#e98aa8b761b93c2cff21213770a1bafb971f2c07" - integrity sha512-Hy4hJaKg6UUyivkUM77nCHccv4/lO++ZG9F88qBFVPdBlCwMHHnUrR7Hgje5cCVAy0jK6LyYlD3cWO6nS9OR8w== - dependencies: - "@emotion/use-insertion-effect-with-fallbacks" "^1.0.1" - "@storybook/client-logger" "8.0.5" - "@storybook/global" "^5.0.0" - memoizerific "^1.11.3" - -"@storybook/theming@^8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-8.3.0.tgz#96edd021c1cffd030974747a5a645bc9ef0f8dbd" - integrity sha512-lJCarAzswZvUgBt/o1LMJp+07Io5G2VI1+Fw+bgn+92kRD8otCFwuMZIy0u7cEjHiEGqGnpzThlIki6vFjEXeA== - -"@storybook/types@8.0.5": - version "8.0.5" - resolved "https://registry.yarnpkg.com/@storybook/types/-/types-8.0.5.tgz#268566058ee2871b13ba42df21abf861e823abf2" - integrity sha512-lYXwYF9qooQhYJkg3HWr6PD/vnQK+iO8fSKS8jtntwgJUKJvTbGZKAhNnS8WzNEI9jIp5QXFsSA367NjIDPaeQ== - dependencies: - "@storybook/channels" "8.0.5" - "@types/express" "^4.7.0" - file-system-cache "2.3.0" +"@storybook/theming@^8.0.0", "@storybook/theming@^8.3.0", "@storybook/theming@^8.3.3": + version "8.3.3" + resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-8.3.3.tgz#38f2fb24e719f7a97c359a84c93be86ca2c9a20e" + integrity sha512-gWJKetI6XJQgkrvvry4ez10+jLaGNCQKi5ygRPM9N+qrjA3BB8F2LCuFUTBuisa4l64TILDNjfwP/YTWV5+u5A== "@svgr/babel-plugin-add-jsx-attribute@8.0.0": version "8.0.0" @@ -2441,145 +1836,76 @@ "@svgr/hast-util-to-babel-ast" "8.0.0" svg-parser "^2.0.4" -"@swc/core-darwin-arm64@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.4.0.tgz#11abf23b884929a467ba270cf6789b9c50c4248b" - integrity sha512-UTJ/Vz+s7Pagef6HmufWt6Rs0aUu+EJF4Pzuwvr7JQQ5b1DZeAAUeUtkUTFx/PvCbM8Xfw4XdKBUZfrIKCfW8A== - -"@swc/core-darwin-arm64@1.7.26": - version "1.7.26" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.26.tgz#5f4096c00e71771ca1b18c824f0c92a052c70760" - integrity sha512-FF3CRYTg6a7ZVW4yT9mesxoVVZTrcSWtmZhxKCYJX9brH4CS/7PRPjAKNk6kzWgWuRoglP7hkjQcd6EpMcZEAw== - -"@swc/core-darwin-x64@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.4.0.tgz#f044ddaca60c5081e907b148721ad7461f6f6dfe" - integrity sha512-f8v58u2GsGak8EtZFN9guXqE0Ep10Suny6xriaW2d8FGqESPyNrnBzli3aqkSeQk5gGqu2zJ7WiiKp3XoUOidA== - -"@swc/core-darwin-x64@1.7.26": - version "1.7.26" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.7.26.tgz#867b7a4f094e6b64201090ca5fcbf3da7d0f3e22" - integrity sha512-az3cibZdsay2HNKmc4bjf62QVukuiMRh5sfM5kHR/JMTrLyS6vSw7Ihs3UTkZjUxkLTT8ro54LI6sV6sUQUbLQ== - -"@swc/core-linux-arm-gnueabihf@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.4.0.tgz#52ceea673fc76692c0bd6d58e1863125c3e6173b" - integrity sha512-q2KAkBzmPcTnRij/Y1fgHCKAGevUX/H4uUESrw1J5gmUg9Qip6onKV80lTumA1/aooGJ18LOsB31qdbwmZk9OA== - -"@swc/core-linux-arm-gnueabihf@1.7.26": - version "1.7.26" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.7.26.tgz#35bb43894def296d92aaa2cc9372d48042f37777" - integrity sha512-VYPFVJDO5zT5U3RpCdHE5v1gz4mmR8BfHecUZTmD2v1JeFY6fv9KArJUpjrHEEsjK/ucXkQFmJ0jaiWXmpOV9Q== - -"@swc/core-linux-arm64-gnu@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.4.0.tgz#7f3ff1ab824ec48acdb39d231cbcb4096a4f9dd0" - integrity sha512-SknGu96W0mzHtLHWm+62fk5+Omp9fMPFO7AWyGFmz2tr8EgRRXtTSrBUnWhAbgcalnhen48GsvtMdxf1KNputg== - -"@swc/core-linux-arm64-gnu@1.7.26": - version "1.7.26" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.7.26.tgz#8e2321cc4ec84cbfed8f8e16ff1ed7b854450443" - integrity sha512-YKevOV7abpjcAzXrhsl+W48Z9mZvgoVs2eP5nY+uoMAdP2b3GxC0Df1Co0I90o2lkzO4jYBpTMcZlmUXLdXn+Q== - -"@swc/core-linux-arm64-musl@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.4.0.tgz#26c3b1f7947c19ef725997af716f230957d586f8" - integrity sha512-/k3TDvpBRMDNskHooNN1KqwUhcwkfBlIYxRTnJvsfT2C7My4pffR+4KXmt0IKynlTTbCdlU/4jgX4801FSuliw== - -"@swc/core-linux-arm64-musl@1.7.26": - version "1.7.26" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.7.26.tgz#b1c16e4b23ffa9ff19973eda6ffee35d2a7de7b0" - integrity sha512-3w8iZICMkQQON0uIcvz7+Q1MPOW6hJ4O5ETjA0LSP/tuKqx30hIniCGOgPDnv3UTMruLUnQbtBwVCZTBKR3Rkg== - -"@swc/core-linux-x64-gnu@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.4.0.tgz#2c7d03a04a7d045394cfed7d46419ff8816ec22e" - integrity sha512-GYsTMvNt5+WTVlwwQzOOWsPMw6P/F41u5PGHWmfev8Nd4QJ1h3rWPySKk4mV42IJwH9MgQCVSl3ygwNqwl6kFg== - -"@swc/core-linux-x64-gnu@1.7.26": - version "1.7.26" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.7.26.tgz#388e2cc13a010cd28787aead2cecf31eb491836d" - integrity sha512-c+pp9Zkk2lqb06bNGkR2Looxrs7FtGDMA4/aHjZcCqATgp348hOKH5WPvNLBl+yPrISuWjbKDVn3NgAvfvpH4w== - -"@swc/core-linux-x64-musl@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.4.0.tgz#0e76442dfb6d5026d8d6e7db6b2f4922b7692d0f" - integrity sha512-jGVPdM/VwF7kK/uYRW5N6FwzKf/FnDjGIR3RPvQokjYJy7Auk+3Oj21C0Jev7sIT9RYnO/TrFEoEozKeD/z2Qw== - -"@swc/core-linux-x64-musl@1.7.26": - version "1.7.26" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.7.26.tgz#51e0ff30981f26d7a5b97a7a7b5b291bad050d1a" - integrity sha512-PgtyfHBF6xG87dUSSdTJHwZ3/8vWZfNIXQV2GlwEpslrOkGqy+WaiiyE7Of7z9AvDILfBBBcJvJ/r8u980wAfQ== - -"@swc/core-win32-arm64-msvc@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.4.0.tgz#0177bebf312eb251d6749ab76259c0e08088e837" - integrity sha512-biHYm1AronEKlt47O/H8sSOBM2BKXMmWT+ApvlxUw50m1RGNnVnE0bgY7tylFuuSiWyXsQPJbmUV708JqORXVg== - -"@swc/core-win32-arm64-msvc@1.7.26": - version "1.7.26" - resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.7.26.tgz#a7fdcc4074c34ee6a026506b594d00323383c11f" - integrity sha512-9TNXPIJqFynlAOrRD6tUQjMq7KApSklK3R/tXgIxc7Qx+lWu8hlDQ/kVPLpU7PWvMMwC/3hKBW+p5f+Tms1hmA== - -"@swc/core-win32-ia32-msvc@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.4.0.tgz#27fa650280e5651aa42129eaf03e02787b866417" - integrity sha512-TL5L2tFQb19kJwv6+elToGBj74QXCn9j+hZfwQatvZEJRA5rDK16eH6oAE751dGUArhnWlW3Vj65hViPvTuycw== - -"@swc/core-win32-ia32-msvc@1.7.26": - version "1.7.26" - resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.7.26.tgz#ae7be6dde798eebee2000b8fd84e01a439b5bd6a" - integrity sha512-9YngxNcG3177GYdsTum4V98Re+TlCeJEP4kEwEg9EagT5s3YejYdKwVAkAsJszzkXuyRDdnHUpYbTrPG6FiXrQ== - -"@swc/core-win32-x64-msvc@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.4.0.tgz#bd575c599bd6847bddc4863a3babd85e3db5e11e" - integrity sha512-e2xVezU7XZ2Stzn4i7TOQe2Kn84oYdG0M3A7XI7oTdcpsKCcKwgiMoroiAhqCv+iN20KNqhnWwJiUiTj/qN5AA== - -"@swc/core-win32-x64-msvc@1.7.26": - version "1.7.26" - resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.7.26.tgz#310d607004d7319085a4dec20c0c38c3405cc05b" - integrity sha512-VR+hzg9XqucgLjXxA13MtV5O3C0bK0ywtLIBw/+a+O+Oc6mxFWHtdUeXDbIi5AiPbn0fjgVJMqYnyjGyyX8u0w== - -"@swc/core@^1.3.1": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.4.0.tgz#3a0ceeea5b889173f4592955fe1da4d071d86a76" - integrity sha512-wc5DMI5BJftnK0Fyx9SNJKkA0+BZSJQx8430yutWmsILkHMBD3Yd9GhlMaxasab9RhgKqZp7Ht30hUYO5ZDvQg== - dependencies: - "@swc/counter" "^0.1.1" - "@swc/types" "^0.1.5" - optionalDependencies: - "@swc/core-darwin-arm64" "1.4.0" - "@swc/core-darwin-x64" "1.4.0" - "@swc/core-linux-arm-gnueabihf" "1.4.0" - "@swc/core-linux-arm64-gnu" "1.4.0" - "@swc/core-linux-arm64-musl" "1.4.0" - "@swc/core-linux-x64-gnu" "1.4.0" - "@swc/core-linux-x64-musl" "1.4.0" - "@swc/core-win32-arm64-msvc" "1.4.0" - "@swc/core-win32-ia32-msvc" "1.4.0" - "@swc/core-win32-x64-msvc" "1.4.0" - -"@swc/core@^1.5.7": - version "1.7.26" - resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.7.26.tgz#beda9b82063fcec7b56c958804a4d175aecf9a9d" - integrity sha512-f5uYFf+TmMQyYIoxkn/evWhNGuUzC730dFwAKGwBVHHVoPyak1/GvJUm6i1SKl+2Hrj9oN0i3WSoWWZ4pgI8lw== +"@swc/core-darwin-arm64@1.7.28": + version "1.7.28" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.28.tgz#f4ff1c09443a0040a29c7e1e7615f5f5642b6945" + integrity sha512-BNkj6enHo2pdzOpCtQGKZbXT2A/qWIr0CVtbTM4WkJ3MCK/glbFsyO6X59p1r8+gfaZG4bWYnTTu+RuUAcsL5g== + +"@swc/core-darwin-x64@1.7.28": + version "1.7.28" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.7.28.tgz#ce0a6d559084a794517a81457cdadbf61a55c55d" + integrity sha512-96zQ+X5Fd6P/RNPkOyikTJgEc2M4TzznfYvjRd2hye5h22jhxCLL/csoauDgN7lYfd7mwsZ/sVXwJTMKl+vZSA== + +"@swc/core-linux-arm-gnueabihf@1.7.28": + version "1.7.28" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.7.28.tgz#501375ac84c61dc718ed07239c7e44972f6c44e0" + integrity sha512-l2100Wx6LdXMOmOW3+KoHhBhyZrGdz8ylkygcVOC0QHp6YIATfuG+rRHksfyEWCSOdL3anM9MJZJX26KT/s+XQ== + +"@swc/core-linux-arm64-gnu@1.7.28": + version "1.7.28" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.7.28.tgz#75e99da625939627f5b45d3004a6cfd8d6cbf46e" + integrity sha512-03m6iQ5Bv9u2VPnNRyaBmE8eHi056eE39L0gXcqGoo46GAGuoqYHt9pDz8wS6EgoN4t85iBMUZrkCNqFKkN6ZQ== + +"@swc/core-linux-arm64-musl@1.7.28": + version "1.7.28" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.7.28.tgz#c737def355c0bf8db7d8e7bd87a3ae8bb3f9f8fc" + integrity sha512-vqVOpG/jc8mvTKQjaPBLhr7tnWyzuztOHsPnJqMWmg7zGcMeQC/2c5pU4uzRAfXMTp25iId6s4Y4wWfPS1EeDw== + +"@swc/core-linux-x64-gnu@1.7.28": + version "1.7.28" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.7.28.tgz#eb612272ceb1331310eb79ef6094c5a6cc085d23" + integrity sha512-HGwpWuB83Kr+V0E+zT5UwIIY9OxiS8aLd0UVMRVWuO8SrQyKm9HKJ46+zoAb8tfJrpZftfxvbn2ayZWR7gqosA== + +"@swc/core-linux-x64-musl@1.7.28": + version "1.7.28" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.7.28.tgz#a39749a71e690685aabeb7fd60141ccca2e62411" + integrity sha512-q2Y2T8y8EgFtIiRyInnAXNe94aaHX74F0ha1Bl9VdRxE0u1/So+3VLbPvtp4V3Z6pj5pOePfCQJKifnllgAQ9A== + +"@swc/core-win32-arm64-msvc@1.7.28": + version "1.7.28" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.7.28.tgz#93b22667b027e0a5060c91df7e0cc7406d27b01f" + integrity sha512-bCqh4uBT/59h3dWK1v91In6qzz8rKoWoFRxCtNQLIK4jP55K0U231ZK9oN7neZD6bzcOUeFvOGgcyMAgDfFWfA== + +"@swc/core-win32-ia32-msvc@1.7.28": + version "1.7.28" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.7.28.tgz#4d7dbc43a1de79ac0c7cccf35bebf9fe887b2e24" + integrity sha512-XTHbHrksnrqK3JSJ2sbuMWvdJ6/G0roRpgyVTmNDfhTYPOwcVaL/mSrPGLwbksYUbq7ckwoKzrobhdxvQzPsDA== + +"@swc/core-win32-x64-msvc@1.7.28": + version "1.7.28" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.7.28.tgz#d00acea3339a90768279096e6e5f1540c599e6ce" + integrity sha512-jyXeoq6nX8abiCy2EpporsC5ywNENs4ocYuvxo1LSxDktWN1E2MTXq3cdJcEWB2Vydxq0rDcsGyzkRPMzFhkZw== + +"@swc/core@^1.3.1", "@swc/core@^1.5.7": + version "1.7.28" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.7.28.tgz#74aec7a31344da7cfd305a09f14f22420351d495" + integrity sha512-XapcMgsOS0cKh01AFEj+qXOk6KM4NZhp7a5vPicdhkRR8RzvjrCa7DTtijMxfotU8bqaEHguxmiIag2HUlT8QQ== dependencies: "@swc/counter" "^0.1.3" "@swc/types" "^0.1.12" optionalDependencies: - "@swc/core-darwin-arm64" "1.7.26" - "@swc/core-darwin-x64" "1.7.26" - "@swc/core-linux-arm-gnueabihf" "1.7.26" - "@swc/core-linux-arm64-gnu" "1.7.26" - "@swc/core-linux-arm64-musl" "1.7.26" - "@swc/core-linux-x64-gnu" "1.7.26" - "@swc/core-linux-x64-musl" "1.7.26" - "@swc/core-win32-arm64-msvc" "1.7.26" - "@swc/core-win32-ia32-msvc" "1.7.26" - "@swc/core-win32-x64-msvc" "1.7.26" - -"@swc/counter@^0.1.1", "@swc/counter@^0.1.3": + "@swc/core-darwin-arm64" "1.7.28" + "@swc/core-darwin-x64" "1.7.28" + "@swc/core-linux-arm-gnueabihf" "1.7.28" + "@swc/core-linux-arm64-gnu" "1.7.28" + "@swc/core-linux-arm64-musl" "1.7.28" + "@swc/core-linux-x64-gnu" "1.7.28" + "@swc/core-linux-x64-musl" "1.7.28" + "@swc/core-win32-arm64-msvc" "1.7.28" + "@swc/core-win32-ia32-msvc" "1.7.28" + "@swc/core-win32-x64-msvc" "1.7.28" + +"@swc/counter@^0.1.3": version "0.1.3" resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9" integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ== @@ -2591,11 +1917,6 @@ dependencies: "@swc/counter" "^0.1.3" -"@swc/types@^0.1.5": - version "0.1.5" - resolved "https://registry.yarnpkg.com/@swc/types/-/types-0.1.5.tgz#043b731d4f56a79b4897a3de1af35e75d56bc63a" - integrity sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw== - "@tanstack/query-core@5.51.24": version "5.51.24" resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.51.24.tgz#da901637c8652ba5703b92bd07496e7c9ae27836" @@ -2629,9 +1950,9 @@ "@testing-library/dom" "^10.1.0" "@testing-library/dom@^10.1.0": - version "10.1.0" - resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-10.1.0.tgz#2d073e49771ad614da999ca48f199919e5176fb6" - integrity sha512-wdsYKy5zupPyLCW2Je5DLHSxSfbIp6h80WoHOQc+RPtmPGA52O9x5MJEkv92Sjonpq+poOAtUKhh1kBGAXBrNA== + version "10.4.0" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-10.4.0.tgz#82a9d9462f11d240ecadbf406607c6ceeeff43a8" + integrity sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ== dependencies: "@babel/code-frame" "^7.10.4" "@babel/runtime" "^7.12.5" @@ -2643,23 +1964,23 @@ pretty-format "^27.0.2" "@testing-library/jest-dom@~6.4.2": - version "6.4.2" - resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-6.4.2.tgz#38949f6b63722900e2d75ba3c6d9bf8cffb3300e" - integrity sha512-CzqH0AFymEMG48CpzXFriYYkOjk6ZGPCLMhW9e9jg3KMCn5OfJecF8GtGW7yGfR/IgCe3SX8BSwjdzI6BBbZLw== + version "6.4.8" + resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-6.4.8.tgz#9c435742b20c6183d4e7034f2b329d562c079daa" + integrity sha512-JD0G+Zc38f5MBHA4NgxQMR5XtO5Jx9g86jqturNTt2WUfRmLDIY7iKkWHDCCTiDuFMre6nxAD5wHw9W5kI4rGw== dependencies: - "@adobe/css-tools" "^4.3.2" + "@adobe/css-tools" "^4.4.0" "@babel/runtime" "^7.9.2" aria-query "^5.0.0" chalk "^3.0.0" css.escape "^1.5.1" dom-accessibility-api "^0.6.3" - lodash "^4.17.15" + lodash "^4.17.21" redent "^3.0.0" "@testing-library/react@~16.0.0": - version "16.0.0" - resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-16.0.0.tgz#0a1e0c7a3de25841c3591b8cb7fb0cf0c0a27321" - integrity sha512-guuxUKRWQ+FgNX0h0NS0FIq3Q3uLtWVpBzcLOggmfMoUpgBnzBzvLLd4fbm6yS8ydJd94cIfY4yP9qUQjM2KwQ== + version "16.0.1" + resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-16.0.1.tgz#29c0ee878d672703f5e7579f239005e4e0faa875" + integrity sha512-dSmwJVtJXmku+iocRhWOUFbrERC76TX2Mnf0ATODz8brzAZrMBbzLwQixlBSanZxR6LddK3eiwpSFZgDET1URg== dependencies: "@babel/runtime" "^7.12.5" @@ -2668,43 +1989,6 @@ resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.5.2.tgz#db7257d727c891905947bd1c1a99da20e03c2ebd" integrity sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ== -"@tokens-studio/sd-transforms@1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@tokens-studio/sd-transforms/-/sd-transforms-1.2.0.tgz#467ca4adf53cd955d8b6ebb2704ed147f10f1145" - integrity sha512-Ygj0nHiS0b/xMOcCovgrBylKk7EgDM9K3DiWEvdSGQZHAfOshAR7UCYQ5vEIH7NZaIVZqgqu2rB8FCIA9PDxbw== - dependencies: - "@bundled-es-modules/deepmerge" "^4.3.1" - "@bundled-es-modules/postcss-calc-ast-parser" "^0.1.6" - "@tokens-studio/types" "^0.5.1" - colorjs.io "^0.4.3" - expr-eval-fork "^2.0.2" - is-mergeable-object "^1.1.1" - -"@tokens-studio/types@^0.5.1": - version "0.5.1" - resolved "https://registry.yarnpkg.com/@tokens-studio/types/-/types-0.5.1.tgz#5037e58c4b2c306762f12e8d9685e9aeebb21685" - integrity sha512-LdCF9ZH5ej4Gb6n58x5fTkhstxjXDZc1SWteMWY6EiddLQJVONMIgYOrWrf1extlkSLjagX8WS0B63bAqeltnA== - -"@tsconfig/node10@^1.0.7": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" - integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== - -"@tsconfig/node12@^1.0.7": - version "1.0.11" - resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" - integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== - -"@tsconfig/node14@^1.0.0": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" - integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== - -"@tsconfig/node16@^1.0.2": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" - integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== - "@types/aria-query@^5.0.1": version "5.0.4" resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-5.0.4.tgz#1a31c3d378850d2778dabb6374d036dcba4ba708" @@ -2737,9 +2021,9 @@ "@babel/types" "^7.0.0" "@types/babel__traverse@*", "@types/babel__traverse@^7.18.0": - version "7.20.5" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.5.tgz#7b7502be0aa80cc4ef22978846b983edaafcd4dd" - integrity sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ== + version "7.20.6" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.6.tgz#8dc9f0ae0f202c08d8d4dab648912c8d6038e3f7" + integrity sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg== dependencies: "@babel/types" "^7.20.7" @@ -2752,9 +2036,9 @@ "@types/node" "*" "@types/braintree-web@^3.75.23": - version "3.96.10" - resolved "https://registry.yarnpkg.com/@types/braintree-web/-/braintree-web-3.96.10.tgz#c718cd9b6b107748746c04b3d02b0d07af7f951b" - integrity sha512-WB68hhxId8cUxddF9Au8STWULeeT2ZGvSJ+SvJz5ACqV3mYg7rlFkCOY88wHvbWBQAerqdxQ8NLVTe5V05R4/Q== + version "3.96.14" + resolved "https://registry.yarnpkg.com/@types/braintree-web/-/braintree-web-3.96.14.tgz#7303a5439bbc4a3a4b497bbac4bec77921e97cab" + integrity sha512-gRq2BbKUNACKXz6Tiqi4BX1fyMtWXUJZ82ooagwhXpIPQRx/HSRvz/aFzEA48jXr7k9dNchFOs6tMoo3cIgoiA== dependencies: "@types/googlepay" "*" "@types/paypal-checkout-components" "*" @@ -2767,9 +2051,9 @@ "@types/chai" "*" "@types/chai@*": - version "4.3.11" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.11.tgz#e95050bf79a932cb7305dd130254ccdf9bde671c" - integrity sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ== + version "5.0.0" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-5.0.0.tgz#7f981e71e69c9b2d422f58f78de1c59179782133" + integrity sha512-+DwhEHAaFPPdJ2ral3kNHFQXnTfscEEFsUxzD+d7nlcLrFK23JtNjH71RGasTcHb88b4vVi4mTyfpf8u2L8bdA== "@types/chart.js@^2.9.21": version "2.9.41" @@ -2870,7 +2154,7 @@ resolved "https://registry.yarnpkg.com/@types/escodegen/-/escodegen-0.0.6.tgz#5230a9ce796e042cda6f086dbf19f22ea330659c" integrity sha512-AjwI4MvWx3HAOaZqYsjKWyEObT9lcVV0Y0V8nXo6cXzN8ZiMxVhf6F3d/UNvXVGKrEzL/Dluc5p+y9GkzlTWig== -"@types/estree@1.0.5", "@types/estree@^1.0.0": +"@types/estree@1.0.5": version "1.0.5" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== @@ -2880,17 +2164,22 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== +"@types/estree@^1.0.0", "@types/estree@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== + "@types/express-serve-static-core@^4.17.33": - version "4.17.43" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz#10d8444be560cb789c4735aea5eac6e5af45df54" - integrity sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg== + version "4.19.6" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz#e01324c2a024ff367d92c66f48553ced0ab50267" + integrity sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A== dependencies: "@types/node" "*" "@types/qs" "*" "@types/range-parser" "*" "@types/send" "*" -"@types/express@^4.17.21", "@types/express@^4.7.0": +"@types/express@^4.17.21": version "4.17.21" resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.21.tgz#c26d4a151e60efe0084b23dc3369ebc631ed192d" integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ== @@ -2914,9 +2203,9 @@ "@types/node" "*" "@types/googlepay@*": - version "0.7.5" - resolved "https://registry.yarnpkg.com/@types/googlepay/-/googlepay-0.7.5.tgz#b944cd0e4c49f4661c9b966cb45614eb7ae87a26" - integrity sha512-158egcRaqkMSpW6unyGV4uG4FpoCklRf3J5emCzOXSRVAohMfIuZ481JNvp4X6+KxoNjxWiGtMx5vb1YfQADPw== + version "0.7.6" + resolved "https://registry.yarnpkg.com/@types/googlepay/-/googlepay-0.7.6.tgz#ba444ad8b2945e70f873673b8f5371745b8cfe37" + integrity sha512-5003wG+qvf4Ktf1hC9IJuRakNzQov00+Xf09pAWGJLpdOjUrq0SSLCpXX7pwSeTG9r5hrdzq1iFyZcW7WVyr4g== "@types/hast@^3.0.0": version "3.0.4" @@ -2960,16 +2249,7 @@ resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f" integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== -"@types/jsdom@^21.1.4": - version "21.1.6" - resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-21.1.6.tgz#bcbc7b245787ea863f3da1ef19aa1dcfb9271a1b" - integrity sha512-/7kkMsC+/kMs7gAYmmBR9P0vGTnOoLhQhyhQJSlXGI5bzTHp6xdo0TtKWQAsz6pmSAeVqKSbqeyP6hytqr9FDw== - dependencies: - "@types/node" "*" - "@types/tough-cookie" "*" - parse5 "^7.0.0" - -"@types/json-schema@^7.0.12", "@types/json-schema@^7.0.3", "@types/json-schema@^7.0.9": +"@types/json-schema@^7.0.12", "@types/json-schema@^7.0.15", "@types/json-schema@^7.0.3", "@types/json-schema@^7.0.9": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== @@ -2980,33 +2260,14 @@ integrity sha512-DqwyAKpVuv+7DniCp2Deq1xGvfdnKSNgl9Agun2w6dFvR5UKamiv4VfYUgcypd8S9ojUyARFIlZqBrYrBMQlew== "@types/linkify-it@*": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-3.0.5.tgz#1e78a3ac2428e6d7e6c05c1665c242023a4601d8" - integrity sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw== - -"@types/lodash.clonedeep@^4.5.9": - version "4.5.9" - resolved "https://registry.yarnpkg.com/@types/lodash.clonedeep/-/lodash.clonedeep-4.5.9.tgz#ea48276c7cc18d080e00bb56cf965bcceb3f0fc1" - integrity sha512-19429mWC+FyaAhOLzsS8kZUsI+/GmBAQ0HFiCPsKGU+7pBXOQWhyrY6xNNDwUSX8SMZMJvuFVMF9O5dQOlQK9Q== - dependencies: - "@types/lodash" "*" - -"@types/lodash.curry@^4.1.9": - version "4.1.9" - resolved "https://registry.yarnpkg.com/@types/lodash.curry/-/lodash.curry-4.1.9.tgz#b9a0f5032747309c3cbe78e1acffc1599fb78d94" - integrity sha512-QV967vSflHEza0d0IMTK7fwbl+baPBXZjcESeAHrA5eSE+EHetaggZjPpkzX1NJh4qa8DLOLScwUR+f7FN85Zg== - dependencies: - "@types/lodash" "*" - -"@types/lodash@*": - version "4.17.0" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.0.tgz#d774355e41f372d5350a4d0714abb48194a489c3" - integrity sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA== + version "5.0.0" + resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-5.0.0.tgz#21413001973106cda1c3a9b91eedd4ccd5469d76" + integrity sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q== "@types/lodash@^4.14.167", "@types/lodash@^4.14.175": - version "4.14.202" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.202.tgz#f09dbd2fb082d507178b2f2a5c7e74bd72ff98f8" - integrity sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ== + version "4.17.9" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.9.tgz#0dc4902c229f6b8e2ac5456522104d7b1a230290" + integrity sha512-w9iWudx1XWOHW5lQRS9iKpK/XuRhnN+0T7HvdCCd802FYkT1AMTnxndJHGrNJwRoRHkslGr4S29tjm1cT7x/7w== "@types/luxon@3.4.2": version "3.4.2" @@ -3029,26 +2290,21 @@ integrity sha512-/i42wjYNgE6wf0j2bcTX6kuowmdL/6PE4IVitMpm2eYKBUuYCprdcWVK+xEF0gcV6ufMCRhtxmReGfc6hIK7Jw== "@types/mdast@^4.0.0": - version "4.0.3" - resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-4.0.3.tgz#1e011ff013566e919a4232d1701ad30d70cab333" - integrity sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg== + version "4.0.4" + resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-4.0.4.tgz#7ccf72edd2f1aa7dd3437e180c64373585804dd6" + integrity sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA== dependencies: "@types/unist" "*" "@types/mdurl@*": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-1.0.5.tgz#3e0d2db570e9fb6ccb2dc8fde0be1d79ac810d39" - integrity sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA== + version "2.0.0" + resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-2.0.0.tgz#d43878b5b20222682163ae6f897b20447233bdfd" + integrity sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg== "@types/mdx@^2.0.0": - version "2.0.11" - resolved "https://registry.yarnpkg.com/@types/mdx/-/mdx-2.0.11.tgz#21f4c166ed0e0a3a733869ba04cd8daea9834b8e" - integrity sha512-HM5bwOaIQJIQbAYfax35HCKxx7a3KrK3nBtIqJgSOitivTD1y3oW9P3rxY9RkXYPUk7y/AjAohfHKmFpGE79zw== - -"@types/mime@*": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.4.tgz#2198ac274de6017b44d941e00261d5bc6a0e0a45" - integrity sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw== + version "2.0.13" + resolved "https://registry.yarnpkg.com/@types/mdx/-/mdx-2.0.13.tgz#68f6877043d377092890ff5b298152b0a21671bd" + integrity sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw== "@types/mime@^1": version "1.3.5" @@ -3061,9 +2317,9 @@ integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== "@types/mocha@^10.0.2": - version "10.0.6" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.6.tgz#818551d39113081048bdddbef96701b4e8bb9d1b" - integrity sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg== + version "10.0.8" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.8.tgz#a7eff5816e070c3b4d803f1d3cd780c4e42934a1" + integrity sha512-HfMcUmy9hTMJh66VNcmeC9iVErIZJli2bszuXc6julh5YGuRb/W5OnkHjwLNYdFlMis0sY3If5SEAp+PktdJjw== "@types/ms@*": version "0.7.34" @@ -3077,37 +2333,18 @@ dependencies: "@types/node" "*" -"@types/node@*": - version "20.11.17" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.17.tgz#cdd642d0e62ef3a861f88ddbc2b61e32578a9292" - integrity sha512-QmgQZGWu1Yw9TDyAP9ZzpFJKynYNeOvwMJmaxABfieQoVoiVOS6MN1WSpqpRcbeA5+RW82kraAVxCCJg+780Qw== +"@types/node@*", "@types/node@^22.0.0", "@types/node@^22.5.5": + version "22.7.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.1.tgz#c6a2628c8a68511ab7b68f3be7c9b38716bdf04f" + integrity sha512-adOMRLVmleuWs/5V/w5/l7o0chDK/az+5ncCsIapTKogsu/3MVWvSgP58qVTXi5IwpfGt8pMobNq9rOWtJyu5Q== dependencies: - undici-types "~5.26.4" + undici-types "~6.19.2" "@types/node@^12.7.1": version "12.20.55" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== -"@types/node@^20.11.26": - version "20.11.27" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.27.tgz#debe5cfc8a507dd60fe2a3b4875b1604f215c2ac" - integrity sha512-qyUZfMnCg1KEz57r7pzFtSGt49f6RPkPBis3Vo4PbS7roQEDn22hiHzl/Lo1q4i4hDEgBJmBF/NTNg2XR0HbFg== - dependencies: - undici-types "~5.26.4" - -"@types/node@^22.0.0": - version "22.5.4" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.4.tgz#83f7d1f65bc2ed223bdbf57c7884f1d5a4fa84e8" - integrity sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg== - dependencies: - undici-types "~6.19.2" - -"@types/normalize-package-data@^2.4.0": - version "2.4.4" - resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901" - integrity sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA== - "@types/parse-json@^4.0.0": version "4.0.2" resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239" @@ -3118,15 +2355,10 @@ resolved "https://registry.yarnpkg.com/@types/paypal-checkout-components/-/paypal-checkout-components-4.0.8.tgz#dae11a164fb77fe370b013c0be44951bdc4ebf4d" integrity sha512-Z3IWbFPGdgL3O+Bg+TyVmMT8S3uGBsBjw3a8uRNR4OlYWa9m895djENErJMYU8itoki9rtcQMzoHOSFn8NFb1A== -"@types/prop-types@*", "@types/prop-types@^15.7.11": - version "15.7.11" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.11.tgz#2596fb352ee96a1379c657734d4b913a613ad563" - integrity sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng== - -"@types/prop-types@^15.7.12": - version "15.7.12" - resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6" - integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q== +"@types/prop-types@*", "@types/prop-types@^15.7.12": + version "15.7.13" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.13.tgz#2af91918ee12d9d32914feb13f5326658461b451" + integrity sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA== "@types/qrcode.react@^0.8.0": version "0.8.2" @@ -3136,9 +2368,9 @@ "@types/react" "*" "@types/qs@*": - version "6.9.11" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.11.tgz#208d8a30bc507bd82e03ada29e4732ea46a6bbda" - integrity sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ== + version "6.9.16" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.16.tgz#52bba125a07c0482d26747d5d4947a64daf8f794" + integrity sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A== "@types/raf@^3.4.0": version "3.4.3" @@ -3170,16 +2402,16 @@ "@types/react" "*" "@types/react-dom@*", "@types/react-dom@^18.2.18": - version "18.2.19" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.19.tgz#b84b7c30c635a6c26c6a6dfbb599b2da9788be58" - integrity sha512-aZvQL6uUbIJpjZk4U8JZGbau9KDeAwMfmhyWorxgBkqDIEf6ROjRozcmPIicqsUwPUjbkDfHKgGee1Lq65APcA== + version "18.3.0" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.0.tgz#0cbc818755d87066ab6ca74fbedb2547d74a82b0" + integrity sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg== dependencies: "@types/react" "*" "@types/react-redux@^7.1.20", "@types/react-redux@~7.1.7": - version "7.1.33" - resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.33.tgz#53c5564f03f1ded90904e3c90f77e4bd4dc20b15" - integrity sha512-NF8m5AjWCkert+fosDsN3hAlHzpjSiXlVy9EgQEmLoBhaNXbmyeGs/aj5dQzKuF+/q+S7JQagorGDW8pJ28Hmg== + version "7.1.34" + resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.34.tgz#83613e1957c481521e6776beeac4fd506d11bd0e" + integrity sha512-GdFaVjEbYv4Fthm2ZLvj1VSCedV7TqE5y1kNwnjSdBOTXuRSgowux6J8TAct15T3CKBr63UMk+2CO7ilRhyrAQ== dependencies: "@types/hoist-non-react-statics" "^3.3.0" "@types/react" "*" @@ -3220,35 +2452,27 @@ "@types/react-dom" "*" "@types/react-transition-group" "*" -"@types/react-transition-group@*", "@types/react-transition-group@^4.4.10": - version "4.4.10" - resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.10.tgz#6ee71127bdab1f18f11ad8fb3322c6da27c327ac" - integrity sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q== +"@types/react-transition-group@*", "@types/react-transition-group@^4.4.10", "@types/react-transition-group@^4.4.11": + version "4.4.11" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.11.tgz#d963253a611d757de01ebb241143b1017d5d63d5" + integrity sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA== dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^18.2.55": - version "18.2.55" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.55.tgz#38141821b7084404b5013742bc4ae08e44da7a67" - integrity sha512-Y2Tz5P4yz23brwm2d7jNon39qoAtMMmalOQv6+fEFt1mT+FcM3D841wDpoUvFXhaYenuROCy3FZYqdTjM7qVyA== - dependencies: - "@types/prop-types" "*" - "@types/scheduler" "*" - csstype "^3.0.2" - -"@types/react@^16.8.0 || ^17.0.0 || ^18.0.0": - version "18.2.73" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.73.tgz#0579548ad122660d99e00499d22e33b81e73ed94" - integrity sha512-XcGdod0Jjv84HOC7N5ziY3x+qL0AfmubvKOZ9hJjJ2yd5EE+KYjWhdOjt387e9HPheHkdggF9atTifMRtyAaRA== +"@types/react@*", "@types/react@^16.8.0 || ^17.0.0 || ^18.0.0", "@types/react@^18.2.55": + version "18.3.9" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.9.tgz#2cdf5f425ec8a133d67e9e3673909738b783db20" + integrity sha512-+BpAVyTpJkNWWSSnaLBk6ePpHLOGJKnEQNbINNovPWzvEUyAe3e+/d494QdEh71RekM/qV7lw6jzf1HGrJyAtQ== dependencies: "@types/prop-types" "*" csstype "^3.0.2" "@types/recompose@^0.30.0": - version "0.30.14" - resolved "https://registry.yarnpkg.com/@types/recompose/-/recompose-0.30.14.tgz#06c5b3ff3f1df746ab6e8baecc3e288971936892" - integrity sha512-DDxwOemcQhtXuwIODKz8UVRroNoMkLoHiLJ/kIML3nC4WWE/0sfdrCev4zsazHCuj9BwDTTn/LsNtxwxTRK1WA== + version "0.30.15" + resolved "https://registry.yarnpkg.com/@types/recompose/-/recompose-0.30.15.tgz#29ba4e6ffc7714c9026fd709931125f42c11ed3f" + integrity sha512-glX9JbRTG4WSaWxDrsHlinoRC1YRb0vNr+ocPBgBTJgMawkYx8fqwuduahzy25XBSc3xfG/k9b5XPyW6FuHVkw== dependencies: + "@types/prop-types" "*" "@types/react" "*" "@types/redux-mock-store@^1.0.1": @@ -3263,17 +2487,7 @@ resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.6.tgz#e6e60dad29c2c8c206c026e6dd8d6d1bdda850b8" integrity sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ== -"@types/scheduler@*": - version "0.16.8" - resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.8.tgz#ce5ace04cfeabe7ef87c0091e50752e36707deff" - integrity sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A== - -"@types/semver@^7.3.12": - version "7.5.6" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.6.tgz#c65b2bfce1bec346582c07724e3f8c1017a20339" - integrity sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A== - -"@types/semver@^7.5.0": +"@types/semver@^7.3.12", "@types/semver@^7.5.0": version "7.5.8" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== @@ -3287,13 +2501,13 @@ "@types/node" "*" "@types/serve-static@*": - version "1.15.5" - resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.5.tgz#15e67500ec40789a1e8c9defc2d32a896f05b033" - integrity sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ== + version "1.15.7" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.7.tgz#22174bbd74fb97fe303109738e9b5c2f3064f714" + integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw== dependencies: "@types/http-errors" "*" - "@types/mime" "*" "@types/node" "*" + "@types/send" "*" "@types/sinonjs__fake-timers@8.1.1": version "8.1.1" @@ -3315,7 +2529,7 @@ resolved "https://registry.yarnpkg.com/@types/throttle-debounce/-/throttle-debounce-1.1.1.tgz#4a78636c36a4534b76d85ee244fce238d435f22a" integrity sha512-VhX9p0l8p3TS27XU+CnDfhdnzW7HpVgtKiYDh/lfucSAz8s9uTt0q4aPwcYIr+q+3/NghlU3smXBW6ItvfJKYQ== -"@types/tough-cookie@*": +"@types/tough-cookie@^4.0.5": version "4.0.5" resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.5.tgz#cb6e2a691b70cb177c6e3ae9c1d2e8b2ea8cd304" integrity sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA== @@ -3326,9 +2540,9 @@ integrity sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw== "@types/unist@*", "@types/unist@^3.0.0": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.2.tgz#6dd61e43ef60b34086287f83683a5c1b2dc53d20" - integrity sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ== + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.3.tgz#acaab0f919ce69cce629c2d4ed2eb4adc1b6c20c" + integrity sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q== "@types/uuid@^3.4.3": version "3.4.13" @@ -3370,9 +2584,9 @@ integrity sha512-Ynb/CjHhE/Xp/4bhHmQC4U1Ox+I2OpfRYF3dnNgQqn1cHa6LK3H1wJMNPT02tSVZA6FYuXE2ITORfbnb6zBCSA== "@types/zxcvbn@^4.4.0": - version "4.4.4" - resolved "https://registry.yarnpkg.com/@types/zxcvbn/-/zxcvbn-4.4.4.tgz#987f5fcd87e957097433c476c3a1c91a54f53131" - integrity sha512-Tuk4q7q0DnpzyJDI4aMeghGuFu2iS1QAdKpabn8JfbtfGmVDUgvZv1I7mEjP61Bvnp3ljKCC8BE6YYSTNxmvRQ== + version "4.4.5" + resolved "https://registry.yarnpkg.com/@types/zxcvbn/-/zxcvbn-4.4.5.tgz#8ce8623ed7a36e3a76d1c0b539708dfb2e859bc0" + integrity sha512-FZJgC5Bxuqg7Rhsm/bx6gAruHHhDQ55r+s0JhDh8CQ16fD7NsJJ+p8YMMQDhSQoIrSmjpqqYWA96oQVMNkjRyA== "@typescript-eslint/eslint-plugin@^6.21.0": version "6.21.0" @@ -3545,7 +2759,7 @@ "@typescript-eslint/types" "6.21.0" eslint-visitor-keys "^3.4.1" -"@ungap/structured-clone@^1.0.0", "@ungap/structured-clone@^1.2.0": +"@ungap/structured-clone@^1.0.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== @@ -3652,22 +2866,7 @@ resolved "https://registry.yarnpkg.com/@xterm/xterm/-/xterm-5.5.0.tgz#275fb8f6e14afa6e8a0c05d4ebc94523ff775396" integrity sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A== -"@yarnpkg/lockfile@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" - integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== - -"@zeit/schemas@2.29.0": - version "2.29.0" - resolved "https://registry.yarnpkg.com/@zeit/schemas/-/schemas-2.29.0.tgz#a59ae6ebfdf4ddc66a876872dd736baa58b6696c" - integrity sha512-g5QiLIfbg3pLuYUJPlisNKY+epQJTcMDsOnVNkscrDP1oi7vmJnzOANYJI/1pZcVJ6umUkBv3aFtlg1UvUHGzA== - -"@zip.js/zip.js@^2.7.44": - version "2.7.45" - resolved "https://registry.yarnpkg.com/@zip.js/zip.js/-/zip.js-2.7.45.tgz#823fe2789401d8c1d836ce866578379ec1bd6f0b" - integrity sha512-Mm2EXF33DJQ/3GWWEWeP1UCqzpQ5+fiMvT3QWspsXY05DyqqxWu7a9awSzU4/spHMHVFrTjani1PR0vprgZpow== - -accepts@~1.3.5, accepts@~1.3.8: +accepts@~1.3.8: version "1.3.8" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== @@ -3685,20 +2884,15 @@ acorn-walk@^7.2.0: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== -acorn-walk@^8.1.1: - version "8.3.2" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.2.tgz#7703af9415f1b6db9315d6895503862e231d34aa" - integrity sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A== - acorn@^7.1.1, acorn@^7.4.0, acorn@^7.4.1: version "7.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.11.3, acorn@^8.4.1, acorn@^8.9.0: - version "8.11.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" - integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== +acorn@^8.12.0, acorn@^8.12.1: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== agent-base@^7.0.2, agent-base@^7.1.0: version "7.1.1" @@ -3715,16 +2909,6 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" -ajv@8.11.0: - version "8.11.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" - integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" @@ -3736,41 +2920,35 @@ ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.4: uri-js "^4.2.2" ajv@^8.0.1: - version "8.16.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.16.0.tgz#22e2a92b94f005f7e0f9c9d39652ef0b8f6f0cb4" - integrity sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw== + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== dependencies: fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" json-schema-traverse "^1.0.0" require-from-string "^2.0.2" - uri-js "^4.4.1" algoliasearch@^4.14.3: - version "4.22.1" - resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.22.1.tgz#f10fbecdc7654639ec20d62f109c1b3a46bc6afc" - integrity sha512-jwydKFQJKIx9kIZ8Jm44SdpigFwRGPESaxZBaHSV0XWN2yBJAOT4mT7ppvlrpA4UGzz92pqFnVKr/kaZXrcreg== - dependencies: - "@algolia/cache-browser-local-storage" "4.22.1" - "@algolia/cache-common" "4.22.1" - "@algolia/cache-in-memory" "4.22.1" - "@algolia/client-account" "4.22.1" - "@algolia/client-analytics" "4.22.1" - "@algolia/client-common" "4.22.1" - "@algolia/client-personalization" "4.22.1" - "@algolia/client-search" "4.22.1" - "@algolia/logger-common" "4.22.1" - "@algolia/logger-console" "4.22.1" - "@algolia/requester-browser-xhr" "4.22.1" - "@algolia/requester-common" "4.22.1" - "@algolia/requester-node-http" "4.22.1" - "@algolia/transporter" "4.22.1" - -ansi-align@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59" - integrity sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w== - dependencies: - string-width "^4.1.0" + version "4.24.0" + resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.24.0.tgz#b953b3e2309ef8f25da9de311b95b994ac918275" + integrity sha512-bf0QV/9jVejssFBmz2HQLxUadxk574t4iwjCKp5E7NBzwKkrDEhKPISIIjAU/p6K5qDx3qoeh4+26zWN1jmw3g== + dependencies: + "@algolia/cache-browser-local-storage" "4.24.0" + "@algolia/cache-common" "4.24.0" + "@algolia/cache-in-memory" "4.24.0" + "@algolia/client-account" "4.24.0" + "@algolia/client-analytics" "4.24.0" + "@algolia/client-common" "4.24.0" + "@algolia/client-personalization" "4.24.0" + "@algolia/client-search" "4.24.0" + "@algolia/logger-common" "4.24.0" + "@algolia/logger-console" "4.24.0" + "@algolia/recommend" "4.24.0" + "@algolia/requester-browser-xhr" "4.24.0" + "@algolia/requester-common" "4.24.0" + "@algolia/requester-node-http" "4.24.0" + "@algolia/transporter" "4.24.0" ansi-colors@^4.1.1: version "4.1.3" @@ -3791,16 +2969,6 @@ ansi-escapes@^7.0.0: dependencies: environment "^1.0.0" -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== - -ansi-regex@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1" - integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== - ansi-regex@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" @@ -3812,9 +2980,9 @@ ansi-regex@^5.0.1: integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-regex@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" - integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" @@ -3858,16 +3026,6 @@ arch@^2.2.0: resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== -arg@5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c" - integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg== - -arg@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -3880,12 +3038,24 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -aria-query@5.3.0, aria-query@^5.0.0, aria-query@^5.3.0: +aria-query@5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.0.tgz#650c569e41ad90b51b3d7df5e5eed1c7549c103e" integrity sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A== dependencies: - dequal "^2.0.3" + dequal "^2.0.3" + +aria-query@^5.0.0: + version "5.3.2" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.2.tgz#93f81a43480e33a338f19163a3d10a50c01dcd59" + integrity sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw== + +aria-query@~5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.1.3.tgz#19db27cd101152773631396f7a95a3b58c22c35e" + integrity sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ== + dependencies: + deep-equal "^2.0.5" array-buffer-byte-length@^1.0.0, array-buffer-byte-length@^1.0.1: version "1.0.1" @@ -3900,15 +3070,16 @@ array-flatten@1.1.1: resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== -array-includes@^3.1.6, array-includes@^3.1.7: - version "3.1.7" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.7.tgz#8cd2e01b26f7a3086cbc87271593fe921c62abda" - integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== +array-includes@^3.1.6, array-includes@^3.1.8: + version "3.1.8" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" + integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" is-string "^1.0.7" array-union@^2.1.0: @@ -3916,6 +3087,18 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== +array.prototype.findlast@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz#3e4fbcb30a15a7f5bf64cf2faae22d139c2e4904" + integrity sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-shim-unscopables "^1.0.2" + array.prototype.flat@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" @@ -3926,7 +3109,7 @@ array.prototype.flat@^1.3.1: es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" -array.prototype.flatmap@^1.3.1, array.prototype.flatmap@^1.3.2: +array.prototype.flatmap@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== @@ -3936,18 +3119,18 @@ array.prototype.flatmap@^1.3.1, array.prototype.flatmap@^1.3.2: es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" -array.prototype.tosorted@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz#c8c89348337e51b8a3c48a9227f9ce93ceedcba8" - integrity sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg== +array.prototype.tosorted@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz#fe954678ff53034e717ea3352a03f0b0b86f7ffc" + integrity sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA== dependencies: - call-bind "^1.0.5" + call-bind "^1.0.7" define-properties "^1.2.1" - es-abstract "^1.22.3" - es-errors "^1.1.0" + es-abstract "^1.23.3" + es-errors "^1.3.0" es-shim-unscopables "^1.0.2" -arraybuffer.prototype.slice@^1.0.2: +arraybuffer.prototype.slice@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== @@ -3978,17 +3161,6 @@ assert-plus@1.0.0, assert-plus@^1.0.0: resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== -assert@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/assert/-/assert-2.1.0.tgz#6d92a238d05dc02e7427c881fb8be81c8448b2dd" - integrity sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw== - dependencies: - call-bind "^1.0.2" - is-nan "^1.3.2" - object-is "^1.1.5" - object.assign "^4.1.4" - util "^0.12.5" - assertion-error@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" @@ -4017,16 +3189,9 @@ astral-regex@^2.0.0: integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== async@^3.2.0: - version "3.2.5" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66" - integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== - -asynciterator.prototype@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz#8c5df0514936cdd133604dfcc9d3fb93f09b2b62" - integrity sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg== - dependencies: - has-symbols "^1.0.3" + version "3.2.6" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" + integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== asynckit@^0.4.0: version "0.4.0" @@ -4048,10 +3213,12 @@ attr-accept@^2.2.1: resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-2.2.2.tgz#646613809660110749e92f2c10833b70968d929b" integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg== -available-typed-arrays@^1.0.5, available-typed-arrays@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.6.tgz#ac812d8ce5a6b976d738e1c45f08d0b00bc7d725" - integrity sha512-j1QzY8iPNPG4o4xmO3ptzpRxTciqD3MgEHtifP/YnJpIo58Xu+ne4BejlbkuaLfXn/nz6HFiw29bLpj2PNMdGg== +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" aws-sign2@~0.7.0: version "0.7.0" @@ -4059,16 +3226,11 @@ aws-sign2@~0.7.0: integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA== aws4@^1.8.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3" - integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg== - -axe-core@=4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf" - integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ== + version "1.13.2" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.13.2.tgz#0aa167216965ac9474ccfa83892cfb6b3e1e52ef" + integrity sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw== -axe-core@^4.2.0: +axe-core@^4.10.0, axe-core@^4.2.0: version "4.10.0" resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.10.0.tgz#d9e56ab0147278272739a000880196cdfe113b59" integrity sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g== @@ -4082,20 +3244,18 @@ axios-mock-adapter@^1.22.0: is-buffer "^2.0.5" axios@~1.7.4: - version "1.7.4" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.4.tgz#4c8ded1b43683c8dd362973c393f3ede24052aa2" - integrity sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw== + version "1.7.7" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" + integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== dependencies: follow-redirects "^1.15.6" form-data "^4.0.0" proxy-from-env "^1.1.0" -axobject-query@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-3.2.1.tgz#39c378a6e3b06ca679f29138151e45b2b32da62a" - integrity sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg== - dependencies: - dequal "^2.0.3" +axobject-query@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-4.1.0.tgz#28768c76d0e3cff21bc62a9e2d0b6ac30042a1ee" + integrity sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ== babel-eslint@>=4.1.1: version "10.1.0" @@ -4175,10 +3335,17 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" +better-opn@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/better-opn/-/better-opn-3.0.2.tgz#f96f35deaaf8f34144a4102651babcf00d1d8817" + integrity sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ== + dependencies: + open "^8.0.4" + binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== blob-util@^2.0.2: version "2.0.2" @@ -4190,10 +3357,10 @@ bluebird@^3.7.2: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== -body-parser@1.20.2: - version "1.20.2" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" - integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== +body-parser@1.20.3: + version "1.20.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" + integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== dependencies: bytes "3.1.2" content-type "~1.0.5" @@ -4203,25 +3370,11 @@ body-parser@1.20.2: http-errors "2.0.0" iconv-lite "0.4.24" on-finished "2.4.1" - qs "6.11.0" + qs "6.13.0" raw-body "2.5.2" type-is "~1.6.18" unpipe "1.0.0" -boxen@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/boxen/-/boxen-7.0.0.tgz#9e5f8c26e716793fc96edcf7cf754cdf5e3fbf32" - integrity sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg== - dependencies: - ansi-align "^3.0.1" - camelcase "^7.0.0" - chalk "^5.0.1" - cli-boxes "^3.0.0" - string-width "^5.1.2" - type-fest "^2.13.0" - widest-line "^4.0.1" - wrap-ansi "^8.0.1" - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -4237,7 +3390,7 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^3.0.2, braces@^3.0.3, braces@~3.0.2: +braces@^3.0.3, braces@~3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== @@ -4245,22 +3398,23 @@ braces@^3.0.2, braces@^3.0.3, braces@~3.0.2: fill-range "^7.1.1" braintree-web@^3.92.2: - version "3.100.0" - resolved "https://registry.yarnpkg.com/braintree-web/-/braintree-web-3.100.0.tgz#e12b3f5aa5b6f8ca3d4c234a9481b611a81306ef" - integrity sha512-+paeD3D5uYUfKKa3dnuIj6sRyivXQMoKmlwH3Iiy4f1e+4BZyirMj8egO4J9srPf+mIInLSYP60RwoymalfMsQ== + version "3.109.0" + resolved "https://registry.yarnpkg.com/braintree-web/-/braintree-web-3.109.0.tgz#366005e6e84ac016f48fd0b2acab962b193ad740" + integrity sha512-89CLzvldYeSD0cxmInE1mq+viMl7sIGkVm74/6cX91pQWrrO+qaA4r2fpgrqPJ7gWJDQp+5YVa0HliwsbFBYTg== dependencies: - "@braintree/asset-loader" "0.4.4" - "@braintree/browser-detection" "1.17.1" + "@braintree/asset-loader" "2.0.1" + "@braintree/browser-detection" "2.0.1" "@braintree/event-emitter" "0.4.1" - "@braintree/extended-promise" "0.4.1" - "@braintree/iframer" "1.1.0" - "@braintree/sanitize-url" "6.0.4" - "@braintree/uuid" "0.1.0" + "@braintree/extended-promise" "1.0.0" + "@braintree/iframer" "2.0.0" + "@braintree/sanitize-url" "7.0.4" + "@braintree/uuid" "1.0.0" "@braintree/wrap-promise" "2.1.0" - card-validator "8.1.1" - credit-card-type "9.1.0" - framebus "5.2.1" - inject-stylesheet "5.0.0" + "@paypal/accelerated-checkout-loader" "1.1.0" + card-validator "10.0.0" + credit-card-type "10.0.1" + framebus "6.0.0" + inject-stylesheet "6.0.1" promise-polyfill "8.2.3" restricted-input "3.0.5" @@ -4269,15 +3423,15 @@ browser-assert@^1.2.1: resolved "https://registry.yarnpkg.com/browser-assert/-/browser-assert-1.2.1.tgz#9aaa5a2a8c74685c2ae05bfe46efd606f068c200" integrity sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ== -browserslist@^4.22.2: - version "4.22.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.3.tgz#299d11b7e947a6b843981392721169e27d60c5a6" - integrity sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A== +browserslist@^4.23.1: + version "4.24.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.0.tgz#a1325fe4bc80b64fda169629fc01b3d6cecd38d4" + integrity sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A== dependencies: - caniuse-lite "^1.0.30001580" - electron-to-chromium "^1.4.648" - node-releases "^2.0.14" - update-browserslist-db "^1.0.13" + caniuse-lite "^1.0.30001663" + electron-to-chromium "^1.5.28" + node-releases "^2.0.18" + update-browserslist-db "^1.1.0" btoa@^1.2.1: version "1.2.1" @@ -4302,14 +3456,6 @@ buffer@^5.7.1: base64-js "^1.3.1" ieee754 "^1.1.13" -buffer@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" - integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - bundle-require@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/bundle-require/-/bundle-require-5.0.0.tgz#071521bdea6534495cf23e92a83f889f91729e93" @@ -4317,11 +3463,6 @@ bundle-require@^5.0.0: dependencies: load-tsconfig "^0.2.3" -bytes@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" - integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== - bytes@3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" @@ -4337,17 +3478,7 @@ cachedir@^2.3.0: resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-2.4.0.tgz#7fef9cf7367233d7c88068fe6e34ed0d355a610d" integrity sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ== -call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.6.tgz#6c46675fc7a5e9de82d75a233d586c8b7ac0d931" - integrity sha512-Mj50FLHtlsoVfRfnHaZvyrooHcrlceNZdL/QBvJJVd9Ta55qCQK0gs4ss2oZDeV9zFCs6ewzYgVE5yfVmfFpVg== - dependencies: - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.3" - set-function-length "^1.2.0" - -call-bind@^1.0.7: +call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== @@ -4358,25 +3489,6 @@ call-bind@^1.0.7: get-intrinsic "^1.2.4" set-function-length "^1.2.1" -caller-callsite@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" - integrity sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ== - dependencies: - callsites "^2.0.0" - -caller-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" - integrity sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A== - dependencies: - caller-callsite "^2.0.0" - -callsites@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" - integrity sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ== - callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -4387,15 +3499,10 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -camelcase@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-7.0.1.tgz#f02e50af9fd7782bc8b88a3558c32fd3a388f048" - integrity sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw== - -caniuse-lite@^1.0.30001580: - version "1.0.30001653" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001653.tgz" - integrity sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw== +caniuse-lite@^1.0.30001663: + version "1.0.30001663" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001663.tgz#1529a723505e429fdfd49532e9fc42273ba7fed7" + integrity sha512-o9C3X27GLKbLeTYZ6HBOLU1tsAcBZsLis28wrVzddShCS16RujjHp9GDHKZqrB3meE0YjhawvMFsGb/igqiPzA== canvg@^3.0.6: version "3.0.10" @@ -4411,10 +3518,10 @@ canvg@^3.0.6: stackblur-canvas "^2.0.0" svg-pathdata "^6.0.3" -card-validator@8.1.1: - version "8.1.1" - resolved "https://registry.yarnpkg.com/card-validator/-/card-validator-8.1.1.tgz#418f5f32435553fb9ca2a02634ad413bb38697a9" - integrity sha512-cN4FsKwoTfTFnqPwVc7TQLSsH/QMDB3n/gWm0XelcApz4sKipnOQ6k33sa3bWsNnnIpgs7eXOF+mUV2UQAX2Sw== +card-validator@10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/card-validator/-/card-validator-10.0.0.tgz#288a5525cae765566c4ff7d6e841d8e1ae63cd4c" + integrity sha512-2fLyCBOxO7/b56sxoYav8FeJqv9bWpZSyKq8sXKxnpxTGXHnM/0c8WEKG+ZJ+OXFcabnl98pD0EKBtTn+Tql0g== dependencies: credit-card-type "^9.1.0" @@ -4444,18 +3551,6 @@ chai@^5.1.1: loupe "^3.1.0" pathval "^2.0.0" -chalk-template@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/chalk-template/-/chalk-template-0.4.0.tgz#692c034d0ed62436b9062c1707fadcd0f753204b" - integrity sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg== - dependencies: - chalk "^4.1.2" - -chalk@5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.0.1.tgz#ca57d71e82bb534a296df63bbacc4a1c22b2a4b6" - integrity sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w== - chalk@^2.1.0, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -4481,16 +3576,11 @@ chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^5.0.1, chalk@^5.2.0, chalk@^5.3.0, chalk@~5.3.0: +chalk@^5.2.0, chalk@~5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== -change-case@^5.3.0: - version "5.4.4" - resolved "https://registry.yarnpkg.com/change-case/-/change-case-5.4.4.tgz#0d52b507d8fb8f204343432381d1a6d7bff97a02" - integrity sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w== - change-emitter@^0.1.2: version "0.1.6" resolved "https://registry.yarnpkg.com/change-emitter/-/change-emitter-0.1.6.tgz#e8b2fe3d7f1ab7d69a32199aff91ea6931409515" @@ -4559,12 +3649,7 @@ chokidar@^3.5.3, chokidar@^3.6.0: optionalDependencies: fsevents "~2.3.2" -ci-info@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" - integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== - -ci-info@^3.2.0, ci-info@^3.7.0: +ci-info@^3.2.0: version "3.9.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== @@ -4574,11 +3659,6 @@ clean-stack@^2.0.0: resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== -cli-boxes@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-3.0.0.tgz#71a10c716feeba005e4504f36329ef0b17cf3145" - integrity sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g== - cli-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" @@ -4593,15 +3673,10 @@ cli-cursor@^5.0.0: dependencies: restore-cursor "^5.0.0" -cli-spinners@^2.9.2: - version "2.9.2" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.2.tgz#1773a8f4b9c4d6ac31563df53b3fc1d79462fe41" - integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg== - cli-table3@~0.6.1: - version "0.6.3" - resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.3.tgz#61ab765aac156b52f222954ffc607a6f01dbeeb2" - integrity sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg== + version "0.6.5" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.5.tgz#013b91351762739c16a9567c21a04632e449bf2f" + integrity sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ== dependencies: string-width "^4.2.0" optionalDependencies: @@ -4633,24 +3708,6 @@ cli-width@^4.1.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-4.1.0.tgz#42daac41d3c254ef38ad8ac037672130173691c5" integrity sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ== -clipboardy@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-3.0.0.tgz#f3876247404d334c9ed01b6f269c11d09a5e3092" - integrity sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg== - dependencies: - arch "^2.2.0" - execa "^5.1.1" - is-wsl "^2.2.0" - -cliui@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" - integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== - dependencies: - string-width "^2.1.1" - strip-ansi "^4.0.0" - wrap-ansi "^2.0.0" - cliui@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" @@ -4674,21 +3731,11 @@ clsx@^1.1.0: resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== -clsx@^2.0.0, clsx@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.0.tgz#e851283bcb5c80ee7608db18487433f7b23f77cb" - integrity sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg== - -clsx@^2.1.1: +clsx@^2.0.0, clsx@^2.1.0, clsx@^2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA== - color-convert@^1.9.0, color-convert@^1.9.3: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -4718,12 +3765,7 @@ colorette@^2.0.16, colorette@^2.0.20: resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== -colorjs.io@^0.4.3: - version "0.4.5" - resolved "https://registry.yarnpkg.com/colorjs.io/-/colorjs.io-0.4.5.tgz#7775f787ff90aca7a38f6edb7b7c0f8cce1e6418" - integrity sha512-yCtUNCmge7llyfd/Wou19PMAcf5yC3XXhgFoAh6zsO2pGswhUPBaaUh8jzgHnXtXuZyFKzXZNAnyF5i+apICow== - -combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: +combined-stream@^1.0.8, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== @@ -4745,11 +3787,6 @@ commander@^6.2.1: resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== -commander@^8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" - integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== - common-tags@^1.8.0: version "1.8.2" resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6" @@ -4760,50 +3797,23 @@ commondir@^1.0.1: resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== -component-emitter@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-2.0.0.tgz#3a137dfe66fcf2efe3eab7cb7d5f51741b3620c6" - integrity sha512-4m5s3Me2xxlVKG9PkZpQqHQR7bgpnN7joDMJ4yvVkVXngjoITG76IaZmzmywSeRTeTpc6N6r3H3+KyUurV8OYw== - -compressible@~2.0.16: - version "2.0.18" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" - integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== - dependencies: - mime-db ">= 1.43.0 < 2" - -compression@1.7.4: - version "1.7.4" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" - integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== - dependencies: - accepts "~1.3.5" - bytes "3.0.0" - compressible "~2.0.16" - debug "2.6.9" - on-headers "~1.0.2" - safe-buffer "5.1.2" - vary "~1.1.2" - concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -concurrently@^4.1.1: - version "4.1.2" - resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-4.1.2.tgz#1a683b2b5c41e9ed324c9002b9f6e4c6e1f3b6d7" - integrity sha512-Kim9SFrNr2jd8/0yNYqDTFALzUX1tvimmwFWxmp/D4mRI+kbqIIwE2RkBDrxS2ic25O1UgQMI5AtBqdtX3ynYg== +concurrently@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-9.0.1.tgz#01e171bf6c7af0c022eb85daef95bff04d8185aa" + integrity sha512-wYKvCd/f54sTXJMSfV6Ln/B8UrfLBKOYa+lzc6CHay3Qek+LorVSBdMVfyewFhRbH0Rbabsk4D+3PL/VjQ5gzg== dependencies: - chalk "^2.4.2" - date-fns "^1.30.1" - lodash "^4.17.15" - read-pkg "^4.0.1" - rxjs "^6.5.2" - spawn-command "^0.0.2-1" - supports-color "^4.5.0" - tree-kill "^1.2.1" - yargs "^12.0.5" + chalk "^4.1.2" + lodash "^4.17.21" + rxjs "^7.8.1" + shell-quote "^1.8.1" + supports-color "^8.1.1" + tree-kill "^1.2.2" + yargs "^17.7.2" consola@^3.2.3: version "3.2.3" @@ -4815,11 +3825,6 @@ consola@^3.2.3: resolved "https://registry.yarnpkg.com/consolidated-events/-/consolidated-events-2.0.2.tgz#da8d8f8c2b232831413d9e190dc11669c79f4a91" integrity sha512-2/uRVMdRypf5z/TW/ncD/66l75P5hH2vM/GR8Jf8HLc2xnfJtmina6F6du8+v4Z2vTrMo7jC+W1tmEEuuELgkQ== -content-disposition@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" - integrity sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA== - content-disposition@0.5.4: version "0.5.4" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" @@ -4857,7 +3862,7 @@ cookie@^0.5.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== -copy-to-clipboard@^3.0.8, copy-to-clipboard@^3.3.1: +copy-to-clipboard@^3.0.8: version "3.3.3" resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz#55ac43a1db8ae639a4bd99511c148cdd1b83a1b0" integrity sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA== @@ -4870,25 +3875,15 @@ core-js@^1.0.0: integrity sha512-ZiPp9pZlgxpWRu0M+YWbm6+aQ84XEfH1JRXvfOc/fILWI0VKhLC2LX13X1NYq4fULzLMq7Hfh43CSo2/aIaUPA== core-js@^3.6.0, core-js@^3.8.3: - version "3.35.1" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.35.1.tgz#9c28f8b7ccee482796f8590cc8d15739eaaf980c" - integrity sha512-IgdsbxNyMskrTFxa9lWHyMwAJU5gXOPP+1yO+K59d50VLVAIDAbs7gIv705KzALModfK3ZrSZTPNpC0PQgIZuw== + version "3.38.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.38.1.tgz#aa375b79a286a670388a1a363363d53677c0383e" + integrity sha512-OP35aUorbU3Zvlx7pjsFdu1rGNnD4pgw/CWoYzRY3t2EzoVT7shKHY1dlAy3f41cGIO7ZDPQimhGFTlEYkG/Hw== core-util-is@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== -cosmiconfig@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" - integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== - dependencies: - import-fresh "^2.0.0" - is-directory "^0.3.1" - js-yaml "^3.13.1" - parse-json "^4.0.0" - cosmiconfig@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" @@ -4933,17 +3928,17 @@ create-eslint-index@^1.0.0: dependencies: lodash.get "^4.3.0" -create-require@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" - integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== +credit-card-type@10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/credit-card-type/-/credit-card-type-10.0.1.tgz#3464309395a9942f0f9768481645b696f9f7c58a" + integrity sha512-vQOuWmBgsgG1ovGeDi8m6Zeu1JaqH/JncrxKmaqMbv/LunyOQdLiQhPHtOsNlbUI05TocR5nod/Mbs3HYtr6sQ== -credit-card-type@9.1.0, credit-card-type@^9.1.0: +credit-card-type@^9.1.0: version "9.1.0" resolved "https://registry.yarnpkg.com/credit-card-type/-/credit-card-type-9.1.0.tgz#54dd96c93b6579623e9c8656e6798fc2b93f5f05" integrity sha512-CpNFuLxiPFxuZqhSKml3M+t0K/484pMAnfYWH14JoD7OZMnmC0Lmo+P7JX9SobqFpRoo7ifA18kOHdxJywYPEA== -cross-spawn@^6.0.0, cross-spawn@^6.0.5: +cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== @@ -4993,11 +3988,11 @@ css.escape@^1.5.1: integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg== cssstyle@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-4.0.1.tgz#ef29c598a1e90125c870525490ea4f354db0660a" - integrity sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ== + version "4.1.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-4.1.0.tgz#161faee382af1bafadb6d3867a92a19bcb4aea70" + integrity sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA== dependencies: - rrweb-cssom "^0.6.0" + rrweb-cssom "^0.7.1" csstype@^2.5.7: version "2.6.21" @@ -5020,9 +4015,9 @@ cypress-file-upload@^5.0.8: integrity sha512-+8VzNabRk3zG6x8f8BWArF/xA/W0VK4IZNx3MV0jFWrJS/qKn8eHfa5nU73P9fOQAgwHFJx7zjg4lwOnljMO8g== cypress-real-events@^1.12.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/cypress-real-events/-/cypress-real-events-1.12.0.tgz#ffeb2b23686ba5b16ac91dd9bc3b6785d36d38d3" - integrity sha512-oiy+4kGKkzc2PT36k3GGQqkGxNiVypheWjMtfyi89iIk6bYmTzeqxapaLHS3pnhZOX1IEbTDUVxh8T4Nhs1tyQ== + version "1.13.0" + resolved "https://registry.yarnpkg.com/cypress-real-events/-/cypress-real-events-1.13.0.tgz#6b7cd32dcac172db1493608f97a2576c7d0bd5af" + integrity sha512-LoejtK+dyZ1jaT8wGT5oASTPfsNV8/ClRp99ruN60oPj8cBJYod80iJDyNwfPAu4GCxTXOhhAv9FO65Hpwt6Hg== cypress-vite@^1.5.0: version "1.5.0" @@ -5171,15 +4166,37 @@ data-urls@^5.0.0: whatwg-mimetype "^4.0.0" whatwg-url "^14.0.0" -date-fns@^1.30.1: - version "1.30.1" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" - integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw== +data-view-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" + integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" + integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" + integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" dayjs@^1.10.4: - version "1.11.10" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.10.tgz#68acea85317a6e164457d6d6947564029a6a16a0" - integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ== + version "1.11.13" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" + integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== debug@2.6.9: version "2.6.9" @@ -5188,12 +4205,12 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== +debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5, debug@^4.3.6, debug@~4.3.6: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== dependencies: - ms "2.1.2" + ms "^2.1.3" debug@^3.1.0: version "3.2.7" @@ -5202,25 +4219,6 @@ debug@^3.1.0: dependencies: ms "^2.1.1" -debug@^4.3.5, debug@~4.3.6: - version "4.3.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b" - integrity sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg== - dependencies: - ms "2.1.2" - -debug@^4.3.6: - version "4.3.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" - integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== - dependencies: - ms "^2.1.3" - -decamelize@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== - decimal.js-light@^2.4.1: version "2.5.1" resolved "https://registry.yarnpkg.com/decimal.js-light/-/decimal.js-light-2.5.1.tgz#134fd32508f19e208f4fb2f8dac0d2626a867934" @@ -5243,10 +4241,29 @@ deep-eql@^5.0.1: resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-5.0.2.tgz#4b756d8d770a9257300825d52a2c2cff99c3a341" integrity sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q== -deep-extend@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== +deep-equal@^2.0.5: + version "2.2.3" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.2.3.tgz#af89dafb23a396c7da3e862abc0be27cf51d56e1" + integrity sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA== + dependencies: + array-buffer-byte-length "^1.0.0" + call-bind "^1.0.5" + es-get-iterator "^1.1.3" + get-intrinsic "^1.2.2" + is-arguments "^1.1.1" + is-array-buffer "^3.0.2" + is-date-object "^1.0.5" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + isarray "^2.0.5" + object-is "^1.1.5" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.5.1" + side-channel "^1.0.4" + which-boxed-primitive "^1.0.2" + which-collection "^1.0.1" + which-typed-array "^1.1.13" deep-is@^0.1.3, deep-is@~0.1.3: version "0.1.4" @@ -5258,22 +4275,7 @@ deepmerge@^2.1.1: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170" integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA== -deepmerge@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" - integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== - -define-data-property@^1.0.1, define-data-property@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.2.tgz#f3c33b4f0102360cd7c0f5f28700f5678510b63a" - integrity sha512-SRtsSqsDbgpJBbW3pABMCOt6rQyeM8s8RiyeSN8jYG8sYmt/kGJejbydttUsnDs1tadr19tvhT4ShwMyoqAm4g== - dependencies: - es-errors "^1.3.0" - get-intrinsic "^1.2.2" - gopd "^1.0.1" - has-property-descriptors "^1.0.1" - -define-data-property@^1.1.4: +define-data-property@^1.0.1, define-data-property@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== @@ -5282,6 +4284,11 @@ define-data-property@^1.1.4: es-errors "^1.3.0" gopd "^1.0.1" +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" @@ -5318,11 +4325,6 @@ devlop@^1.0.0, devlop@^1.1.0: dependencies: dequal "^2.0.0" -diff@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== - dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -5381,9 +4383,9 @@ dot-case@^3.0.4: tslib "^2.0.3" dotenv@^16.0.3: - version "16.4.1" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.1.tgz#1d9931f1d3e5d2959350d1250efab299561f7f11" - integrity sha512-CjA3y+Dr3FyFDOAMnxZEGtnW9KBR2M0JvvUtXNW+dYJL5ROWxP9DUHCwgFqpMk0OXCc0ljhaNTr2w/kutYIcHQ== + version "16.4.5" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" + integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== eastasianwidth@^0.2.0: version "0.2.0" @@ -5403,15 +4405,15 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== -electron-to-chromium@^1.4.648: - version "1.4.665" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.665.tgz#681700bd590b0e5a3be66e3e2874ce62abcf5da5" - integrity sha512-UpyCWObBoD+nSZgOC2ToaIdZB0r9GhqT2WahPKiSki6ckkSuKhQNso8V2PrFcHBMleI/eqbKgVQgVC4Wni4ilw== +electron-to-chromium@^1.5.28: + version "1.5.28" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.28.tgz#aee074e202c6ee8a0030a9c2ef0b3fe9f967d576" + integrity sha512-VufdJl+rzaKZoYVUijN13QcXVF5dWPZANeFTLNy+OSpHdDL5ynXTF35+60RSBbaQYB1ae723lQXHCrf4pyLsMw== emoji-regex@^10.3.0: - version "10.3.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.3.0.tgz#76998b9268409eb3dae3de989254d456e70cfe23" - integrity sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw== + version "10.4.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.4.0.tgz#03553afea80b3975749cfcb36f776ca268e413d4" + integrity sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw== emoji-regex@^7.0.1: version "7.0.3" @@ -5433,6 +4435,11 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== +encodeurl@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" @@ -5458,6 +4465,14 @@ entities@~2.1.0: resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5" integrity sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w== +envify@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/envify/-/envify-4.1.0.tgz#f39ad3db9d6801b4e6b478b61028d3f0b6819f7e" + integrity sha512-IKRVVoAYr4pIx4yIWNsz9mOsboxlNXiu7TNBnem/K/uTHdkyzXWDzHCK7UTolqBbgaBz0tQHsD3YNls0uIIjiw== + dependencies: + esprima "^4.0.0" + through "~2.3.4" + environment@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/environment/-/environment-1.1.0.tgz#8e86c66b180f363c7ab311787e0259665f45a9f1" @@ -5470,50 +4485,57 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.22.1, es-abstract@^1.22.3: - version "1.22.3" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.3.tgz#48e79f5573198de6dee3589195727f4f74bc4f32" - integrity sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA== +es-abstract@^1.17.5, es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.1, es-abstract@^1.23.2, es-abstract@^1.23.3: + version "1.23.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" + integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== dependencies: - array-buffer-byte-length "^1.0.0" - arraybuffer.prototype.slice "^1.0.2" - available-typed-arrays "^1.0.5" - call-bind "^1.0.5" - es-set-tostringtag "^2.0.1" + array-buffer-byte-length "^1.0.1" + arraybuffer.prototype.slice "^1.0.3" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + data-view-buffer "^1.0.1" + data-view-byte-length "^1.0.1" + data-view-byte-offset "^1.0.0" + es-define-property "^1.0.0" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-set-tostringtag "^2.0.3" es-to-primitive "^1.2.1" function.prototype.name "^1.1.6" - get-intrinsic "^1.2.2" - get-symbol-description "^1.0.0" + get-intrinsic "^1.2.4" + get-symbol-description "^1.0.2" globalthis "^1.0.3" gopd "^1.0.1" - has-property-descriptors "^1.0.0" - has-proto "^1.0.1" + has-property-descriptors "^1.0.2" + has-proto "^1.0.3" has-symbols "^1.0.3" - hasown "^2.0.0" - internal-slot "^1.0.5" - is-array-buffer "^3.0.2" + hasown "^2.0.2" + internal-slot "^1.0.7" + is-array-buffer "^3.0.4" is-callable "^1.2.7" - is-negative-zero "^2.0.2" + is-data-view "^1.0.1" + is-negative-zero "^2.0.3" is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" + is-shared-array-buffer "^1.0.3" is-string "^1.0.7" - is-typed-array "^1.1.12" + is-typed-array "^1.1.13" is-weakref "^1.0.2" object-inspect "^1.13.1" object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.5.1" - safe-array-concat "^1.0.1" - safe-regex-test "^1.0.0" - string.prototype.trim "^1.2.8" - string.prototype.trimend "^1.0.7" - string.prototype.trimstart "^1.0.7" - typed-array-buffer "^1.0.0" - typed-array-byte-length "^1.0.0" - typed-array-byte-offset "^1.0.0" - typed-array-length "^1.0.4" + object.assign "^4.1.5" + regexp.prototype.flags "^1.5.2" + safe-array-concat "^1.1.2" + safe-regex-test "^1.0.3" + string.prototype.trim "^1.2.9" + string.prototype.trimend "^1.0.8" + string.prototype.trimstart "^1.0.8" + typed-array-buffer "^1.0.2" + typed-array-byte-length "^1.0.1" + typed-array-byte-offset "^1.0.2" + typed-array-length "^1.0.6" unbox-primitive "^1.0.2" - which-typed-array "^1.1.13" + which-typed-array "^1.1.15" es-define-property@^1.0.0: version "1.0.0" @@ -5522,44 +4544,66 @@ es-define-property@^1.0.0: dependencies: get-intrinsic "^1.2.4" -es-errors@^1.0.0, es-errors@^1.1.0, es-errors@^1.2.1, es-errors@^1.3.0: +es-errors@^1.2.1, es-errors@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== -es-iterator-helpers@^1.0.12, es-iterator-helpers@^1.0.15: - version "1.0.15" - resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.15.tgz#bd81d275ac766431d19305923707c3efd9f1ae40" - integrity sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g== +es-get-iterator@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.3.tgz#3ef87523c5d464d41084b2c3c9c214f1199763d6" + integrity sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw== dependencies: - asynciterator.prototype "^1.0.0" call-bind "^1.0.2" + get-intrinsic "^1.1.3" + has-symbols "^1.0.3" + is-arguments "^1.1.1" + is-map "^2.0.2" + is-set "^2.0.2" + is-string "^1.0.7" + isarray "^2.0.5" + stop-iteration-iterator "^1.0.0" + +es-iterator-helpers@^1.0.19: + version "1.0.19" + resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz#117003d0e5fec237b4b5c08aded722e0c6d50ca8" + integrity sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw== + dependencies: + call-bind "^1.0.7" define-properties "^1.2.1" - es-abstract "^1.22.1" - es-set-tostringtag "^2.0.1" - function-bind "^1.1.1" - get-intrinsic "^1.2.1" + es-abstract "^1.23.3" + es-errors "^1.3.0" + es-set-tostringtag "^2.0.3" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" globalthis "^1.0.3" - has-property-descriptors "^1.0.0" - has-proto "^1.0.1" + has-property-descriptors "^1.0.2" + has-proto "^1.0.3" has-symbols "^1.0.3" - internal-slot "^1.0.5" + internal-slot "^1.0.7" iterator.prototype "^1.1.2" - safe-array-concat "^1.0.1" + safe-array-concat "^1.1.2" es-module-lexer@^1.5.0: - version "1.5.2" - resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.2.tgz#00b423304f2500ac59359cc9b6844951f372d497" - integrity sha512-l60ETUTmLqbVbVHv1J4/qj+M8nq7AwMzEcg3kmJDt9dCNrTk+yHcYFf/Kw75pMDwd9mPcIGCG5LcS20SxYRzFA== + version "1.5.4" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.4.tgz#a8efec3a3da991e60efa6b633a7cad6ab8d26b78" + integrity sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw== -es-set-tostringtag@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz#11f7cc9f63376930a5f20be4915834f4bc74f9c9" - integrity sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q== +es-object-atoms@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" + integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== dependencies: - get-intrinsic "^1.2.2" - has-tostringtag "^1.0.0" - hasown "^2.0.0" + es-errors "^1.3.0" + +es-set-tostringtag@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" + integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== + dependencies: + get-intrinsic "^1.2.4" + has-tostringtag "^1.0.2" + hasown "^2.0.1" es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2: version "1.0.2" @@ -5578,13 +4622,13 @@ es-to-primitive@^1.2.1: is-symbol "^1.0.2" esbuild-register@^3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/esbuild-register/-/esbuild-register-3.5.0.tgz#449613fb29ab94325c722f560f800dd946dc8ea8" - integrity sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A== + version "3.6.0" + resolved "https://registry.yarnpkg.com/esbuild-register/-/esbuild-register-3.6.0.tgz#cf270cfa677baebbc0010ac024b823cbf723a36d" + integrity sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg== dependencies: debug "^4.3.4" -"esbuild@^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0", esbuild@^0.23.0: +"esbuild@^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0", esbuild@^0.23.0, esbuild@~0.23.0: version "0.23.1" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.23.1.tgz#40fdc3f9265ec0beae6f59824ade1bd3d3d2dab8" integrity sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg== @@ -5614,35 +4658,6 @@ esbuild-register@^3.5.0: "@esbuild/win32-ia32" "0.23.1" "@esbuild/win32-x64" "0.23.1" -esbuild@^0.19.3: - version "0.19.12" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.12.tgz#dc82ee5dc79e82f5a5c3b4323a2a641827db3e04" - integrity sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg== - optionalDependencies: - "@esbuild/aix-ppc64" "0.19.12" - "@esbuild/android-arm" "0.19.12" - "@esbuild/android-arm64" "0.19.12" - "@esbuild/android-x64" "0.19.12" - "@esbuild/darwin-arm64" "0.19.12" - "@esbuild/darwin-x64" "0.19.12" - "@esbuild/freebsd-arm64" "0.19.12" - "@esbuild/freebsd-x64" "0.19.12" - "@esbuild/linux-arm" "0.19.12" - "@esbuild/linux-arm64" "0.19.12" - "@esbuild/linux-ia32" "0.19.12" - "@esbuild/linux-loong64" "0.19.12" - "@esbuild/linux-mips64el" "0.19.12" - "@esbuild/linux-ppc64" "0.19.12" - "@esbuild/linux-riscv64" "0.19.12" - "@esbuild/linux-s390x" "0.19.12" - "@esbuild/linux-x64" "0.19.12" - "@esbuild/netbsd-x64" "0.19.12" - "@esbuild/openbsd-x64" "0.19.12" - "@esbuild/sunos-x64" "0.19.12" - "@esbuild/win32-arm64" "0.19.12" - "@esbuild/win32-ia32" "0.19.12" - "@esbuild/win32-x64" "0.19.12" - esbuild@^0.21.3: version "0.21.5" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d" @@ -5672,10 +4687,10 @@ esbuild@^0.21.3: "@esbuild/win32-ia32" "0.21.5" "@esbuild/win32-x64" "0.21.5" -escalade@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" - integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== +escalade@^3.1.1, escalade@^3.1.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== escape-html@~1.0.3: version "1.0.3" @@ -5714,53 +4729,33 @@ eslint-config-prettier@~8.1.0: integrity sha512-oKMhGv3ihGbCIimCAjqkdzx2Q+jthoqnXSP+d86M9tptwugycmTFdVR4IpLgq2c4SHifbwO90z2fQ8/Aio73yw== eslint-plugin-cypress@^2.11.3: - version "2.15.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-2.15.1.tgz#336afa7e8e27451afaf65aa359c9509e0a4f3a7b" - integrity sha512-eLHLWP5Q+I4j2AWepYq0PgFEei9/s5LvjuSqWrxurkg1YZ8ltxdvMNmdSf0drnsNo57CTgYY/NIHHLRSWejR7w== + version "2.15.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-2.15.2.tgz#f22e12fad4c434edad7b298ef92bac8fa087ffa0" + integrity sha512-CtcFEQTDKyftpI22FVGpx8bkpKyYXBlNge6zSo0pl5/qJvBAnzaD76Vu2AsP16d6mTj478Ldn2mhgrWV+Xr0vQ== dependencies: globals "^13.20.0" -eslint-plugin-es@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz#75a7cdfdccddc0589934aeeb384175f221c57893" - integrity sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ== - dependencies: - eslint-utils "^2.0.0" - regexpp "^3.0.0" - eslint-plugin-jsx-a11y@^6.7.1: - version "6.8.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz#2fa9c701d44fcd722b7c771ec322432857fcbad2" - integrity sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA== + version "6.10.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.0.tgz#36fb9dead91cafd085ddbe3829602fb10ef28339" + integrity sha512-ySOHvXX8eSN6zz8Bywacm7CvGNhUtdjvqfQDVe6020TUK34Cywkw7m0KsCCk1Qtm9G1FayfTN1/7mMYnYO2Bhg== dependencies: - "@babel/runtime" "^7.23.2" - aria-query "^5.3.0" - array-includes "^3.1.7" + aria-query "~5.1.3" + array-includes "^3.1.8" array.prototype.flatmap "^1.3.2" ast-types-flow "^0.0.8" - axe-core "=4.7.0" - axobject-query "^3.2.1" + axe-core "^4.10.0" + axobject-query "^4.1.0" damerau-levenshtein "^1.0.8" emoji-regex "^9.2.2" - es-iterator-helpers "^1.0.15" - hasown "^2.0.0" + es-iterator-helpers "^1.0.19" + hasown "^2.0.2" jsx-ast-utils "^3.3.5" language-tags "^1.0.9" minimatch "^3.1.2" - object.entries "^1.1.7" - object.fromentries "^2.0.7" - -eslint-plugin-node@^11.0.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz#c95544416ee4ada26740a30474eefc5402dc671d" - integrity sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g== - dependencies: - eslint-plugin-es "^3.0.0" - eslint-utils "^2.0.0" - ignore "^5.1.1" - minimatch "^3.0.4" - resolve "^1.10.1" - semver "^6.1.0" + object.fromentries "^2.0.8" + safe-regex-test "^1.0.3" + string.prototype.includes "^2.0.0" eslint-plugin-perfectionist@^1.4.0: version "1.5.1" @@ -5796,26 +4791,28 @@ eslint-plugin-react-hooks@^3.0.0: integrity sha512-EjxTHxjLKIBWFgDJdhKKzLh5q+vjTFrqNZX36uIxWS4OfyXe5DawqPj3U5qeJ1ngLwatjzQnmR0Lz0J0YH3kxw== eslint-plugin-react@^7.19.0: - version "7.33.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz#69ee09443ffc583927eafe86ffebb470ee737608" - integrity sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw== + version "7.36.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.36.1.tgz#f1dabbb11f3d4ebe8b0cf4e54aff4aee81144ee5" + integrity sha512-/qwbqNXZoq+VP30s1d4Nc1C5GTxjJQjk4Jzs4Wq2qzxFM7dSmuG2UkIjg2USMLh3A/aVcUNrK7v0J5U1XEGGwA== dependencies: - array-includes "^3.1.6" - array.prototype.flatmap "^1.3.1" - array.prototype.tosorted "^1.1.1" + array-includes "^3.1.8" + array.prototype.findlast "^1.2.5" + array.prototype.flatmap "^1.3.2" + array.prototype.tosorted "^1.1.4" doctrine "^2.1.0" - es-iterator-helpers "^1.0.12" + es-iterator-helpers "^1.0.19" estraverse "^5.3.0" + hasown "^2.0.2" jsx-ast-utils "^2.4.1 || ^3.0.0" minimatch "^3.1.2" - object.entries "^1.1.6" - object.fromentries "^2.0.6" - object.hasown "^1.1.2" - object.values "^1.1.6" + object.entries "^1.1.8" + object.fromentries "^2.0.8" + object.values "^1.2.0" prop-types "^15.8.1" - resolve "^2.0.0-next.4" + resolve "^2.0.0-next.5" semver "^6.3.1" - string.prototype.matchall "^4.0.8" + string.prototype.matchall "^4.0.11" + string.prototype.repeat "^1.0.0" eslint-plugin-scanjs-rules@^0.2.1: version "0.2.1" @@ -5830,16 +4827,6 @@ eslint-plugin-sonarjs@^0.5.0: resolved "https://registry.yarnpkg.com/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.5.0.tgz#ce17b2daba65a874c2862213a9e38e8986ad7d7d" integrity sha512-XW5MnzlRjhXpIdbULC/qAdJYHWw3rRLws/DyawdlPU/IdVr9AmRK1r2LaCvabwKOAW2XYYSo3kDX58E4MrB7PQ== -eslint-plugin-storybook@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-storybook/-/eslint-plugin-storybook-0.8.0.tgz#23185ecabdc289cae55248c090f0c1d8fbae6c41" - integrity sha512-CZeVO5EzmPY7qghO2t64oaFM+8FTaD4uzOEjHKp516exyTKo+skKAL9GI3QALS2BXhyALJjNtwbmr1XinGE8bA== - dependencies: - "@storybook/csf" "^0.0.1" - "@typescript-eslint/utils" "^5.62.0" - requireindex "^1.2.0" - ts-dedent "^2.2.0" - eslint-plugin-testing-library@^3.1.2: version "3.10.2" resolved "https://registry.yarnpkg.com/eslint-plugin-testing-library/-/eslint-plugin-testing-library-3.10.2.tgz#609ec2b0369da7cf2e6d9edff5da153cc31d87bd" @@ -5862,10 +4849,10 @@ eslint-scope@^5.0.0, eslint-scope@^5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-scope@^7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" - integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== +eslint-scope@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.0.2.tgz#5cbb33d4384c9136083a71190d548158fe128f94" + integrity sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" @@ -5894,48 +4881,52 @@ eslint-visitor-keys@^2.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1: version "3.4.3" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== +eslint-visitor-keys@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz#e3adc021aa038a2a8e0b2f8b0ce8f66b9483b1fb" + integrity sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw== + eslint@>=1.1: - version "8.56.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.56.0.tgz#4957ce8da409dc0809f99ab07a1b94832ab74b15" - integrity sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ== + version "9.11.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.11.1.tgz#701e5fc528990153f9cef696d8427003b5206567" + integrity sha512-MobhYKIoAO1s1e4VUrgx1l1Sk2JBR/Gqjjgw8+mfgoLE2xwsHur4gdfTxyTgShrhvdVFTaJSgMiQBl1jv/AWxg== dependencies: "@eslint-community/eslint-utils" "^4.2.0" - "@eslint-community/regexpp" "^4.6.1" - "@eslint/eslintrc" "^2.1.4" - "@eslint/js" "8.56.0" - "@humanwhocodes/config-array" "^0.11.13" + "@eslint-community/regexpp" "^4.11.0" + "@eslint/config-array" "^0.18.0" + "@eslint/core" "^0.6.0" + "@eslint/eslintrc" "^3.1.0" + "@eslint/js" "9.11.1" + "@eslint/plugin-kit" "^0.2.0" "@humanwhocodes/module-importer" "^1.0.1" + "@humanwhocodes/retry" "^0.3.0" "@nodelib/fs.walk" "^1.2.8" - "@ungap/structured-clone" "^1.2.0" + "@types/estree" "^1.0.6" + "@types/json-schema" "^7.0.15" ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" debug "^4.3.2" - doctrine "^3.0.0" escape-string-regexp "^4.0.0" - eslint-scope "^7.2.2" - eslint-visitor-keys "^3.4.3" - espree "^9.6.1" - esquery "^1.4.2" + eslint-scope "^8.0.2" + eslint-visitor-keys "^4.0.0" + espree "^10.1.0" + esquery "^1.5.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" + file-entry-cache "^8.0.0" find-up "^5.0.0" glob-parent "^6.0.2" - globals "^13.19.0" - graphemer "^1.4.0" ignore "^5.2.0" imurmurhash "^0.1.4" is-glob "^4.0.0" is-path-inside "^3.0.3" - js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" lodash.merge "^4.6.2" minimatch "^3.1.2" natural-compare "^1.4.0" @@ -6032,6 +5023,15 @@ eslint@^7.1.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" +espree@^10.0.1, espree@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.1.0.tgz#8788dae611574c0f070691f522e4116c5a11fc56" + integrity sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA== + dependencies: + acorn "^8.12.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^4.0.0" + espree@^6.1.2: version "6.2.1" resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" @@ -6050,24 +5050,15 @@ espree@^7.3.0, espree@^7.3.1: acorn-jsx "^5.3.1" eslint-visitor-keys "^1.3.0" -espree@^9.6.0, espree@^9.6.1: - version "9.6.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" - integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== - dependencies: - acorn "^8.9.0" - acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.4.1" - esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.0.1, esquery@^1.4.0, esquery@^1.4.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" - integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== +esquery@^1.0.1, esquery@^1.4.0, esquery@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== dependencies: estraverse "^5.1.0" @@ -6125,11 +5116,6 @@ eventemitter3@^5.0.1: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== -events@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" - integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== - execa@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" @@ -6145,19 +5131,6 @@ execa@4.1.0: signal-exit "^3.0.2" strip-final-newline "^2.0.0" -execa@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" - integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== - dependencies: - cross-spawn "^6.0.0" - get-stream "^4.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - execa@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" @@ -6195,42 +5168,37 @@ executable@^4.1.1: dependencies: pify "^2.2.0" -expr-eval-fork@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/expr-eval-fork/-/expr-eval-fork-2.0.2.tgz#97136ac0a8178522055500f55d3d3c5ad54f400d" - integrity sha512-NaAnObPVwHEYrODd7Jzp3zzT9pgTAlUUL4MZiZu9XAYPDpx89cPsfyEImFb2XY0vQNbrqg2CG7CLiI+Rs3seaQ== - express@^4.19.2: - version "4.19.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465" - integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== + version "4.21.0" + resolved "https://registry.yarnpkg.com/express/-/express-4.21.0.tgz#d57cb706d49623d4ac27833f1cbc466b668eb915" + integrity sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng== dependencies: accepts "~1.3.8" array-flatten "1.1.1" - body-parser "1.20.2" + body-parser "1.20.3" content-disposition "0.5.4" content-type "~1.0.4" cookie "0.6.0" cookie-signature "1.0.6" debug "2.6.9" depd "2.0.0" - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" etag "~1.8.1" - finalhandler "1.2.0" + finalhandler "1.3.1" fresh "0.5.2" http-errors "2.0.0" - merge-descriptors "1.0.1" + merge-descriptors "1.0.3" methods "~1.1.2" on-finished "2.4.1" parseurl "~1.3.3" - path-to-regexp "0.1.7" + path-to-regexp "0.1.10" proxy-addr "~2.0.7" - qs "6.11.0" + qs "6.13.0" range-parser "~1.2.1" safe-buffer "5.2.1" - send "0.18.0" - serve-static "1.15.0" + send "0.19.0" + serve-static "1.16.2" setprototypeof "1.2.0" statuses "2.0.1" type-is "~1.6.18" @@ -6321,12 +5289,10 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== -fast-url-parser@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d" - integrity sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ== - dependencies: - punycode "^1.3.2" +fast-uri@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.1.tgz#cddd2eecfc83a71c1be2cc2ef2061331be8a7134" + integrity sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw== fastq@^1.6.0: version "1.17.1" @@ -6386,6 +5352,13 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== + dependencies: + flat-cache "^4.0.0" + file-selector@^0.2.2: version "0.2.4" resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.2.4.tgz#7b98286f9dbb9925f420130ea5ed0a69238d4d80" @@ -6393,14 +5366,6 @@ file-selector@^0.2.2: dependencies: tslib "^2.0.3" -file-system-cache@2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/file-system-cache/-/file-system-cache-2.3.0.tgz#201feaf4c8cd97b9d0d608e96861bb6005f46fe6" - integrity sha512-l4DMNdsIPsVnKrgEXbJwDJsA5mB8rGwHYERMgqQx/xAUtChPJMre1bXBzDEqqVbWv9AIbFezXMxeEkZDSrXUOQ== - dependencies: - fs-extra "11.1.1" - ramda "0.29.0" - fill-range@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" @@ -6408,13 +5373,13 @@ fill-range@^7.1.1: dependencies: to-regex-range "^5.0.1" -finalhandler@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" - integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== +finalhandler@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" + integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== dependencies: debug "2.6.9" - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" on-finished "2.4.1" parseurl "~1.3.3" @@ -6435,13 +5400,6 @@ find-root@^1.1.0: resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== -find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== - dependencies: - locate-path "^3.0.0" - find-up@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" @@ -6458,13 +5416,6 @@ find-up@^5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" -find-yarn-workspace-root@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz#f47fb8d239c900eb78179aa81b66673eac88f7bd" - integrity sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ== - dependencies: - micromatch "^4.0.2" - flag-icons@^6.6.5: version "6.15.0" resolved "https://registry.yarnpkg.com/flag-icons/-/flag-icons-6.15.0.tgz#9b9ea631f408ff41844872d1d7df9bd020d4c76d" @@ -6488,25 +5439,28 @@ flat-cache@^3.0.4: keyv "^4.5.3" rimraf "^3.0.2" +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.4" + flatted@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== -flatted@^3.2.9: - version "3.2.9" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf" - integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== - -flatted@^3.3.1: +flatted@^3.2.9, flatted@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== follow-redirects@^1.15.6: - version "1.15.6" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" - integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== + version "1.15.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== font-logos@^0.18.0: version "0.18.0" @@ -6521,9 +5475,9 @@ for-each@^0.3.3: is-callable "^1.1.3" foreground-child@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" - integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== + version "3.3.0" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" + integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== dependencies: cross-spawn "^7.0.0" signal-exit "^4.0.1" @@ -6533,7 +5487,7 @@ forever-agent@~0.6.1: resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== -form-data@^4.0.0: +form-data@^4.0.0, form-data@~4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== @@ -6542,15 +5496,6 @@ form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - formik@~2.1.3: version "2.1.7" resolved "https://registry.yarnpkg.com/formik/-/formik-2.1.7.tgz#40bd04e59b242176d0a17c701830f1536cd7506b" @@ -6570,10 +5515,10 @@ forwarded@0.2.0: resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== -framebus@5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/framebus/-/framebus-5.2.1.tgz#6b7468191c020e28ee339c15561d4bd12864c636" - integrity sha512-K6pw+M2wNBuOhEoFrmMbf1O+fm7PnNDIfA9y0KpAyQzXRIJ420szGgJ/dI2Ikz0XG+5VfspLqA72M6bXhuyKIQ== +framebus@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/framebus/-/framebus-6.0.0.tgz#4ebafaf4d78441fdb1f6c55cb9a6ea9f72c55cff" + integrity sha512-bL9V68hVaVBCY9rveoWbPFFI9hAXIJtESs51B+9XmzvMt38+wP8b4VdiJsavjMS6NfPZ/afQ/jc2qaHmSGI1kQ== dependencies: "@braintree/uuid" "^0.1.0" @@ -6582,15 +5527,6 @@ fresh@0.5.2: resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== -fs-extra@11.1.1: - version "11.1.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.1.1.tgz#da69f7c39f3b002378b0954bb6ae7efdc0876e2d" - integrity sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - fs-extra@^11.1.0: version "11.2.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.2.0.tgz#e70e17dfad64232287d01929399e0ea7c86b0e5b" @@ -6600,7 +5536,7 @@ fs-extra@^11.1.0: jsonfile "^6.0.1" universalify "^2.0.0" -fs-extra@^9.0.0, fs-extra@^9.1.0: +fs-extra@^9.1.0: version "9.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== @@ -6620,12 +5556,12 @@ fsevents@~2.3.2, fsevents@~2.3.3: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== -function-bind@^1.1.1, function-bind@^1.1.2: +function-bind@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== -function.prototype.name@^1.1.5, function.prototype.name@^1.1.6: +function.prototype.name@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== @@ -6650,11 +5586,6 @@ gensync@^1.0.0-beta.2: resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== -get-caller-file@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" - integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== - get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" @@ -6670,7 +5601,7 @@ get-func-name@^2.0.1: resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== -get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: +get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== @@ -6681,18 +5612,6 @@ get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@ has-symbols "^1.0.3" hasown "^2.0.0" -get-stdin@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-7.0.0.tgz#8d5de98f15171a125c5e516643c7a6d0ea8a96f6" - integrity sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ== - -get-stream@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - dependencies: - pump "^3.0.0" - get-stream@^5.0.0, get-stream@^5.1.0: version "5.2.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" @@ -6710,7 +5629,7 @@ get-stream@^8.0.1: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2" integrity sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA== -get-symbol-description@^1.0.0: +get-symbol-description@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== @@ -6719,6 +5638,13 @@ get-symbol-description@^1.0.0: es-errors "^1.3.0" get-intrinsic "^1.2.4" +get-tsconfig@^4.7.5: + version "4.8.1" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.8.1.tgz#8995eb391ae6e1638d251118c7b56de7eb425471" + integrity sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg== + dependencies: + resolve-pkg-maps "^1.0.0" + getos@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/getos/-/getos-3.2.1.tgz#0134d1f4e00eb46144c5a9c0ac4dc087cbb27dc5" @@ -6738,13 +5664,20 @@ github-slugger@^2.0.0: resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-2.0.0.tgz#52cf2f9279a21eb6c59dd385b410f0c0adda8f1a" integrity sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw== -glob-parent@^5.0.0, glob-parent@^5.1.2, glob-parent@^6.0.2, glob-parent@~5.1.2: +glob-parent@^5.0.0, glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + glob-promise@^4.2.0: version "4.2.2" resolved "https://registry.yarnpkg.com/glob-promise/-/glob-promise-4.2.2.tgz#15f44bcba0e14219cd93af36da6bb905ff007877" @@ -6752,18 +5685,7 @@ glob-promise@^4.2.0: dependencies: "@types/glob" "^7.1.3" -glob@^10.3.1, glob@^10.3.10: - version "10.3.10" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b" - integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== - dependencies: - foreground-child "^3.1.0" - jackspeak "^2.3.5" - minimatch "^9.0.1" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" - path-scurry "^1.10.1" - -glob@^10.4.1, glob@^10.4.2: +glob@^10.3.1, glob@^10.3.10, glob@^10.4.1: version "10.4.5" resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== @@ -6806,19 +5728,25 @@ globals@^12.1.0: dependencies: type-fest "^0.8.1" -globals@^13.19.0, globals@^13.20.0, globals@^13.6.0, globals@^13.9.0: +globals@^13.20.0, globals@^13.6.0, globals@^13.9.0: version "13.24.0" resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== dependencies: type-fest "^0.20.2" +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== + globalthis@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" - integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== + version "1.0.4" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" + integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== dependencies: - define-properties "^1.1.3" + define-properties "^1.2.1" + gopd "^1.0.1" globby@^11.1.0: version "11.1.0" @@ -6844,7 +5772,7 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" -graceful-fs@^4.1.11, graceful-fs@^4.1.6, graceful-fs@^4.2.0: +graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -6855,20 +5783,15 @@ graphemer@^1.4.0: integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== graphql@^16.8.1: - version "16.8.1" - resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.8.1.tgz#1930a965bef1170603702acdb68aedd3f3cf6f07" - integrity sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw== + version "16.9.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.9.0.tgz#1c310e63f16a49ce1fbb230bd0a000e99f6f115f" + integrity sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw== has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== -has-flag@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" - integrity sha512-P+1n3MnwjR/Epg9BBo1KT8qbye2g2Ou4sFumihwt6I4tsUX7jnLcX4BTOSKg/B1ZrIYMN9FcEnG4x5a7NB8Eng== - has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -6879,41 +5802,34 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz#52ba30b6c5ec87fd89fa574bc1c39125c6f65340" - integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg== - dependencies: - get-intrinsic "^1.2.2" - -has-property-descriptors@^1.0.2: +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== dependencies: es-define-property "^1.0.0" -has-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" - integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== +has-proto@^1.0.1, has-proto@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== -has-tostringtag@^1.0.0, has-tostringtag@^1.0.1: +has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== dependencies: has-symbols "^1.0.3" -hasown@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" - integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== +hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== dependencies: function-bind "^1.1.2" @@ -6944,9 +5860,9 @@ he@^1.2.0: integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== headers-polyfill@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/headers-polyfill/-/headers-polyfill-4.0.2.tgz#9115a76eee3ce8fbf95b6e3c6bf82d936785b44a" - integrity sha512-EWGTfnTqAO2L/j5HZgoM/3z82L7necsJ0pO9Tp0X1wil3PDLrkypTBRgVO2ExehEEvUycejZD3FuRaXpZZc3kw== + version "4.0.3" + resolved "https://registry.yarnpkg.com/headers-polyfill/-/headers-polyfill-4.0.3.tgz#922a0155de30ecc1f785bcf04be77844ca95ad07" + integrity sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ== hi-base32@^0.5.0: version "0.5.1" @@ -6954,9 +5870,9 @@ hi-base32@^0.5.0: integrity sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA== highlight.js@*: - version "11.9.0" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.9.0.tgz#04ab9ee43b52a41a047432c8103e2158a1b8b5b0" - integrity sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw== + version "11.10.0" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.10.0.tgz#6e3600dc4b33d6dc23d5bd94fbf72405f5892b92" + integrity sha512-SYVnVFswQER+zu1laSya563s+F8VDGt7o35d4utbamowvUNLLMovFqwCLSocpZTz3MgaSRA1IbqRWZv97dtErQ== highlight.js@^9.7.0: version "9.18.5" @@ -6992,13 +5908,6 @@ hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react- dependencies: react-is "^16.7.0" -hosted-git-info@^2.1.4, hosted-git-info@^5.0.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-5.2.1.tgz#0ba1c97178ef91f3ab30842ae63d6a272341156f" - integrity sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw== - dependencies: - lru-cache "^7.5.1" - html-encoding-sniffer@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz#696df529a7cfd82446369dc5193e590a3735b448" @@ -7043,14 +5952,14 @@ http-proxy-agent@^7.0.2: agent-base "^7.1.0" debug "^4.3.4" -http-signature@~1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.3.6.tgz#cb6fbfdf86d1c974f343be94e87f7fc128662cf9" - integrity sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw== +http-signature@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.4.0.tgz#dee5a9ba2bf49416abc544abd6d967f6a94c8c3f" + integrity sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg== dependencies: assert-plus "^1.0.0" jsprim "^2.0.2" - sshpk "^1.14.1" + sshpk "^1.18.0" https-proxy-agent@^7.0.5: version "7.0.5" @@ -7075,27 +5984,10 @@ human-signals@^5.0.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28" integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== -husky@^3.0.1: - version "3.1.0" - resolved "https://registry.yarnpkg.com/husky/-/husky-3.1.0.tgz#5faad520ab860582ed94f0c1a77f0f04c90b57c0" - integrity sha512-FJkPoHHB+6s4a+jwPqBudBDvYZsoQW5/HBuMSehC8qDiCe50kpcxeqFoDSlow+9I6wg47YxBoT3WxaURlrDIIQ== - dependencies: - chalk "^2.4.2" - ci-info "^2.0.0" - cosmiconfig "^5.2.1" - execa "^1.0.0" - get-stdin "^7.0.0" - opencollective-postinstall "^2.0.2" - pkg-dir "^4.2.0" - please-upgrade-node "^3.2.0" - read-pkg "^5.2.0" - run-node "^1.0.0" - slash "^3.0.0" - -hyperdyperid@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/hyperdyperid/-/hyperdyperid-1.2.0.tgz#59668d323ada92228d2a869d3e474d5a33b69e6b" - integrity sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A== +husky@^9.1.6: + version "9.1.6" + resolved "https://registry.yarnpkg.com/husky/-/husky-9.1.6.tgz#e23aa996b6203ab33534bdc82306b0cf2cb07d6c" + integrity sha512-sqbjZKK7kf44hfdE94EoX8MZNk0n7HeW37O4YrVGCF4wzgQjp+akPAkfUK5LZ6KuR/6sqeAVuXHji+RzQgOn5A== iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" @@ -7111,7 +6003,7 @@ iconv-lite@0.6.3: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -ieee754@^1.1.13, ieee754@^1.2.1: +ieee754@^1.1.13: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -7121,24 +6013,21 @@ ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.1.1, ignore@^5.2.0, ignore@^5.2.4: - version "5.3.1" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" - integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== +ignore@^5.2.0, ignore@^5.2.4: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== immer@^9.0.6: version "9.0.21" resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.21.tgz#1e025ea31a40f24fb064f1fef23e931496330176" integrity sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA== -import-fresh@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" - integrity sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg== - dependencies: - caller-path "^2.0.0" - resolve-from "^3.0.0" - import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1, import-fresh@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" @@ -7170,25 +6059,15 @@ inherits@2, inherits@2.0.4, inherits@^2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== - ini@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== -ini@~1.3.0: - version "1.3.8" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" - integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== - -inject-stylesheet@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/inject-stylesheet/-/inject-stylesheet-5.0.0.tgz#bb34acf05ca6ed86e5763d886cd6c9b19f360ab1" - integrity sha512-GzncrJP8E/pavMQzoO93CXoYCfTttwVm2cX2TyXJdgtVE0cCvWSFCn1/uMsM6ZkEg7LUsOcKuamcLiGWlv2p9A== +inject-stylesheet@6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/inject-stylesheet/-/inject-stylesheet-6.0.1.tgz#ab724474ac300684875e8980d1285cb4e99b33ae" + integrity sha512-2fvune1D4+8mvJoLVo95ncY4HrDkIaYIReRzXv8tkWFgdG9iuc5QuX57gtSDPWTWQI/f5BGwwtH85wxHouzucg== inquirer@^7.0.0: version "7.3.3" @@ -7209,7 +6088,7 @@ inquirer@^7.0.0: strip-ansi "^6.0.0" through "^2.3.6" -internal-slot@^1.0.5: +internal-slot@^1.0.4, internal-slot@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== @@ -7230,27 +6109,22 @@ invariant@^2.2.4: dependencies: loose-envify "^1.0.0" -invert-kv@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" - integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== - ipaddr.js@1.9.1, ipaddr.js@^1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== ipaddr.js@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.1.0.tgz#2119bc447ff8c257753b196fc5f1ce08a4cdf39f" - integrity sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ== + version "2.2.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.2.0.tgz#d33fa7bac284f4de7af949638c9d68157c6b92e8" + integrity sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA== is-absolute-url@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-4.0.1.tgz#16e4d487d4fded05cfe0685e53ec86804a5e94dc" integrity sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A== -is-arguments@^1.0.4: +is-arguments@^1.0.4, is-arguments@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== @@ -7323,11 +6197,18 @@ is-ci@^3.0.1: ci-info "^3.2.0" is-core-module@^2.12.1, is-core-module@^2.13.0: - version "2.13.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" - integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + version "2.15.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37" + integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== dependencies: - hasown "^2.0.0" + hasown "^2.0.2" + +is-data-view@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" + integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== + dependencies: + is-typed-array "^1.1.13" is-date-object@^1.0.1, is-date-object@^1.0.5: version "1.0.5" @@ -7336,12 +6217,7 @@ is-date-object@^1.0.1, is-date-object@^1.0.5: dependencies: has-tostringtag "^1.0.0" -is-directory@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" - integrity sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw== - -is-docker@^2.0.0: +is-docker@^2.0.0, is-docker@^2.1.1: version "2.2.1" resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== @@ -7358,13 +6234,6 @@ is-finalizationregistry@^1.0.2: dependencies: call-bind "^1.0.2" -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw== - dependencies: - number-is-nan "^1.0.0" - is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" @@ -7409,28 +6278,15 @@ is-installed-globally@~0.4.0: global-dirs "^3.0.0" is-path-inside "^3.0.2" -is-map@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" - integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== - -is-mergeable-object@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-mergeable-object/-/is-mergeable-object-1.1.1.tgz#faaa3ed1cfce87d6f7d2f5885e92cc30af3e2ebf" - integrity sha512-CPduJfuGg8h8vW74WOxHtHmtQutyQBzR+3MjQ6iDHIYdbOnm1YC7jv43SqCoU8OPGTJD4nibmiryA4kmogbGrA== - -is-nan@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d" - integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" +is-map@^2.0.2, is-map@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" + integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== -is-negative-zero@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" - integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== +is-negative-zero@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" + integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== is-node-process@^1.2.0: version "1.2.0" @@ -7454,7 +6310,7 @@ is-path-inside@^3.0.2, is-path-inside@^3.0.3: resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== -is-plain-obj@^4.0.0, is-plain-obj@^4.1.0: +is-plain-obj@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0" integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg== @@ -7471,11 +6327,6 @@ is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" -is-port-reachable@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-port-reachable/-/is-port-reachable-4.0.0.tgz#dac044091ef15319c8ab2f34604d8794181f8c2d" - integrity sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig== - is-potential-custom-element-name@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" @@ -7489,22 +6340,17 @@ is-regex@^1.1.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-set@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" - integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== +is-set@^2.0.2, is-set@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d" + integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== -is-shared-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" - integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== +is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" + integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== dependencies: - call-bind "^1.0.2" - -is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ== + call-bind "^1.0.7" is-stream@^2.0.0: version "2.0.1" @@ -7530,7 +6376,7 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" -is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.13, is-typed-array@^1.1.3, is-typed-array@^1.1.9: +is-typed-array@^1.1.13, is-typed-array@^1.1.3: version "1.1.13" resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== @@ -7547,10 +6393,10 @@ is-unicode-supported@^0.1.0: resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -is-weakmap@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" - integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== +is-weakmap@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" + integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w== is-weakref@^1.0.2: version "1.0.2" @@ -7559,15 +6405,15 @@ is-weakref@^1.0.2: dependencies: call-bind "^1.0.2" -is-weakset@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.2.tgz#4569d67a747a1ce5a994dfd4ef6dcea76e7c0a1d" - integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg== +is-weakset@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.3.tgz#e801519df8c0c43e12ff2834eead84ec9e624007" + integrity sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" + call-bind "^1.0.7" + get-intrinsic "^1.2.4" -is-wsl@^2.1.1, is-wsl@^2.2.0: +is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== @@ -7649,12 +6495,12 @@ iterator.prototype@^1.1.2: reflect.getprototypeof "^1.0.4" set-function-name "^2.0.1" -jackspeak@2.1.1, jackspeak@^2.3.5, jackspeak@^3.1.2: - version "2.1.1" - resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.1.1.tgz#2a42db4cfbb7e55433c28b6f75d8b796af9669cd" - integrity sha512-juf9stUEwUaILepraGOWIJTLwg48bUnBmRqd2ln2Os1sW987zeoj/hzhbvRB95oMuS2ZTpjULmdwHNX4rzZIZw== +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== dependencies: - cliui "^8.0.1" + "@isaacs/cliui" "^8.0.2" optionalDependencies: "@pkgjs/parseargs" "^0.11.0" @@ -7688,10 +6534,15 @@ jsbn@~0.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== +jsdoc-type-pratt-parser@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz#ff6b4a3f339c34a6c188cbf50a16087858d22113" + integrity sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg== + jsdom@^24.1.1: - version "24.1.1" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-24.1.1.tgz#f41df8f4f3b2fbfa7e1bdc5df62c9804fd14a9d0" - integrity sha512-5O1wWV99Jhq4DV7rCLIoZ/UIhyQeDR7wHVyZAHAshbrvZsLs+Xzz7gtwnlJTJDjleiTKh54F4dXrX70vJQTyJQ== + version "24.1.3" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-24.1.3.tgz#88e4a07cb9dd21067514a619e9f17b090a394a9f" + integrity sha512-MyL55p3Ut3cXbeBEG7Hcv0mVM8pp8PBNWxRqchZnSfAiES1v1mRnMeFfaHWIPULpwsYfvO+ZmMZz5tGCnjzDUQ== dependencies: cssstyle "^4.0.1" data-urls "^5.0.0" @@ -7725,11 +6576,6 @@ json-buffer@3.0.1: resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== -json-parse-better-errors@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - json-parse-even-better-errors@^2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" @@ -7755,16 +6601,6 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== -json-stable-stringify@^1.0.2: - version "1.1.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.1.1.tgz#52d4361b47d49168bcc4e564189a42e5a7439454" - integrity sha512-SU/971Kt5qVQfJpyDveVhQ/vya+5hvrjClFOcr8c0Fq5aODJjMwutrOfCU+eCnVD5gpx1Q3fEqkyom77zH1iIg== - dependencies: - call-bind "^1.0.5" - isarray "^2.0.5" - jsonify "^0.0.1" - object-keys "^1.1.1" - json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -7784,15 +6620,10 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" -jsonify@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.1.tgz#2aa3111dae3d34a0f151c63f3a45d995d9420978" - integrity sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg== - jspdf-autotable@^3.5.14: - version "3.8.1" - resolved "https://registry.yarnpkg.com/jspdf-autotable/-/jspdf-autotable-3.8.1.tgz#e4d9b62356a412024e8f08e84fdeb5b85e1383b5" - integrity sha512-UjJqo80Z3/WUzDi4JipTGp0pAvNvR3Gsm38inJ5ZnwsJH0Lw4pEbssRSH6zMWAhR1ZkTrsDpQo5p6rZk987/AQ== + version "3.8.3" + resolved "https://registry.yarnpkg.com/jspdf-autotable/-/jspdf-autotable-3.8.3.tgz#b469730c28376a81298d04d18136f1fb464cd4b8" + integrity sha512-PQFdljBt+ijm6ZWXYxhZ54A/awV63UKcipYoA2+YGsz0BXXiXTIL/FIg+V30j7wPdSdzClfbB3qKX9UeuFylPQ== jspdf@^2.5.2: version "2.5.2" @@ -7830,37 +6661,30 @@ jsprim@^2.0.2: object.values "^1.1.6" junit2json@^3.1.4: - version "3.1.5" - resolved "https://registry.yarnpkg.com/junit2json/-/junit2json-3.1.5.tgz#6832ae2c0bd0de9c59b532a92f32721af6cbee5b" - integrity sha512-6fAHN5OMb0VV3+f+8DJ3/8yysRJxajrnUmkBeR+QjQQtUXZ5h4E3RMzF7gFhLnIhFewBUAyQGalgCJrkHieHqQ== + version "3.1.12" + resolved "https://registry.yarnpkg.com/junit2json/-/junit2json-3.1.12.tgz#7abcb34d394662b36f519651d945432b2ae3b1df" + integrity sha512-pVll/UUqeDGA0rao+2x1JyGiXB77+g+vb1TYO/Eq8eFjKxPjcOnilX/cY3YH0xm8Ufl3f6hIbQLgYnH+zI73Uw== dependencies: "@types/xml2js" "0.4.14" xml2js "0.6.2" yargs "17.7.2" -keyv@^4.5.3: +keyv@^4.5.3, keyv@^4.5.4: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== dependencies: json-buffer "3.0.1" -kind-of@^6.0.2, kind-of@^6.0.3: +kind-of@^6.0.2: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== -klaw-sync@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/klaw-sync/-/klaw-sync-6.0.0.tgz#1fd2cfd56ebb6250181114f0a581167099c2b28c" - integrity sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ== - dependencies: - graceful-fs "^4.1.11" - language-subtag-registry@^0.3.20: - version "0.3.22" - resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d" - integrity sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w== + version "0.3.23" + resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz#23529e04d9e3b74679d70142df3fd2eb6ec572e7" + integrity sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ== language-tags@^1.0.9: version "1.0.9" @@ -7870,17 +6694,17 @@ language-tags@^1.0.9: language-subtag-registry "^0.3.20" launchdarkly-js-client-sdk@^3.1.4: - version "3.1.4" - resolved "https://registry.yarnpkg.com/launchdarkly-js-client-sdk/-/launchdarkly-js-client-sdk-3.1.4.tgz#e613cb53412533c07ccf140ae570fc994c59758d" - integrity sha512-yq0FeklpVuHMSRz7jfUAfyM7I/659RvGztqJ0Y9G5eN/ZrG1o2W61ZU0Nrv/gqZCtLXjarh/u1otxSFFBjTpHw== + version "3.4.0" + resolved "https://registry.yarnpkg.com/launchdarkly-js-client-sdk/-/launchdarkly-js-client-sdk-3.4.0.tgz#5b5959b548edac8a0f368eb40b079d942573d37b" + integrity sha512-3v1jKy1RECT0SG/3SGlyRO32vweoNxvWiJuIChRh/Zhk98cHpANuwameXVhwJ4WEDNZJTur73baaKAyatSP46A== dependencies: escape-string-regexp "^4.0.0" - launchdarkly-js-sdk-common "5.0.3" + launchdarkly-js-sdk-common "5.3.0" -launchdarkly-js-sdk-common@5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/launchdarkly-js-sdk-common/-/launchdarkly-js-sdk-common-5.0.3.tgz#345f899f5779be8b03d6599978c855eb838d8b7f" - integrity sha512-wKG8UsVbPVq8+7eavgAm5CVmulQWN6Ddod2ZoA3euZ1zPvJPwIQ2GrOYaCJr3cFrrMIX+nQyBJHBHYxUAPcM+Q== +launchdarkly-js-sdk-common@5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/launchdarkly-js-sdk-common/-/launchdarkly-js-sdk-common-5.3.0.tgz#336a54843f5ba3541632e10014e49dff45d41674" + integrity sha512-NI5wFF8qhjtpRb4KelGdnwNIOf/boLlbLiseV7uf1jxSeoM/L30DAz87RT8VhYCSGCo4LedGILQFednI/MKFkA== dependencies: base64-js "^1.3.0" fast-deep-equal "^2.0.1" @@ -7900,13 +6724,6 @@ lazy-ass@^1.6.0: resolved "https://registry.yarnpkg.com/lazy-ass/-/lazy-ass-1.6.0.tgz#7999655e8646c17f089fdd187d150d3324d54513" integrity sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw== -lcid@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" - integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== - dependencies: - invert-kv "^2.0.0" - levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" @@ -7924,9 +6741,16 @@ levn@^0.4.1: type-check "~0.4.0" libphonenumber-js@^1.10.6: - version "1.10.55" - resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.10.55.tgz#ec864e369bf7babde02021d06b5f2433d7e9c78e" - integrity sha512-MrTg2JFLscgmTY6/oT9vopYETlgUls/FU6OaeeamGwk4LFxjIgOUML/ZSZICgR0LPYXaonVJo40lzMvaaTJlQA== + version "1.11.9" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.11.9.tgz#e653042b11da2b50b7ea3b206fa7ca998436ae99" + integrity sha512-Zs5wf5HaWzW2/inlupe2tstl0I/Tbqo7lH20ZLr6Is58u7Dz2n+gRFGNlj9/gWxFvNfp9+YyDsiegjNhdixB9A== + +lie@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" + integrity sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw== + dependencies: + immediate "~3.0.5" lilconfig@^3.1.1, lilconfig@~3.1.2: version "3.1.2" @@ -7946,9 +6770,9 @@ linkify-it@^3.0.1: uc.micro "^1.0.1" lint-staged@^15.2.9: - version "15.2.9" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-15.2.9.tgz#bf70d40b6b192df6ad756fb89822211615e0f4da" - integrity sha512-BZAt8Lk3sEnxw7tfxM7jeZlPRuT4M68O0/CwZhhaw6eeWu0Lz5eERE3m386InivXB64fp/mDID452h48tvKlRQ== + version "15.2.10" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-15.2.10.tgz#92ac222f802ba911897dcf23671da5bb80643cd2" + integrity sha512-5dY5t743e1byO19P9I4b3x8HJwalIznL5E1FWYnU6OWw33KxNBSLAc6Cy7F2PsFEO8FKnLwjwm5hx7aMF0jzZg== dependencies: chalk "~5.3.0" commander "~12.1.0" @@ -7956,7 +6780,7 @@ lint-staged@^15.2.9: execa "~8.0.1" lilconfig "~3.1.2" listr2 "~8.2.4" - micromatch "~4.0.7" + micromatch "~4.0.8" pidtree "~0.6.0" string-argv "~0.3.2" yaml "~2.5.0" @@ -7992,13 +6816,12 @@ load-tsconfig@^0.2.3: resolved "https://registry.yarnpkg.com/load-tsconfig/-/load-tsconfig-0.2.5.tgz#453b8cd8961bfb912dea77eb6c168fe8cca3d3a1" integrity sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg== -locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== +localforage@^1.8.1: + version "1.10.0" + resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.10.0.tgz#5c465dc5f62b2807c3a84c0c6a1b1b3212781dd4" + integrity sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg== dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" + lie "3.1.1" locate-path@^5.0.0: version "5.0.0" @@ -8024,16 +6847,6 @@ lodash.camelcase@^4.3.0: resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== -lodash.clonedeep@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" - integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ== - -lodash.curry@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.curry/-/lodash.curry-4.1.1.tgz#248e36072ede906501d75966200a86dab8b23170" - integrity sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA== - lodash.get@^4.3.0: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" @@ -8141,16 +6954,6 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" -lru-cache@^7.5.1: - version "7.18.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" - integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== - -"lru-cache@^9.1.1 || ^10.0.0": - version "10.2.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3" - integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q== - luxon@3.4.4: version "3.4.4" resolved "https://registry.yarnpkg.com/luxon/-/luxon-3.4.4.tgz#cf20dc27dc532ba41a169c43fdcc0063601577af" @@ -8168,14 +6971,7 @@ magic-string@^0.27.0: dependencies: "@jridgewell/sourcemap-codec" "^1.4.13" -magic-string@^0.30.0: - version "0.30.7" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.7.tgz#0cecd0527d473298679da95a2d7aeb8c64048505" - integrity sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA== - dependencies: - "@jridgewell/sourcemap-codec" "^1.4.15" - -magic-string@^0.30.11: +magic-string@^0.30.0, magic-string@^0.30.11: version "0.30.11" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.11.tgz#301a6f93b3e8c2cb13ac1a7a673492c0dfd12954" integrity sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A== @@ -8205,18 +7001,6 @@ make-dir@^4.0.0: dependencies: semver "^7.5.3" -make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -map-age-cleaner@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" - integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== - dependencies: - p-defer "^1.0.0" - map-or-similar@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/map-or-similar/-/map-or-similar-1.5.0.tgz#6de2653174adfb5d9edc33c69d3e92a1b76faf08" @@ -8263,9 +7047,9 @@ mdast-util-find-and-replace@^3.0.0: unist-util-visit-parents "^6.0.0" mdast-util-from-markdown@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.0.tgz#52f14815ec291ed061f2922fd14d6689c810cb88" - integrity sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA== + version "2.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.1.tgz#32a6e8f512b416e1f51eb817fc64bd867ebcd9cc" + integrity sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA== dependencies: "@types/mdast" "^4.0.0" "@types/unist" "^3.0.0" @@ -8281,9 +7065,9 @@ mdast-util-from-markdown@^2.0.0: unist-util-stringify-position "^4.0.0" mdast-util-gfm-autolink-literal@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.0.tgz#5baf35407421310a08e68c15e5d8821e8898ba2a" - integrity sha512-FyzMsduZZHSc3i0Px3PQcBT4WJY/X/RCtEJKuybiC6sjPqLv7h1yqAkmILZtuxMSsUyaLUWNp71+vQH2zqp5cg== + version "2.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz#abd557630337bd30a6d5a4bd8252e1c2dc0875d5" + integrity sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ== dependencies: "@types/mdast" "^4.0.0" ccount "^2.0.0" @@ -8384,25 +7168,6 @@ 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== -mem@^4.0.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" - integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w== - dependencies: - map-age-cleaner "^0.1.1" - mimic-fn "^2.0.0" - p-is-promise "^2.0.0" - -memfs@^4.9.3: - version "4.9.4" - resolved "https://registry.yarnpkg.com/memfs/-/memfs-4.9.4.tgz#803eb7f2091d1c6198ec9ba9b582505ad8699c9e" - integrity sha512-Xlj8b2rU11nM6+KU6wC7cuWcHQhVINWCUgdPS4Ar9nPxLaOya3RghqK7ALyDW2QtGebYAYs6uEdEVnwPVT942A== - dependencies: - "@jsonjoy.com/json-pack" "^1.0.3" - "@jsonjoy.com/util" "^1.1.2" - tree-dump "^1.0.1" - tslib "^2.0.0" - memoize-one@^5.0.0, memoize-one@^5.1.1: version "5.2.1" resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" @@ -8415,10 +7180,10 @@ memoizerific@^1.11.3: dependencies: map-or-similar "^1.5.0" -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== +merge-descriptors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" + integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== merge-stream@^2.0.0: version "2.0.0" @@ -8436,9 +7201,9 @@ methods@~1.1.2: integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== micromark-core-commonmark@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-2.0.0.tgz#50740201f0ee78c12a675bf3e68ffebc0bf931a3" - integrity sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz#9a45510557d068605c6e9a80f282b2bb8581e43d" + integrity sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA== dependencies: decode-named-character-reference "^1.0.0" devlop "^1.0.0" @@ -8458,9 +7223,9 @@ micromark-core-commonmark@^2.0.0: micromark-util-types "^2.0.0" micromark-extension-gfm-autolink-literal@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.0.0.tgz#f1e50b42e67d441528f39a67133eddde2bbabfd9" - integrity sha512-rTHfnpt/Q7dEAK1Y5ii0W8bhfJlVJFnJMHIPisfPK3gpVNuOP0VnRl96+YJ3RYWV/P4gFeQoGKNlT3RhuvpqAg== + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz#6286aee9686c4462c1e3552a9d505feddceeb935" + integrity sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw== dependencies: micromark-util-character "^2.0.0" micromark-util-sanitize-uri "^2.0.0" @@ -8468,9 +7233,9 @@ micromark-extension-gfm-autolink-literal@^2.0.0: micromark-util-types "^2.0.0" micromark-extension-gfm-footnote@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.0.0.tgz#91afad310065a94b636ab1e9dab2c60d1aab953c" - integrity sha512-6Rzu0CYRKDv3BfLAUnZsSlzx3ak6HAoI85KTiijuKIz5UxZxbUI+pD6oHgw+6UtQuiRwnGRhzMmPRv4smcz0fg== + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz#4dab56d4e398b9853f6fe4efac4fc9361f3e0750" + integrity sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw== dependencies: devlop "^1.0.0" micromark-core-commonmark "^2.0.0" @@ -8482,9 +7247,9 @@ micromark-extension-gfm-footnote@^2.0.0: micromark-util-types "^2.0.0" micromark-extension-gfm-strikethrough@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.0.0.tgz#6917db8e320da70e39ffbf97abdbff83e6783e61" - integrity sha512-c3BR1ClMp5fxxmwP6AoOY2fXO9U8uFMKs4ADD66ahLTNcwzSCyRVU4k7LPV5Nxo/VJiR4TdzxRQY2v3qIUceCw== + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz#86106df8b3a692b5f6a92280d3879be6be46d923" + integrity sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw== dependencies: devlop "^1.0.0" micromark-util-chunked "^2.0.0" @@ -8494,9 +7259,9 @@ micromark-extension-gfm-strikethrough@^2.0.0: micromark-util-types "^2.0.0" micromark-extension-gfm-table@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.0.0.tgz#2cf3fe352d9e089b7ef5fff003bdfe0da29649b7" - integrity sha512-PoHlhypg1ItIucOaHmKE8fbin3vTLpDOUg8KAr8gRCF1MOZI9Nquq2i/44wFvviM4WuxJzc3demT8Y3dkfvYrw== + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.0.tgz#5cadedfbb29fca7abf752447967003dc3b6583c9" + integrity sha512-Ub2ncQv+fwD70/l4ou27b4YzfNaCJOvyX4HxXU15m7mpYY+rjuWzsLIPZHJL253Z643RpbcP1oeIJlQ/SKW67g== dependencies: devlop "^1.0.0" micromark-factory-space "^2.0.0" @@ -8512,9 +7277,9 @@ micromark-extension-gfm-tagfilter@^2.0.0: micromark-util-types "^2.0.0" micromark-extension-gfm-task-list-item@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.0.1.tgz#ee8b208f1ced1eb9fb11c19a23666e59d86d4838" - integrity sha512-cY5PzGcnULaN5O7T+cOzfMoHjBW7j+T9D2sucA5d/KbsBTPcYdebm9zUd9zzdgJGCwahV+/W78Z3nbulBYVbTw== + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz#bcc34d805639829990ec175c3eea12bb5b781f2c" + integrity sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw== dependencies: devlop "^1.0.0" micromark-factory-space "^2.0.0" @@ -8666,9 +7431,9 @@ micromark-util-sanitize-uri@^2.0.0: micromark-util-symbol "^2.0.0" micromark-util-subtokenize@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.0.tgz#9f412442d77e0c5789ffdf42377fa8a2bcbdf581" - integrity sha512-vc93L1t+gpR3p8jxeVdaYlbV2jTYteDje19rNSS/H5dlhxUYll5Fy6vJ2cDwP8RnsXi818yGty1ayP55y3W6fg== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz#76129c49ac65da6e479c09d0ec4b5f29ec6eace5" + integrity sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q== dependencies: devlop "^1.0.0" micromark-util-chunked "^2.0.0" @@ -8708,15 +7473,7 @@ micromark@^4.0.0: micromark-util-symbol "^2.0.0" micromark-util-types "^2.0.0" -micromatch@^4.0.2, micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== - dependencies: - braces "^3.0.2" - picomatch "^2.3.1" - -micromatch@~4.0.7: +micromatch@^4.0.4, micromatch@~4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== @@ -8724,23 +7481,11 @@ micromatch@~4.0.7: braces "^3.0.3" picomatch "^2.3.1" -mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": +mime-db@1.52.0: version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-db@~1.33.0: - version "1.33.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" - integrity sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ== - -mime-types@2.1.18: - version "2.1.18" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" - integrity sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ== - dependencies: - mime-db "~1.33.0" - mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" @@ -8753,7 +7498,7 @@ mime@1.6.0: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -mimic-fn@^2.0.0, mimic-fn@^2.1.0: +mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== @@ -8770,41 +7515,36 @@ mimic-function@^5.0.0: min-indent@^1.0.0, min-indent@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" - integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== - -minimatch@3.1.2, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" + resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== -minimatch@9.0.3, minimatch@^9.0.1, minimatch@^9.0.3: +minimatch@9.0.3: version "9.0.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== dependencies: brace-expansion "^2.0.1" -minimatch@^9.0.4: +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" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^9.0.3, minimatch@^9.0.4: version "9.0.5" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== dependencies: brace-expansion "^2.0.1" -minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6, minimist@^1.2.8: +minimist@^1.2.6, minimist@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0": - version "7.0.4" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" - integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== - -minipass@^7.1.2: +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== @@ -8847,26 +7587,21 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - ms@2.1.3, ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== msw@^2.2.3: - version "2.2.3" - resolved "https://registry.yarnpkg.com/msw/-/msw-2.2.3.tgz#d05b46d73e8832cbf2145743938635beaaafa0d7" - integrity sha512-84CoNCkcJ/EvY8Tv0tD/6HKVd4S5HyGowHjM5W12K8Wgryp4fikqS7IaTOceyQgP5dNedxo2icTLDXo7dkpxCg== + version "2.4.9" + resolved "https://registry.yarnpkg.com/msw/-/msw-2.4.9.tgz#350a84cedb90b578a32c7764431e3750900f8407" + integrity sha512-1m8xccT6ipN4PTqLinPwmzhxQREuxaEJYdx4nIbggxP8aM7r1e71vE7RtOUSQoAm1LydjGfZKy7370XD/tsuYg== dependencies: "@bundled-es-modules/cookie" "^2.0.0" "@bundled-es-modules/statuses" "^1.0.1" + "@bundled-es-modules/tough-cookie" "^0.1.6" "@inquirer/confirm" "^3.0.0" - "@mswjs/cookies" "^1.1.0" - "@mswjs/interceptors" "^0.25.16" + "@mswjs/interceptors" "^0.35.8" "@open-draft/until" "^2.1.0" "@types/cookie" "^0.6.0" "@types/statuses" "^2.0.4" @@ -8875,7 +7610,7 @@ msw@^2.2.3: headers-polyfill "^4.0.2" is-node-process "^1.2.0" outvariant "^1.4.2" - path-to-regexp "^6.2.0" + path-to-regexp "^6.3.0" strict-event-emitter "^0.5.1" type-fest "^4.9.0" yargs "^17.7.2" @@ -8944,20 +7679,10 @@ node-fetch@^1.0.1, node-fetch@^2.6.7: dependencies: whatwg-url "^5.0.0" -node-releases@^2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" - integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== - -normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" +node-releases@^2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" @@ -8972,13 +7697,6 @@ notistack@^3.0.1: clsx "^1.1.0" goober "^2.0.33" -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw== - dependencies: - path-key "^2.0.0" - npm-run-path@^4.0.0, npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" @@ -8987,17 +7705,12 @@ npm-run-path@^4.0.0, npm-run-path@^4.0.1: path-key "^3.0.0" npm-run-path@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.2.0.tgz#224cdd22c755560253dd71b83a1ef2f758b2e955" - integrity sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg== + version "5.3.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.3.0.tgz#e23353d0ebb9317f174e93417e4a4d82d0249e9f" + integrity sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ== dependencies: path-key "^4.0.0" -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ== - nwsapi@^2.2.12: version "2.2.12" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.12.tgz#fb6af5c0ec35b27b4581eb3bbad34ec9e5c696f8" @@ -9009,24 +7722,24 @@ object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== object-inspect@^1.13.1: - version "1.13.1" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" - integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== object-is@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" - integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + version "1.1.6" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.6.tgz#1a6a53aed2dd8f7e6775ff870bea58545956ab07" + integrity sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" + call-bind "^1.0.7" + define-properties "^1.2.1" object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object.assign@^4.1.4: +object.assign@^4.1.4, object.assign@^4.1.5: version "4.1.5" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== @@ -9036,40 +7749,33 @@ object.assign@^4.1.4: has-symbols "^1.0.3" object-keys "^1.1.1" -object.entries@^1.1.6, object.entries@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.7.tgz#2b47760e2a2e3a752f39dd874655c61a7f03c131" - integrity sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - -object.fromentries@^2.0.6, object.fromentries@^2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.7.tgz#71e95f441e9a0ea6baf682ecaaf37fa2a8d7e616" - integrity sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA== +object.entries@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.8.tgz#bffe6f282e01f4d17807204a24f8edd823599c41" + integrity sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" -object.hasown@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.3.tgz#6a5f2897bb4d3668b8e79364f98ccf971bda55ae" - integrity sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA== +object.fromentries@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" + integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== dependencies: - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" -object.values@^1.1.6: - version "1.1.7" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.7.tgz#617ed13272e7e1071b43973aa1655d9291b8442a" - integrity sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng== +object.values@^1.1.6, object.values@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b" + integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" on-finished@2.4.1: version "2.4.1" @@ -9078,11 +7784,6 @@ on-finished@2.4.1: dependencies: ee-first "1.1.1" -on-headers@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" - integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== - once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -9111,18 +7812,14 @@ onetime@^7.0.0: dependencies: mimic-function "^5.0.0" -open@^7.4.2: - version "7.4.2" - resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" - integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== +open@^8.0.4: + version "8.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" + integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== dependencies: - is-docker "^2.0.0" - is-wsl "^2.1.1" - -opencollective-postinstall@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" - integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q== + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" optionator@^0.8.3: version "0.8.3" @@ -9136,7 +7833,7 @@ optionator@^0.8.3: type-check "~0.3.2" word-wrap "~1.2.3" -optionator@^0.9.1: +optionator@^0.9.1, optionator@^0.9.3: version "0.9.4" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== @@ -9148,27 +7845,6 @@ optionator@^0.9.1: type-check "^0.4.0" word-wrap "^1.2.5" -optionator@^0.9.3: - version "0.9.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" - integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== - dependencies: - "@aashutoshrathi/word-wrap" "^1.2.3" - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - -os-locale@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" - integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== - dependencies: - execa "^1.0.0" - lcid "^2.0.0" - mem "^4.0.0" - os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -9179,27 +7855,12 @@ ospath@^1.2.2: resolved "https://registry.yarnpkg.com/ospath/-/ospath-1.2.2.tgz#1276639774a3f8ef2572f7fe4280e0ea4550c07b" integrity sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA== -outvariant@^1.2.1, outvariant@^1.4.0, outvariant@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/outvariant/-/outvariant-1.4.2.tgz#f54f19240eeb7f15b28263d5147405752d8e2066" - integrity sha512-Ou3dJ6bA/UJ5GVHxah4LnqDwZRwAmWxrG3wtrHrbGnP4RnLCtA64A4F+ae7Y8ww660JaddSoArUR5HjipWSHAQ== - -p-defer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" - integrity sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw== - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== - -p-is-promise@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" - integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== +outvariant@^1.4.0, outvariant@^1.4.2, outvariant@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/outvariant/-/outvariant-1.4.3.tgz#221c1bfc093e8fec7075497e7799fdbf43d14873" + integrity sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA== -p-limit@^2.0.0, p-limit@^2.2.0: +p-limit@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== @@ -9213,13 +7874,6 @@ p-limit@^3.0.2: dependencies: yocto-queue "^0.1.0" -p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== - dependencies: - p-limit "^2.0.0" - p-locate@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" @@ -9258,14 +7912,6 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw== - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - 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" @@ -9276,7 +7922,7 @@ parse-json@^5.0.0, parse-json@^5.2.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" -parse5@^7.0.0, parse5@^7.1.2: +parse5@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== @@ -9288,32 +7934,6 @@ parseurl@~1.3.3: resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== -patch-package@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-8.0.0.tgz#d191e2f1b6e06a4624a0116bcb88edd6714ede61" - integrity sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA== - dependencies: - "@yarnpkg/lockfile" "^1.1.0" - chalk "^4.1.2" - ci-info "^3.7.0" - cross-spawn "^7.0.3" - find-yarn-workspace-root "^2.0.0" - fs-extra "^9.0.0" - json-stable-stringify "^1.0.2" - klaw-sync "^6.0.0" - minimist "^1.2.6" - open "^7.4.2" - rimraf "^2.6.3" - semver "^7.5.3" - slash "^2.0.0" - tmp "^0.0.33" - yaml "^2.2.2" - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== - path-exists@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" @@ -9324,12 +7944,7 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -path-is-inside@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - integrity sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w== - -path-key@^2.0.0, path-key@^2.0.1: +path-key@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== @@ -9349,14 +7964,6 @@ 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-scurry@^1.10.1: - version "1.10.1" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698" - integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ== - dependencies: - lru-cache "^9.1.1 || ^10.0.0" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" - path-scurry@^1.11.1: version "1.11.1" resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" @@ -9365,46 +7972,28 @@ path-scurry@^1.11.1: lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== - -path-to-regexp@2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.2.1.tgz#90b617025a16381a879bc82a38d4e8bdeb2bcf45" - integrity sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ== +path-to-regexp@0.1.10: + version "0.1.10" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b" + integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w== 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== + version "1.9.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.9.0.tgz#5dc0753acbf8521ca2e0f137b4578b917b10cf24" + integrity sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g== dependencies: isarray "0.0.1" -path-to-regexp@^6.2.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.1.tgz#d54934d6798eb9e5ef14e7af7962c945906918e5" - integrity sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw== +path-to-regexp@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.3.0.tgz#2b6a26a337737a8e1416f9272ed0766b1c0389f4" + integrity sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ== 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== -path-unified@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/path-unified/-/path-unified-0.1.0.tgz#fd751e787ab019a88cdf5cecbd7e5e4711c66c7d" - integrity sha512-/Oaz9ZJforrkmFrwkR/AcvjVsCAwGSJHO0X6O6ISj8YeFbATjIEBXLDcZfnK3MO4uvCBrJTdVIxdOc79PMqSdg== - -path@^0.12.7: - version "0.12.7" - resolved "https://registry.yarnpkg.com/path/-/path-0.12.7.tgz#d4dc2a506c4ce2197eb481ebfcd5b36c0140b10f" - integrity sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q== - dependencies: - process "^0.11.1" - util "^0.10.3" - pathe@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec" @@ -9434,17 +8023,7 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== -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== - -picocolors@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" - integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== - -picocolors@^1.1.0: +picocolors@^1.0.0, picocolors@^1.0.1, picocolors@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== @@ -9469,30 +8048,18 @@ pify@^2.2.0: resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg== - pirates@^4.0.1: version "4.0.6" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== -pkg-dir@^4.1.0, pkg-dir@^4.2.0: +pkg-dir@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== dependencies: find-up "^4.0.0" -please-upgrade-node@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" - integrity sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg== - dependencies: - semver-compare "^1.0.0" - polished@^4.2.2: version "4.3.1" resolved "https://registry.yarnpkg.com/polished/-/polished-4.3.1.tgz#5a00ae32715609f83d89f6f31d0f0261c6170548" @@ -9500,12 +8067,10 @@ polished@^4.2.2: dependencies: "@babel/runtime" "^7.17.8" -postcss-calc-ast-parser@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/postcss-calc-ast-parser/-/postcss-calc-ast-parser-0.1.4.tgz#9aeee3650a91c0b2902789689bc044c9f83bc447" - integrity sha512-CebpbHc96zgFjGgdQ6BqBy6XIUgRx1xXWCAAk6oke02RZ5nxwo9KQejTg8y7uYEeI9kv8jKQPYjoe6REsY23vw== - dependencies: - postcss-value-parser "^3.3.1" +possible-typed-array-names@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" + integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== postcss-load-config@^6.0.1: version "6.0.1" @@ -9514,20 +8079,6 @@ postcss-load-config@^6.0.1: dependencies: lilconfig "^3.1.1" -postcss-value-parser@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" - integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== - -postcss@^8.4.35: - version "8.4.35" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.35.tgz#60997775689ce09011edf083a549cea44aabe2f7" - integrity sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA== - dependencies: - nanoid "^3.3.7" - picocolors "^1.0.0" - source-map-js "^1.0.2" - postcss@^8.4.43: version "8.4.47" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.47.tgz#5bf6c9a010f3e724c503bf03ef7947dcb0fea365" @@ -9555,9 +8106,9 @@ prettier-linter-helpers@^1.0.0: fast-diff "^1.1.2" prettier@^3.1.1: - version "3.2.5" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368" - integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A== + version "3.3.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105" + integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== prettier@~2.2.1: version "2.2.1" @@ -9578,7 +8129,7 @@ pretty-format@^27.0.2: ansi-styles "^5.0.0" react-is "^17.0.1" -process@^0.11.1, process@^0.11.10: +process@^0.11.10: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== @@ -9593,7 +8144,7 @@ promise-polyfill@8.2.3: resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-8.2.3.tgz#2edc7e4b81aff781c88a0d577e5fe9da822107c6" integrity sha512-Og0+jCRQetV84U8wVjMNccfGCnMQ9mGs9Hv78QFe+pSDD3gWTpz0y+1QCuxy5d/vBFuZ3iwP2eycAkvqIMPmWg== -promise-polyfill@^8.1.3, promise-polyfill@^8.3.0: +promise-polyfill@^8.3.0: version "8.3.0" resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-8.3.0.tgz#9284810268138d103807b11f4e23d5e945a4db63" integrity sha512-H5oELycFml5yto/atYqmjyigJoAo3+OXwolYiH7OfQuYlAqhxNvTfiNMbV9hsC6Yp83yE5r2KTVmtrG6R9i6Pg== @@ -9643,18 +8194,13 @@ psl@^1.1.33: integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + version "3.0.2" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.2.tgz#836f3edd6bc2ee599256c924ffe0d88573ddcbf8" + integrity sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw== dependencies: end-of-stream "^1.1.0" once "^1.3.1" -punycode@^1.3.2, punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== - punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" @@ -9673,31 +8219,10 @@ qrcode.react@^0.8.0: prop-types "^15.6.0" qr.js "0.0.0" -qs@6.10.4: - version "6.10.4" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.4.tgz#6a3003755add91c0ec9eacdc5f878b034e73f9e7" - integrity sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g== - dependencies: - side-channel "^1.0.4" - -qs@6.11.0: - version "6.11.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" - integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== - dependencies: - side-channel "^1.0.4" - -qs@^6.10.0: - version "6.11.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" - integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== - dependencies: - side-channel "^1.0.4" - -qs@^6.11.2: - version "6.12.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.12.1.tgz#39422111ca7cbdb70425541cba20c7d7b216599a" - integrity sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ== +qs@6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" + integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== dependencies: side-channel "^1.0.6" @@ -9728,16 +8253,6 @@ ramda@0.25.0, ramda@~0.25.0: resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.25.0.tgz#8fdf68231cffa90bc2f9460390a0cb74a29b29a9" integrity sha512-GXpfrYVPwx3K7RQ6aYT8KPS8XViSXUVJT1ONhoKPE9VAleW42YE+U+8VEyGWt41EnEQW7gwecYJriTI0pKoecQ== -ramda@0.29.0: - version "0.29.0" - resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.29.0.tgz#fbbb67a740a754c8a4cbb41e2a6e0eb8507f55fb" - integrity sha512-BBea6L67bYLtdbOqfp8f58fPMqEwx0doL+pAi8TZyp2YWz8R9G8z9x75CZI8W+ftqhFHCpEX2cRnUUXK130iKA== - -range-parser@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" - integrity sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A== - range-parser@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" @@ -9753,16 +8268,6 @@ raw-body@2.5.2: iconv-lite "0.4.24" unpipe "1.0.0" -rc@^1.0.1, rc@^1.1.6: - version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== - dependencies: - deep-extend "^0.6.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - react-beautiful-dnd@^13.0.0: version "13.1.1" resolved "https://registry.yarnpkg.com/react-beautiful-dnd/-/react-beautiful-dnd-13.1.1.tgz#b0f3087a5840920abf8bb2325f1ffa46d8c4d0a2" @@ -9781,14 +8286,6 @@ react-colorful@^5.1.2: resolved "https://registry.yarnpkg.com/react-colorful/-/react-colorful-5.6.1.tgz#7dc2aed2d7c72fac89694e834d179e32f3da563b" integrity sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw== -react-copy-to-clipboard@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz#09aae5ec4c62750ccb2e6421a58725eabc41255c" - integrity sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A== - dependencies: - copy-to-clipboard "^3.3.1" - prop-types "^15.8.1" - react-csv@^2.0.3: version "2.2.2" resolved "https://registry.yarnpkg.com/react-csv/-/react-csv-2.2.2.tgz#5bbf0d72a846412221a14880f294da9d6def9bfb" @@ -9816,21 +8313,12 @@ react-docgen@^7.0.0: strip-indent "^4.0.0" "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0", react-dom@^18.2.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" - integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== - dependencies: - loose-envify "^1.1.0" - scheduler "^0.23.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== + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" + integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== dependencies: loose-envify "^1.1.0" - object-assign "^4.1.1" - scheduler "^0.20.2" + scheduler "^0.23.2" react-dropzone@~11.2.0: version "11.2.4" @@ -9856,9 +8344,9 @@ react-fast-compare@^2.0.1: integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== react-hook-form@^7.51.0: - version "7.51.0" - resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.51.0.tgz#757ae71b37c26e00590bd3788508287dcc5ecdaf" - integrity sha512-BggOy5j58RdhdMzzRUHGOYhSz1oeylFAv6jUSG86OvCIvlAvS7KvnRY7yoAf2pfEiPN7BesnR0xx73nEk3qIiw== + version "7.53.0" + resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.53.0.tgz#3cf70951bf41fa95207b34486203ebefbd3a05ab" + integrity sha512-M1n3HhqCww6S2hxLxciEXy2oISPnAzxY7gvwVPrtlczTM/1dDadXgUxDpHMrMTblDOcm/AXtXxHwZ3jpg1mqKQ== react-input-autosize@^2.2.2: version "2.2.2" @@ -9872,7 +8360,7 @@ react-is@18.1.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.1.0.tgz#61aaed3096d30eacf2a2127118b5b41387d32a67" integrity sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg== -react-is@^16.10.2, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.6, react-is@^16.9.0: +react-is@^16.10.2, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.9.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== @@ -9882,14 +8370,9 @@ react-is@^17.0.1, react-is@^17.0.2: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -"react-is@^17.0.1 || ^18.0.0", react-is@^18.2.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" - integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== - -react-is@^18.3.1: +"react-is@^17.0.1 || ^18.0.0", react-is@^18.3.1: version "18.3.1" - resolved "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== react-lifecycles-compat@^3.0.2: @@ -9978,24 +8461,14 @@ react-select@~3.1.0: react-transition-group "^4.3.0" react-smooth@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/react-smooth/-/react-smooth-4.0.0.tgz#69e560ab69b69a066187d70cb92c1a664f7f046a" - integrity sha512-2NMXOBY1uVUQx1jBeENGA497HK20y6CPGYL1ZnJLeoQ8rrc3UfmOM82sRxtzpcoCkUMy4CS0RGylfuVhuFjBgg== + version "4.0.1" + resolved "https://registry.yarnpkg.com/react-smooth/-/react-smooth-4.0.1.tgz#6200d8699bfe051ae40ba187988323b1449eab1a" + integrity sha512-OE4hm7XqR0jNOq3Qmk9mFLyd6p2+j6bvbPJ7qlB7+oo0eNcL2l7WQzG6MBnT3EXY6xzkLMUBec3AfewJdA0J8w== dependencies: fast-equals "^5.0.1" prop-types "^15.8.1" react-transition-group "^4.4.5" -react-test-renderer@16.14.0: - version "16.14.0" - resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.14.0.tgz#e98360087348e260c56d4fe2315e970480c228ae" - integrity sha512-L8yPjqPE5CZO6rKsKXRO/rVPiaCOy0tQQJbC+UjPNlobl5mad59lvPjwFsQHTvL03caVDIVr9x9/OSgDe6I5Eg== - dependencies: - object-assign "^4.1.1" - prop-types "^15.6.2" - react-is "^16.8.6" - scheduler "^0.19.1" - react-transition-group@^4.3.0, react-transition-group@^4.4.5: version "4.4.5" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1" @@ -10022,38 +8495,11 @@ react-waypoint@^10.3.0: react-is "^17.0.1 || ^18.0.0" "react@^16.8.0 || ^17.0.0 || ^18.0.0", react@^18.2.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" - integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== - dependencies: - loose-envify "^1.1.0" - -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== + version "18.3.1" + resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" + integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== dependencies: loose-envify "^1.1.0" - object-assign "^4.1.1" - -read-pkg@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-4.0.1.tgz#963625378f3e1c4d48c85872b5a6ec7d5d093237" - integrity sha512-+UBirHHDm5J+3WDmLBZYSklRYg82nMlz+enn+GMZ22nSR2f4bzxmhso6rzQW/3mT2PVzpzDTiYIZahk8UmZ44w== - dependencies: - normalize-package-data "^2.3.2" - parse-json "^4.0.0" - pify "^3.0.0" - -read-pkg@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" - integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== - dependencies: - "@types/normalize-package-data" "^2.4.0" - normalize-package-data "^2.5.0" - parse-json "^5.0.0" - type-fest "^0.6.0" readdirp@~3.6.0: version "3.6.0" @@ -10063,9 +8509,9 @@ readdirp@~3.6.0: picomatch "^2.2.1" recast@^0.23.5: - version "0.23.6" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.23.6.tgz#198fba74f66143a30acc81929302d214ce4e3bfa" - integrity sha512-9FHoNjX1yjuesMwuthAmPKabxYQdOgihFYmT5ebXfYGBcnqXZf3WOVz+5foEZ8Y83P4ZY6yQD5GMmtV+pgCCAQ== + version "0.23.9" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.23.9.tgz#587c5d3a77c2cfcb0c18ccce6da4361528c2587b" + integrity sha512-Hx/BGIbwj+Des3+xy5uAtAbdCyqK9y9wbBcDFDYanLS9JnMqf7OeF87HQwUimE87OEc72mr6tkKUKMBBL+hF9Q== dependencies: ast-types "^0.16.1" esprima "~4.0.0" @@ -10081,13 +8527,13 @@ recharts-scale@^0.4.4: decimal.js-light "^2.4.1" recharts@^2.9.3: - version "2.12.0" - resolved "https://registry.yarnpkg.com/recharts/-/recharts-2.12.0.tgz#e731e2733359d7942d5807c34c70f67673096d25" - integrity sha512-rVNcdNQ5b7+40Ue7mcEKZJyEv+3SUk2bDEVvOyXPDXXVE7TU3lrvnJUgAvO36hSzhRP2DnAamKXvHLFIFOU0Ww== + version "2.12.7" + resolved "https://registry.yarnpkg.com/recharts/-/recharts-2.12.7.tgz#c7f42f473a257ff88b43d88a92530930b5f9e773" + integrity sha512-hlLJMhPQfv4/3NBSAyq3gzGg4h2v69RJh6KU7b3pXYNNAELs9kEoXOjbkxdXpALqKBoVmVptGfLpxdaVYqjmXQ== dependencies: clsx "^2.0.0" eventemitter3 "^4.0.1" - lodash "^4.17.19" + lodash "^4.17.21" react-is "^16.10.2" react-smooth "^4.0.0" recharts-scale "^0.4.4" @@ -10134,15 +8580,15 @@ redux@^4.0.0, redux@^4.0.4, redux@^4.0.5: "@babel/runtime" "^7.9.2" reflect.getprototypeof@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.5.tgz#e0bd28b597518f16edaf9c0e292c631eb13e0674" - integrity sha512-62wgfC8dJWrmxv44CA36pLDnP6KKl3Vhxb7PL+8+qrrFMMoJij4vgiMP8zV4O8+CBMXY1mHxI5fITGHXFHVmQQ== + version "1.0.6" + resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz#3ab04c32a8390b770712b7a8633972702d278859" + integrity sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg== dependencies: - call-bind "^1.0.5" + call-bind "^1.0.7" define-properties "^1.2.1" - es-abstract "^1.22.3" - es-errors "^1.0.0" - get-intrinsic "^1.2.3" + es-abstract "^1.23.1" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" globalthis "^1.0.3" which-builtin-type "^1.1.3" @@ -10156,40 +8602,26 @@ regenerator-runtime@^0.14.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== -regexp.prototype.flags@^1.5.0, regexp.prototype.flags@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz#90ce989138db209f81492edd734183ce99f9677e" - integrity sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg== +regexp.prototype.flags@^1.5.1, regexp.prototype.flags@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" + integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - set-function-name "^2.0.0" + call-bind "^1.0.6" + define-properties "^1.2.1" + es-errors "^1.3.0" + set-function-name "^2.0.1" regexpp@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== -regexpp@^3.0.0, regexpp@^3.1.0: +regexpp@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== -registry-auth-token@3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20" - integrity sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ== - dependencies: - rc "^1.1.6" - safe-buffer "^5.0.1" - -registry-url@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" - integrity sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA== - dependencies: - rc "^1.0.1" - rehype-external-links@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/rehype-external-links/-/rehype-external-links-3.0.0.tgz#2b28b5cda1932f83f045b6f80a3e1b15f168c6f6" @@ -10266,16 +8698,6 @@ require-from-string@^2.0.2: resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== -require-main-filename@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" - integrity sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug== - -requireindex@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/requireindex/-/requireindex-1.2.0.tgz#3463cdb22ee151902635aa6c9535d4de9c2ef1ef" - integrity sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww== - requireindex@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/requireindex/-/requireindex-1.1.0.tgz#e5404b81557ef75db6e49c5a72004893fe03e162" @@ -10286,28 +8708,11 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== -reselect-tools@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/reselect-tools/-/reselect-tools-0.0.7.tgz#bff19df422ebebd1a7c322262db94a554f6b44ed" - integrity sha512-+RGguS8ph21y04l6YwQwL+VfJ/c0qyZKCkhCd5ZwbNJ/lklsJml3CIim+uaG/t+7jYZQcwDW4bk5+VzTeuzwtw== - dependencies: - reselect "4.0.0" - -reselect@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.0.0.tgz#f2529830e5d3d0e021408b246a206ef4ea4437f7" - integrity sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA== - reselect@^4.0.0: version "4.1.8" resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.8.tgz#3f5dc671ea168dccdeb3e141236f69f02eaec524" integrity sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ== -resolve-from@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" - integrity sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw== - resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" @@ -10323,7 +8728,12 @@ resolve-pathname@^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@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.19.0, resolve@^1.22.1, resolve@^1.22.8: +resolve-pkg-maps@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" + integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== + +resolve@^1.12.0, resolve@^1.19.0, resolve@^1.22.1, resolve@^1.22.8: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -10332,7 +8742,7 @@ resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.19.0, resolve@^1.2 path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@^2.0.0-next.4: +resolve@^2.0.0-next.5: version "2.0.0-next.5" resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c" integrity sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA== @@ -10369,12 +8779,7 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rfdc@^1.3.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.1.tgz#2b6d4df52dffe8bb346992a10ea9451f24373a8f" - integrity sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg== - -rfdc@^1.4.1: +rfdc@^1.3.0, rfdc@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.4.1.tgz#778f76c4fb731d93414e8f925fbecf64cce7f6ca" integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== @@ -10391,97 +8796,38 @@ rimraf@2.6.3: dependencies: glob "^7.1.3" -rimraf@^2.6.3: - version "2.7.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== - dependencies: - glob "^7.1.3" - -rimraf@^3.0.0, rimraf@^3.0.2: +rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: glob "^7.1.3" -rollup@^4.19.0: - version "4.21.0" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.21.0.tgz#28db5f5c556a5180361d35009979ccc749560b9d" - integrity sha512-vo+S/lfA2lMS7rZ2Qoubi6I5hwZwzXeUIctILZLbHI+laNtvhhOIon2S1JksA5UEDQ7l3vberd0fxK44lTYjbQ== - dependencies: - "@types/estree" "1.0.5" - optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.21.0" - "@rollup/rollup-android-arm64" "4.21.0" - "@rollup/rollup-darwin-arm64" "4.21.0" - "@rollup/rollup-darwin-x64" "4.21.0" - "@rollup/rollup-linux-arm-gnueabihf" "4.21.0" - "@rollup/rollup-linux-arm-musleabihf" "4.21.0" - "@rollup/rollup-linux-arm64-gnu" "4.21.0" - "@rollup/rollup-linux-arm64-musl" "4.21.0" - "@rollup/rollup-linux-powerpc64le-gnu" "4.21.0" - "@rollup/rollup-linux-riscv64-gnu" "4.21.0" - "@rollup/rollup-linux-s390x-gnu" "4.21.0" - "@rollup/rollup-linux-x64-gnu" "4.21.0" - "@rollup/rollup-linux-x64-musl" "4.21.0" - "@rollup/rollup-win32-arm64-msvc" "4.21.0" - "@rollup/rollup-win32-ia32-msvc" "4.21.0" - "@rollup/rollup-win32-x64-msvc" "4.21.0" - fsevents "~2.3.2" - -rollup@^4.2.0: - version "4.9.6" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.9.6.tgz#4515facb0318ecca254a2ee1315e22e09efc50a0" - integrity sha512-05lzkCS2uASX0CiLFybYfVkwNbKZG5NFQ6Go0VWyogFTXXbR039UVsegViTntkk4OglHBdF54ccApXRRuXRbsg== - dependencies: - "@types/estree" "1.0.5" - optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.9.6" - "@rollup/rollup-android-arm64" "4.9.6" - "@rollup/rollup-darwin-arm64" "4.9.6" - "@rollup/rollup-darwin-x64" "4.9.6" - "@rollup/rollup-linux-arm-gnueabihf" "4.9.6" - "@rollup/rollup-linux-arm64-gnu" "4.9.6" - "@rollup/rollup-linux-arm64-musl" "4.9.6" - "@rollup/rollup-linux-riscv64-gnu" "4.9.6" - "@rollup/rollup-linux-x64-gnu" "4.9.6" - "@rollup/rollup-linux-x64-musl" "4.9.6" - "@rollup/rollup-win32-arm64-msvc" "4.9.6" - "@rollup/rollup-win32-ia32-msvc" "4.9.6" - "@rollup/rollup-win32-x64-msvc" "4.9.6" - fsevents "~2.3.2" - -rollup@^4.20.0: - version "4.21.1" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.21.1.tgz#65b9b9e9de9a64604fab083fb127f3e9eac2935d" - integrity sha512-ZnYyKvscThhgd3M5+Qt3pmhO4jIRR5RGzaSovB6Q7rGNrK5cUncrtLmcTTJVSdcKXyZjW8X8MB0JMSuH9bcAJg== +rollup@^4.19.0, rollup@^4.20.0: + version "4.22.4" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.22.4.tgz#4135a6446671cd2a2453e1ad42a45d5973ec3a0f" + integrity sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A== dependencies: "@types/estree" "1.0.5" optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.21.1" - "@rollup/rollup-android-arm64" "4.21.1" - "@rollup/rollup-darwin-arm64" "4.21.1" - "@rollup/rollup-darwin-x64" "4.21.1" - "@rollup/rollup-linux-arm-gnueabihf" "4.21.1" - "@rollup/rollup-linux-arm-musleabihf" "4.21.1" - "@rollup/rollup-linux-arm64-gnu" "4.21.1" - "@rollup/rollup-linux-arm64-musl" "4.21.1" - "@rollup/rollup-linux-powerpc64le-gnu" "4.21.1" - "@rollup/rollup-linux-riscv64-gnu" "4.21.1" - "@rollup/rollup-linux-s390x-gnu" "4.21.1" - "@rollup/rollup-linux-x64-gnu" "4.21.1" - "@rollup/rollup-linux-x64-musl" "4.21.1" - "@rollup/rollup-win32-arm64-msvc" "4.21.1" - "@rollup/rollup-win32-ia32-msvc" "4.21.1" - "@rollup/rollup-win32-x64-msvc" "4.21.1" + "@rollup/rollup-android-arm-eabi" "4.22.4" + "@rollup/rollup-android-arm64" "4.22.4" + "@rollup/rollup-darwin-arm64" "4.22.4" + "@rollup/rollup-darwin-x64" "4.22.4" + "@rollup/rollup-linux-arm-gnueabihf" "4.22.4" + "@rollup/rollup-linux-arm-musleabihf" "4.22.4" + "@rollup/rollup-linux-arm64-gnu" "4.22.4" + "@rollup/rollup-linux-arm64-musl" "4.22.4" + "@rollup/rollup-linux-powerpc64le-gnu" "4.22.4" + "@rollup/rollup-linux-riscv64-gnu" "4.22.4" + "@rollup/rollup-linux-s390x-gnu" "4.22.4" + "@rollup/rollup-linux-x64-gnu" "4.22.4" + "@rollup/rollup-linux-x64-musl" "4.22.4" + "@rollup/rollup-win32-arm64-msvc" "4.22.4" + "@rollup/rollup-win32-ia32-msvc" "4.22.4" + "@rollup/rollup-win32-x64-msvc" "4.22.4" fsevents "~2.3.2" -rrweb-cssom@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz#ed298055b97cbddcdeb278f904857629dec5e0e1" - integrity sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw== - rrweb-cssom@^0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz#c73451a484b86dd7cfb1e0b2898df4b703183e4b" @@ -10492,16 +8838,6 @@ run-async@^2.4.0: resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== -run-async@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-3.0.0.tgz#42a432f6d76c689522058984384df28be379daad" - integrity sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q== - -run-node@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/run-node/-/run-node-1.0.0.tgz#46b50b946a2aa2d4947ae1d886e9856fd9cabe5e" - integrity sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A== - run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -10509,41 +8845,36 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rxjs@^6.5.2, rxjs@^6.6.0: +rxjs@^6.6.0: version "6.6.7" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== dependencies: tslib "^1.9.0" -rxjs@^7.5.1: +rxjs@^7.5.1, rxjs@^7.8.1: version "7.8.1" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== dependencies: tslib "^2.1.0" -safe-array-concat@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.0.tgz#8d0cae9cb806d6d1c06e08ab13d847293ebe0692" - integrity sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg== +safe-array-concat@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" + integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== dependencies: - call-bind "^1.0.5" - get-intrinsic "^1.2.2" + call-bind "^1.0.7" + get-intrinsic "^1.2.4" has-symbols "^1.0.3" isarray "^2.0.5" -safe-buffer@5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.2: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -safe-regex-test@^1.0.0: +safe-regex-test@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== @@ -10558,9 +8889,9 @@ safe-regex-test@^1.0.0: integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== sax@>=0.6.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.3.0.tgz#a5dbe77db3be05c9d1ee7785dbd3ea9de51593d0" - integrity sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA== + version "1.4.1" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f" + integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg== saxes@^6.0.0: version "6.0.0" @@ -10569,34 +8900,18 @@ saxes@^6.0.0: dependencies: xmlchars "^2.2.0" -scheduler@^0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.18.0.tgz#5901ad6659bc1d8f3fdaf36eb7a67b0d6746b1c4" - integrity sha512-agTSHR1Nbfi6ulI0kYNK0203joW2Y5W4po4l+v03tOoiJKpTBbxpNhWDvqc/4IcOw+KLmSiQLTasZ4cab2/UWQ== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - -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" - -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== +scheduler@^0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.18.0.tgz#5901ad6659bc1d8f3fdaf36eb7a67b0d6746b1c4" + integrity sha512-agTSHR1Nbfi6ulI0kYNK0203joW2Y5W4po4l+v03tOoiJKpTBbxpNhWDvqc/4IcOw+KLmSiQLTasZ4cab2/UWQ== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" -scheduler@^0.23.0: - version "0.23.0" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" - integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw== +scheduler@^0.23.2: + version "0.23.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" + integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== dependencies: loose-envify "^1.1.0" @@ -10605,20 +8920,15 @@ search-string@^3.1.0: resolved "https://registry.yarnpkg.com/search-string/-/search-string-3.1.0.tgz#3f111c6919a33de33a8e304fd5f8395c3d806ffb" integrity sha512-yY3b0VlaXfKi2B//34PN5AFF+GQvwme6Kj4FjggmoSBOa7B8AHfS1nYZbsrYu+IyGeYOAkF8ywL9LN9dkrOo6g== -semver-compare@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" - integrity sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow== - -"semver@2 || 3 || 4 || 5", semver@7.6.0, semver@^5.5.0, semver@^6.0.0, semver@^6.1.0, semver@^6.1.2, semver@^6.3.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.7, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.6.2: +semver@7.6.0, semver@^5.5.0, semver@^6.0.0, semver@^6.1.2, semver@^6.3.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.7, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.6.2: version "7.6.3" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== -send@0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" - integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== +send@0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" + integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== dependencies: debug "2.6.9" depd "2.0.0" @@ -10634,63 +8944,15 @@ send@0.18.0: range-parser "~1.2.1" statuses "2.0.1" -serve-handler@6.1.5: - version "6.1.5" - resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.5.tgz#a4a0964f5c55c7e37a02a633232b6f0d6f068375" - integrity sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg== - dependencies: - bytes "3.0.0" - content-disposition "0.5.2" - fast-url-parser "1.1.3" - mime-types "2.1.18" - minimatch "3.1.2" - path-is-inside "1.0.2" - path-to-regexp "2.2.1" - range-parser "1.2.0" - -serve-static@1.15.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" - integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== +serve-static@1.16.2: + version "1.16.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" + integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== dependencies: - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" parseurl "~1.3.3" - send "0.18.0" - -serve@^14.0.1: - version "14.2.1" - resolved "https://registry.yarnpkg.com/serve/-/serve-14.2.1.tgz#3f078d292ed5e7b2c5a64f957af2765b0459798b" - integrity sha512-48er5fzHh7GCShLnNyPBRPEjs2I6QBozeGr02gaacROiyS/8ARADlj595j39iZXAqBbJHH/ivJJyPRWY9sQWZA== - dependencies: - "@zeit/schemas" "2.29.0" - ajv "8.11.0" - arg "5.0.2" - boxen "7.0.0" - chalk "5.0.1" - chalk-template "0.4.0" - clipboardy "3.0.0" - compression "1.7.4" - is-port-reachable "4.0.0" - serve-handler "6.1.5" - update-check "1.5.4" - -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== - -set-function-length@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.1.tgz#47cc5945f2c771e2cf261c6737cf9684a2a5e425" - integrity sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g== - dependencies: - define-data-property "^1.1.2" - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.3" - gopd "^1.0.1" - has-property-descriptors "^1.0.1" + send "0.19.0" set-function-length@^1.2.1: version "1.2.2" @@ -10704,14 +8966,15 @@ set-function-length@^1.2.1: gopd "^1.0.1" has-property-descriptors "^1.0.2" -set-function-name@^2.0.0, set-function-name@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.1.tgz#12ce38b7954310b9f61faa12701620a0c882793a" - integrity sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA== +set-function-name@^2.0.1, set-function-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== dependencies: - define-data-property "^1.0.1" + define-data-property "^1.1.4" + es-errors "^1.3.0" functions-have-names "^1.2.3" - has-property-descriptors "^1.0.0" + has-property-descriptors "^1.0.2" setimmediate@^1.0.5: version "1.0.5" @@ -10754,17 +9017,12 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -side-channel@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.5.tgz#9a84546599b48909fb6af1211708d23b1946221b" - integrity sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ== - dependencies: - call-bind "^1.0.6" - es-errors "^1.3.0" - get-intrinsic "^1.2.4" - object-inspect "^1.13.1" +shell-quote@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" + integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== -side-channel@^1.0.6: +side-channel@^1.0.4, side-channel@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== @@ -10779,7 +9037,7 @@ siginfo@^2.0.0: resolved "https://registry.yarnpkg.com/siginfo/-/siginfo-2.0.0.tgz#32e76c70b79724e3bb567cb9d543eb858ccfaf30" integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g== -signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: +signal-exit@^3.0.2, signal-exit@^3.0.3: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -10790,13 +9048,13 @@ signal-exit@^4.0.1, signal-exit@^4.1.0: integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== simple-git@^3.19.0: - version "3.22.0" - resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-3.22.0.tgz#616d41c661e30f9c65778956317d422b1729a242" - integrity sha512-6JujwSs0ac82jkGjMHiCnTifvf1crOiY/+tfs/Pqih6iow7VrpNKRRNdWm6RtaXpvvv/JGNYhlUtLhGFqHF+Yw== + version "3.27.0" + resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-3.27.0.tgz#f4b09e807bda56a4a3968f635c0e4888d3decbd5" + integrity sha512-ivHoFS9Yi9GY49ogc6/YAi3Fl9ROnF4VyubNylgCkA+RVqLaKWnDSzXOVzya8csELIaWaYNutsEuAhZrtOjozA== dependencies: "@kwsites/file-exists" "^1.1.1" "@kwsites/promise-deferred" "^1.1.1" - debug "^4.3.4" + debug "^4.3.5" sirv@^2.0.4: version "2.0.4" @@ -10807,11 +9065,6 @@ sirv@^2.0.4: mrmime "^2.0.0" totalist "^3.0.0" -slash@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" - integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== - slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" @@ -10873,17 +9126,7 @@ source-map-generator@0.8.0: resolved "https://registry.yarnpkg.com/source-map-generator/-/source-map-generator-0.8.0.tgz#10d5ca0651e2c9302ea338739cbd4408849c5d00" integrity sha512-psgxdGMwl5MZM9S3FWee4EgsEaIjahYV5AzGnwUvPhWeITz/j6rKpysQHlQ4USdxvINlb8lKfWGIXwfkrgtqkA== -source-map-js@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" - integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== - -source-map-js@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" - integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== - -source-map-js@^1.2.1: +source-map-js@^1.2.0, source-map-js@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== @@ -10918,43 +9161,12 @@ space-separated-tokens@^2.0.0: resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz#1ecd9d2350a3844572c3f4a312bceb018348859f" integrity sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q== -spawn-command@^0.0.2-1: - version "0.0.2-1" - resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2-1.tgz#62f5e9466981c1b796dc5929937e11c9c6921bd0" - integrity sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg== - -spdx-correct@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" - integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.4.0.tgz#c07a4ede25b16e4f78e6707bbd84b15a45c19c1b" - integrity sha512-hcjppoJ68fhxA/cjbN4T8N6uCUejN8yFw69ttpqtBeCbF3u13n7mb31NB9jKwGTTWWnt9IbRA/mf1FprYS8wfw== - -spdx-expression-parse@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" - integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.17" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz#887da8aa73218e51a1d917502d79863161a93f9c" - integrity sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg== - sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== -sshpk@^1.14.1: +sshpk@^1.18.0: version "1.18.0" resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.18.0.tgz#1663e55cddf4d688b86a46b77f0d5fe363aba028" integrity sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ== @@ -10989,12 +9201,14 @@ std-env@^3.7.0: resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.7.0.tgz#c9f7386ced6ecf13360b6c6c55b8aaa4ef7481d2" integrity sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg== -store2@^2.14.2: - version "2.14.2" - resolved "https://registry.yarnpkg.com/store2/-/store2-2.14.2.tgz#56138d200f9fe5f582ad63bc2704dbc0e4a45068" - integrity sha512-siT1RiqlfQnGqgT/YzXVUNsom9S0H1OX+dpdGN1xkyYATo4I6sep5NmsRD/40s3IIOvlCq6akxkqG82urIZW1w== +stop-iteration-iterator@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz#6a60be0b4ee757d1ed5254858ec66b10c49285e4" + integrity sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ== + dependencies: + internal-slot "^1.0.4" -storybook-dark-mode@^4.0.1: +storybook-dark-mode@4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/storybook-dark-mode/-/storybook-dark-mode-4.0.1.tgz#899cedb527f43aec1a1a782b767ba2ac32a113da" integrity sha512-9l3qY8NdgwZnY+NlO1XHB3eUb6FmZo9GazJeUSeFkjRqwA5FmnMSeq0YVqEOqfwniM/TvQwOiTYd5g/hC2wugA== @@ -11009,18 +9223,11 @@ storybook-dark-mode@^4.0.1: memoizerific "^1.11.3" storybook@^8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/storybook/-/storybook-8.3.0.tgz#172a5d5e415b83bcb08a3a670a2e6f34383dfea1" - integrity sha512-XKU+nem9OKX/juvJPwka1Q7DTpSbOe0IMp8ZyLQWorhFKpquJdUjryl7Z9GiFZyyTykCqH4ItQ7h8PaOmqVMOw== + version "8.3.3" + resolved "https://registry.yarnpkg.com/storybook/-/storybook-8.3.3.tgz#3de9be589815403539660653d2ec810348e7dafb" + integrity sha512-FG2KAVQN54T9R6voudiEftehtkXtLO+YVGP2gBPfacEdDQjY++ld7kTbHzpTT/bpCDx7Yq3dqOegLm9arVJfYw== dependencies: - "@storybook/core" "8.3.0" - -stream@^0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/stream/-/stream-0.0.3.tgz#3f3934a900a561ce3e2b9ffbd2819cead32699d9" - integrity sha512-aMsbn7VKrl4A2T7QAQQbzgN7NVc70vgF5INQrBXqn4dCXN1zy3L9HGgLO5s7PExmdrzTJ8uR/27aviW8or8/+A== - dependencies: - component-emitter "^2.0.0" + "@storybook/core" "8.3.3" strict-event-emitter@^0.5.1: version "0.5.1" @@ -11032,22 +9239,14 @@ string-argv@~0.3.2: resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw== - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -string-width@^2.0.0, string-width@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" string-width@^3.0.0: version "3.1.0" @@ -11058,15 +9257,6 @@ string-width@^3.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" @@ -11085,68 +9275,74 @@ string-width@^7.0.0: get-east-asian-width "^1.0.0" strip-ansi "^7.1.0" -string.prototype.matchall@^4.0.8: - version "4.0.10" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz#a1553eb532221d4180c51581d6072cd65d1ee100" - integrity sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ== +string.prototype.includes@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string.prototype.includes/-/string.prototype.includes-2.0.0.tgz#8986d57aee66d5460c144620a6d873778ad7289f" + integrity sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" - has-symbols "^1.0.3" - internal-slot "^1.0.5" - regexp.prototype.flags "^1.5.0" - set-function-name "^2.0.0" - side-channel "^1.0.4" + define-properties "^1.1.3" + es-abstract "^1.17.5" -string.prototype.trim@^1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz#f9ac6f8af4bd55ddfa8895e6aea92a96395393bd" - integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== +string.prototype.matchall@^4.0.11: + version "4.0.11" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz#1092a72c59268d2abaad76582dccc687c0297e0a" + integrity sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-symbols "^1.0.3" + internal-slot "^1.0.7" + regexp.prototype.flags "^1.5.2" + set-function-name "^2.0.2" + side-channel "^1.0.6" -string.prototype.trimend@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz#1bb3afc5008661d73e2dc015cd4853732d6c471e" - integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA== +string.prototype.repeat@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz#e90872ee0308b29435aa26275f6e1b762daee01a" + integrity sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + define-properties "^1.1.3" + es-abstract "^1.17.5" -string.prototype.trimstart@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz#d4cdb44b83a4737ffbac2d406e405d43d0184298" - integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== +string.prototype.trim@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" + integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.0" + es-object-atoms "^1.0.0" -string_decoder@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== +string.prototype.trimend@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" + integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== dependencies: - safe-buffer "~5.2.0" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg== +string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== dependencies: - ansi-regex "^2.0.0" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow== +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: - ansi-regex "^3.0.0" + ansi-regex "^5.0.1" strip-ansi@^5.1.0, strip-ansi@^5.2.0: version "5.2.0" @@ -11155,13 +9351,6 @@ strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.0.1, strip-ansi@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -11174,11 +9363,6 @@ strip-bom@^3.0.0: resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q== - strip-final-newline@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" @@ -11208,29 +9392,6 @@ strip-json-comments@^3.0.1, strip-json-comments@^3.1.0, strip-json-comments@^3.1 resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== - -style-dictionary@4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/style-dictionary/-/style-dictionary-4.0.1.tgz#d8347d18874e7dff3f4a6faed0ddcb30c797cff0" - integrity sha512-aZ2iouI0i0DIXk3QhCkwOeo5rQeuk5Ja0PhHo32/EXCNuay4jK4CZ+hQJW0Er0J74VWniR+qaeoWgjklcULxOQ== - dependencies: - "@bundled-es-modules/deepmerge" "^4.3.1" - "@bundled-es-modules/glob" "^10.4.2" - "@bundled-es-modules/memfs" "^4.9.4" - "@zip.js/zip.js" "^2.7.44" - chalk "^5.3.0" - change-case "^5.3.0" - commander "^8.3.0" - is-plain-obj "^4.1.0" - json5 "^2.2.2" - patch-package "^8.0.0" - path-unified "^0.1.0" - tinycolor2 "^1.6.0" - stylis@4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51" @@ -11249,13 +9410,6 @@ sucrase@^3.35.0: pirates "^4.0.1" ts-interface-checker "^0.1.9" -supports-color@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b" - integrity sha512-ycQR/UbvI9xIlEdQT1TQqwoXtEldExbCEAJgRo5YXlmSKjv6ThHnP9/vwGa1gr19Gfw+LkFd7KqYMhzrRC5JYw== - dependencies: - has-flag "^2.0.0" - supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -11365,11 +9519,6 @@ thenify-all@^1.0.0: dependencies: any-promise "^1.0.0" -thingies@^1.20.0: - version "1.21.0" - resolved "https://registry.yarnpkg.com/thingies/-/thingies-1.21.0.tgz#e80fbe58fd6fdaaab8fad9b67bd0a5c943c445c1" - integrity sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g== - throttle-debounce@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-2.3.0.tgz#fd31865e66502071e411817e241465b3e9c372e2" @@ -11380,17 +9529,12 @@ throttleit@^1.0.0: resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.1.tgz#304ec51631c3b770c65c6c6f76938b384000f4d5" integrity sha512-vDZpf9Chs9mAdfY046mcPt8fg5QSZr37hEH4TXYBnDF+izxgrbRGUAAaBvIk/fJm9aOFCGFd1EsNg5AZCbnQCQ== -through@^2.3.6, through@^2.3.8: +through@^2.3.6, through@^2.3.8, through@~2.3.4: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== -tiny-invariant@^1.0.2, tiny-invariant@^1.0.6, tiny-invariant@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642" - integrity sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw== - -tiny-invariant@^1.3.3: +tiny-invariant@^1.0.2, tiny-invariant@^1.0.6, tiny-invariant@^1.3.1, tiny-invariant@^1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127" integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg== @@ -11405,17 +9549,12 @@ tinybench@^2.9.0: resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.9.0.tgz#103c9f8ba6d7237a47ab6dd1dcff77251863426b" integrity sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg== -tinycolor2@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.6.0.tgz#f98007460169b0263b97072c5ae92484ce02d09e" - integrity sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw== - tinyexec@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-0.3.0.tgz#ed60cfce19c17799d4a241e06b31b0ec2bee69e6" integrity sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg== -tinyglobby@^0.2.6: +tinyglobby@^0.2.1, tinyglobby@^0.2.6: version "0.2.6" resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.6.tgz#950baf1462d0c0b443bc3d754d0d39c2e589aaae" integrity sha512-NbBoFBpqfcgd1tCiO8Lkfdk+xrA7mlLR9zgvZcZWQQwU63XAfUePyd6wZBaU93Hqw347lHnwFzttAkemHzzz4g== @@ -11434,9 +9573,9 @@ tinyrainbow@^1.2.0: integrity sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ== tinyspy@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-3.0.0.tgz#cb61644f2713cd84dee184863f4642e06ddf0585" - integrity sha512-q5nmENpTHgiPVd1cJDDc9cVoYN5x4vCvwT3FMilvKPKneCBZAxn2YWQjDF0UMcE9k0Cay1gBiDfTMU0g+mPMQA== + version "3.0.2" + resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-3.0.2.tgz#86dd3cf3d737b15adcf17d7887c84a75201df20a" + integrity sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q== tmp@^0.0.33: version "0.0.33" @@ -11446,11 +9585,9 @@ tmp@^0.0.33: os-tmpdir "~1.0.2" tmp@~0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" - integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== - dependencies: - rimraf "^3.0.0" + version "0.2.3" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae" + integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w== to-fast-properties@^2.0.0: version "2.0.0" @@ -11485,9 +9622,9 @@ totalist@^3.0.0: integrity sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ== tough-cookie@^4.1.3, tough-cookie@^4.1.4: - version "4.1.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" - integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== + version "4.1.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36" + integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag== dependencies: psl "^1.1.33" punycode "^2.1.1" @@ -11513,12 +9650,7 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== -tree-dump@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/tree-dump/-/tree-dump-1.0.2.tgz#c460d5921caeb197bde71d0e9a7b479848c5b8ac" - integrity sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ== - -tree-kill@^1.2.1, tree-kill@^1.2.2: +tree-kill@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== @@ -11533,7 +9665,7 @@ ts-api-utils@^1.0.1: resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== -ts-dedent@^2.0.0, ts-dedent@^2.2.0: +ts-dedent@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5" integrity sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ== @@ -11543,25 +9675,6 @@ ts-interface-checker@^0.1.9: resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== -ts-node@^10.9.2: - version "10.9.2" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" - integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== - dependencies: - "@cspotcode/source-map-support" "^0.8.0" - "@tsconfig/node10" "^1.0.7" - "@tsconfig/node12" "^1.0.7" - "@tsconfig/node14" "^1.0.0" - "@tsconfig/node16" "^1.0.2" - acorn "^8.4.1" - acorn-walk "^8.1.1" - arg "^4.1.0" - create-require "^1.1.0" - diff "^4.0.1" - make-error "^1.1.1" - v8-compile-cache-lib "^3.0.1" - yn "3.1.1" - tsconfig-paths@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz#ef78e19039133446d244beac0fd6a1632e2d107c" @@ -11577,23 +9690,23 @@ tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0: integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0: - version "2.6.2" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" - integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + version "2.7.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" + integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== tss-react@^4.8.2: - version "4.9.4" - resolved "https://registry.yarnpkg.com/tss-react/-/tss-react-4.9.4.tgz#037603ed2f8765c2f208ac1c75e9293753aa18cd" - integrity sha512-4o+XFdaTcraNEIsCRxKiEX7g6xhcsdSxfHRjos3Kg9GbYIpzfK4M2MHMETTuXT54nUrldtnkipNC003v/q5KVg== + version "4.9.13" + resolved "https://registry.yarnpkg.com/tss-react/-/tss-react-4.9.13.tgz#e6ac0bfea3977e58b5ef5a261cd0b035e6bd8254" + integrity sha512-Gu19qqPH8/SAyKVIgDE5qHygirEDnNIQcXhiEc+l4Q9T7C1sfvUnbVWs+yBpmN26/wyk4FTOupjYS2wq4vH0yA== dependencies: "@emotion/cache" "*" "@emotion/serialize" "*" "@emotion/utils" "*" tsup@^8.2.4: - version "8.2.4" - resolved "https://registry.yarnpkg.com/tsup/-/tsup-8.2.4.tgz#5e31790c1e66392cee384ad746ed51c106614beb" - integrity sha512-akpCPePnBnC/CXgRrcy72ZSntgIEUa1jN0oJbbvpALWKNOz1B7aM+UVDWGRGIO/T/PZugAESWDJUAb5FD48o8Q== + version "8.3.0" + resolved "https://registry.yarnpkg.com/tsup/-/tsup-8.3.0.tgz#c7dae40b13d11d81fb144c0f90077a99102a572a" + integrity sha512-ALscEeyS03IomcuNdFdc0YWGVIkwH1Ws7nfTbAPuoILvEV2hpGQAY72LIOjglGo4ShWpZfpBqP/jpQVCzqYQag== dependencies: bundle-require "^5.0.0" cac "^6.7.14" @@ -11602,7 +9715,6 @@ tsup@^8.2.4: debug "^4.3.5" esbuild "^0.23.0" execa "^5.1.1" - globby "^11.1.0" joycon "^3.1.1" picocolors "^1.0.1" postcss-load-config "^6.0.1" @@ -11610,6 +9722,7 @@ tsup@^8.2.4: rollup "^4.19.0" source-map "0.8.0-beta.0" sucrase "^3.35.0" + tinyglobby "^0.2.1" tree-kill "^1.2.2" tsutils@^3.17.1, tsutils@^3.21.0: @@ -11619,6 +9732,16 @@ tsutils@^3.17.1, tsutils@^3.21.0: dependencies: tslib "^1.8.1" +tsx@^4.19.1: + version "4.19.1" + resolved "https://registry.yarnpkg.com/tsx/-/tsx-4.19.1.tgz#b7bffdf4b565813e4dea14b90872af279cd0090b" + integrity sha512-0flMz1lh74BR4wOvBjuh9olbnwqCPc35OOlfyzHba0Dc+QNUeWX/Gq2YTbnwcWPO3BMd8fkzRVrHcsR+a7z7rA== + dependencies: + esbuild "~0.23.0" + get-tsconfig "^4.7.5" + optionalDependencies: + fsevents "~2.3.3" + tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" @@ -11655,25 +9778,20 @@ type-fest@^0.21.3: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== -type-fest@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" - integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== - type-fest@^0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== -type-fest@^2.13.0, type-fest@^2.19.0, type-fest@~2.19: +type-fest@^2.19.0, type-fest@~2.19: version "2.19.0" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== type-fest@^4.9.0: - version "4.12.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.12.0.tgz#00ae70d02161b81ecd095158143c4bb8c879760d" - integrity sha512-5Y2/pp2wtJk8o08G0CMkuFPCO354FGwk/vbidxrdhRGZfd0tFnb4Qb8anp9XxXriwBgVPjdWbKpGl4J9lJY2jQ== + version "4.26.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.26.1.tgz#a4a17fa314f976dd3e6d6675ef6c775c16d7955e" + integrity sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg== type-is@~1.6.18: version "1.6.18" @@ -11683,44 +9801,49 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typed-array-buffer@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.1.tgz#0608ffe6bca71bf15a45bff0ca2604107a1325f5" - integrity sha512-RSqu1UEuSlrBhHTWC8O9FnPjOduNs4M7rJ4pRKoEjtx1zUNOPN2sSXHLDX+Y2WPbHIxbvg4JFo2DNAEfPIKWoQ== +typed-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" + integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== dependencies: - call-bind "^1.0.6" + call-bind "^1.0.7" es-errors "^1.3.0" is-typed-array "^1.1.13" -typed-array-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz#d787a24a995711611fb2b87a4052799517b230d0" - integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== +typed-array-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" + integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== dependencies: - call-bind "^1.0.2" + call-bind "^1.0.7" for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" -typed-array-byte-offset@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz#cbbe89b51fdef9cd6aaf07ad4707340abbc4ea0b" - integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== +typed-array-byte-offset@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" + integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" -typed-array-length@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" - integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== +typed-array-length@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" + integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== dependencies: - call-bind "^1.0.2" + call-bind "^1.0.7" for-each "^0.3.3" - is-typed-array "^1.1.9" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + possible-typed-array-names "^1.0.0" typescript-fsa-reducers@^1.2.0: version "1.2.2" @@ -11732,12 +9855,17 @@ typescript-fsa@^3.0.0: resolved "https://registry.yarnpkg.com/typescript-fsa/-/typescript-fsa-3.0.0.tgz#3ad1cb915a67338e013fc21f67c9b3e0e110c912" integrity sha512-xiXAib35i0QHl/+wMobzPibjAH5TJLDj+qGq5jwVLG9qR4FUswZURBw2qihBm0m06tHoyb3FzpnJs1GRhRwVag== +typescript@^4.6.4: + version "4.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== + typescript@^5.5.4: - version "5.5.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba" - integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== + version "5.6.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.2.tgz#d1de67b6bef77c41823f822df8f0b3bcff60a5a0" + integrity sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw== -ua-parser-js@^0.7.30, ua-parser-js@^0.7.33: +ua-parser-js@^0.7.30: version "0.7.39" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.39.tgz#c71efb46ebeabc461c4612d22d54f88880fabe7e" integrity sha512-IZ6acm6RhQHNibSt7+c09hhvsKy9WUr4DVbeq9U8o71qxyYtJpQeDxQnMrVqnIFMLcQjHO0I9wgfO2vIahht4w== @@ -11757,20 +9885,15 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" -undici-types@~5.26.4: - version "5.26.5" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" - integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== - undici-types@~6.19.2: version "6.19.8" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== unified@^11.0.0: - version "11.0.4" - resolved "https://registry.yarnpkg.com/unified/-/unified-11.0.4.tgz#f4be0ac0fe4c88cb873687c07c64c49ed5969015" - integrity sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ== + version "11.0.5" + resolved "https://registry.yarnpkg.com/unified/-/unified-11.0.5.tgz#f66677610a5c0a9ee90cab2b8d4d66037026d9e1" + integrity sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA== dependencies: "@types/unist" "^3.0.0" bail "^2.0.0" @@ -11827,37 +9950,27 @@ unpipe@1.0.0, unpipe@~1.0.0: integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== unplugin@^1.3.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-1.7.1.tgz#009571e3128640f4e327f33680d2db27afaf1e11" - integrity sha512-JqzORDAPxxs8ErLV4x+LL7bk5pk3YlcWqpSNsIkAZj972KzFZLClc/ekppahKkOczGkwIG6ElFgdOgOlK4tXZw== + version "1.14.1" + resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-1.14.1.tgz#c76d6155a661e43e6a897bce6b767a1ecc344c1a" + integrity sha512-lBlHbfSFPToDYp9pjXlUEFVxYLaue9f9T1HC+4OHlmj+HnMDdz9oZY+erXfoCe/5V/7gKUSY2jpXPb9S7f0f/w== dependencies: - acorn "^8.11.3" - chokidar "^3.5.3" - webpack-sources "^3.2.3" - webpack-virtual-modules "^0.6.1" + acorn "^8.12.1" + webpack-virtual-modules "^0.6.2" untildify@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== -update-browserslist-db@^1.0.13: - version "1.0.13" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" - integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== - dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" - -update-check@1.5.4: - version "1.5.4" - resolved "https://registry.yarnpkg.com/update-check/-/update-check-1.5.4.tgz#5b508e259558f1ad7dbc8b4b0457d4c9d28c8743" - integrity sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ== +update-browserslist-db@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" + integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== dependencies: - registry-auth-token "3.3.2" - registry-url "3.1.0" + escalade "^3.1.2" + picocolors "^1.0.1" -uri-js@^4.2.2, uri-js@^4.4.1: +uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== @@ -11872,14 +9985,6 @@ url-parse@^1.5.3: querystringify "^2.1.1" requires-port "^1.0.0" -url@^0.11.3: - version "0.11.3" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.3.tgz#6f495f4b935de40ce4a0a52faee8954244f3d3ad" - integrity sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw== - dependencies: - punycode "^1.4.1" - qs "^6.11.2" - use-memo-one@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/use-memo-one/-/use-memo-one-1.1.3.tgz#2fd2e43a2169eabc7496960ace8c79efef975e99" @@ -11890,13 +9995,6 @@ util-deprecate@^1.0.2: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== -util@^0.10.3: - version "0.10.4" - resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" - integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A== - dependencies: - inherits "2.0.3" - util@^0.12.5: version "0.12.5" resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc" @@ -11930,24 +10028,11 @@ uuid@^9.0.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== -v8-compile-cache-lib@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" - integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== - v8-compile-cache@^2.0.3: version "2.4.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz#cdada8bec61e15865f05d097c5f4fd30e94dc128" integrity sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw== -validate-npm-package-license@^3.0.1: - version "3.0.4" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - value-equal@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" @@ -11976,18 +10061,17 @@ vfile-message@^4.0.0: unist-util-stringify-position "^4.0.0" vfile@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/vfile/-/vfile-6.0.1.tgz#1e8327f41eac91947d4fe9d237a2dd9209762536" - integrity sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw== + version "6.0.3" + resolved "https://registry.yarnpkg.com/vfile/-/vfile-6.0.3.tgz#3652ab1c496531852bf55a6bac57af981ebc38ab" + integrity sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q== dependencies: "@types/unist" "^3.0.0" - unist-util-stringify-position "^4.0.0" vfile-message "^4.0.0" victory-vendor@^36.6.8: - version "36.9.1" - resolved "https://registry.yarnpkg.com/victory-vendor/-/victory-vendor-36.9.1.tgz#a7536766ca9725711c7dc1a36dd1d1d248cfa22d" - integrity sha512-+pZIP+U3pEJdDCeFmsXwHzV7vNHQC/eIbHklfe2ZCZqayYRH7lQbHcVgsJ0XOOv27hWs4jH4MONgXxHMObTMSA== + version "36.9.2" + resolved "https://registry.yarnpkg.com/victory-vendor/-/victory-vendor-36.9.2.tgz#668b02a448fa4ea0f788dbf4228b7e64669ff801" + integrity sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ== dependencies: "@types/d3-array" "^3.0.3" "@types/d3-ease" "^3.0.0" @@ -12023,21 +10107,10 @@ vite-plugin-svgr@^3.2.0: "@svgr/core" "^8.1.0" "@svgr/plugin-jsx" "^8.1.0" -vite@^5.0.0: - version "5.1.7" - resolved "https://registry.yarnpkg.com/vite/-/vite-5.1.7.tgz#9f685a2c4c70707fef6d37341b0e809c366da619" - integrity sha512-sgnEEFTZYMui/sTlH1/XEnVNHMujOahPLGMxn1+5sIT45Xjng1Ec1K78jRP15dSmVgg5WBin9yO81j3o9OxofA== - dependencies: - esbuild "^0.19.3" - postcss "^8.4.35" - rollup "^4.2.0" - optionalDependencies: - fsevents "~2.3.3" - -vite@^5.4.6: - version "5.4.6" - resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.6.tgz#85a93a1228a7fb5a723ca1743e337a2588ed008f" - integrity sha512-IeL5f8OO5nylsgzd9tq4qD2QqI0k2CQLGrWD0rCN0EQJZpBK5vJAx0I+GDkMOXxQX/OfFHMuLIx6ddAxGX/k+Q== +vite@^5.0.0, vite@^5.4.6: + version "5.4.8" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.8.tgz#af548ce1c211b2785478d3ba3e8da51e39a287e8" + integrity sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ== dependencies: esbuild "^0.21.3" postcss "^8.4.43" @@ -12099,15 +10172,10 @@ webidl-conversions@^7.0.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== -webpack-sources@^3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" - integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== - -webpack-virtual-modules@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.1.tgz#ac6fdb9c5adb8caecd82ec241c9631b7a3681b6f" - integrity sha512-poXpCylU7ExuvZK8z+On3kX+S8o/2dQ/SVYueKA0D4WEMXROXgY8Ez50/bQEUmvoSMMrWcrJqCHuhAbsiwg7Dg== +webpack-virtual-modules@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz#057faa9065c8acf48f24cb57ac0e77739ab9a7e8" + integrity sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ== whatwg-encoding@^3.1.1: version "3.1.1" @@ -12163,12 +10231,12 @@ which-boxed-primitive@^1.0.2: is-symbol "^1.0.3" which-builtin-type@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.1.3.tgz#b1b8443707cc58b6e9bf98d32110ff0c2cbd029b" - integrity sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw== + version "1.1.4" + resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.1.4.tgz#592796260602fc3514a1b5ee7fa29319b72380c3" + integrity sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w== dependencies: - function.prototype.name "^1.1.5" - has-tostringtag "^1.0.0" + function.prototype.name "^1.1.6" + has-tostringtag "^1.0.2" is-async-function "^2.0.0" is-date-object "^1.0.5" is-finalizationregistry "^1.0.2" @@ -12177,34 +10245,29 @@ which-builtin-type@^1.1.3: is-weakref "^1.0.2" isarray "^2.0.5" which-boxed-primitive "^1.0.2" - which-collection "^1.0.1" - which-typed-array "^1.1.9" + which-collection "^1.0.2" + which-typed-array "^1.1.15" -which-collection@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" - integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== +which-collection@^1.0.1, which-collection@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0" + integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw== dependencies: - is-map "^2.0.1" - is-set "^2.0.1" - is-weakmap "^2.0.1" - is-weakset "^2.0.1" - -which-module@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" - integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== + is-map "^2.0.3" + is-set "^2.0.3" + is-weakmap "^2.0.2" + is-weakset "^2.0.3" -which-typed-array@^1.1.13, which-typed-array@^1.1.14, which-typed-array@^1.1.2, which-typed-array@^1.1.9: - version "1.1.14" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.14.tgz#1f78a111aee1e131ca66164d8bdc3ab062c95a06" - integrity sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg== +which-typed-array@^1.1.13, which-typed-array@^1.1.14, which-typed-array@^1.1.15, which-typed-array@^1.1.2: + version "1.1.15" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" + integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== dependencies: - available-typed-arrays "^1.0.6" - call-bind "^1.0.5" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" for-each "^0.3.3" gopd "^1.0.1" - has-tostringtag "^1.0.1" + has-tostringtag "^1.0.2" which@^1.2.9: version "1.3.1" @@ -12228,25 +10291,19 @@ why-is-node-running@^2.3.0: siginfo "^2.0.0" stackback "0.0.2" -widest-line@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-4.0.1.tgz#a0fc673aaba1ea6f0a0d35b3c2795c9a9cc2ebf2" - integrity sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig== - dependencies: - string-width "^5.0.1" - -word-wrap@^1.2.4, word-wrap@^1.2.5, word-wrap@~1.2.3: +word-wrap@^1.2.5, word-wrap@~1.2.3: version "1.2.5" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== -wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - integrity sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw== +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" wrap-ansi@^6.2.0: version "6.2.0" @@ -12257,16 +10314,7 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^8.0.1: +wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== @@ -12296,16 +10344,11 @@ write@1.0.3: dependencies: mkdirp "^0.5.1" -ws@^8.18.0: +ws@^8.18.0, ws@^8.2.3: version "8.18.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== -ws@^8.2.3: - version "8.16.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.16.0.tgz#d1cd774f36fbc07165066a60e40323eab6446fd4" - integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ== - xml-name-validator@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-5.0.0.tgz#82be9b957f7afdacf961e5980f1bf227c0bf7673" @@ -12334,11 +10377,6 @@ xmlchars@^2.2.0: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== -"y18n@^3.2.1 || ^4.0.0": - version "4.0.3" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" - integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== - y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" @@ -12349,12 +10387,12 @@ yallist@^3.0.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== -yaml@^1.10.0, yaml@^1.7.2, yaml@^2.2.2, yaml@^2.3.0, yaml@~2.5.0: +yaml@^1.10.0, yaml@^1.7.2, yaml@^2.3.0, yaml@~2.5.0: version "2.5.1" resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.5.1.tgz#c9772aacf62cb7494a95b0c4f1fb065b563db130" integrity sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q== -yargs-parser@^11.1.1, yargs-parser@^21.1.1: +yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== @@ -12372,24 +10410,6 @@ yargs@17.7.2, yargs@^17.7.2: y18n "^5.0.5" yargs-parser "^21.1.1" -yargs@^12.0.5: - version "12.0.5" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" - integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== - dependencies: - cliui "^4.0.0" - decamelize "^1.2.0" - find-up "^3.0.0" - get-caller-file "^1.0.1" - os-locale "^3.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1 || ^4.0.0" - yargs-parser "^11.1.1" - yauzl@^2.10.0: version "2.10.0" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" @@ -12398,16 +10418,16 @@ yauzl@^2.10.0: buffer-crc32 "~0.2.3" fd-slicer "~1.1.0" -yn@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" - integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== - yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== +yoctocolors-cjs@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz#f4b905a840a37506813a7acaa28febe97767a242" + integrity sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA== + yup@^0.32.9: version "0.32.11" resolved "https://registry.yarnpkg.com/yup/-/yup-0.32.11.tgz#d67fb83eefa4698607982e63f7ca4c5ed3cf18c5" From bce5d791dca4cba8ab81ff89a219cb9a2369a304 Mon Sep 17 00:00:00 2001 From: agorthi Date: Tue, 1 Oct 2024 13:45:53 +0530 Subject: [PATCH 115/474] Syncing file processesLanding.tsx with develop --- .../LongviewDetail/DetailTabs/Processes/ProcessesLanding.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/Longview/LongviewDetail/DetailTabs/Processes/ProcessesLanding.tsx b/packages/manager/src/features/Longview/LongviewDetail/DetailTabs/Processes/ProcessesLanding.tsx index 91c29ac8a10..3157c738200 100644 --- a/packages/manager/src/features/Longview/LongviewDetail/DetailTabs/Processes/ProcessesLanding.tsx +++ b/packages/manager/src/features/Longview/LongviewDetail/DetailTabs/Processes/ProcessesLanding.tsx @@ -128,7 +128,7 @@ export const ProcessesLanding = React.memo((props: Props) => { defaultValue={'Past 30 Minutes'} handleStatsChange={handleStatsChange} hideLabel - label="Select a Time Range" + label="Select Time Range" /> Date: Tue, 1 Oct 2024 15:51:03 +0530 Subject: [PATCH 116/474] upcoming:[DI-20585]- Added code review comments --- .../linode-widget-verification.spec.ts | 76 ++++++------------- .../cypress/support/constants/widgets.ts | 6 ++ .../cypress/support/intercepts/cloudpulse.ts | 2 +- .../cypress/support/util/cloudpulse.ts | 54 +++++++++++++ packages/manager/src/factories/dashboards.ts | 44 ----------- 5 files changed, 86 insertions(+), 96 deletions(-) create mode 100644 packages/manager/cypress/support/util/cloudpulse.ts diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 50804d1d094..4a721669ad6 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -3,7 +3,7 @@ */ import { mockAppendFeatureFlags } from 'support/intercepts/feature-flags'; import { - mockCloudPulseJWSToken, + mockCloudPulseJWEToken, mockCloudPulseDashboardServicesResponse, mockCloudPulseCreateMetrics, mockCloudPulseGetDashboards, @@ -17,7 +17,6 @@ import { cloudPulseMetricsResponseFactory, dashboardFactory, dashboardMetricFactory, - generateRandomMetricsData, kubeLinodeFactory, linodeFactory, regionFactory, @@ -32,6 +31,7 @@ import { CloudPulseMetricsResponse } from '@linode/api-v4'; import { transformData } from 'src/features/CloudPulse/Utils/unitConversion'; import { getMetrics } from 'src/utilities/statMetrics'; import { Interception } from 'cypress/types/net-stubbing'; +import { generateRandomMetricsData } from 'support/util/cloudpulse'; /** * This test ensures that widget titles are displayed correctly on the dashboard. @@ -95,18 +95,7 @@ const mockRegion = extendRegion( const metricsAPIResponsePayload = cloudPulseMetricsResponseFactory.build({ data: generateRandomMetricsData(timeDurationToSelect, '5 min'), }); -/** - * `verifyWidgetValues` processes and verifies the metric values of a widget from the provided response payload. - * - * This method performs the following steps: - * 1. Transforms the raw data from the response payload into a more manageable format using `transformData`. - * 2. Extracts key metrics (average, last, and max) from the transformed data using `getMetrics`. - * 3. Rounds these metrics to two decimal places for accuracy. - * 4. Returns an object containing the rounded average, last, and max values for further verification or comparison. - * - * @param {CloudPulseMetricsResponse} responsePayload - The response payload containing metric data for a widget. - * @returns {Object} An object with the rounded average, last, and max metric values. - */ + const getWidgetLegendRowValuesFromResponse = ( responsePayload: CloudPulseMetricsResponse ) => { @@ -129,7 +118,7 @@ describe('Integration Tests for Linode Dashboard ', () => { mockCloudPulseGetDashboards([dashboard], serviceType); mockCloudPulseServices(serviceType); mockCloudPulseDashboardServicesResponse(dashboard, id); - mockCloudPulseJWSToken(serviceType); + mockCloudPulseJWEToken(serviceType); mockCloudPulseCreateMetrics(metricsAPIResponsePayload, serviceType).as( 'getMetrics' ); @@ -166,6 +155,7 @@ describe('Integration Tests for Linode Dashboard ', () => { cy.findByText(resource).should('be.visible'); + // Iterate over each metric to find the corresponding widget and verify the title and unit are displayed and visible for (const { title, unit } of metrics) { const widgetSelector = `[data-qa-widget="${title}"]`; cy.get(widgetSelector) @@ -176,12 +166,15 @@ describe('Integration Tests for Linode Dashboard ', () => { }); it('should allow users to select desired granularity and see the most recent data from the API reflected in the graph', () => { + // validate the widget level granularity selection and its metrics + for (const testData of metrics) { const { title: testDataTitle, expectedGranularity } = testData; const widgetSelector = `[data-qa-widget="${testDataTitle}"]`; cy.get(widgetSelector).within(() => { + // check for all available granularity in popper ui.autocomplete .findByLabel('Select an Interval') @@ -217,15 +210,19 @@ describe('Integration Tests for Linode Dashboard ', () => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( metricsAPIResponsePayload ); + cy.findByText(`${testData.title} (${testData.unit})`).should( 'be.visible' ); + cy.findByText(`${expectedWidgetValues.max} ${testData.unit}`).should( 'be.visible' ); + cy.findByText( `${expectedWidgetValues.average} ${testData.unit}` ).should('be.visible'); + cy.findByText(`${expectedWidgetValues.last} ${testData.unit}`).should( 'be.visible' ); @@ -280,18 +277,10 @@ describe('Integration Tests for Linode Dashboard ', () => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( metricsAPIResponsePayload ); - cy.findByText(`${testData.title} (${testData.unit})`).should( - 'be.visible' - ); - cy.findByText(`${expectedWidgetValues.max} ${testData.unit}`).should( - 'be.visible' - ); - cy.findByText( - `${expectedWidgetValues.average} ${testData.unit}` - ).should('be.visible'); - cy.findByText(`${expectedWidgetValues.last} ${testData.unit}`).should( - 'be.visible' - ); + cy.findByText(`${testData.title} (${testData.unit})`).should( 'be.visible'); + cy.findByText( `${expectedWidgetValues.max} ${testData.unit}`).should('be.visible'); + cy.findByText(`${expectedWidgetValues.average} ${testData.unit}` ).should('be.visible'); + cy.findByText( `${expectedWidgetValues.last} ${testData.unit}`).should('be.visible'); }); }); } @@ -347,18 +336,10 @@ describe('Integration Tests for Linode Dashboard ', () => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( metricsAPIResponsePayload ); - cy.findByText(`${testData.title} (${testData.unit})`).should( - 'be.visible' - ); - cy.findByText( - `${expectedWidgetValues.max} ${testData.unit}` - ).should('be.visible'); - cy.findByText( - `${expectedWidgetValues.average} ${testData.unit}` - ).should('be.visible'); - cy.findByText( - `${expectedWidgetValues.last} ${testData.unit}` - ).should('be.visible'); + cy.findByText(`${testData.title} (${testData.unit})`).should( 'be.visible'); + cy.findByText( `${expectedWidgetValues.max} ${testData.unit}`).should('be.visible'); + cy.findByText(`${expectedWidgetValues.average} ${testData.unit}` ).should('be.visible'); + cy.findByText( `${expectedWidgetValues.last} ${testData.unit}`).should('be.visible'); }); // click zoom out and validate the same @@ -374,18 +355,11 @@ describe('Integration Tests for Linode Dashboard ', () => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( metricsAPIResponsePayload ); - cy.findByText(`${testData.title} (${testData.unit})`).should( - 'be.visible' - ); - cy.findByText( - `${expectedWidgetValues.max} ${testData.unit}` - ).should('be.visible'); - cy.findByText( - `${expectedWidgetValues.average} ${testData.unit}` - ).should('be.visible'); - cy.findByText( - `${expectedWidgetValues.last} ${testData.unit}` - ).should('be.visible'); + cy.findByText(`${testData.title} (${testData.unit})`).should( 'be.visible'); + cy.findByText( `${expectedWidgetValues.max} ${testData.unit}`).should('be.visible'); + cy.findByText(`${expectedWidgetValues.average} ${testData.unit}` ).should('be.visible'); + cy.findByText( `${expectedWidgetValues.last} ${testData.unit}`).should('be.visible'); + }); }); }); diff --git a/packages/manager/cypress/support/constants/widgets.ts b/packages/manager/cypress/support/constants/widgets.ts index 96c7d4f1720..46f8413996e 100644 --- a/packages/manager/cypress/support/constants/widgets.ts +++ b/packages/manager/cypress/support/constants/widgets.ts @@ -1,3 +1,9 @@ +/** + * Provides configuration details for dashboards, including service types (DBaaS, Linode), + * related metrics (such as CPU utilization, memory usage, disk I/O), and their properties like + * expected aggregations, granularity, units, and labels. This configuration is used for validating + * and interacting with dashboard widgets. + */ export const widgetDetails = { dbaas: { clusterName: 'mysql-cluster', diff --git a/packages/manager/cypress/support/intercepts/cloudpulse.ts b/packages/manager/cypress/support/intercepts/cloudpulse.ts index e1c851b1091..76310326baf 100644 --- a/packages/manager/cypress/support/intercepts/cloudpulse.ts +++ b/packages/manager/cypress/support/intercepts/cloudpulse.ts @@ -126,7 +126,7 @@ export const mockCloudPulseDashboardServicesResponse = ( * @returns {Cypress.Chainable} - Returns a Cypress chainable object, enabling command chaining in tests. */ -export const mockCloudPulseJWSToken = ( +export const mockCloudPulseJWEToken = ( serviceType: string, token?: string ): Cypress.Chainable => { diff --git a/packages/manager/cypress/support/util/cloudpulse.ts b/packages/manager/cypress/support/util/cloudpulse.ts new file mode 100644 index 00000000000..78c36f4b8d4 --- /dev/null +++ b/packages/manager/cypress/support/util/cloudpulse.ts @@ -0,0 +1,54 @@ +// Function to generate random values based on the number of points + +import type { CloudPulseMetricsResponseData } from '@linode/api-v4'; +export const generateRandomMetricsData = ( + time: + | 'Last 7 Days' + | 'Last 12 Hours' + | 'Last 24 Hours' + | 'Last 30 Days' + | 'Last 30 Minutes', + granularityData: '1 day' | '1 hr' | '5 min' | 'Auto' +): CloudPulseMetricsResponseData => { + const currentTime = Math.floor(Date.now() / 1000); + + const intervals: Record = { + ['1 day']: 86400, + ['1 hr']: 3600, + ['5 min']: 5 * 60, + ['Auto']: 3600, + }; + + const timeRanges: Record = { + ['Last 7 Days']: 7 * 24 * 3600, + ['Last 12 Hours']: 12 * 3600, + ['Last 24 Hours']: 24 * 3600, + ['Last 30 Days']: 30 * 24 * 3600, + ['Last 30 Minutes']: 30 * 60, + }; + + const interval = intervals[granularityData]; + const timeRangeInSeconds = timeRanges[time]; + const startTime = currentTime - timeRangeInSeconds; + + if (!timeRangeInSeconds) { + throw new Error(`Unsupported time range: ${time}`); + } + + if (!interval) { + throw new Error(`Unsupported interval: ${interval}`); + } + + const values: [number, string][] = Array.from( + { length: Math.ceil(timeRangeInSeconds / interval) + 1 }, + (_, i) => { + const timestamp = startTime + i * interval; + const value = (Math.round(Math.random() * 100 * 100) / 100).toFixed(2); // Round and convert to string with 2 decimal places + return [timestamp, value]; + } + ); + return { + result: [{ metric: {}, values }], + result_type: 'matrix', + }; +}; diff --git a/packages/manager/src/factories/dashboards.ts b/packages/manager/src/factories/dashboards.ts index aa80f0cf29c..f812a23304a 100644 --- a/packages/manager/src/factories/dashboards.ts +++ b/packages/manager/src/factories/dashboards.ts @@ -148,50 +148,6 @@ export const dashboardMetricFactory = Factory.Sync.makeFactory unit: 'defaultUnit', } ); -// Function to generate random values based on the number of points -export const generateRandomMetricsData = ( - time: - | 'Last 7 Days' - | 'Last 12 Hours' - | 'Last 24 Hours' - | 'Last 30 Days' - | 'Last 30 Minutes', - granularityData: '1 day' | '1 hr' | '5 min' | 'Auto' -): CloudPulseMetricsResponseData => { - const currentTime = Math.floor(Date.now() / 1000); - - const intervals: Record = { - ['1 day']: 86400, - ['1 hr']: 3600, - ['5 min']: 5 * 60, - ['Auto']: 3600, - }; - - const timeRanges: Record = { - ['Last 7 Days']: 7 * 24 * 3600, - ['Last 12 Hours']: 12 * 3600, - ['Last 24 Hours']: 24 * 3600, - ['Last 30 Days']: 30 * 24 * 3600, - ['Last 30 Minutes']: 30 * 60, - }; - - const interval = intervals[granularityData]; - const timeRangeInSeconds = timeRanges[time]; - const startTime = currentTime - timeRangeInSeconds; - - const values: [number, string][] = Array.from( - { length: Math.ceil(timeRangeInSeconds / interval) + 1 }, - (_, i) => { - const timestamp = startTime + i * interval; - const value = (Math.round(Math.random() * 100 * 100) / 100).toFixed(2); // Round and convert to string with 2 decimal places - return [timestamp, value]; - } - ); - return { - result: [{ metric: {}, values }], - result_type: 'matrix', - }; -}; // Factory for CloudPulseMetricsResponseData export const cloudPulseMetricsResponseDataFactory = Factory.Sync.makeFactory( From 469426a117d9f7a4535c3f2a5030288ee50003dc Mon Sep 17 00:00:00 2001 From: Nikhil Agrawal <165884194+nikhagra-akamai@users.noreply.github.com> Date: Tue, 1 Oct 2024 16:03:14 +0530 Subject: [PATCH 117/474] Update CODEOWNERS --- CODEOWNERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 6143dc6f4a9..fd2b17cc4b5 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,2 +1 @@ -* @nikhagra-akamai -* @venkymano-akamai +* @ACLPManager/reviewers From 8e55f24d0c81cac6cccd87ac38f1d87a27367d84 Mon Sep 17 00:00:00 2001 From: Nikhil Agrawal <165884194+nikhagra-akamai@users.noreply.github.com> Date: Tue, 1 Oct 2024 16:06:27 +0530 Subject: [PATCH 118/474] Update CODEOWNERS --- CODEOWNERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index fd2b17cc4b5..6143dc6f4a9 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +1,2 @@ -* @ACLPManager/reviewers +* @nikhagra-akamai +* @venkymano-akamai From 87bb3e08abde376c304815187af283fd91036a82 Mon Sep 17 00:00:00 2001 From: agorthi Date: Tue, 1 Oct 2024 17:57:57 +0530 Subject: [PATCH 119/474] upcoming:[DI-20585]- Added code review comments --- .../linode-widget-verification.spec.ts | 284 ++++++++++-------- .../cypress/support/intercepts/cloudpulse.ts | 14 +- 2 files changed, 168 insertions(+), 130 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 4a721669ad6..8b5e5208924 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -96,6 +96,18 @@ const metricsAPIResponsePayload = cloudPulseMetricsResponseFactory.build({ data: generateRandomMetricsData(timeDurationToSelect, '5 min'), }); +/** + * `verifyWidgetValues` processes and verifies the metric values of a widget from the provided response payload. + * + * This method performs the following steps: + * 1. Transforms the raw data from the response payload into a more manageable format using `transformData`. + * 2. Extracts key metrics (average, last, and max) from the transformed data using `getMetrics`. + * 3. Rounds these metrics to two decimal places for accuracy. + * 4. Returns an object containing the rounded average, last, and max values for further verification or comparison. + * + * @param {CloudPulseMetricsResponse} responsePayload - The response payload containing metric data for a widget. + * @returns {Object} An object with the rounded average, last, and max metric values. + */ const getWidgetLegendRowValuesFromResponse = ( responsePayload: CloudPulseMetricsResponse ) => { @@ -106,6 +118,42 @@ const getWidgetLegendRowValuesFromResponse = ( const roundedMax = Math.round(max * 100) / 100; return { average: roundedAverage, last: roundedLast, max: roundedMax }; }; +/** + * Compares actual widget values to the expected values and asserts their equality. + * + * @param actualValues - The actual values retrieved from the widget, consisting of: + * @param actualValues.max - The maximum value shown on the widget. + * @param actualValues.average - The average value shown on the widget. + * @param actualValues.last - The last or most recent value shown on the widget. + * + * @param expectedValues - The expected values that the widget should display, consisting of: + * @param expectedValues.max - The expected maximum value. + * @param expectedValues.average - The expected average value. + * @param expectedValues.last - The expected last or most recent value. + */ + +const compareWidgetValues = ( + actualValues: { title: string; max: number; average: number; last: number }, + expectedValues: { max: number; average: number; last: number }, + title: string +) => { + expect(actualValues.max).to.equal( + expectedValues.max, + `Expected ${expectedValues.max} for max, but got ${actualValues.max}` + ); + expect(actualValues.average).to.equal( + expectedValues.average, + `Expected ${expectedValues.average} for average, but got ${actualValues.average}` + ); + expect(actualValues.last).to.equal( + expectedValues.last, + `Expected ${expectedValues.last} for last, but got ${actualValues.last}` + ); + expect( actualValues.title).startWith( + title, + `Expected ${title} for title ${actualValues.title}` + ); +}; describe('Integration Tests for Linode Dashboard ', () => { beforeEach(() => { @@ -165,124 +213,115 @@ describe('Integration Tests for Linode Dashboard ', () => { } }); - it('should allow users to select desired granularity and see the most recent data from the API reflected in the graph', () => { + it('should allow users to select their desired granularity and see the most recent data from the API reflected in the graph', () => { // validate the widget level granularity selection and its metrics - for (const testData of metrics) { - const { title: testDataTitle, expectedGranularity } = testData; - const widgetSelector = `[data-qa-widget="${testDataTitle}"]`; - - cy.get(widgetSelector).within(() => { - - // check for all available granularity in popper - ui.autocomplete - .findByLabel('Select an Interval') - .should('be.visible') - .click(); - - expectedGranularityArray.forEach((option) => { - ui.autocompletePopper.findByTitle(option).should('exist'); - }); - - mockCloudPulseCreateMetrics(metricsAPIResponsePayload, serviceType).as( - 'getGranularityMetrics' - ); - - //find the interval component and select the expected granularity - ui.autocomplete - .findByLabel('Select an Interval') - .should('be.visible') - .type(`${expectedGranularity}{enter}`); - - //check if the API call is made correctly with the selected time granularity value - cy.wait('@getGranularityMetrics').then((interception) => { - expect(interception) - .to.have.property('response') - .with.property('statusCode', 200); - expect(expectedGranularity).to.include( - interception.request.body.time_granularity.value - ); - }); - - //validate the widget line graph is present and its legend rows - cy.findByTestId('linegraph-wrapper').within(() => { - const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( - metricsAPIResponsePayload - ); + const widgetSelector = `[data-qa-widget="${testData.title}"]`; + cy.get(widgetSelector) + .should('be.visible') + .first() + .within(() => { + // check for all available granularity in popper + ui.autocomplete + .findByLabel('Select an Interval') + .should('be.visible') + .click(); - cy.findByText(`${testData.title} (${testData.unit})`).should( - 'be.visible' - ); + expectedGranularityArray.forEach((option) => { + ui.autocompletePopper.findByTitle(option).should('exist'); + }); - cy.findByText(`${expectedWidgetValues.max} ${testData.unit}`).should( - 'be.visible' - ); + mockCloudPulseCreateMetrics( metricsAPIResponsePayload, serviceType ).as('getGranularityMetrics'); - cy.findByText( - `${expectedWidgetValues.average} ${testData.unit}` - ).should('be.visible'); + //find the interval component and select the expected granularity + ui.autocomplete + .findByLabel('Select an Interval') + .should('be.visible') + .type(`${testData.expectedGranularity}{enter}`); //type expected granularity + + //check if the API call is made correctly with time granularity value selected + cy.wait('@getGranularityMetrics').then((interception) => { + expect(interception) + .to.have.property('response') + .with.property('statusCode', 200); + expect(testData.expectedGranularity).to.include( + interception.request.body.time_granularity.value + ); + }); - cy.findByText(`${expectedWidgetValues.last} ${testData.unit}`).should( - 'be.visible' - ); + //validate the widget linegrah is present + cy.findByTestId('linegraph-wrapper') + .should('be.visible') + .find('tbody tr') + .each(($tr) => { + const cells = $tr + .find('td') + .map((i, el) => { + const text = Cypress.$(el).text().trim(); + return text; + }) + .get(); + const [title, actualMax, actualAvg, actualLast] = cells; // the average, max and last present in the widget + const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( metricsAPIResponsePayload); + // the average, max and last from the response payload + compareWidgetValues({title, max: parseFloat(actualMax),average: parseFloat(actualAvg),last: parseFloat(actualLast)}, + expectedWidgetValues, + testData.title + ); + + }); }); - }); } }); - - it('should allow users to select the desired aggregation and see the most recent data from the API displayed in the graph', () => { + it('should allow users to select the desired aggregation and view the latest data from the API displayed in the graph', () => { for (const testData of metrics) { - const { - title: testDataTitle, - expectedAggregation, - expectedAggregationArray, - } = testData; - - const widgetSelector = `[data-qa-widget="${testDataTitle}"]`; - - cy.get(widgetSelector).within(() => { - // check for all available aggregation in popper - ui.autocomplete - .findByLabel('Select an Aggregate Function') - .should('be.visible') - .click(); - - expectedAggregationArray.forEach((option) => { - ui.autocompletePopper.findByTitle(option).should('exist'); - }); - - mockCloudPulseCreateMetrics(metricsAPIResponsePayload, serviceType).as( - 'getAggregationMetrics' - ); - - //find the interval component and select the expected granularity - ui.autocomplete - .findByLabel('Select an Aggregate Function') - .should('be.visible') - .type(`${expectedAggregation}{enter}`); - - //check if the API call is made correctly with time granularity value selected - cy.wait('@getAggregationMetrics').then((interception) => { - expect(interception) - .to.have.property('response') - .with.property('statusCode', 200); - expect(expectedAggregation).to.equal( - interception.request.body.aggregate_function - ); - }); + const widgetSelector = `[data-qa-widget="${testData.title}"]`; + cy.get(widgetSelector) + .should('be.visible') + .first() + .within(() => { + mockCloudPulseCreateMetrics( + metricsAPIResponsePayload, + serviceType + ).as('getAggregationMetrics'); + + //find the interval component and select the expected granularity + ui.autocomplete + .findByLabel('Select an Aggregate Function') + .should('be.visible') + .type(`${testData.expectedAggregation}{enter}`); //type expected granularity + + //check if the API call is made correctly with time granularity value selected + cy.wait('@getAggregationMetrics').then((interception) => { + expect(interception) + .to.have.property('response') + .with.property('statusCode', 200); + expect(testData.expectedAggregation).to.equal( + interception.request.body.aggregate_function + ); + }); - //validate the widget line graph is present and its legend rows - cy.findByTestId('linegraph-wrapper').within(() => { - const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( - metricsAPIResponsePayload - ); - cy.findByText(`${testData.title} (${testData.unit})`).should( 'be.visible'); - cy.findByText( `${expectedWidgetValues.max} ${testData.unit}`).should('be.visible'); - cy.findByText(`${expectedWidgetValues.average} ${testData.unit}` ).should('be.visible'); - cy.findByText( `${expectedWidgetValues.last} ${testData.unit}`).should('be.visible'); + //validate the widget linegrah is present + cy.findByTestId('linegraph-wrapper') + .should('be.visible') + .find('tbody tr') + .each(($tr) => { + const cells = $tr + .find('td') + .map((i, el) => { + const text = Cypress.$(el).text().trim(); + return text; + }) + .get(); + const [title, actualMax, actualAvg, actualLast] = cells; // the average, max and last present in the widget + const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( + metricsAPIResponsePayload + ); // the average, max and last from the response payload + compareWidgetValues( { title,max: parseFloat(actualMax),average: parseFloat(actualAvg),last: parseFloat(actualLast)}, + expectedWidgetValues, testData.title ); + }); }); - }); } }); it('should trigger the global refresh button and verify the corresponding network calls', () => { @@ -318,21 +357,18 @@ describe('Integration Tests for Linode Dashboard ', () => { it('should zoom in and out of all the widgets', () => { // do zoom in and zoom out test on all the widgets metrics.forEach((testData) => { - const { title: testDataTitle } = testData; - - cy.get(`[data-qa-widget="${testDataTitle}"]`).as('widget'); + cy.get(`[data-qa-widget="${testData.title}"]`).as('widget'); cy.get('@widget') .should('be.visible') .within(() => { - // find and click the zoom in button ui.button .findByAttribute('aria-label', 'Zoom In') .should('be.visible') + .should('be.enabled') .click(); cy.get('@widget').should('be.visible'); - - // validate the widget details - cy.findByTestId('linegraph-wrapper').within(() => { + cy.findByTestId('linegraph-wrapper') + .within(() => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( metricsAPIResponsePayload ); @@ -346,22 +382,22 @@ describe('Integration Tests for Linode Dashboard ', () => { ui.button .findByAttribute('aria-label', 'Zoom Out') .should('be.visible') + .should('be.enabled') .scrollIntoView() .click({ force: true }); cy.get('@widget').should('be.visible'); - - // validate the widget details - cy.findByTestId('linegraph-wrapper').within(() => { - const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( - metricsAPIResponsePayload - ); - cy.findByText(`${testData.title} (${testData.unit})`).should( 'be.visible'); - cy.findByText( `${expectedWidgetValues.max} ${testData.unit}`).should('be.visible'); - cy.findByText(`${expectedWidgetValues.average} ${testData.unit}` ).should('be.visible'); - cy.findByText( `${expectedWidgetValues.last} ${testData.unit}`).should('be.visible'); - - }); + cy.findByTestId('linegraph-wrapper') + .within(() => { + const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( + metricsAPIResponsePayload + ); + cy.findByText(`${testData.title} (${testData.unit})`).should( 'be.visible'); + cy.findByText( `${expectedWidgetValues.max} ${testData.unit}`).should('be.visible'); + cy.findByText(`${expectedWidgetValues.average} ${testData.unit}` ).should('be.visible'); + cy.findByText( `${expectedWidgetValues.last} ${testData.unit}`).should('be.visible'); + }); }); }); }); }); + diff --git a/packages/manager/cypress/support/intercepts/cloudpulse.ts b/packages/manager/cypress/support/intercepts/cloudpulse.ts index 76310326baf..7b1d780a806 100644 --- a/packages/manager/cypress/support/intercepts/cloudpulse.ts +++ b/packages/manager/cypress/support/intercepts/cloudpulse.ts @@ -31,7 +31,7 @@ export const mockCloudPulseGetMetricDefinitions = ( return cy.intercept( 'GET', apiMatcher(`/monitor/services/${serviceType}/metric-definitions`), - metricDefinitions + makeResponse(metricDefinitions) ); }; @@ -47,9 +47,11 @@ export const mockCloudPulseGetMetricDefinitions = ( export const mockCloudPulseServices = ( serviceType: string ): Cypress.Chainable => { - return cy.intercept('GET', apiMatcher('/monitor/services'), { - data: [{ service_type: serviceType }], - }); + return cy.intercept( + 'GET', + apiMatcher('/monitor/services'), + paginateResponse([{ service_type: serviceType }]) + ); }; /** @@ -87,7 +89,7 @@ export const mockCloudPulseCreateMetrics = ( return cy.intercept( 'POST', `**/monitor/services/${serviceType}/metrics`, - mockResponse + makeResponse(mockResponse) ); }; @@ -110,7 +112,7 @@ export const mockCloudPulseDashboardServicesResponse = ( return cy.intercept( 'GET', apiMatcher(`/monitor/dashboards/${id}`), - dashboard + makeResponse(dashboard) ); }; From fe8c04a3c8bb8b702d6c05ed86141e9d94b54db1 Mon Sep 17 00:00:00 2001 From: agorthi Date: Wed, 2 Oct 2024 09:19:21 +0530 Subject: [PATCH 120/474] upcoming:[DI-20585]- Added code review comments --- .../e2e/core/cloudpulse/linode-widget-verification.spec.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 8b5e5208924..838481eda45 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -220,7 +220,6 @@ describe('Integration Tests for Linode Dashboard ', () => { const widgetSelector = `[data-qa-widget="${testData.title}"]`; cy.get(widgetSelector) .should('be.visible') - .first() .within(() => { // check for all available granularity in popper ui.autocomplete @@ -279,7 +278,6 @@ describe('Integration Tests for Linode Dashboard ', () => { const widgetSelector = `[data-qa-widget="${testData.title}"]`; cy.get(widgetSelector) .should('be.visible') - .first() .within(() => { mockCloudPulseCreateMetrics( metricsAPIResponsePayload, From d2ffb4d60adff51e8edf21cb3e9440fdf2ca80da Mon Sep 17 00:00:00 2001 From: vmangalr Date: Wed, 2 Oct 2024 10:57:46 +0530 Subject: [PATCH 121/474] upcoming: [DI-20800] - Test URL and disable beta --- packages/api-v4/src/cloudpulse/dashboards.ts | 16 ++++++++++---- packages/api-v4/src/cloudpulse/services.ts | 22 ++++++++++++++----- packages/manager/src/MainContent.tsx | 4 ++-- .../src/components/PrimaryNav/PrimaryNav.tsx | 2 +- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/packages/api-v4/src/cloudpulse/dashboards.ts b/packages/api-v4/src/cloudpulse/dashboards.ts index c8802747e52..08b2ed268e7 100644 --- a/packages/api-v4/src/cloudpulse/dashboards.ts +++ b/packages/api-v4/src/cloudpulse/dashboards.ts @@ -1,7 +1,9 @@ import { ResourcePage } from 'src/types'; -import Request, { setMethod, setURL } from '../request'; +import Request, { setHeaders, setMethod, setURL } from '../request'; import { Dashboard } from './types'; -import { BETA_API_ROOT as API_ROOT } from 'src/constants'; +// import { BETA_API_ROOT as API_ROOT } from 'src/constants'; + +const API_ROOT = 'https://blr-lhvm1i.bangalore.corp.akamai.com:9000/v4beta'; // Returns the list of all the dashboards available export const getDashboards = (serviceType: string) => @@ -11,11 +13,17 @@ export const getDashboards = (serviceType: string) => serviceType )}/dashboards` ), - setMethod('GET') + setMethod('GET'), + setHeaders({ + Authorization: 'Bearer vagrant' + }) ); export const getDashboardById = (dashboardId: number) => Request( setURL(`${API_ROOT}/monitor/dashboards/${encodeURIComponent(dashboardId)}`), - setMethod('GET') + setMethod('GET'), + setHeaders({ + Authorization: 'Bearer vagrant' + }) ); diff --git a/packages/api-v4/src/cloudpulse/services.ts b/packages/api-v4/src/cloudpulse/services.ts index 5eb06faa0e5..8258d048052 100644 --- a/packages/api-v4/src/cloudpulse/services.ts +++ b/packages/api-v4/src/cloudpulse/services.ts @@ -1,5 +1,5 @@ -import { BETA_API_ROOT as API_ROOT } from 'src/constants'; -import Request, { setData, setMethod, setURL } from '../request'; +// import { BETA_API_ROOT as API_ROOT } from 'src/constants'; +import Request, { setData, setHeaders, setMethod, setURL } from '../request'; import { JWEToken, JWETokenPayLoad, @@ -8,6 +8,9 @@ import { } from './types'; import { ResourcePage as Page } from 'src/types'; + +const API_ROOT = 'https://blr-lhvm1i.bangalore.corp.akamai.com:9000/v4beta'; + export const getMetricDefinitionsByServiceType = (serviceType: string) => { return Request>( setURL( @@ -15,7 +18,10 @@ export const getMetricDefinitionsByServiceType = (serviceType: string) => { serviceType )}/metric-definitions` ), - setMethod('GET') + setMethod('GET'), + setHeaders({ + Authorization: 'Bearer vagrant' + }) ); }; @@ -25,12 +31,18 @@ export const getJWEToken = (data: JWETokenPayLoad, serviceType: string) => `${API_ROOT}/monitor/services/${encodeURIComponent(serviceType)}/token` ), setMethod('POST'), - setData(data) + setData(data), + setHeaders({ + Authorization: 'Bearer mlishuser' + }) ); // Returns the list of service types available export const getCloudPulseServiceTypes = () => Request( setURL(`${API_ROOT}/monitor/services`), - setMethod('GET') + setMethod('GET'), + setHeaders({ + Authorization: 'Bearer vagrant' + }) ); diff --git a/packages/manager/src/MainContent.tsx b/packages/manager/src/MainContent.tsx index faf51f6d9c5..76cf84f2e1e 100644 --- a/packages/manager/src/MainContent.tsx +++ b/packages/manager/src/MainContent.tsx @@ -360,12 +360,12 @@ export const MainContent = () => { )} - {isACLPEnabled && ( + {/* {isACLPEnabled && ( */} - )} + {/* )} */} {/** We don't want to break any bookmarks. This can probably be removed eventually. */} diff --git a/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx b/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx index 73c476bdb9d..4c09e9582cd 100644 --- a/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx +++ b/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx @@ -189,7 +189,7 @@ export const PrimaryNav = (props: PrimaryNavProps) => { }, { display: 'Monitor', - hide: !isACLPEnabled, + // hide: !isACLPEnabled, href: '/monitor/cloudpulse', icon: , isBeta: flags.aclp?.beta, From 89b776d6a04256c67ebc8b72492663154cc88e36 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Wed, 2 Oct 2024 11:41:08 +0530 Subject: [PATCH 122/474] upcoming: [DI-20800] - UT fixes --- .../CloudPulseAggregateFunction.test.tsx | 10 +++++++--- .../shared/CloudPulseTooltip.test.tsx | 20 +++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.test.tsx diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.test.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.test.tsx index e40a09c699e..29ad9a26d7c 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.test.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.test.tsx @@ -3,6 +3,7 @@ import React from 'react'; import { renderWithTheme } from 'src/utilities/testHelpers'; +import { convertStringToCamelCasesWithSpaces } from '../../Utils/utils'; import { CloudPulseAggregateFunction } from './CloudPulseAggregateFunction'; import type { AggregateFunctionProperties } from './CloudPulseAggregateFunction'; @@ -25,15 +26,18 @@ describe('Cloud Pulse Aggregate Function', () => { const dropdown = getByRole('combobox'); - expect(dropdown).toHaveAttribute('value', defaultAggregateFunction); + expect(dropdown).toHaveAttribute( + 'value', + convertStringToCamelCasesWithSpaces(defaultAggregateFunction) + ); }); it('should select the aggregate function on click', () => { renderWithTheme(); fireEvent.click(screen.getByRole('button', { name: 'Open' })); - fireEvent.click(screen.getByRole('option', { name: 'min' })); + fireEvent.click(screen.getByRole('option', { name: 'Min' })); - expect(screen.getByRole('combobox')).toHaveAttribute('value', 'min'); + expect(screen.getByRole('combobox')).toHaveAttribute('value', 'Min'); }); }); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.test.tsx new file mode 100644 index 00000000000..a113c38da40 --- /dev/null +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.test.tsx @@ -0,0 +1,20 @@ +import * as React from 'react'; + +import { Typography } from 'src/components/Typography'; +import { renderWithTheme } from 'src/utilities/testHelpers'; + +import { CloudPulseTooltip } from './CloudPulseTooltip'; + +describe('Cloud Pulse Tooltip Component Tests', () => { + it('renders the tooltip', async () => { + const screen = renderWithTheme( + + Test + + ); + + expect( + await screen.container.querySelector('[data-qa-tooltip="Test"]') + ).toBeInTheDocument(); + }); +}); From a75f392e9afb9cae4eb8359a1c0bf0ab4ff9b5d1 Mon Sep 17 00:00:00 2001 From: agorthi Date: Wed, 2 Oct 2024 23:55:38 +0530 Subject: [PATCH 123/474] upcoming:[DI-20585]- Added code review comments --- .../linode-widget-verification.spec.ts | 191 +++++++++--------- .../cypress/support/intercepts/cloudpulse.ts | 12 +- 2 files changed, 101 insertions(+), 102 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 838481eda45..f58e792d687 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -3,12 +3,12 @@ */ import { mockAppendFeatureFlags } from 'support/intercepts/feature-flags'; import { - mockCloudPulseJWEToken, - mockCloudPulseDashboardServicesResponse, - mockCloudPulseCreateMetrics, - mockCloudPulseGetDashboards, - mockCloudPulseGetMetricDefinitions, - mockCloudPulseServices, + mockCreateCloudPulseJWEToken, + mockGetCloudPulseDashboard, + mockCreateCloudPulseMetrics, + mockGetCloudPulseDashboards, + mockGetCloudPulseMetricDefinitions, + mockGetCloudPulseServices, } from 'support/intercepts/cloudpulse'; import { ui } from 'support/ui'; import { widgetDetails } from 'support/constants/widgets'; @@ -46,14 +46,8 @@ import { generateRandomMetricsData } from 'support/util/cloudpulse'; const expectedGranularityArray = ['Auto', '1 day', '1 hr', '5 min']; const timeDurationToSelect = 'Last 24 Hours'; -const { - metrics, - id, - serviceType, - dashboardName, - region, - resource, -} = widgetDetails.linode; +const { metrics, id, serviceType, dashboardName, region, resource } = + widgetDetails.linode; const dashboard = dashboardFactory.build({ label: dashboardName, @@ -149,7 +143,7 @@ const compareWidgetValues = ( expectedValues.last, `Expected ${expectedValues.last} for last, but got ${actualValues.last}` ); - expect( actualValues.title).startWith( + expect(actualValues.title).startWith( title, `Expected ${title} for title ${actualValues.title}` ); @@ -162,20 +156,19 @@ describe('Integration Tests for Linode Dashboard ', () => { }); mockGetAccount(mockAccount); // Enables the account to have capability for Akamai Cloud Pulse mockGetLinodes([mockLinode]); - mockCloudPulseGetMetricDefinitions(metricDefinitions, serviceType); - mockCloudPulseGetDashboards([dashboard], serviceType); - mockCloudPulseServices(serviceType); - mockCloudPulseDashboardServicesResponse(dashboard, id); - mockCloudPulseJWEToken(serviceType); - mockCloudPulseCreateMetrics(metricsAPIResponsePayload, serviceType).as( + mockGetCloudPulseMetricDefinitions(metricDefinitions, serviceType); + mockGetCloudPulseDashboards([dashboard], serviceType); + mockGetCloudPulseServices(serviceType); + mockGetCloudPulseDashboard(dashboard, id); + mockCreateCloudPulseJWEToken(serviceType); + mockCreateCloudPulseMetrics(metricsAPIResponsePayload, serviceType).as( 'getMetrics' ); mockGetRegions([mockRegion]); mockGetUserPreferences({}); // navigate to the cloudpulse page - cy.visitWithLogin('monitor/cloudpulse').as('cloudPulsePage'); - cy.get('@cloudPulsePage'); + cy.visitWithLogin('monitor/cloudpulse'); // Selecting a dashboard from the autocomplete input. ui.autocomplete @@ -202,22 +195,16 @@ describe('Integration Tests for Linode Dashboard ', () => { .click(); cy.findByText(resource).should('be.visible'); - - // Iterate over each metric to find the corresponding widget and verify the title and unit are displayed and visible - for (const { title, unit } of metrics) { - const widgetSelector = `[data-qa-widget="${title}"]`; - cy.get(widgetSelector) - .find('h2') - .should('have.text', `${title} (${unit.trim()})`) - .should('be.visible'); - } }); - it('should allow users to select their desired granularity and see the most recent data from the API reflected in the graph', () => { // validate the widget level granularity selection and its metrics - for (const testData of metrics) { + metrics.forEach((testData) => { const widgetSelector = `[data-qa-widget="${testData.title}"]`; + cy.get(widgetSelector) + .should('be.visible') + .find('h2') + .should('have.text', `${testData.title} (${testData.unit.trim()})`); cy.get(widgetSelector) .should('be.visible') .within(() => { @@ -231,7 +218,10 @@ describe('Integration Tests for Linode Dashboard ', () => { ui.autocompletePopper.findByTitle(option).should('exist'); }); - mockCloudPulseCreateMetrics( metricsAPIResponsePayload, serviceType ).as('getGranularityMetrics'); + mockCreateCloudPulseMetrics( + metricsAPIResponsePayload, + serviceType + ).as('getGranularityMetrics'); //find the interval component and select the expected granularity ui.autocomplete @@ -250,36 +240,33 @@ describe('Integration Tests for Linode Dashboard ', () => { }); //validate the widget linegrah is present - cy.findByTestId('linegraph-wrapper') - .should('be.visible') - .find('tbody tr') - .each(($tr) => { - const cells = $tr - .find('td') - .map((i, el) => { - const text = Cypress.$(el).text().trim(); - return text; - }) - .get(); - const [title, actualMax, actualAvg, actualLast] = cells; // the average, max and last present in the widget - const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( metricsAPIResponsePayload); - // the average, max and last from the response payload - compareWidgetValues({title, max: parseFloat(actualMax),average: parseFloat(actualAvg),last: parseFloat(actualLast)}, - expectedWidgetValues, - testData.title - ); - - }); + cy.findByTestId('linegraph-wrapper').within(() => { + const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( + metricsAPIResponsePayload + ); + cy.findByText(`${testData.title} (${testData.unit})`).should( + 'be.visible' + ); + cy.findByText( + `${expectedWidgetValues.max} ${testData.unit}` + ).should('be.visible'); + cy.findByText( + `${expectedWidgetValues.average} ${testData.unit}` + ).should('be.visible'); + cy.findByText( + `${expectedWidgetValues.last} ${testData.unit}` + ).should('be.visible'); + }); }); - } + }); }); it('should allow users to select the desired aggregation and view the latest data from the API displayed in the graph', () => { - for (const testData of metrics) { + metrics.forEach((testData) => { const widgetSelector = `[data-qa-widget="${testData.title}"]`; - cy.get(widgetSelector) + cy.get(widgetSelector) .should('be.visible') .within(() => { - mockCloudPulseCreateMetrics( + mockCreateCloudPulseMetrics( metricsAPIResponsePayload, serviceType ).as('getAggregationMetrics'); @@ -301,29 +288,28 @@ describe('Integration Tests for Linode Dashboard ', () => { }); //validate the widget linegrah is present - cy.findByTestId('linegraph-wrapper') - .should('be.visible') - .find('tbody tr') - .each(($tr) => { - const cells = $tr - .find('td') - .map((i, el) => { - const text = Cypress.$(el).text().trim(); - return text; - }) - .get(); - const [title, actualMax, actualAvg, actualLast] = cells; // the average, max and last present in the widget - const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( - metricsAPIResponsePayload - ); // the average, max and last from the response payload - compareWidgetValues( { title,max: parseFloat(actualMax),average: parseFloat(actualAvg),last: parseFloat(actualLast)}, - expectedWidgetValues, testData.title ); - }); + cy.findByTestId('linegraph-wrapper').within(() => { + const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( + metricsAPIResponsePayload + ); + cy.findByText(`${testData.title} (${testData.unit})`).should( + 'be.visible' + ); + cy.findByText( + `${expectedWidgetValues.max} ${testData.unit}` + ).should('be.visible'); + cy.findByText( + `${expectedWidgetValues.average} ${testData.unit}` + ).should('be.visible'); + cy.findByText( + `${expectedWidgetValues.last} ${testData.unit}` + ).should('be.visible'); + }); }); - } + }); }); it('should trigger the global refresh button and verify the corresponding network calls', () => { - mockCloudPulseCreateMetrics(metricsAPIResponsePayload, serviceType).as( + mockCreateCloudPulseMetrics(metricsAPIResponsePayload, serviceType).as( 'refreshMetrics' ); // click the global refresh button @@ -365,15 +351,22 @@ describe('Integration Tests for Linode Dashboard ', () => { .should('be.enabled') .click(); cy.get('@widget').should('be.visible'); - cy.findByTestId('linegraph-wrapper') - .within(() => { + cy.findByTestId('linegraph-wrapper').within(() => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( metricsAPIResponsePayload ); - cy.findByText(`${testData.title} (${testData.unit})`).should( 'be.visible'); - cy.findByText( `${expectedWidgetValues.max} ${testData.unit}`).should('be.visible'); - cy.findByText(`${expectedWidgetValues.average} ${testData.unit}` ).should('be.visible'); - cy.findByText( `${expectedWidgetValues.last} ${testData.unit}`).should('be.visible'); + cy.findByText(`${testData.title} (${testData.unit})`).should( + 'be.visible' + ); + cy.findByText( + `${expectedWidgetValues.max} ${testData.unit}` + ).should('be.visible'); + cy.findByText( + `${expectedWidgetValues.average} ${testData.unit}` + ).should('be.visible'); + cy.findByText( + `${expectedWidgetValues.last} ${testData.unit}` + ).should('be.visible'); }); // click zoom out and validate the same @@ -384,18 +377,24 @@ describe('Integration Tests for Linode Dashboard ', () => { .scrollIntoView() .click({ force: true }); cy.get('@widget').should('be.visible'); - cy.findByTestId('linegraph-wrapper') - .within(() => { - const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( - metricsAPIResponsePayload - ); - cy.findByText(`${testData.title} (${testData.unit})`).should( 'be.visible'); - cy.findByText( `${expectedWidgetValues.max} ${testData.unit}`).should('be.visible'); - cy.findByText(`${expectedWidgetValues.average} ${testData.unit}` ).should('be.visible'); - cy.findByText( `${expectedWidgetValues.last} ${testData.unit}`).should('be.visible'); - }); + cy.findByTestId('linegraph-wrapper').within(() => { + const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( + metricsAPIResponsePayload + ); + cy.findByText(`${testData.title} (${testData.unit})`).should( + 'be.visible' + ); + cy.findByText( + `${expectedWidgetValues.max} ${testData.unit}` + ).should('be.visible'); + cy.findByText( + `${expectedWidgetValues.average} ${testData.unit}` + ).should('be.visible'); + cy.findByText( + `${expectedWidgetValues.last} ${testData.unit}` + ).should('be.visible'); + }); }); }); }); }); - diff --git a/packages/manager/cypress/support/intercepts/cloudpulse.ts b/packages/manager/cypress/support/intercepts/cloudpulse.ts index 7b1d780a806..e6deed24904 100644 --- a/packages/manager/cypress/support/intercepts/cloudpulse.ts +++ b/packages/manager/cypress/support/intercepts/cloudpulse.ts @@ -24,7 +24,7 @@ import type { * @returns {Cypress.Chainable} The chainable Cypress object. */ -export const mockCloudPulseGetMetricDefinitions = ( +export const mockGetCloudPulseMetricDefinitions = ( metricDefinitions: MetricDefinitions, serviceType: string ): Cypress.Chainable => { @@ -44,7 +44,7 @@ export const mockCloudPulseGetMetricDefinitions = ( * @returns {Cypress.Chainable} The chainable Cypress object. */ -export const mockCloudPulseServices = ( +export const mockGetCloudPulseServices = ( serviceType: string ): Cypress.Chainable => { return cy.intercept( @@ -63,7 +63,7 @@ export const mockCloudPulseServices = ( + * @returns The chainable Cypress object. + */ -export const mockCloudPulseGetDashboards = ( +export const mockGetCloudPulseDashboards = ( dashboards: Dashboard[], serviceType: string ): Cypress.Chainable => { @@ -82,7 +82,7 @@ export const mockCloudPulseGetDashboards = ( * @param {any} mockResponse - The mock response to return for the intercepted request. * @returns {Cypress.Chainable} The chainable Cypress object. */ -export const mockCloudPulseCreateMetrics = ( +export const mockCreateCloudPulseMetrics = ( mockResponse: CloudPulseMetricsResponse, serviceType: string ): Cypress.Chainable => { @@ -105,7 +105,7 @@ export const mockCloudPulseCreateMetrics = ( * @returns {Cypress.Chainable} - Returns a Cypress chainable object, allowing for command chaining in tests. */ -export const mockCloudPulseDashboardServicesResponse = ( +export const mockGetCloudPulseDashboard = ( dashboard: Dashboard, id: number ): Cypress.Chainable => { @@ -128,7 +128,7 @@ export const mockCloudPulseDashboardServicesResponse = ( * @returns {Cypress.Chainable} - Returns a Cypress chainable object, enabling command chaining in tests. */ -export const mockCloudPulseJWEToken = ( +export const mockCreateCloudPulseJWEToken = ( serviceType: string, token?: string ): Cypress.Chainable => { From 1f5fee919bf0921e7a73ae0f9a0a6bd30992f0eb Mon Sep 17 00:00:00 2001 From: agorthi Date: Wed, 2 Oct 2024 23:56:58 +0530 Subject: [PATCH 124/474] upcoming:[DI-20585]- Added code review comments --- .../linode-widget-verification.spec.ts | 36 ------------------- 1 file changed, 36 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index f58e792d687..156ddf637da 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -112,42 +112,6 @@ const getWidgetLegendRowValuesFromResponse = ( const roundedMax = Math.round(max * 100) / 100; return { average: roundedAverage, last: roundedLast, max: roundedMax }; }; -/** - * Compares actual widget values to the expected values and asserts their equality. - * - * @param actualValues - The actual values retrieved from the widget, consisting of: - * @param actualValues.max - The maximum value shown on the widget. - * @param actualValues.average - The average value shown on the widget. - * @param actualValues.last - The last or most recent value shown on the widget. - * - * @param expectedValues - The expected values that the widget should display, consisting of: - * @param expectedValues.max - The expected maximum value. - * @param expectedValues.average - The expected average value. - * @param expectedValues.last - The expected last or most recent value. - */ - -const compareWidgetValues = ( - actualValues: { title: string; max: number; average: number; last: number }, - expectedValues: { max: number; average: number; last: number }, - title: string -) => { - expect(actualValues.max).to.equal( - expectedValues.max, - `Expected ${expectedValues.max} for max, but got ${actualValues.max}` - ); - expect(actualValues.average).to.equal( - expectedValues.average, - `Expected ${expectedValues.average} for average, but got ${actualValues.average}` - ); - expect(actualValues.last).to.equal( - expectedValues.last, - `Expected ${expectedValues.last} for last, but got ${actualValues.last}` - ); - expect(actualValues.title).startWith( - title, - `Expected ${title} for title ${actualValues.title}` - ); -}; describe('Integration Tests for Linode Dashboard ', () => { beforeEach(() => { From 489b9e64ea204511e383b6d0ee074617e621b8b1 Mon Sep 17 00:00:00 2001 From: agorthi Date: Thu, 3 Oct 2024 00:21:03 +0530 Subject: [PATCH 125/474] upcoming:[DI-20585]- Added code review comments --- .../cypress/support/intercepts/cloudpulse.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/manager/cypress/support/intercepts/cloudpulse.ts b/packages/manager/cypress/support/intercepts/cloudpulse.ts index e6deed24904..2c63c892e70 100644 --- a/packages/manager/cypress/support/intercepts/cloudpulse.ts +++ b/packages/manager/cypress/support/intercepts/cloudpulse.ts @@ -16,7 +16,7 @@ import type { } from '@linode/api-v4'; /** - * Intercepts GET requests for metric definitions. + * Intercepts GET requests for metric definitions. * * This function mocks the API response for requests to the endpoint * `dashboardMetricsData`. @@ -25,8 +25,8 @@ import type { */ export const mockGetCloudPulseMetricDefinitions = ( - metricDefinitions: MetricDefinitions, - serviceType: string + serviceType: string, + metricDefinitions: MetricDefinitions ): Cypress.Chainable => { return cy.intercept( 'GET', @@ -64,8 +64,8 @@ export const mockGetCloudPulseServices = ( + */ export const mockGetCloudPulseDashboards = ( - dashboards: Dashboard[], - serviceType: string + serviceType: string, + dashboards: Dashboard[] ): Cypress.Chainable => { return cy.intercept( 'GET', @@ -83,8 +83,8 @@ export const mockGetCloudPulseDashboards = ( * @returns {Cypress.Chainable} The chainable Cypress object. */ export const mockCreateCloudPulseMetrics = ( - mockResponse: CloudPulseMetricsResponse, - serviceType: string + serviceType: string, + mockResponse: CloudPulseMetricsResponse ): Cypress.Chainable => { return cy.intercept( 'POST', @@ -106,8 +106,8 @@ export const mockCreateCloudPulseMetrics = ( */ export const mockGetCloudPulseDashboard = ( - dashboard: Dashboard, - id: number + id: number, + dashboard: Dashboard ): Cypress.Chainable => { return cy.intercept( 'GET', From ffea26d81a43be7029a0e9cc9063f0cfe83a4798 Mon Sep 17 00:00:00 2001 From: agorthi Date: Thu, 3 Oct 2024 00:45:18 +0530 Subject: [PATCH 126/474] upcoming:[DI-20585]- Added code review comments --- .../linode-widget-verification.spec.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 156ddf637da..bfce9c407df 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -120,12 +120,12 @@ describe('Integration Tests for Linode Dashboard ', () => { }); mockGetAccount(mockAccount); // Enables the account to have capability for Akamai Cloud Pulse mockGetLinodes([mockLinode]); - mockGetCloudPulseMetricDefinitions(metricDefinitions, serviceType); - mockGetCloudPulseDashboards([dashboard], serviceType); + mockGetCloudPulseMetricDefinitions(serviceType, metricDefinitions); + mockGetCloudPulseDashboards(serviceType, [dashboard]); mockGetCloudPulseServices(serviceType); - mockGetCloudPulseDashboard(dashboard, id); + mockGetCloudPulseDashboard(id, dashboard); mockCreateCloudPulseJWEToken(serviceType); - mockCreateCloudPulseMetrics(metricsAPIResponsePayload, serviceType).as( + mockCreateCloudPulseMetrics(serviceType, metricsAPIResponsePayload).as( 'getMetrics' ); mockGetRegions([mockRegion]); @@ -183,8 +183,8 @@ describe('Integration Tests for Linode Dashboard ', () => { }); mockCreateCloudPulseMetrics( - metricsAPIResponsePayload, - serviceType + serviceType, + metricsAPIResponsePayload ).as('getGranularityMetrics'); //find the interval component and select the expected granularity @@ -231,8 +231,8 @@ describe('Integration Tests for Linode Dashboard ', () => { .should('be.visible') .within(() => { mockCreateCloudPulseMetrics( - metricsAPIResponsePayload, - serviceType + serviceType, + metricsAPIResponsePayload ).as('getAggregationMetrics'); //find the interval component and select the expected granularity @@ -273,7 +273,7 @@ describe('Integration Tests for Linode Dashboard ', () => { }); }); it('should trigger the global refresh button and verify the corresponding network calls', () => { - mockCreateCloudPulseMetrics(metricsAPIResponsePayload, serviceType).as( + mockCreateCloudPulseMetrics(serviceType, metricsAPIResponsePayload).as( 'refreshMetrics' ); // click the global refresh button From 1f7a11c939f89b0acaa85eff80a51e7e1f4c4fb0 Mon Sep 17 00:00:00 2001 From: agorthi Date: Thu, 3 Oct 2024 01:18:40 +0530 Subject: [PATCH 127/474] upcoming:[DI-20585]- Added code review comments --- .../dbaas-widgets-verification.spec.ts | 405 ++++++++++++++++++ .../cypress/support/constants/widgets.ts | 4 +- 2 files changed, 407 insertions(+), 2 deletions(-) create mode 100644 packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts new file mode 100644 index 00000000000..54c5803940e --- /dev/null +++ b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts @@ -0,0 +1,405 @@ +/** + * @file Integration Tests for CloudPulse Dbass Dashboard. + */ +import { mockAppendFeatureFlags } from 'support/intercepts/feature-flags'; +import { + mockCreateCloudPulseJWEToken, + mockGetCloudPulseDashboard, + mockCreateCloudPulseMetrics, + mockGetCloudPulseDashboards, + mockGetCloudPulseMetricDefinitions, + mockGetCloudPulseServices, +} from 'support/intercepts/cloudpulse'; +import { ui } from 'support/ui'; +import { widgetDetails } from 'support/constants/widgets'; +import { + accountFactory, + cloudPulseMetricsResponseFactory, + dashboardFactory, + dashboardMetricFactory, + databaseFactory, + kubeLinodeFactory, + linodeFactory, + regionFactory, + widgetFactory, +} from 'src/factories'; +import { mockGetAccount } from 'support/intercepts/account'; +import { mockGetLinodes } from 'support/intercepts/linodes'; +import { mockGetUserPreferences } from 'support/intercepts/profile'; +import { mockGetRegions } from 'support/intercepts/regions'; +import { extendRegion } from 'support/util/regions'; +import { CloudPulseMetricsResponse, Database } from '@linode/api-v4'; +import { transformData } from 'src/features/CloudPulse/Utils/unitConversion'; +import { getMetrics } from 'src/utilities/statMetrics'; +import { Interception } from 'cypress/types/net-stubbing'; +import { generateRandomMetricsData } from 'support/util/cloudpulse'; +import { mockGetDatabases } from 'support/intercepts/databases'; + +/** + * This test ensures that widget titles are displayed correctly on the dashboard. + * This test suite is dedicated to verifying the functionality and display of widgets on the Cloudpulse dashboard. + * It includes: + * Validating that widgets are correctly loaded and displayed. + * Ensuring that widget titles and data match the expected values. + * Verifying that widget settings, such as granularity and aggregation, are applied correctly. + * Testing widget interactions, including zooming and filtering, to ensure proper behavior. + * Each test ensures that widgets on the dashboard operate correctly and display accurate information. + */ +const expectedGranularityArray = ['Auto', '1 day', '1 hr', '5 min']; +const timeDurationToSelect = 'Last 24 Hours'; + +const { + metrics, + id, + serviceType, + dashboardName, + region, + engine, + clusterName, + nodeType, +} = widgetDetails.dbaas; + +const dashboard = dashboardFactory.build({ + label: dashboardName, + service_type: serviceType, + widgets: metrics.map(({ title, yLabel, name, unit }) => { + return widgetFactory.build({ + label: title, + y_label: yLabel, + metric: name, + unit, + }); + }), +}); + +const metricDefinitions = { + data: metrics.map(({ title, name, unit }) => + dashboardMetricFactory.build({ + label: title, + metric: name, + unit, + }) + ), +}; + +const mockLinode = linodeFactory.build({ + label: clusterName, + id: kubeLinodeFactory.build().instance_id ?? undefined, +}); + +const mockAccount = accountFactory.build(); +const mockRegion = extendRegion( + regionFactory.build({ + capabilities: ['Linodes'], + id: 'us-ord', + label: 'Chicago, IL', + country: 'us', + }) +); +const metricsAPIResponsePayload = cloudPulseMetricsResponseFactory.build({ + data: generateRandomMetricsData(timeDurationToSelect, '5 min'), +}); + +/** + * Verifies the presence and values of specific properties within the aclpPreference object + * of the request payload. This function checks that the expected properties exist + * and have the expected values, allowing for validation of user preferences in the application. + * + * @param requestPayload - The payload received from the request, containing the aclpPreference object. + * @param expectedValues - An object containing the expected values for properties to validate against the requestPayload. + * Expected properties may include: + * - dashboardId: The ID of the dashboard. + * - timeDuration: The selected time duration for metrics. + * - engine: The database engine used. + * - region: The selected region for the dashboard. + * - resources: An array of resource identifiers. + * - role: The role associated with the dashboard user. + */ +const getWidgetLegendRowValuesFromResponse = ( + responsePayload: CloudPulseMetricsResponse +) => { + const data = transformData(responsePayload.data.result[0].values, 'Bytes'); + const { average, last, max } = getMetrics(data); + const roundedAverage = Math.round(average * 100) / 100; + const roundedLast = Math.round(last * 100) / 100; + const roundedMax = Math.round(max * 100) / 100; + return { average: roundedAverage, last: roundedLast, max: roundedMax }; +}; + +const databaseMock: Database = databaseFactory.build({ + label: widgetDetails.dbaas.clusterName, + type: widgetDetails.dbaas.engine, + region: widgetDetails.dbaas.region, + version: '1', + status: 'provisioning', + cluster_size: 1, + engine: 'mysql', + hosts: { + primary: undefined, + secondary: undefined, + }, +}); + +describe('Integration Tests for dbaas Dashboard ', () => { + beforeEach(() => { + mockAppendFeatureFlags({ + aclp: { beta: true, enabled: true }, + }); + mockGetAccount(mockAccount); // Enables the account to have capability for Akamai Cloud Pulse + mockGetLinodes([mockLinode]); + mockGetCloudPulseMetricDefinitions(serviceType, metricDefinitions); + mockGetCloudPulseDashboards(serviceType, [dashboard]); + mockGetCloudPulseServices(serviceType); + mockGetCloudPulseDashboard(id, dashboard); + mockCreateCloudPulseJWEToken(serviceType); + mockCreateCloudPulseMetrics(serviceType, metricsAPIResponsePayload).as( + 'getMetrics' + ); + mockGetRegions([mockRegion]); + mockGetUserPreferences({}); + mockGetDatabases([databaseMock]).as('getDatabases'); + + // navigate to the cloudpulse page + cy.visitWithLogin('monitor/cloudpulse').as('cloudPulsePage'); + cy.get('@cloudPulsePage'); + + // Selecting a dashboard from the autocomplete input. + ui.autocomplete + .findByLabel('Select a Dashboard') + .should('be.visible') + .type(`${dashboardName}{enter}`) + .should('be.visible'); + + // Select a time duration from the autocomplete input. + ui.autocomplete + .findByLabel('Select a Time Duration') + .should('be.visible') + .type(`${timeDurationToSelect}{enter}`) + .should('be.visible'); + + //Select a Engine from the autocomplete input. + ui.autocomplete + .findByLabel('Select an Engine') + .should('be.visible') + .type(`${engine}{enter}`) + .should('be.visible'); + + // Select a region from the dropdown. + ui.regionSelect.find().click().type(`${region}{enter}`); + + // Select a resource from the autocomplete input. + ui.autocomplete + .findByLabel('Select a Resource') + .should('be.visible') + .type(`${clusterName}{enter}`) + .click(); + cy.findByText(clusterName).should('be.visible'); + + //Select a Node from the autocomplete input. + ui.autocomplete + .findByLabel('Select a Node Type') + .should('be.visible') + .type(`${nodeType}{enter}`); + }); + + it('should allow users to select their desired granularity and see the most recent data from the API reflected in the graph', () => { + // validate the widget level granularity selection and its metrics + metrics.forEach((testData) => { + const widgetSelector = `[data-qa-widget="${testData.title}"]`; + cy.get(widgetSelector) + .should('be.visible') + .find('h2') + .should('have.text', `${testData.title} (${testData.unit.trim()})`); + cy.get(widgetSelector) + .should('be.visible') + .within(() => { + // check for all available granularity in popper + ui.autocomplete + .findByLabel('Select an Interval') + .should('be.visible') + .click(); + + expectedGranularityArray.forEach((option) => { + ui.autocompletePopper.findByTitle(option).should('exist'); + }); + + mockCreateCloudPulseMetrics( + serviceType, + metricsAPIResponsePayload + ).as('getGranularityMetrics'); + + //find the interval component and select the expected granularity + ui.autocomplete + .findByLabel('Select an Interval') + .should('be.visible') + .type(`${testData.expectedGranularity}{enter}`); //type expected granularity + + //check if the API call is made correctly with time granularity value selected + cy.wait('@getGranularityMetrics').then((interception) => { + expect(interception) + .to.have.property('response') + .with.property('statusCode', 200); + expect(testData.expectedGranularity).to.include( + interception.request.body.time_granularity.value + ); + }); + + //validate the widget linegrah is present + cy.findByTestId('linegraph-wrapper').within(() => { + const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( + metricsAPIResponsePayload + ); + cy.findByText(`${testData.title} (${testData.unit})`).should( + 'be.visible' + ); + cy.findByText( + `${expectedWidgetValues.max} ${testData.unit}` + ).should('be.visible'); + cy.findByText( + `${expectedWidgetValues.average} ${testData.unit}` + ).should('be.visible'); + cy.findByText( + `${expectedWidgetValues.last} ${testData.unit}` + ).should('be.visible'); + }); + }); + }); + }); + it('should allow users to select the desired aggregation and view the latest data from the API displayed in the graph', () => { + metrics.forEach((testData) => { + const widgetSelector = `[data-qa-widget="${testData.title}"]`; + cy.get(widgetSelector) + .should('be.visible') + .within(() => { + mockCreateCloudPulseMetrics( + serviceType, + metricsAPIResponsePayload + ).as('getAggregationMetrics'); + + //find the interval component and select the expected granularity + ui.autocomplete + .findByLabel('Select an Aggregate Function') + .should('be.visible') + .type(`${testData.expectedAggregation}{enter}`); //type expected granularity + + //check if the API call is made correctly with time granularity value selected + cy.wait('@getAggregationMetrics').then((interception) => { + expect(interception) + .to.have.property('response') + .with.property('statusCode', 200); + expect(testData.expectedAggregation).to.equal( + interception.request.body.aggregate_function + ); + }); + + //validate the widget linegrah is present + cy.findByTestId('linegraph-wrapper').within(() => { + const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( + metricsAPIResponsePayload + ); + cy.findByText(`${testData.title} (${testData.unit})`).should( + 'be.visible' + ); + cy.findByText( + `${expectedWidgetValues.max} ${testData.unit}` + ).should('be.visible'); + cy.findByText( + `${expectedWidgetValues.average} ${testData.unit}` + ).should('be.visible'); + cy.findByText( + `${expectedWidgetValues.last} ${testData.unit}` + ).should('be.visible'); + }); + }); + }); + }); + it('should trigger the global refresh button and verify the corresponding network calls', () => { + mockCreateCloudPulseMetrics(serviceType, metricsAPIResponsePayload).as( + 'refreshMetrics' + ); + // click the global refresh button + ui.button + .findByAttribute('aria-label', 'Refresh Dashboard Metrics') + .should('be.visible') + .click(); + + // validate the API calls are going with intended payload + cy.get('@refreshMetrics.all') + .should('have.length', 4) + .each((xhr: unknown) => { + const interception = xhr as Interception; + const { body: requestPayload } = interception.request; + const { metric, relative_time_duration: timeRange } = requestPayload; + const metricData = metrics.find(({ name }) => name === metric); + + if (!metricData) { + throw new Error( + `Unexpected metric name '${metric}' included in the outgoing refresh API request` + ); + } + expect(metric).to.equal(metricData.name); + expect(timeRange).to.have.property('unit', 'hr'); + expect(timeRange).to.have.property('value', 24); + }); + }); + + it('should zoom in and out of all the widgets', () => { + // do zoom in and zoom out test on all the widgets + metrics.forEach((testData) => { + cy.get(`[data-qa-widget="${testData.title}"]`).as('widget'); + cy.get('@widget') + .should('be.visible') + .within(() => { + ui.button + .findByAttribute('aria-label', 'Zoom In') + .should('be.visible') + .should('be.enabled') + .click(); + cy.get('@widget').should('be.visible'); + cy.findByTestId('linegraph-wrapper').within(() => { + const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( + metricsAPIResponsePayload + ); + cy.findByText(`${testData.title} (${testData.unit})`).should( + 'be.visible' + ); + cy.findByText( + `${expectedWidgetValues.max} ${testData.unit}` + ).should('be.visible'); + cy.findByText( + `${expectedWidgetValues.average} ${testData.unit}` + ).should('be.visible'); + cy.findByText( + `${expectedWidgetValues.last} ${testData.unit}` + ).should('be.visible'); + }); + + // click zoom out and validate the same + ui.button + .findByAttribute('aria-label', 'Zoom Out') + .should('be.visible') + .should('be.enabled') + .scrollIntoView() + .click({ force: true }); + cy.get('@widget').should('be.visible'); + cy.findByTestId('linegraph-wrapper').within(() => { + const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( + metricsAPIResponsePayload + ); + cy.findByText(`${testData.title} (${testData.unit})`).should( + 'be.visible' + ); + cy.findByText( + `${expectedWidgetValues.max} ${testData.unit}` + ).should('be.visible'); + cy.findByText( + `${expectedWidgetValues.average} ${testData.unit}` + ).should('be.visible'); + cy.findByText( + `${expectedWidgetValues.last} ${testData.unit}` + ).should('be.visible'); + }); + }); + }); + }); +}); diff --git a/packages/manager/cypress/support/constants/widgets.ts b/packages/manager/cypress/support/constants/widgets.ts index 46f8413996e..30c97edaf94 100644 --- a/packages/manager/cypress/support/constants/widgets.ts +++ b/packages/manager/cypress/support/constants/widgets.ts @@ -35,7 +35,7 @@ export const widgetDetails = { expectedGranularity: '1 hr', name: 'system_memory_usage_by_resource', title: 'Memory Usage', - unit: 'Bytes', + unit: 'B', yLabel: 'system_memory_usage_bytes', }, { @@ -44,7 +44,7 @@ export const widgetDetails = { expectedGranularity: '1 hr', name: 'system_network_io_by_resource', title: 'Network Traffic', - unit: 'Bytes', + unit: 'B', yLabel: 'system_network_io_bytes_total', }, ], From 9a838635f716b69a4e28a1ae37a9e6a10f9b932c Mon Sep 17 00:00:00 2001 From: vmangalr Date: Thu, 3 Oct 2024 10:09:16 +0530 Subject: [PATCH 128/474] upcoming: [DI-20800] - Code clean up and review comments --- .../Widget/components/CloudPulseAggregateFunction.tsx | 2 +- .../src/features/CloudPulse/Widget/components/Zoomer.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx index 4a3291805a3..8b129827146 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx @@ -60,7 +60,7 @@ export const CloudPulseAggregateFunction = React.memo( return convertStringToCamelCasesWithSpaces(option.label); // options needed to be display in Caps first }} isOptionEqualToValue={(option, value) => { - return option.label == value.label; + return option.label === value.label; }} onChange={(e, selectedAggregateFunc: AggregateFunction) => { setSelectedAggregateFunction(selectedAggregateFunc); diff --git a/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx b/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx index e4d4a848aeb..413a19718dd 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx @@ -22,7 +22,7 @@ export const ZoomIcon = React.memo((props: ZoomIconProperties) => { const ToggleZoomer = () => { if (props.zoomIn) { return ( - + { } return ( - + Date: Thu, 3 Oct 2024 10:45:49 +0530 Subject: [PATCH 129/474] DI-20844 - Beta feedbacks and zero state time duration issue fix (#8) * upcoming: [DI-20800] - Tooltip changes * upcoming: [DI-20800] - Tooltip and publishing the resource selection onClose from Autocomplete * upcoming: [DI-20800] - Resource Selection close state handling updates * upcoming: [DI-20800] - Tooltip code refactoring * upcoming: [DI-20800] - Tooltip code refactoring * upcoming: [DI-20800] - Global Filters * upcoming: [DI-20800] - As per dev * upcoming: [DI-20800] - Code clean up and refactoring * upcoming: [DI-20800] - UT fixes * upcoming: [DI-20800] - Code clean up and review comments --------- Co-authored-by: vmangalr --- .../CloudPulse/Overview/GlobalFilters.tsx | 25 ++++---- .../CloudPulse/Utils/UserPreference.ts | 3 +- .../CloudPulseAggregateFunction.test.tsx | 10 +++- .../CloudPulseAggregateFunction.tsx | 45 ++++++++------ .../components/CloudPulseIntervalSelect.tsx | 58 ++++++++++--------- .../Widget/components/CloudPulseLineGraph.tsx | 4 +- .../CloudPulse/Widget/components/Zoomer.tsx | 48 +++++++++------ .../shared/CloudPulseResourcesSelect.tsx | 19 +++++- .../shared/CloudPulseTimeRangeSelect.tsx | 8 ++- .../shared/CloudPulseTooltip.test.tsx | 20 +++++++ .../CloudPulse/shared/CloudPulseTooltip.tsx | 48 +++++++++++++++ 11 files changed, 201 insertions(+), 87 deletions(-) create mode 100644 packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.test.tsx create mode 100644 packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.tsx diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index 0cd8b7c95bf..157db0a26cc 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -9,6 +9,7 @@ import { Divider } from 'src/components/Divider'; import { CloudPulseDashboardFilterBuilder } from '../shared/CloudPulseDashboardFilterBuilder'; import { CloudPulseDashboardSelect } from '../shared/CloudPulseDashboardSelect'; import { CloudPulseTimeRangeSelect } from '../shared/CloudPulseTimeRangeSelect'; +import { CloudPulseTooltip } from '../shared/CloudPulseTooltip'; import { DASHBOARD_ID, REFRESH, TIME_DURATION } from '../Utils/constants'; import { useAclpPreference } from '../Utils/UserPreference'; @@ -109,17 +110,19 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { label="Select Time Range" savePreferences /> - - - + + + + + diff --git a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts index 18550ae5f25..69d193c87e8 100644 --- a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts +++ b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts @@ -5,7 +5,7 @@ import { usePreferences, } from 'src/queries/profile/preferences'; -import { DASHBOARD_ID, TIME_DURATION, WIDGETS } from './constants'; +import { DASHBOARD_ID, WIDGETS } from './constants'; import type { AclpConfig, AclpWidget } from '@linode/api-v4'; @@ -37,7 +37,6 @@ export const useAclpPreference = (): AclpPreferenceObject => { if (keys.includes(DASHBOARD_ID)) { currentPreferences = { ...data, - [TIME_DURATION]: currentPreferences[TIME_DURATION], [WIDGETS]: {}, }; } else { diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.test.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.test.tsx index e40a09c699e..29ad9a26d7c 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.test.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.test.tsx @@ -3,6 +3,7 @@ import React from 'react'; import { renderWithTheme } from 'src/utilities/testHelpers'; +import { convertStringToCamelCasesWithSpaces } from '../../Utils/utils'; import { CloudPulseAggregateFunction } from './CloudPulseAggregateFunction'; import type { AggregateFunctionProperties } from './CloudPulseAggregateFunction'; @@ -25,15 +26,18 @@ describe('Cloud Pulse Aggregate Function', () => { const dropdown = getByRole('combobox'); - expect(dropdown).toHaveAttribute('value', defaultAggregateFunction); + expect(dropdown).toHaveAttribute( + 'value', + convertStringToCamelCasesWithSpaces(defaultAggregateFunction) + ); }); it('should select the aggregate function on click', () => { renderWithTheme(); fireEvent.click(screen.getByRole('button', { name: 'Open' })); - fireEvent.click(screen.getByRole('option', { name: 'min' })); + fireEvent.click(screen.getByRole('option', { name: 'Min' })); - expect(screen.getByRole('combobox')).toHaveAttribute('value', 'min'); + expect(screen.getByRole('combobox')).toHaveAttribute('value', 'Min'); }); }); diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx index dba98c8726f..8b129827146 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx @@ -1,6 +1,8 @@ import React from 'react'; +import { CloudPulseTooltip } from '../../shared/CloudPulseTooltip'; import { StyledWidgetAutocomplete } from '../../Utils/CloudPulseWidgetUtils'; +import { convertStringToCamelCasesWithSpaces } from '../../Utils/utils'; export interface AggregateFunctionProperties { /** @@ -52,25 +54,30 @@ export const CloudPulseAggregateFunction = React.memo( ] = React.useState(defaultValue); return ( - { - return option.label == value.label; - }} - onChange={(e, selectedAggregateFunc: AggregateFunction) => { - setSelectedAggregateFunction(selectedAggregateFunc); - onAggregateFuncChange(selectedAggregateFunc.label); - }} - textFieldProps={{ - hideLabel: true, - }} - disableClearable - fullWidth={false} - label="Select an Aggregate Function" - noMarginTop={true} - options={availableAggregateFunc} - sx={{ width: '100%' }} - value={selectedAggregateFunction} - /> + + { + return convertStringToCamelCasesWithSpaces(option.label); // options needed to be display in Caps first + }} + isOptionEqualToValue={(option, value) => { + return option.label === value.label; + }} + onChange={(e, selectedAggregateFunc: AggregateFunction) => { + setSelectedAggregateFunction(selectedAggregateFunc); + onAggregateFuncChange(selectedAggregateFunc.label); + }} + textFieldProps={{ + hideLabel: true, + }} + disableClearable + fullWidth={false} + label="Select an Aggregate Function" + noMarginTop={true} + options={availableAggregateFunc} + sx={{ width: '100%' }} + value={selectedAggregateFunction} + /> + ); } ); diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx index 13a5bdee9eb..517516378da 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx @@ -1,5 +1,6 @@ import React from 'react'; +import { CloudPulseTooltip } from '../../shared/CloudPulseTooltip'; import { StyledWidgetAutocomplete } from '../../Utils/CloudPulseWidgetUtils'; import type { TimeGranularity } from '@linode/api-v4'; @@ -119,34 +120,35 @@ export const CloudPulseIntervalSelect = React.memo( ); return ( - { - return option?.value === value?.value && option?.unit === value?.unit; - }} - onChange={( - _: React.SyntheticEvent, - selectedInterval: IntervalOptions - ) => { - setSelectedInterval(selectedInterval); - onIntervalChange({ - unit: selectedInterval?.unit, - value: selectedInterval?.value, - }); - }} - textFieldProps={{ - hideLabel: true, - }} - disableClearable - fullWidth={false} - label="Select an Interval" - noMarginTop={true} - options={[autoIntervalOption, ...availableIntervalOptions]} - sx={{ width: { xs: '100%' } }} - value={selectedInterval} - /> + + option?.value === value?.value && option?.unit === value?.unit} + onChange={( + _: React.SyntheticEvent, + selectedInterval: IntervalOptions + ) => { + setSelectedInterval(selectedInterval); + onIntervalChange({ + unit: selectedInterval?.unit, + value: selectedInterval?.value, + }); + }} + textFieldProps={{ + hideLabel: true, + }} + autoHighlight + disableClearable + fullWidth={false} + label="Select an Interval" + noMarginTop={true} + options={[autoIntervalOption, ...availableIntervalOptions]} + sx={{ width: { xs: '100%' } }} + value={selectedInterval} + /> + ); } ); diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index 4547d306b41..5c3ce2fd3fd 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -49,10 +49,10 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { border: 0, }, backgroundColor: theme.bg.offWhite, - height: `calc(${theme.spacing(14)} + 3px)`, // 115px maxHeight: `calc(${theme.spacing(14)} + 3px)`, + minHeight: `calc(${theme.spacing(10)})`, overflow: 'auto', - padding: theme.spacing(1), + paddingLeft: theme.spacing(1), }} ariaLabel={ariaLabel} data={data} diff --git a/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx b/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx index f21148cc831..413a19718dd 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx @@ -1,9 +1,11 @@ -import { useTheme } from '@mui/material'; +import { IconButton, useTheme } from '@mui/material'; import * as React from 'react'; import ZoomInMap from 'src/assets/icons/zoomin.svg'; import ZoomOutMap from 'src/assets/icons/zoomout.svg'; +import { CloudPulseTooltip } from '../../shared/CloudPulseTooltip'; + export interface ZoomIconProperties { className?: string; handleZoomToggle: (zoomIn: boolean) => void; @@ -20,28 +22,38 @@ export const ZoomIcon = React.memo((props: ZoomIconProperties) => { const ToggleZoomer = () => { if (props.zoomIn) { return ( - + handleClick(false)} + > + + + + ); + } + + return ( + + handleClick(false)} - /> - ); - } - - return ( - handleClick(true)} - /> + data-testid="zoom-out" + onClick={() => handleClick(true)} + > + + + ); }; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index c9ad5c13d3f..52fb36b03be 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -39,6 +39,8 @@ export const CloudPulseResourcesSelect = React.memo( xFilter, } = props; + const isAutocompleteOpen = React.useRef(false); + const { data: resources, isLoading } = useResourcesQuery( disabled !== undefined ? !disabled : Boolean(region && resourceType), resourceType, @@ -79,9 +81,22 @@ export const CloudPulseResourcesSelect = React.memo( return ( { + onChange={( + _: React.SyntheticEvent, + resourceSelections: CloudPulseResources[] + ) => { setSelectedResources(resourceSelections); - handleResourcesSelection(resourceSelections, savePreferences); + + if (!isAutocompleteOpen.current) { + handleResourcesSelection(resourceSelections, savePreferences); + } + }} + onClose={() => { + isAutocompleteOpen.current = false; + handleResourcesSelection(selectedResources ?? [], savePreferences); + }} + onOpen={() => { + isAutocompleteOpen.current = true; }} placeholder={ selectedResources?.length ? '' : placeholder || 'Select a Resource' diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx index 8c288622307..1b22edcdc7d 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx @@ -43,7 +43,7 @@ export const CloudPulseTimeRangeSelect = React.memo( return options[0]; } return options.find((o) => o.label === defaultValue) || options[0]; - }, []); + }, [defaultValue]); const [selectedTimeRange, setSelectedTimeRange] = React.useState< Item >(getDefaultValue()); @@ -58,8 +58,12 @@ export const CloudPulseTimeRangeSelect = React.memo( false ); } + + if (item !== selectedTimeRange) { + setSelectedTimeRange(item); + } // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); // need to execute only once, during mounting of this component + }, [defaultValue]); // need to execute only once, during mounting of this component const handleChange = (item: Item) => { setSelectedTimeRange(item); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.test.tsx new file mode 100644 index 00000000000..a113c38da40 --- /dev/null +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.test.tsx @@ -0,0 +1,20 @@ +import * as React from 'react'; + +import { Typography } from 'src/components/Typography'; +import { renderWithTheme } from 'src/utilities/testHelpers'; + +import { CloudPulseTooltip } from './CloudPulseTooltip'; + +describe('Cloud Pulse Tooltip Component Tests', () => { + it('renders the tooltip', async () => { + const screen = renderWithTheme( + + Test + + ); + + expect( + await screen.container.querySelector('[data-qa-tooltip="Test"]') + ).toBeInTheDocument(); + }); +}); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.tsx new file mode 100644 index 00000000000..f6afa0a455f --- /dev/null +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.tsx @@ -0,0 +1,48 @@ +import { styled, tooltipClasses } from '@mui/material'; +import React from 'react'; + +import { Tooltip } from 'src/components/Tooltip'; + +import type { TooltipProps } from '@mui/material'; + +export const CloudPulseTooltip = React.memo((props: TooltipProps) => { + const { children, placement, title } = props; + + return ( + + {children} + + ); +}); + +const StyledTooltip = styled(({ className, ...props }: TooltipProps) => ( + +))(({ theme }) => ({ + [`& .${tooltipClasses.arrow}`]: { + color: theme.palette.common.black, + }, + [`& .${tooltipClasses.tooltip}`]: { + backgroundColor: theme.palette.common.black, + color: theme.palette.common.white, + fontSize: theme.spacing(1.75), + maxHeight: theme.spacing(3.5), + maxWidth: theme.spacing(30), + padding: theme.spacing(0.75), + }, +})); From d94279d6f23af88c0ea37a5d74673ef4fa51c4ef Mon Sep 17 00:00:00 2001 From: vmangalr Date: Thu, 3 Oct 2024 11:52:23 +0530 Subject: [PATCH 130/474] upcoming: [DI-20800] - Mock related changes --- .../CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx index 517516378da..8f00fcbd7a9 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx @@ -120,7 +120,7 @@ export const CloudPulseIntervalSelect = React.memo( ); return ( - + Date: Thu, 3 Oct 2024 23:17:28 +0530 Subject: [PATCH 131/474] upcoming:[DI-20585]- Added code review comments --- .../dbaas-widgets-verification.spec.ts | 94 +++++++++++-------- .../linode-widget-verification.spec.ts | 92 ++++++++++-------- .../src/components/LineGraph/LineGraph.tsx | 2 + .../manager/src/queries/cloudpulse/metrics.ts | 2 +- 4 files changed, 108 insertions(+), 82 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts index 54c5803940e..42b6b828831 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts @@ -140,7 +140,7 @@ const databaseMock: Database = databaseFactory.build({ }, }); -describe('Integration Tests for dbaas Dashboard ', () => { +describe('Integration Tests for DBaaS Dashboard ', () => { beforeEach(() => { mockAppendFeatureFlags({ aclp: { beta: true, enabled: true }, @@ -148,8 +148,8 @@ describe('Integration Tests for dbaas Dashboard ', () => { mockGetAccount(mockAccount); // Enables the account to have capability for Akamai Cloud Pulse mockGetLinodes([mockLinode]); mockGetCloudPulseMetricDefinitions(serviceType, metricDefinitions); - mockGetCloudPulseDashboards(serviceType, [dashboard]); - mockGetCloudPulseServices(serviceType); + mockGetCloudPulseDashboards(serviceType, [dashboard]).as('fetchDashboard'); + mockGetCloudPulseServices(serviceType).as('fetchServices'); mockGetCloudPulseDashboard(id, dashboard); mockCreateCloudPulseJWEToken(serviceType); mockCreateCloudPulseMetrics(serviceType, metricsAPIResponsePayload).as( @@ -160,8 +160,9 @@ describe('Integration Tests for dbaas Dashboard ', () => { mockGetDatabases([databaseMock]).as('getDatabases'); // navigate to the cloudpulse page - cy.visitWithLogin('monitor/cloudpulse').as('cloudPulsePage'); - cy.get('@cloudPulsePage'); + cy.visitWithLogin('monitor/cloudpulse') + cy.wait('@fetchServices'); // Wait for services + cy.wait('@fetchDashboard'); // Wait for dashboard // Selecting a dashboard from the autocomplete input. ui.autocomplete @@ -200,6 +201,8 @@ describe('Integration Tests for dbaas Dashboard ', () => { .findByLabel('Select a Node Type') .should('be.visible') .type(`${nodeType}{enter}`); + + cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']);// Wait for all metrics query requests to resolve. }); it('should allow users to select their desired granularity and see the most recent data from the API reflected in the graph', () => { @@ -252,15 +255,17 @@ describe('Integration Tests for dbaas Dashboard ', () => { cy.findByText(`${testData.title} (${testData.unit})`).should( 'be.visible' ); - cy.findByText( - `${expectedWidgetValues.max} ${testData.unit}` - ).should('be.visible'); - cy.findByText( - `${expectedWidgetValues.average} ${testData.unit}` - ).should('be.visible'); - cy.findByText( - `${expectedWidgetValues.last} ${testData.unit}` - ).should('be.visible'); + cy.get(`[data-qa-graph-column-title="Max"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.max} ${testData.unit}`); + + cy.get(`[data-qa-graph-column-title="Avg"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.average} ${testData.unit}`); + + cy.get(`[data-qa-graph-column-title="Last"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.last} ${testData.unit}`); }); }); }); @@ -300,15 +305,17 @@ describe('Integration Tests for dbaas Dashboard ', () => { cy.findByText(`${testData.title} (${testData.unit})`).should( 'be.visible' ); - cy.findByText( - `${expectedWidgetValues.max} ${testData.unit}` - ).should('be.visible'); - cy.findByText( - `${expectedWidgetValues.average} ${testData.unit}` - ).should('be.visible'); - cy.findByText( - `${expectedWidgetValues.last} ${testData.unit}` - ).should('be.visible'); + cy.get(`[data-qa-graph-column-title="Max"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.max} ${testData.unit}`); + + cy.get(`[data-qa-graph-column-title="Avg"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.average} ${testData.unit}`); + + cy.get(`[data-qa-graph-column-title="Last"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.last} ${testData.unit}`); }); }); }); @@ -317,6 +324,7 @@ describe('Integration Tests for dbaas Dashboard ', () => { mockCreateCloudPulseMetrics(serviceType, metricsAPIResponsePayload).as( 'refreshMetrics' ); + // click the global refresh button ui.button .findByAttribute('aria-label', 'Refresh Dashboard Metrics') @@ -363,15 +371,17 @@ describe('Integration Tests for dbaas Dashboard ', () => { cy.findByText(`${testData.title} (${testData.unit})`).should( 'be.visible' ); - cy.findByText( - `${expectedWidgetValues.max} ${testData.unit}` - ).should('be.visible'); - cy.findByText( - `${expectedWidgetValues.average} ${testData.unit}` - ).should('be.visible'); - cy.findByText( - `${expectedWidgetValues.last} ${testData.unit}` - ).should('be.visible'); + cy.get(`[data-qa-graph-column-title="Max"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.max} ${testData.unit}`); + + cy.get(`[data-qa-graph-column-title="Avg"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.average} ${testData.unit}`); + + cy.get(`[data-qa-graph-column-title="Last"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.last} ${testData.unit}`); }); // click zoom out and validate the same @@ -389,15 +399,17 @@ describe('Integration Tests for dbaas Dashboard ', () => { cy.findByText(`${testData.title} (${testData.unit})`).should( 'be.visible' ); - cy.findByText( - `${expectedWidgetValues.max} ${testData.unit}` - ).should('be.visible'); - cy.findByText( - `${expectedWidgetValues.average} ${testData.unit}` - ).should('be.visible'); - cy.findByText( - `${expectedWidgetValues.last} ${testData.unit}` - ).should('be.visible'); + cy.get(`[data-qa-graph-column-title="Max"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.max} ${testData.unit}`); + + cy.get(`[data-qa-graph-column-title="Avg"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.average} ${testData.unit}`); + + cy.get(`[data-qa-graph-column-title="Last"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.last} ${testData.unit}`); }); }); }); diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index bfce9c407df..5024fa254c0 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -30,8 +30,8 @@ import { extendRegion } from 'support/util/regions'; import { CloudPulseMetricsResponse } from '@linode/api-v4'; import { transformData } from 'src/features/CloudPulse/Utils/unitConversion'; import { getMetrics } from 'src/utilities/statMetrics'; -import { Interception } from 'cypress/types/net-stubbing'; import { generateRandomMetricsData } from 'support/util/cloudpulse'; +import { Interception } from 'cypress/types/net-stubbing'; /** * This test ensures that widget titles are displayed correctly on the dashboard. @@ -121,9 +121,9 @@ describe('Integration Tests for Linode Dashboard ', () => { mockGetAccount(mockAccount); // Enables the account to have capability for Akamai Cloud Pulse mockGetLinodes([mockLinode]); mockGetCloudPulseMetricDefinitions(serviceType, metricDefinitions); - mockGetCloudPulseDashboards(serviceType, [dashboard]); - mockGetCloudPulseServices(serviceType); - mockGetCloudPulseDashboard(id, dashboard); + mockGetCloudPulseDashboards(serviceType, [dashboard]).as('fetchDashboard'); + mockGetCloudPulseServices(serviceType).as('fetchServices'); + mockGetCloudPulseDashboard(id, dashboard) mockCreateCloudPulseJWEToken(serviceType); mockCreateCloudPulseMetrics(serviceType, metricsAPIResponsePayload).as( 'getMetrics' @@ -133,6 +133,8 @@ describe('Integration Tests for Linode Dashboard ', () => { // navigate to the cloudpulse page cy.visitWithLogin('monitor/cloudpulse'); + cy.wait('@fetchServices'); // Wait for services + cy.wait('@fetchDashboard'); // Wait for dashboard // Selecting a dashboard from the autocomplete input. ui.autocomplete @@ -159,6 +161,7 @@ describe('Integration Tests for Linode Dashboard ', () => { .click(); cy.findByText(resource).should('be.visible'); + cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']);// Wait for all metrics query requests to resolve. }); it('should allow users to select their desired granularity and see the most recent data from the API reflected in the graph', () => { @@ -211,15 +214,17 @@ describe('Integration Tests for Linode Dashboard ', () => { cy.findByText(`${testData.title} (${testData.unit})`).should( 'be.visible' ); - cy.findByText( - `${expectedWidgetValues.max} ${testData.unit}` - ).should('be.visible'); - cy.findByText( - `${expectedWidgetValues.average} ${testData.unit}` - ).should('be.visible'); - cy.findByText( - `${expectedWidgetValues.last} ${testData.unit}` - ).should('be.visible'); + cy.get(`[data-qa-graph-column-title="Max"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.max} ${testData.unit}`); + + cy.get(`[data-qa-graph-column-title="Avg"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.average} ${testData.unit}`); + + cy.get(`[data-qa-graph-column-title="Last"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.last} ${testData.unit}`); }); }); }); @@ -259,15 +264,17 @@ describe('Integration Tests for Linode Dashboard ', () => { cy.findByText(`${testData.title} (${testData.unit})`).should( 'be.visible' ); - cy.findByText( - `${expectedWidgetValues.max} ${testData.unit}` - ).should('be.visible'); - cy.findByText( - `${expectedWidgetValues.average} ${testData.unit}` - ).should('be.visible'); - cy.findByText( - `${expectedWidgetValues.last} ${testData.unit}` - ).should('be.visible'); + cy.get(`[data-qa-graph-column-title="Max"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.max} ${testData.unit}`); + + cy.get(`[data-qa-graph-column-title="Avg"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.average} ${testData.unit}`); + + cy.get(`[data-qa-graph-column-title="Last"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.last} ${testData.unit}`); }); }); }); @@ -276,6 +283,7 @@ describe('Integration Tests for Linode Dashboard ', () => { mockCreateCloudPulseMetrics(serviceType, metricsAPIResponsePayload).as( 'refreshMetrics' ); + // click the global refresh button ui.button .findByAttribute('aria-label', 'Refresh Dashboard Metrics') @@ -322,15 +330,17 @@ describe('Integration Tests for Linode Dashboard ', () => { cy.findByText(`${testData.title} (${testData.unit})`).should( 'be.visible' ); - cy.findByText( - `${expectedWidgetValues.max} ${testData.unit}` - ).should('be.visible'); - cy.findByText( - `${expectedWidgetValues.average} ${testData.unit}` - ).should('be.visible'); - cy.findByText( - `${expectedWidgetValues.last} ${testData.unit}` - ).should('be.visible'); + cy.get(`[data-qa-graph-column-title="Max"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.max} ${testData.unit}`); + + cy.get(`[data-qa-graph-column-title="Avg"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.average} ${testData.unit}`); + + cy.get(`[data-qa-graph-column-title="Last"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.last} ${testData.unit}`); }); // click zoom out and validate the same @@ -348,15 +358,17 @@ describe('Integration Tests for Linode Dashboard ', () => { cy.findByText(`${testData.title} (${testData.unit})`).should( 'be.visible' ); - cy.findByText( - `${expectedWidgetValues.max} ${testData.unit}` - ).should('be.visible'); - cy.findByText( - `${expectedWidgetValues.average} ${testData.unit}` - ).should('be.visible'); - cy.findByText( - `${expectedWidgetValues.last} ${testData.unit}` - ).should('be.visible'); + cy.get(`[data-qa-graph-column-title="Max"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.max} ${testData.unit}`); + + cy.get(`[data-qa-graph-column-title="Avg"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.average} ${testData.unit}`); + + cy.get(`[data-qa-graph-column-title="Last"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.last} ${testData.unit}`); }); }); }); diff --git a/packages/manager/src/components/LineGraph/LineGraph.tsx b/packages/manager/src/components/LineGraph/LineGraph.tsx index fa631573b07..f49657bbca2 100644 --- a/packages/manager/src/components/LineGraph/LineGraph.tsx +++ b/packages/manager/src/components/LineGraph/LineGraph.tsx @@ -459,6 +459,8 @@ export const LineGraph = (props: LineGraphProps) => { rowHeaders ? rowHeaders[idx] : undefined } data-qa-body-cell + data-qa-graph-column-title={finalRowHeaders[i]} + data-qa-graph-row-title={title} key={i} > Date: Fri, 4 Oct 2024 11:28:27 +0530 Subject: [PATCH 132/474] upcoming:[DI-20585]- Added code review comments --- .../dbaas-widgets-verification.spec.ts | 130 +++++++++++------- .../linode-widget-verification.spec.ts | 130 +++++++++++------- .../manager/src/queries/cloudpulse/metrics.ts | 2 +- 3 files changed, 169 insertions(+), 93 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts index 42b6b828831..b5b479ced6d 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts @@ -149,7 +149,7 @@ describe('Integration Tests for DBaaS Dashboard ', () => { mockGetLinodes([mockLinode]); mockGetCloudPulseMetricDefinitions(serviceType, metricDefinitions); mockGetCloudPulseDashboards(serviceType, [dashboard]).as('fetchDashboard'); - mockGetCloudPulseServices(serviceType).as('fetchServices'); + mockGetCloudPulseServices(serviceType).as('fetchServices'); mockGetCloudPulseDashboard(id, dashboard); mockCreateCloudPulseJWEToken(serviceType); mockCreateCloudPulseMetrics(serviceType, metricsAPIResponsePayload).as( @@ -160,9 +160,10 @@ describe('Integration Tests for DBaaS Dashboard ', () => { mockGetDatabases([databaseMock]).as('getDatabases'); // navigate to the cloudpulse page - cy.visitWithLogin('monitor/cloudpulse') - cy.wait('@fetchServices'); // Wait for services - cy.wait('@fetchDashboard'); // Wait for dashboard + cy.visitWithLogin('monitor/cloudpulse'); + + // Wait for the services and dashboard API calls to complete before proceeding + cy.wait(['@fetchServices', '@fetchDashboard']); // Selecting a dashboard from the autocomplete input. ui.autocomplete @@ -202,7 +203,8 @@ describe('Integration Tests for DBaaS Dashboard ', () => { .should('be.visible') .type(`${nodeType}{enter}`); - cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']);// Wait for all metrics query requests to resolve. + // Wait for all metrics query requests to resolve. + cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']); }); it('should allow users to select their desired granularity and see the most recent data from the API reflected in the graph', () => { @@ -256,16 +258,25 @@ describe('Integration Tests for DBaaS Dashboard ', () => { 'be.visible' ); cy.get(`[data-qa-graph-column-title="Max"]`) - .should('be.visible') - .should('have.text', `${expectedWidgetValues.max} ${testData.unit}`); - - cy.get(`[data-qa-graph-column-title="Avg"]`) - .should('be.visible') - .should('have.text', `${expectedWidgetValues.average} ${testData.unit}`); - - cy.get(`[data-qa-graph-column-title="Last"]`) - .should('be.visible') - .should('have.text', `${expectedWidgetValues.last} ${testData.unit}`); + .should('be.visible') + .should( + 'have.text', + `${expectedWidgetValues.max} ${testData.unit}` + ); + + cy.get(`[data-qa-graph-column-title="Avg"]`) + .should('be.visible') + .should( + 'have.text', + `${expectedWidgetValues.average} ${testData.unit}` + ); + + cy.get(`[data-qa-graph-column-title="Last"]`) + .should('be.visible') + .should( + 'have.text', + `${expectedWidgetValues.last} ${testData.unit}` + ); }); }); }); @@ -306,16 +317,25 @@ describe('Integration Tests for DBaaS Dashboard ', () => { 'be.visible' ); cy.get(`[data-qa-graph-column-title="Max"]`) - .should('be.visible') - .should('have.text', `${expectedWidgetValues.max} ${testData.unit}`); - - cy.get(`[data-qa-graph-column-title="Avg"]`) - .should('be.visible') - .should('have.text', `${expectedWidgetValues.average} ${testData.unit}`); - - cy.get(`[data-qa-graph-column-title="Last"]`) - .should('be.visible') - .should('have.text', `${expectedWidgetValues.last} ${testData.unit}`); + .should('be.visible') + .should( + 'have.text', + `${expectedWidgetValues.max} ${testData.unit}` + ); + + cy.get(`[data-qa-graph-column-title="Avg"]`) + .should('be.visible') + .should( + 'have.text', + `${expectedWidgetValues.average} ${testData.unit}` + ); + + cy.get(`[data-qa-graph-column-title="Last"]`) + .should('be.visible') + .should( + 'have.text', + `${expectedWidgetValues.last} ${testData.unit}` + ); }); }); }); @@ -324,7 +344,7 @@ describe('Integration Tests for DBaaS Dashboard ', () => { mockCreateCloudPulseMetrics(serviceType, metricsAPIResponsePayload).as( 'refreshMetrics' ); - + // click the global refresh button ui.button .findByAttribute('aria-label', 'Refresh Dashboard Metrics') @@ -372,16 +392,25 @@ describe('Integration Tests for DBaaS Dashboard ', () => { 'be.visible' ); cy.get(`[data-qa-graph-column-title="Max"]`) - .should('be.visible') - .should('have.text', `${expectedWidgetValues.max} ${testData.unit}`); - - cy.get(`[data-qa-graph-column-title="Avg"]`) - .should('be.visible') - .should('have.text', `${expectedWidgetValues.average} ${testData.unit}`); - - cy.get(`[data-qa-graph-column-title="Last"]`) - .should('be.visible') - .should('have.text', `${expectedWidgetValues.last} ${testData.unit}`); + .should('be.visible') + .should( + 'have.text', + `${expectedWidgetValues.max} ${testData.unit}` + ); + + cy.get(`[data-qa-graph-column-title="Avg"]`) + .should('be.visible') + .should( + 'have.text', + `${expectedWidgetValues.average} ${testData.unit}` + ); + + cy.get(`[data-qa-graph-column-title="Last"]`) + .should('be.visible') + .should( + 'have.text', + `${expectedWidgetValues.last} ${testData.unit}` + ); }); // click zoom out and validate the same @@ -400,16 +429,25 @@ describe('Integration Tests for DBaaS Dashboard ', () => { 'be.visible' ); cy.get(`[data-qa-graph-column-title="Max"]`) - .should('be.visible') - .should('have.text', `${expectedWidgetValues.max} ${testData.unit}`); - - cy.get(`[data-qa-graph-column-title="Avg"]`) - .should('be.visible') - .should('have.text', `${expectedWidgetValues.average} ${testData.unit}`); - - cy.get(`[data-qa-graph-column-title="Last"]`) - .should('be.visible') - .should('have.text', `${expectedWidgetValues.last} ${testData.unit}`); + .should('be.visible') + .should( + 'have.text', + `${expectedWidgetValues.max} ${testData.unit}` + ); + + cy.get(`[data-qa-graph-column-title="Avg"]`) + .should('be.visible') + .should( + 'have.text', + `${expectedWidgetValues.average} ${testData.unit}` + ); + + cy.get(`[data-qa-graph-column-title="Last"]`) + .should('be.visible') + .should( + 'have.text', + `${expectedWidgetValues.last} ${testData.unit}` + ); }); }); }); diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 5024fa254c0..dd95d49c7f2 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -122,8 +122,8 @@ describe('Integration Tests for Linode Dashboard ', () => { mockGetLinodes([mockLinode]); mockGetCloudPulseMetricDefinitions(serviceType, metricDefinitions); mockGetCloudPulseDashboards(serviceType, [dashboard]).as('fetchDashboard'); - mockGetCloudPulseServices(serviceType).as('fetchServices'); - mockGetCloudPulseDashboard(id, dashboard) + mockGetCloudPulseServices(serviceType).as('fetchServices'); + mockGetCloudPulseDashboard(id, dashboard); mockCreateCloudPulseJWEToken(serviceType); mockCreateCloudPulseMetrics(serviceType, metricsAPIResponsePayload).as( 'getMetrics' @@ -133,8 +133,9 @@ describe('Integration Tests for Linode Dashboard ', () => { // navigate to the cloudpulse page cy.visitWithLogin('monitor/cloudpulse'); - cy.wait('@fetchServices'); // Wait for services - cy.wait('@fetchDashboard'); // Wait for dashboard + + // Wait for the services and dashboard API calls to complete before proceeding + cy.wait(['@fetchServices', '@fetchDashboard']); // Selecting a dashboard from the autocomplete input. ui.autocomplete @@ -161,7 +162,8 @@ describe('Integration Tests for Linode Dashboard ', () => { .click(); cy.findByText(resource).should('be.visible'); - cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']);// Wait for all metrics query requests to resolve. + // Wait for all metrics query requests to resolve. + cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']); }); it('should allow users to select their desired granularity and see the most recent data from the API reflected in the graph', () => { @@ -215,16 +217,25 @@ describe('Integration Tests for Linode Dashboard ', () => { 'be.visible' ); cy.get(`[data-qa-graph-column-title="Max"]`) - .should('be.visible') - .should('have.text', `${expectedWidgetValues.max} ${testData.unit}`); - - cy.get(`[data-qa-graph-column-title="Avg"]`) - .should('be.visible') - .should('have.text', `${expectedWidgetValues.average} ${testData.unit}`); - - cy.get(`[data-qa-graph-column-title="Last"]`) - .should('be.visible') - .should('have.text', `${expectedWidgetValues.last} ${testData.unit}`); + .should('be.visible') + .should( + 'have.text', + `${expectedWidgetValues.max} ${testData.unit}` + ); + + cy.get(`[data-qa-graph-column-title="Avg"]`) + .should('be.visible') + .should( + 'have.text', + `${expectedWidgetValues.average} ${testData.unit}` + ); + + cy.get(`[data-qa-graph-column-title="Last"]`) + .should('be.visible') + .should( + 'have.text', + `${expectedWidgetValues.last} ${testData.unit}` + ); }); }); }); @@ -265,16 +276,25 @@ describe('Integration Tests for Linode Dashboard ', () => { 'be.visible' ); cy.get(`[data-qa-graph-column-title="Max"]`) - .should('be.visible') - .should('have.text', `${expectedWidgetValues.max} ${testData.unit}`); - - cy.get(`[data-qa-graph-column-title="Avg"]`) - .should('be.visible') - .should('have.text', `${expectedWidgetValues.average} ${testData.unit}`); - - cy.get(`[data-qa-graph-column-title="Last"]`) - .should('be.visible') - .should('have.text', `${expectedWidgetValues.last} ${testData.unit}`); + .should('be.visible') + .should( + 'have.text', + `${expectedWidgetValues.max} ${testData.unit}` + ); + + cy.get(`[data-qa-graph-column-title="Avg"]`) + .should('be.visible') + .should( + 'have.text', + `${expectedWidgetValues.average} ${testData.unit}` + ); + + cy.get(`[data-qa-graph-column-title="Last"]`) + .should('be.visible') + .should( + 'have.text', + `${expectedWidgetValues.last} ${testData.unit}` + ); }); }); }); @@ -283,7 +303,7 @@ describe('Integration Tests for Linode Dashboard ', () => { mockCreateCloudPulseMetrics(serviceType, metricsAPIResponsePayload).as( 'refreshMetrics' ); - + // click the global refresh button ui.button .findByAttribute('aria-label', 'Refresh Dashboard Metrics') @@ -331,16 +351,25 @@ describe('Integration Tests for Linode Dashboard ', () => { 'be.visible' ); cy.get(`[data-qa-graph-column-title="Max"]`) - .should('be.visible') - .should('have.text', `${expectedWidgetValues.max} ${testData.unit}`); - - cy.get(`[data-qa-graph-column-title="Avg"]`) - .should('be.visible') - .should('have.text', `${expectedWidgetValues.average} ${testData.unit}`); - - cy.get(`[data-qa-graph-column-title="Last"]`) - .should('be.visible') - .should('have.text', `${expectedWidgetValues.last} ${testData.unit}`); + .should('be.visible') + .should( + 'have.text', + `${expectedWidgetValues.max} ${testData.unit}` + ); + + cy.get(`[data-qa-graph-column-title="Avg"]`) + .should('be.visible') + .should( + 'have.text', + `${expectedWidgetValues.average} ${testData.unit}` + ); + + cy.get(`[data-qa-graph-column-title="Last"]`) + .should('be.visible') + .should( + 'have.text', + `${expectedWidgetValues.last} ${testData.unit}` + ); }); // click zoom out and validate the same @@ -359,16 +388,25 @@ describe('Integration Tests for Linode Dashboard ', () => { 'be.visible' ); cy.get(`[data-qa-graph-column-title="Max"]`) - .should('be.visible') - .should('have.text', `${expectedWidgetValues.max} ${testData.unit}`); - - cy.get(`[data-qa-graph-column-title="Avg"]`) - .should('be.visible') - .should('have.text', `${expectedWidgetValues.average} ${testData.unit}`); - - cy.get(`[data-qa-graph-column-title="Last"]`) - .should('be.visible') - .should('have.text', `${expectedWidgetValues.last} ${testData.unit}`); + .should('be.visible') + .should( + 'have.text', + `${expectedWidgetValues.max} ${testData.unit}` + ); + + cy.get(`[data-qa-graph-column-title="Avg"]`) + .should('be.visible') + .should( + 'have.text', + `${expectedWidgetValues.average} ${testData.unit}` + ); + + cy.get(`[data-qa-graph-column-title="Last"]`) + .should('be.visible') + .should( + 'have.text', + `${expectedWidgetValues.last} ${testData.unit}` + ); }); }); }); diff --git a/packages/manager/src/queries/cloudpulse/metrics.ts b/packages/manager/src/queries/cloudpulse/metrics.ts index 7f46adc3b3c..88b6adf02d9 100644 --- a/packages/manager/src/queries/cloudpulse/metrics.ts +++ b/packages/manager/src/queries/cloudpulse/metrics.ts @@ -38,7 +38,7 @@ export const useCloudPulseMetricsQuery = ( ), enabled: !!obj.isFlags, - refetchInterval: 1800000, + refetchInterval: 120000, refetchOnWindowFocus: false, retry: 0, }); From 13ffe73b87539407737591e5d406e396e365a34b Mon Sep 17 00:00:00 2001 From: agorthi Date: Sat, 5 Oct 2024 13:13:43 +0530 Subject: [PATCH 133/474] upcoming:[DI-20585]- Added code review comments --- packages/manager/src/factories/dashboards.ts | 86 +++---------------- .../Overview/GlobalFilters.test.tsx | 2 +- 2 files changed, 15 insertions(+), 73 deletions(-) diff --git a/packages/manager/src/factories/dashboards.ts b/packages/manager/src/factories/dashboards.ts index f812a23304a..fc5fd52308b 100644 --- a/packages/manager/src/factories/dashboards.ts +++ b/packages/manager/src/factories/dashboards.ts @@ -22,23 +22,6 @@ const scrape_interval = ['2m', '30s', '30s', '30s']; * @param {string} service - The type of service to be assigned to the dashboard. * * @returns {Factory} A Factory instance for creating `Dashboard` objects with the specified properties. - * - * @description - * This function uses the `Factory.Sync.makeFactory` method to create a factory for generating `Dashboard` objects. - * The created `Dashboard` object includes: - * - `created`: A timestamp for when the dashboard was created, in ISO string format. - * - `id`: A unique identifier for the dashboard, generated sequentially based on the factory's index. - * - `label`: The label provided via the `dashboardLabel` parameter. - * - `service_type`: The service type provided via the `service` parameter. - * - `time_duration`: An object with a unit of 'min' and a value of 30 minutes, indicating the time duration. - * - `updated`: A timestamp for when the dashboard was last updated, in ISO string format. - * - `widgets`: A list of widgets generated by the `widgetFactory` function. The number of widgets created is equal to the length of the `widgetLabels` array. - * - * Usage Example: - * ```typescript - * const myDashboardFactory = dashboardFactory('Main Dashboard', ['Widget1', 'Widget2'], ['Metric1', 'Metric2'], ['Y1', 'Y2'], 'ServiceA'); - * const myDashboard = myDashboardFactory.build(); // Creates a Dashboard instance with the specified properties. - * ``` */ export const dashboardFactory = Factory.Sync.makeFactory({ @@ -61,33 +44,6 @@ export const dashboardFactory = Factory.Sync.makeFactory({ * @param {string[]} y_labels - An array of Y-axis labels for the metrics. * * @returns {Factory} A Factory instance for creating `Widgets` objects with the specified properties. - * - * @description - * This function uses the `Factory.Sync.makeFactory` method to create a factory for generating `Widgets` objects. - * The created `Widgets` object includes: - * - `aggregate_function`: Set to 'avg' for averaging metric values. - * - `chart_type`: The type of chart for the widget, chosen from a predefined list (`chart_type`). - * - `color`: The color of the widget, chosen from a predefined list (`color`). - * - `filters`: An empty array of filters for the widget. - * - `group_by`: Set to 'region', indicating the grouping criterion for the widget data. - * - `label`: The label for the widget, chosen from the `widgetLabels` array. - * - `metric`: The metric associated with the widget, chosen from the `metricsLabels` array. - * - `namespace_id`: An identifier for the namespace, generated as the modulus of the index with 10. - * - `region_id`: An identifier for the region, generated as the modulus of the index with 5. - * - `resource_id`: A unique resource identifier formatted as `resource-{index}`. - * - `service_type`: Set to 'default', indicating the service type. - * - `serviceType`: Also set to 'default', similar to `service_type`. - * - `size`: Fixed size value of 12 for the widget. - * - `time_duration`: An object with a unit of 'min' and a value of 30 minutes, representing the time duration. - * - `time_granularity`: An object with a unit of 'hour' and a value of 1 hour, representing the granularity of time. - * - `unit`: The unit of measurement, chosen from a predefined list (`units`). - * - `y_label`: The Y-axis label for the widget, chosen from the `y_labels` array. - * - * Usage Example: - * ```typescript - * const myWidgetFactory = widgetFactory(['Widget1', 'Widget2'], ['Metric1', 'Metric2'], ['Y1', 'Y2']); - * const myWidget = myWidgetFactory.build(); // Creates a Widget instance with the specified properties. - * ``` */ export const widgetFactory = Factory.Sync.makeFactory({ aggregate_function: 'avg', @@ -95,8 +51,8 @@ export const widgetFactory = Factory.Sync.makeFactory({ color: Factory.each((i) => color[i % color.length]), filters: [], group_by: 'region', - label: Factory.each((i) => 'widget_label_' + i), - metric: Factory.each((i) => 'widget_metric_' + i), + label: Factory.each((i) => `widget_label_${i}`), + metric: Factory.each((i) => `widget_metric_${i}`), namespace_id: Factory.each((i) => i % 10), region_id: Factory.each((i) => i % 5), resource_id: Factory.each((i) => [`resource-${i}`]), @@ -112,7 +68,7 @@ export const widgetFactory = Factory.Sync.makeFactory({ value: 1, }, unit: 'defaultUnit', - y_label: Factory.each((i) => 'y_label_' + i), + y_label: Factory.each((i) => `y_label_${i}`), }); /** * Factory function to create instances of the `AvailableMetrics` model with predefined properties and values. @@ -122,36 +78,24 @@ export const widgetFactory = Factory.Sync.makeFactory({ * * @returns {Factory} A Factory instance for creating `AvailableMetrics` objects with the specified properties. * - * @description - * This function uses the `Factory.Sync.makeFactory` method to create a factory for generating `AvailableMetrics` objects. - * The created `AvailableMetrics` object includes: - * - `available_aggregate_functions`: A fixed array of aggregate functions that can be applied to the metrics: `'min'`, `'max'`, `'avg'`, and `'sum'`. - * - `dimensions`: An empty array of dimensions for the metric. This property can be expanded if needed. - * - `label`: A label for the metric, chosen from the `widgetLabels` array. The label is selected based on the index modulo the length of `widgetLabels`, allowing for cycling through the provided labels. This property might be overridden if specified differently. - * - `metric`: A metric label chosen from the `metricsLabels` array. The metric is selected based on the index modulo the length of `metricsLabels`, allowing for cycling through the provided labels. This property might be overridden if specified differently. - * - `metric_type`: Set to `'gauge'`, indicating the type of metric. - * - `scrape_interval`: The interval at which metrics are scraped, chosen from a predefined list (`scrape_interval`). The value is selected based on the index modulo the length of `scrape_interval`. - * - `unit`: The unit of measurement for the metric, chosen from a predefined list (`units_interval`). The unit is selected based on the index modulo the length of `units_interval`. - * ``` */ -export const dashboardMetricFactory = Factory.Sync.makeFactory( - { +export const dashboardMetricFactory = + Factory.Sync.makeFactory({ available_aggregate_functions: ['min', 'max', 'avg', 'sum'], dimensions: [], - label: Factory.each((i) => 'widget_label_' + i), // This might be overridden - metric: Factory.each((i) => 'widget_metric_' + i), // This might be overridden + label: Factory.each((i) => `widget_label_${i}`), // This might be overridden + metric: Factory.each((i) => `widget_metric_${i}`), // This might be overridden metric_type: 'gauge', scrape_interval: Factory.each( (i) => scrape_interval[i % scrape_interval.length] ), unit: 'defaultUnit', - } -); + }); // Factory for CloudPulseMetricsResponseData -export const cloudPulseMetricsResponseDataFactory = Factory.Sync.makeFactory( - { +export const cloudPulseMetricsResponseDataFactory = + Factory.Sync.makeFactory({ result: [ { metric: {}, @@ -159,17 +103,15 @@ export const cloudPulseMetricsResponseDataFactory = Factory.Sync.makeFactory( - { +export const cloudPulseMetricsResponseFactory = + Factory.Sync.makeFactory({ data: cloudPulseMetricsResponseDataFactory.build(), // Use the data factory here isPartial: false, stats: { series_fetched: 2, // Adjust based on the number of metrics }, status: 'success', - } -); + }); diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.test.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.test.tsx index d2d9e9a2ebc..bdb9bc34884 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.test.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.test.tsx @@ -35,7 +35,7 @@ describe('Global filters component test', () => { expect(timeRangeSelect).toBeInTheDocument(); expect( - screen.getByRole('combobox', { name: 'Select Time Duration' }) + screen.getByRole('combobox', { name: 'Select a Time Duration' }) ).toHaveAttribute('value', 'Last 30 Minutes'); }); }); From 5e67e04f7e4c051c152daa28779b2708dc10a969 Mon Sep 17 00:00:00 2001 From: agorthi Date: Sat, 5 Oct 2024 13:33:30 +0530 Subject: [PATCH 134/474] upcoming:[DI-20585]- Added code review comments --- packages/manager/src/factories/dashboards.ts | 45 +++----------------- 1 file changed, 7 insertions(+), 38 deletions(-) diff --git a/packages/manager/src/factories/dashboards.ts b/packages/manager/src/factories/dashboards.ts index fc5fd52308b..6183d04101c 100644 --- a/packages/manager/src/factories/dashboards.ts +++ b/packages/manager/src/factories/dashboards.ts @@ -12,18 +12,6 @@ const color = ['blue', 'red', 'green', 'yellow']; const chart_type = ['area', 'area', 'area', 'line']; const scrape_interval = ['2m', '30s', '30s', '30s']; -/** - * Factory function to create instances of the `Dashboard` model with predefined properties and values. - * - * @param {string} dashboardLabel - The label to assign to the dashboard instance. - * @param {string[]} widgetLabels - An array of labels for widgets to be included in the dashboard. - * @param {string[]} metricsLabels - An array of labels for metrics associated with the widgets. - * @param {string[]} y_labels - An array of Y-axis labels for the metrics. - * @param {string} service - The type of service to be assigned to the dashboard. - * - * @returns {Factory} A Factory instance for creating `Dashboard` objects with the specified properties. - */ - export const dashboardFactory = Factory.Sync.makeFactory({ created: new Date().toISOString(), id: Factory.each((i) => i), @@ -36,15 +24,7 @@ export const dashboardFactory = Factory.Sync.makeFactory({ updated: new Date().toISOString(), widgets: [], }); -/** - * Factory function to create instances of the `Widgets` model with predefined properties and values. - * - * @param {string[]} widgetLabels - An array of labels for widgets to be created. - * @param {string[]} metricsLabels - An array of metrics labels associated with each widget. - * @param {string[]} y_labels - An array of Y-axis labels for the metrics. - * - * @returns {Factory} A Factory instance for creating `Widgets` objects with the specified properties. - */ + export const widgetFactory = Factory.Sync.makeFactory({ aggregate_function: 'avg', chart_type: Factory.each((i) => chart_type[i % chart_type.length]), @@ -70,22 +50,13 @@ export const widgetFactory = Factory.Sync.makeFactory({ unit: 'defaultUnit', y_label: Factory.each((i) => `y_label_${i}`), }); -/** - * Factory function to create instances of the `AvailableMetrics` model with predefined properties and values. - * - * @param {string[]} widgetLabels - An array of labels for widgets that will be associated with the metrics. - * @param {string[]} metricsLabels - An array of labels for metrics to be used in the `AvailableMetrics` instances. - * - * @returns {Factory} A Factory instance for creating `AvailableMetrics` objects with the specified properties. - * - */ export const dashboardMetricFactory = Factory.Sync.makeFactory({ available_aggregate_functions: ['min', 'max', 'avg', 'sum'], dimensions: [], - label: Factory.each((i) => `widget_label_${i}`), // This might be overridden - metric: Factory.each((i) => `widget_metric_${i}`), // This might be overridden + label: Factory.each((i) => `widget_label_${i}`), + metric: Factory.each((i) => `widget_metric_${i}`), metric_type: 'gauge', scrape_interval: Factory.each( (i) => scrape_interval[i % scrape_interval.length] @@ -93,25 +64,23 @@ export const dashboardMetricFactory = unit: 'defaultUnit', }); -// Factory for CloudPulseMetricsResponseData export const cloudPulseMetricsResponseDataFactory = Factory.Sync.makeFactory({ result: [ { metric: {}, - values: [], // Generate 10 data points with 1-minute interval + values: [], }, ], - result_type: 'matrix', // Default result type + result_type: 'matrix', }); -// Factory for CloudPulseMetricsResponse export const cloudPulseMetricsResponseFactory = Factory.Sync.makeFactory({ - data: cloudPulseMetricsResponseDataFactory.build(), // Use the data factory here + data: cloudPulseMetricsResponseDataFactory.build(), isPartial: false, stats: { - series_fetched: 2, // Adjust based on the number of metrics + series_fetched: 2, }, status: 'success', }); From 51ef45f0d8089694dc5d2bb6de7d37e45eb62d56 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Sat, 5 Oct 2024 17:18:06 +0530 Subject: [PATCH 135/474] upcoming: [DI-20800] - Bug fix --- .../CloudPulseDashboardFilterBuilder.tsx | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index 73bb56016ad..3209e57377d 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -65,7 +65,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( preferences, } = props; - const [, setDependentFilters] = React.useState<{ + const [dependentFilters, setDependentFilters] = React.useState<{ [key: string]: FilterValueType; }>({}); @@ -73,10 +73,6 @@ export const CloudPulseDashboardFilterBuilder = React.memo( const theme = useTheme(); - const dependentFilterReference: React.MutableRefObject<{ - [key: string]: FilterValueType; - }> = React.useRef({}); - const checkAndUpdateDependentFilters = React.useCallback( (filterKey: string, value: FilterValueType) => { if (dashboard && dashboard.service_type) { @@ -86,13 +82,16 @@ export const CloudPulseDashboardFilterBuilder = React.memo( for (const filter of filters) { if ( Boolean(filter?.configuration.dependency?.length) && - filter?.configuration.dependency?.includes(filterKey) && - dependentFilterReference.current[filterKey] !== value + filter?.configuration.dependency?.includes(filterKey) ) { - dependentFilterReference.current[filterKey] = value; - setDependentFilters(() => ({ - ...dependentFilterReference.current, - })); + // Use the functional form to ensure you're always working with the latest state + setDependentFilters((prev) => { + // Only update if the value is different + if (prev[filterKey] !== value) { + return { ...prev, [filterKey]: value }; + } + return prev; // If no change, return the previous state + }); break; } } @@ -185,7 +184,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( { config, dashboard, - dependentFilters: dependentFilterReference.current, + dependentFilters: dependentFilters, isServiceAnalyticsIntegration, preferences, }, @@ -196,7 +195,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( { config, dashboard, - dependentFilters: dependentFilterReference.current, + dependentFilters: dependentFilters, isServiceAnalyticsIntegration, preferences, }, @@ -211,6 +210,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( handleCustomSelectChange, isServiceAnalyticsIntegration, preferences, + dependentFilters, ] ); @@ -218,7 +218,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( setShowFilter((showFilterPrev) => !showFilterPrev); }; - const RenderFilters = React.useCallback(() => { + const RenderFilters = React.useMemo(() => { const filters = FILTER_CONFIG.get(dashboard.service_type)?.filters || []; if (!filters || filters.length === 0) { @@ -251,7 +251,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( })} )); - }, [dashboard, getProps, isServiceAnalyticsIntegration]); + }, [dashboard, getProps, isServiceAnalyticsIntegration, dependentFilters]); if ( !dashboard || @@ -315,7 +315,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( rowGap={2} xs={12} > - + {RenderFilters} ); @@ -330,6 +330,6 @@ function compareProps( return ( oldProps.dashboard?.id === newProps.dashboard?.id && oldProps.preferences?.[DASHBOARD_ID] === - newProps.preferences?.[DASHBOARD_ID] + newProps.preferences?.[DASHBOARD_ID] ); } From 90607048e5546c7390da524b9bc57f7721d29415 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Sun, 6 Oct 2024 09:59:16 +0530 Subject: [PATCH 136/474] upcoming: [DI-20800] - Remove unused dependency --- .../CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index 3209e57377d..590c9e48cb8 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -251,7 +251,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( })} )); - }, [dashboard, getProps, isServiceAnalyticsIntegration, dependentFilters]); + }, [dashboard, getProps, isServiceAnalyticsIntegration]); if ( !dashboard || From 433287d92a9d66b912d0d6d83e21d1db9fc0706b Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 7 Oct 2024 11:48:53 +0530 Subject: [PATCH 137/474] upcoming: [DI-21254] - Handle unit using reference values --- .../CloudPulse/Widget/CloudPulseWidget.tsx | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 202d8f3466a..c274620ae0e 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -116,7 +116,7 @@ export interface LegendRow { legendTitle: string; } -export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { +export const CloudPulseWidget = React.memo((props: CloudPulseWidgetProperties) => { const { updateWidgetPreference: updatePreferences } = useAclpPreference(); const { data: profile } = useProfile(); const timezone = profile?.timezone ?? DateTime.local().zoneName; @@ -140,6 +140,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { widget: widgetProp, } = props; const flags = useFlags(); + const scaledWidgetUnit = React.useRef(unit === 'Bytes' ? 'B' : unit); const jweTokenExpiryError = 'Token expired'; @@ -237,8 +238,6 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { let legendRows: LegendRow[] = []; let today: boolean = false; - - let currentUnit = unit; if (!isLoading && metricsList) { const generatedData = generateGraphData({ flags, @@ -255,7 +254,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { data = generatedData.dimensions; legendRows = generatedData.legendRowsData; today = generatedData.today; - currentUnit = generatedData.unit; + scaledWidgetUnit.current = scaledWidgetUnit.current !== generatedData.unit ? generatedData.unit : scaledWidgetUnit.current; // here state doesn't matter, as this is always the latest re-render } const metricsApiCallError = error?.[0]?.reason; @@ -273,7 +272,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { padding={1} > - {convertStringToCamelCasesWithSpaces(widget.label)} ({currentUnit} + {convertStringToCamelCasesWithSpaces(widget.label)} ({scaledWidgetUnit.current} {unit.endsWith('ps') ? '/s' : ''}) { {Boolean( availableMetrics?.available_aggregate_functions?.length ) && ( - - )} + + )} { } ariaLabel={ariaLabel ? ariaLabel : ''} data={data} - formatData={(data: number) => convertValueToUnit(data, currentUnit)} + formatData={(data: number) => convertValueToUnit(data, scaledWidgetUnit.current)} formatTooltip={(value: number) => formatToolTip(value, unit)} gridSize={widget.size} loading={isLoading || metricsApiCallError === jweTokenExpiryError} // keep loading until we fetch the refresh token @@ -333,4 +332,4 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { ); -}; +}); From 2904233e4d434d894523cdf206928d5c1e11bc73 Mon Sep 17 00:00:00 2001 From: Nikhil Agrawal <165884194+nikhagra-akamai@users.noreply.github.com> Date: Mon, 7 Oct 2024 14:38:44 +0530 Subject: [PATCH 138/474] Update CODEOWNERS --- CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/CODEOWNERS b/CODEOWNERS index 6143dc6f4a9..ef061bcfbf7 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,2 +1,3 @@ * @nikhagra-akamai * @venkymano-akamai +* @kmuddapo From 649af3e0a40c84e7c3ff86f79dc2d748a3c1129b Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 7 Oct 2024 14:41:23 +0530 Subject: [PATCH 139/474] upcoming: [DI-21254] - Handle unit using reference values --- .../manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index c274620ae0e..e005fb07979 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -254,7 +254,7 @@ export const CloudPulseWidget = React.memo((props: CloudPulseWidgetProperties) = data = generatedData.dimensions; legendRows = generatedData.legendRowsData; today = generatedData.today; - scaledWidgetUnit.current = scaledWidgetUnit.current !== generatedData.unit ? generatedData.unit : scaledWidgetUnit.current; // here state doesn't matter, as this is always the latest re-render + scaledWidgetUnit.current = generatedData.unit; // here state doesn't matter, as this is always the latest re-render } const metricsApiCallError = error?.[0]?.reason; From 239ead4968fdb204e05db96b707ba76a4bcbbc32 Mon Sep 17 00:00:00 2001 From: agorthi Date: Mon, 7 Oct 2024 15:29:26 +0530 Subject: [PATCH 140/474] upcoming:[DI-20585]- Added code review comments --- packages/manager/cypress/support/util/cloudpulse.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/manager/cypress/support/util/cloudpulse.ts b/packages/manager/cypress/support/util/cloudpulse.ts index 78c36f4b8d4..44c9ca8501e 100644 --- a/packages/manager/cypress/support/util/cloudpulse.ts +++ b/packages/manager/cypress/support/util/cloudpulse.ts @@ -1,13 +1,9 @@ // Function to generate random values based on the number of points import type { CloudPulseMetricsResponseData } from '@linode/api-v4'; +import type { Labels } from 'src/features/CloudPulse/shared/CloudPulseTimeRangeSelect'; export const generateRandomMetricsData = ( - time: - | 'Last 7 Days' - | 'Last 12 Hours' - | 'Last 24 Hours' - | 'Last 30 Days' - | 'Last 30 Minutes', + time: Labels, granularityData: '1 day' | '1 hr' | '5 min' | 'Auto' ): CloudPulseMetricsResponseData => { const currentTime = Math.floor(Date.now() / 1000); From 1672d1fafda4e8b5263229f15c436aaa301a26e7 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Mon, 7 Oct 2024 16:14:28 +0530 Subject: [PATCH 141/474] Update metrics api end point --- packages/manager/src/queries/cloudpulse/metrics.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/manager/src/queries/cloudpulse/metrics.ts b/packages/manager/src/queries/cloudpulse/metrics.ts index 88b6adf02d9..cc5e0fbe1c9 100644 --- a/packages/manager/src/queries/cloudpulse/metrics.ts +++ b/packages/manager/src/queries/cloudpulse/metrics.ts @@ -84,9 +84,7 @@ export const fetchCloudPulseMetrics = ( Authorization: `Bearer ${token}`, }, method: 'POST', - url: `https://metrics-query.aclp.linode.com/v1/monitor/services/${encodeURIComponent( - serviceType! - )}/metrics`, + url: `${readApiEndpoint}${encodeURIComponent(serviceType!)}/metrics`, }; return axiosInstance From 57702a7785884a00cbb9e74e06a04f0b7319a456 Mon Sep 17 00:00:00 2001 From: Nikhil Agrawal <165884194+nikhagra-akamai@users.noreply.github.com> Date: Mon, 7 Oct 2024 16:27:44 +0530 Subject: [PATCH 142/474] Update CODEOWNERS --- CODEOWNERS | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index ef061bcfbf7..fd2b17cc4b5 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,3 +1 @@ -* @nikhagra-akamai -* @venkymano-akamai -* @kmuddapo +* @ACLPManager/reviewers From 4de8781171c7f17defeb12372c18035e78d6b1b8 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Mon, 7 Oct 2024 16:42:35 +0530 Subject: [PATCH 143/474] Updated non-null assertions --- packages/manager/src/queries/cloudpulse/metrics.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/queries/cloudpulse/metrics.ts b/packages/manager/src/queries/cloudpulse/metrics.ts index cc5e0fbe1c9..4f6f23622ab 100644 --- a/packages/manager/src/queries/cloudpulse/metrics.ts +++ b/packages/manager/src/queries/cloudpulse/metrics.ts @@ -84,7 +84,7 @@ export const fetchCloudPulseMetrics = ( Authorization: `Bearer ${token}`, }, method: 'POST', - url: `${readApiEndpoint}${encodeURIComponent(serviceType!)}/metrics`, + url: `${readApiEndpoint}${encodeURIComponent(serviceType)}/metrics`, }; return axiosInstance From 8563982a9280fe9911ae0a9eb7d4263da51f427d Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Mon, 7 Oct 2024 18:06:05 +0530 Subject: [PATCH 144/474] Handle new label property for services while selecting dashboard --- packages/api-v4/src/cloudpulse/types.ts | 1 + .../shared/CloudPulseDashboardSelect.test.tsx | 11 ++++- .../shared/CloudPulseDashboardSelect.tsx | 14 +++--- packages/manager/src/mocks/serverHandlers.ts | 45 ++++++++++++------- 4 files changed, 49 insertions(+), 22 deletions(-) diff --git a/packages/api-v4/src/cloudpulse/types.ts b/packages/api-v4/src/cloudpulse/types.ts index 9d24aca5857..19a5149c76a 100644 --- a/packages/api-v4/src/cloudpulse/types.ts +++ b/packages/api-v4/src/cloudpulse/types.ts @@ -126,6 +126,7 @@ export interface CloudPulseMetricsList { export interface ServiceTypes { service_type: string; + label: string; } export interface ServiceTypesList { diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx index 602e96d97aa..1da7044a395 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx @@ -46,7 +46,16 @@ queryMocks.useCloudPulseDashboardsQuery.mockReturnValue({ queryMocks.useCloudPulseServiceTypes.mockReturnValue({ data: { - data: [{ service_type: 'linode' }], + data: [ + { + label: 'Linode', + service_type: 'linode', + }, + { + label: 'Databases', + service_type: 'dbaas', + }, + ], }, }); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index 80ee4f335ad..1d9931bc55a 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -8,7 +8,7 @@ import { useCloudPulseServiceTypes } from 'src/queries/cloudpulse/services'; import { formattedServiceTypes, getAllDashboards } from '../Utils/utils'; -import type { Dashboard, FilterValue } from '@linode/api-v4'; +import type { Dashboard, FilterValue, ServiceTypes } from '@linode/api-v4'; export interface CloudPulseDashboardSelectProps { defaultValue?: Partial; @@ -66,6 +66,7 @@ export const CloudPulseDashboardSelect = React.memo( (a, b) => -b.service_type.localeCompare(a.service_type) ); }; + // Once the data is loaded, set the state variable with value stored in preferences React.useEffect(() => { // only call this code when the component is rendered initially @@ -90,11 +91,12 @@ export const CloudPulseDashboardSelect = React.memo( }} renderGroup={(params) => ( - - {params.group} + + { + serviceTypesList?.data.find( + (type: ServiceTypes) => type.service_type === params.group + )?.label + } {params.children} diff --git a/packages/manager/src/mocks/serverHandlers.ts b/packages/manager/src/mocks/serverHandlers.ts index 2439c495cb6..4d7168f7558 100644 --- a/packages/manager/src/mocks/serverHandlers.ts +++ b/packages/manager/src/mocks/serverHandlers.ts @@ -256,8 +256,8 @@ const databases = [ params.engine === 'mysql' ? pickRandom(possibleMySQLReplicationTypes) : params.engine === 'postgresql' - ? pickRandom(possiblePostgresReplicationTypes) - : (undefined as any), + ? pickRandom(possiblePostgresReplicationTypes) + : (undefined as any), ssl_connection: true, storage_engine: params.engine === 'mongodb' ? 'wiredtiger' : undefined, }); @@ -1295,9 +1295,9 @@ export const handlers = [ headers.status === 'completed' ? accountMaintenanceFactory.buildList(30, { status: 'completed' }) : [ - ...accountMaintenanceFactory.buildList(90, { status: 'pending' }), - ...accountMaintenanceFactory.buildList(3, { status: 'started' }), - ]; + ...accountMaintenanceFactory.buildList(90, { status: 'pending' }), + ...accountMaintenanceFactory.buildList(3, { status: 'started' }), + ]; if (request.headers.get('x-filter')) { accountMaintenance.sort((a, b) => { @@ -1506,9 +1506,9 @@ export const handlers = [ const grantsResponse = grantsFactory.build({ global: parentAccountNonAdminUser.restricted ? { - cancel_account: false, - child_account_access: true, - } + cancel_account: false, + child_account_access: true, + } : undefined, }); return HttpResponse.json(grantsResponse); @@ -2306,24 +2306,39 @@ export const handlers = [ }), http.get('*/monitor/services', () => { const response = { - data: [{ service_type: 'linode' }], + data: [ + { + label: 'Linode', + service_type: 'linode', + }, + { + label: 'Databases', + service_type: 'dbaas', + }, + ], }; return HttpResponse.json(response); }), - http.get('*/monitor/services/:serviceType/dashboards', () => { + http.get('*/monitor/services/:serviceType/dashboards', ({ params }) => { const response = { - data: [ + data: [] as any[], + }; + if (params.serviceType == 'linode') { + response.data.push( dashboardFactory.build({ label: 'Linode Dashboard', service_type: 'linode', - }), + }) + ); + } else if (params.serviceType == 'dbaas') { + response.data.push( dashboardFactory.build({ label: 'DBaaS Dashboard', service_type: 'dbaas', - }), - ], - }; + }) + ); + } return HttpResponse.json(response); }), From a439c4dc17356835b7d6b10b9ddf6c8226e97cf2 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Mon, 7 Oct 2024 19:07:05 +0530 Subject: [PATCH 145/474] upcoming: [DI-21351] - Fixed global filters change issue --- .../src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx index 734d20e6822..d7dcd399161 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx @@ -185,6 +185,7 @@ export const RenderWidgets = React.memo( 'jweToken', 'duration', 'resources', + 'additionalFilters', ]; for (const key of keysToCompare) { From 98f0c4ff325b7529e19e3063a68477bc80ef2e3e Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 8 Oct 2024 10:49:23 +0530 Subject: [PATCH 146/474] Revert "upcoming: [DI-20800] - Remove unused dependency" This reverts commit 90607048e5546c7390da524b9bc57f7721d29415. --- .../CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index 590c9e48cb8..3209e57377d 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -251,7 +251,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( })} )); - }, [dashboard, getProps, isServiceAnalyticsIntegration]); + }, [dashboard, getProps, isServiceAnalyticsIntegration, dependentFilters]); if ( !dashboard || From 1e693ae6798b1e0dee79cf1b485c4a5af2127669 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 8 Oct 2024 10:49:36 +0530 Subject: [PATCH 147/474] Revert "upcoming: [DI-20800] - Bug fix" This reverts commit 51ef45f0d8089694dc5d2bb6de7d37e45eb62d56. --- .../CloudPulseDashboardFilterBuilder.tsx | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index 3209e57377d..73bb56016ad 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -65,7 +65,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( preferences, } = props; - const [dependentFilters, setDependentFilters] = React.useState<{ + const [, setDependentFilters] = React.useState<{ [key: string]: FilterValueType; }>({}); @@ -73,6 +73,10 @@ export const CloudPulseDashboardFilterBuilder = React.memo( const theme = useTheme(); + const dependentFilterReference: React.MutableRefObject<{ + [key: string]: FilterValueType; + }> = React.useRef({}); + const checkAndUpdateDependentFilters = React.useCallback( (filterKey: string, value: FilterValueType) => { if (dashboard && dashboard.service_type) { @@ -82,16 +86,13 @@ export const CloudPulseDashboardFilterBuilder = React.memo( for (const filter of filters) { if ( Boolean(filter?.configuration.dependency?.length) && - filter?.configuration.dependency?.includes(filterKey) + filter?.configuration.dependency?.includes(filterKey) && + dependentFilterReference.current[filterKey] !== value ) { - // Use the functional form to ensure you're always working with the latest state - setDependentFilters((prev) => { - // Only update if the value is different - if (prev[filterKey] !== value) { - return { ...prev, [filterKey]: value }; - } - return prev; // If no change, return the previous state - }); + dependentFilterReference.current[filterKey] = value; + setDependentFilters(() => ({ + ...dependentFilterReference.current, + })); break; } } @@ -184,7 +185,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( { config, dashboard, - dependentFilters: dependentFilters, + dependentFilters: dependentFilterReference.current, isServiceAnalyticsIntegration, preferences, }, @@ -195,7 +196,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( { config, dashboard, - dependentFilters: dependentFilters, + dependentFilters: dependentFilterReference.current, isServiceAnalyticsIntegration, preferences, }, @@ -210,7 +211,6 @@ export const CloudPulseDashboardFilterBuilder = React.memo( handleCustomSelectChange, isServiceAnalyticsIntegration, preferences, - dependentFilters, ] ); @@ -218,7 +218,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( setShowFilter((showFilterPrev) => !showFilterPrev); }; - const RenderFilters = React.useMemo(() => { + const RenderFilters = React.useCallback(() => { const filters = FILTER_CONFIG.get(dashboard.service_type)?.filters || []; if (!filters || filters.length === 0) { @@ -251,7 +251,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( })} )); - }, [dashboard, getProps, isServiceAnalyticsIntegration, dependentFilters]); + }, [dashboard, getProps, isServiceAnalyticsIntegration]); if ( !dashboard || @@ -315,7 +315,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( rowGap={2} xs={12} > - {RenderFilters} + ); @@ -330,6 +330,6 @@ function compareProps( return ( oldProps.dashboard?.id === newProps.dashboard?.id && oldProps.preferences?.[DASHBOARD_ID] === - newProps.preferences?.[DASHBOARD_ID] + newProps.preferences?.[DASHBOARD_ID] ); } From 4afa89a94bde24e7a5b2ceb7359933c24f39cb48 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 8 Oct 2024 11:09:20 +0530 Subject: [PATCH 148/474] upcoming: [DI-21322] - Use deep equal logic for bug fix --- .../CloudPulse/Utils/FilterBuilder.test.ts | 37 ++++++++++ .../CloudPulse/Utils/FilterBuilder.ts | 67 +++++++++++++++++++ .../CloudPulseDashboardFilterBuilder.tsx | 2 +- .../shared/CloudPulseResourcesSelect.tsx | 4 +- 4 files changed, 108 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.test.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.test.ts index 1c4b5894d7d..6687ebbb561 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.test.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.test.ts @@ -2,6 +2,7 @@ import { dashboardFactory } from 'src/factories'; import { databaseQueries } from 'src/queries/databases/databases'; import { RESOURCES } from './constants'; +import { deepEqual } from './FilterBuilder'; import { buildXFilter, checkIfAllMandatoryFiltersAreSelected, @@ -264,3 +265,39 @@ it('test constructAdditionalRequestFilters method', () => { expect(result).toBeDefined(); expect(result.length).toEqual(0); }); + +it('returns true for identical primitive values', () => { + expect(deepEqual(1, 1)).toBe(true); + expect(deepEqual('test', 'test')).toBe(true); + expect(deepEqual(true, true)).toBe(true); +}); + +it('returns false for different primitive values', () => { + expect(deepEqual(1, 2)).toBe(false); + expect(deepEqual('test', 'other')).toBe(false); + expect(deepEqual(true, false)).toBe(false); +}); + +it('returns true for identical objects', () => { + const obj1 = { a: 1, b: { c: 2 } }; + const obj2 = { a: 1, b: { c: 2 } }; + expect(deepEqual(obj1, obj2)).toBe(true); +}); + +it('returns false for different objects', () => { + const obj1 = { a: 1, b: { c: 2 } }; + const obj2 = { a: 1, b: { c: 3 } }; + expect(deepEqual(obj1, obj2)).toBe(false); +}); + +it('returns true for identical arrays', () => { + const arr1 = [1, 2, 3]; + const arr2 = [1, 2, 3]; + expect(deepEqual(arr1, arr2)).toBe(true); +}); + +it('returns false for different arrays', () => { + const arr1 = [1, 2, 3]; + const arr2 = [1, 2, 4]; + expect(deepEqual(arr1, arr2)).toBe(false); +}); diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts index 2a0ee2cd64a..7e415e6c756 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts @@ -373,3 +373,70 @@ const getDependentFiltersByFilterKey = ( : configuration.filterKey ); }; + + +/** + * @param obj1 The first object to be compared + * @param obj2 The second object to be compared + * @returns True if, both are equal else false + */ +export const deepEqual = (obj1: T, obj2: T): boolean => { + if (obj1 === obj2) { + return true; // Identical references or values + } + + // If either is null or undefined, or they are not of object type, return false + if ( + obj1 === null || + obj2 === null || + typeof obj1 !== 'object' || + typeof obj2 !== 'object' + ) { + return false; + } + + // Handle array comparison separately + if (Array.isArray(obj1) && Array.isArray(obj2)) { + return compareArrays(obj1, obj2); + } + + // Ensure both objects have the same number of keys + const keys1 = Object.keys(obj1); + const keys2 = Object.keys(obj2); + + if (keys1.length !== keys2.length) { + return false; + } + + // Recursively check each key + for (const key of keys1) { + if (!(key in obj2)) { + return false; + } + // Recursive deep equal check + if (!deepEqual((obj1 as any)[key], (obj2 as any)[key])) { + return false; + } + } + + return true; +}; + +/** + * @param arr1 Array for comparison + * @param arr2 Array for comparison + * @returns True if, both the arrays are equal, else false + */ +const compareArrays = (arr1: T[], arr2: T[]): boolean => { + if (arr1.length !== arr2.length) { + return false; + } + + for (let i = 0; i < arr1.length; i++) { + if (!deepEqual(arr1[i], arr2[i])) { + return false; + } + } + + return true; +}; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index 73bb56016ad..c4818562563 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -330,6 +330,6 @@ function compareProps( return ( oldProps.dashboard?.id === newProps.dashboard?.id && oldProps.preferences?.[DASHBOARD_ID] === - newProps.preferences?.[DASHBOARD_ID] + newProps.preferences?.[DASHBOARD_ID] ); } diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index 12cde9bcdce..319ab5d3b46 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -4,6 +4,8 @@ import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; import { useResourcesQuery } from 'src/queries/cloudpulse/resources'; import { themes } from 'src/utilities/theme'; +import { deepEqual } from '../Utils/FilterBuilder'; + import type { Filter, FilterValue } from '@linode/api-v4'; export interface CloudPulseResources { @@ -144,7 +146,7 @@ function compareProps( return false; } } - if (prevProps.xFilter !== nextProps.xFilter) { + if (!deepEqual(prevProps.xFilter, nextProps.xFilter)) { return false; } From 6cec8fd9d98cc9ca1e6404636cf5110afb4dc164 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 8 Oct 2024 11:11:14 +0530 Subject: [PATCH 149/474] upcoming: [DI-21322] - Contextual view changes --- .../src/features/Databases/DatabaseDetail/index.tsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/manager/src/features/Databases/DatabaseDetail/index.tsx b/packages/manager/src/features/Databases/DatabaseDetail/index.tsx index 7673d0a71d8..cd2ed2b7ad4 100644 --- a/packages/manager/src/features/Databases/DatabaseDetail/index.tsx +++ b/packages/manager/src/features/Databases/DatabaseDetail/index.tsx @@ -24,6 +24,7 @@ import { getAPIErrorOrDefault } from 'src/utilities/errorUtils'; import type { Engine } from '@linode/api-v4/lib/databases/types'; import type { APIError } from '@linode/api-v4/lib/types'; +import { CloudPulseDashboardWithFilters } from 'src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters'; const DatabaseSummary = React.lazy(() => import('./DatabaseSummary')); const DatabaseBackups = React.lazy(() => import('./DatabaseBackups')); @@ -104,6 +105,11 @@ export const DatabaseDetail = () => { }); } + tabs.push({ + routeName: `/databases/${engine}/${id}/monitor`, + title: 'Monitor', + }); + const getTabIndex = () => { const tabChoice = tabs.findIndex((tab) => Boolean(matchPath(tab.routeName, { path: location.pathname })) @@ -202,6 +208,12 @@ export const DatabaseDetail = () => { disabled={isDatabasesGrantReadOnly} /> + + + {database.platform === 'rdbms-default' && } From 4e4c0c625dcf5d994afab42ea2af55275ae75ab9 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Tue, 8 Oct 2024 14:09:45 +0530 Subject: [PATCH 150/474] eslint finishing --- packages/manager/src/mocks/serverHandlers.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/manager/src/mocks/serverHandlers.ts b/packages/manager/src/mocks/serverHandlers.ts index 4d7168f7558..b65a2f9b3cc 100644 --- a/packages/manager/src/mocks/serverHandlers.ts +++ b/packages/manager/src/mocks/serverHandlers.ts @@ -256,8 +256,8 @@ const databases = [ params.engine === 'mysql' ? pickRandom(possibleMySQLReplicationTypes) : params.engine === 'postgresql' - ? pickRandom(possiblePostgresReplicationTypes) - : (undefined as any), + ? pickRandom(possiblePostgresReplicationTypes) + : (undefined as any), ssl_connection: true, storage_engine: params.engine === 'mongodb' ? 'wiredtiger' : undefined, }); @@ -1295,9 +1295,9 @@ export const handlers = [ headers.status === 'completed' ? accountMaintenanceFactory.buildList(30, { status: 'completed' }) : [ - ...accountMaintenanceFactory.buildList(90, { status: 'pending' }), - ...accountMaintenanceFactory.buildList(3, { status: 'started' }), - ]; + ...accountMaintenanceFactory.buildList(90, { status: 'pending' }), + ...accountMaintenanceFactory.buildList(3, { status: 'started' }), + ]; if (request.headers.get('x-filter')) { accountMaintenance.sort((a, b) => { @@ -1506,9 +1506,9 @@ export const handlers = [ const grantsResponse = grantsFactory.build({ global: parentAccountNonAdminUser.restricted ? { - cancel_account: false, - child_account_access: true, - } + cancel_account: false, + child_account_access: true, + } : undefined, }); return HttpResponse.json(grantsResponse); From 6f3d50a7c08d1881326561f7e1336d7d0434b9b1 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Tue, 8 Oct 2024 15:25:50 +0530 Subject: [PATCH 151/474] upcoming: [DI-21359] - Added auto interval option as defaut interval value if pref is not available --- .../features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx | 5 +++-- .../Widget/components/CloudPulseIntervalSelect.tsx | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx index d7dcd399161..87c2ec319ed 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx @@ -8,6 +8,7 @@ import { createObjectCopy } from '../Utils/utils'; import { CloudPulseWidget } from './CloudPulseWidget'; import { allIntervalOptions, + autoIntervalOption, getInSeconds, getIntervalIndex, } from './components/CloudPulseIntervalSelect'; @@ -80,7 +81,7 @@ export const RenderWidgets = React.memo( serviceType: dashboard?.service_type ?? '', timeStamp: manualRefreshTimeStamp, unit: widget.unit ?? '%', - widget: { ...widget }, + widget: { ...widget, time_granularity: autoIntervalOption }, }; if (savePref) { graphProp.widget = setPreferredWidgetPlan(graphProp.widget); @@ -104,7 +105,7 @@ export const RenderWidgets = React.memo( pref.aggregateFunction ?? widgetObj.aggregate_function, size: pref.size ?? widgetObj.size, time_granularity: { - ...(pref.timeGranularity ?? widgetObj.time_granularity), + ...(pref.timeGranularity ?? autoIntervalOption), }, }; } else { diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx index 8f00fcbd7a9..410b4a6de79 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx @@ -69,7 +69,7 @@ export const allIntervalOptions: IntervalOptions[] = [ }, ]; -const autoIntervalOption: IntervalOptions = { +export const autoIntervalOption: IntervalOptions = { label: 'Auto', unit: 'Auto', value: -1, From 2a7a5c69df8edcf677e9b54f5deda1b3c8de815c Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Tue, 8 Oct 2024 16:16:54 +0530 Subject: [PATCH 152/474] upcoming: [DI-20837] - Updated with the latest pr standards --- packages/manager/src/mocks/serverHandlers.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/manager/src/mocks/serverHandlers.ts b/packages/manager/src/mocks/serverHandlers.ts index b65a2f9b3cc..42b813aa6d3 100644 --- a/packages/manager/src/mocks/serverHandlers.ts +++ b/packages/manager/src/mocks/serverHandlers.ts @@ -110,6 +110,7 @@ import { pickRandom } from 'src/utilities/random'; import type { AccountMaintenance, CreateObjectStorageKeyPayload, + Dashboard, FirewallStatus, NotificationType, ObjectStorageEndpointTypes, @@ -2322,16 +2323,16 @@ export const handlers = [ }), http.get('*/monitor/services/:serviceType/dashboards', ({ params }) => { const response = { - data: [] as any[], + data: [] as Dashboard[], }; - if (params.serviceType == 'linode') { + if (params.serviceType === 'linode') { response.data.push( dashboardFactory.build({ label: 'Linode Dashboard', service_type: 'linode', }) ); - } else if (params.serviceType == 'dbaas') { + } else if (params.serviceType === 'dbaas') { response.data.push( dashboardFactory.build({ label: 'DBaaS Dashboard', From 12fb8c9ccbdd07fadc245da03074c0f81fa5ccb9 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Tue, 8 Oct 2024 16:44:29 +0530 Subject: [PATCH 153/474] upcoming: [DI-20973] - Updated zeroth state message in contextual view --- .../CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx index e8f65dd6842..568dee51f04 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx @@ -148,7 +148,7 @@ export const CloudPulseDashboardWithFilters = React.memo( })} /> ) : ( - renderPlaceHolder('Mandatory Filters not Selected') + renderPlaceHolder('Select filters to visualize metrics.') )} ); From 848f96236ad1e7340e24c3cd02b849460a6f2017 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Tue, 8 Oct 2024 17:03:33 +0530 Subject: [PATCH 154/474] upcoming: [DI-20837] - Optimized label fetching --- .../CloudPulse/shared/CloudPulseDashboardSelect.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index 1d9931bc55a..b992fb6fce9 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -30,6 +30,9 @@ export const CloudPulseDashboardSelect = React.memo( } = useCloudPulseServiceTypes(true); const serviceTypes: string[] = formattedServiceTypes(serviceTypesList); + const serviceTypeMap: Map = new Map( + serviceTypesList?.data.map(item => [item.service_type, item.label]) + ); const { data: dashboardsList, @@ -92,11 +95,7 @@ export const CloudPulseDashboardSelect = React.memo( renderGroup={(params) => ( - { - serviceTypesList?.data.find( - (type: ServiceTypes) => type.service_type === params.group - )?.label - } + {serviceTypeMap.get(params.group)} {params.children} From 90014d5a1c52f97768f0419ada58d6ce842dba6f Mon Sep 17 00:00:00 2001 From: vmangalr Date: Wed, 9 Oct 2024 10:41:24 +0530 Subject: [PATCH 155/474] upcoming: [DI-20800] - We don't need memo here in CloudPulseWidget --- .../CloudPulse/Widget/CloudPulseWidget.tsx | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 66a648b6c67..2f0e8d37783 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -116,7 +116,7 @@ export interface LegendRow { legendTitle: string; } -export const CloudPulseWidget = React.memo((props: CloudPulseWidgetProperties) => { +export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { const { updateWidgetPreference: updatePreferences } = useAclpPreference(); const { data: profile } = useProfile(); const timezone = profile?.timezone ?? DateTime.local().zoneName; @@ -275,7 +275,8 @@ export const CloudPulseWidget = React.memo((props: CloudPulseWidgetProperties) = padding={1} > - {convertStringToCamelCasesWithSpaces(widget.label)} ({scaledWidgetUnit.current} + {convertStringToCamelCasesWithSpaces(widget.label)} ( + {scaledWidgetUnit.current} {unit.endsWith('ps') ? '/s' : ''}) - )} + + )} + convertValueToUnit(data, scaledWidgetUnit.current) + } legendRows={ legendRows && legendRows.length > 0 ? legendRows : undefined } ariaLabel={ariaLabel ? ariaLabel : ''} data={data} - formatData={(data: number) => convertValueToUnit(data, scaledWidgetUnit.current)} formatTooltip={(value: number) => formatToolTip(value, unit)} gridSize={widget.size} loading={isLoading || metricsApiCallError === jweTokenExpiryError} // keep loading until we fetch the refresh token @@ -335,4 +338,4 @@ export const CloudPulseWidget = React.memo((props: CloudPulseWidgetProperties) = ); -}); +}; From c9daf9cd439d13766bafdf4e72dda5bb1dd16aa3 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Wed, 9 Oct 2024 11:17:09 +0530 Subject: [PATCH 156/474] upcoming: [DI-20800] - UT updates --- .../Dashboard/CloudPulseDashboardWithFilters.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.test.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.test.tsx index 68bf5750647..e4c64282ec7 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.test.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.test.tsx @@ -11,7 +11,7 @@ const queryMocks = vi.hoisted(() => ({ })); const circleProgress = 'circle-progress'; -const mandatoryFiltersError = 'Mandatory Filters not Selected'; +const mandatoryFiltersError = 'Select filters to visualize metrics.'; vi.mock('src/queries/cloudpulse/dashboards', async () => { const actual = await vi.importActual('src/queries/cloudpulse/dashboards'); From a3d15ad65db030f8e2c73f05680efe8b6de81863 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Wed, 9 Oct 2024 11:21:30 +0530 Subject: [PATCH 157/474] upcoming: [DI-20800] - Unused variable fix --- packages/manager/src/MainContent.tsx | 2 -- packages/manager/src/components/PrimaryNav/PrimaryNav.tsx | 1 - 2 files changed, 3 deletions(-) diff --git a/packages/manager/src/MainContent.tsx b/packages/manager/src/MainContent.tsx index 76cf84f2e1e..14fc456eee5 100644 --- a/packages/manager/src/MainContent.tsx +++ b/packages/manager/src/MainContent.tsx @@ -231,8 +231,6 @@ export const MainContent = () => { const { data: accountSettings } = useAccountSettings(); const defaultRoot = accountSettings?.managed ? '/managed' : '/linodes'; - const { isACLPEnabled } = useIsACLPEnabled(); - /** * this is the case where the user has successfully completed signup * but needs a manual review from Customer Support. In this case, diff --git a/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx b/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx index 4c09e9582cd..7a58c8319b0 100644 --- a/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx +++ b/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx @@ -189,7 +189,6 @@ export const PrimaryNav = (props: PrimaryNavProps) => { }, { display: 'Monitor', - // hide: !isACLPEnabled, href: '/monitor/cloudpulse', icon: , isBeta: flags.aclp?.beta, From b30f2dd149508b746b166af17d421bba1b53ae53 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 9 Oct 2024 13:01:19 +0530 Subject: [PATCH 158/474] upcoming: [DI-20973] - Updated cloudpulse icon contextual view --- .../Dashboard/CloudPulseDashboardWithFilters.tsx | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx index 568dee51f04..4e6d958e87b 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx @@ -1,14 +1,13 @@ -import { Grid, styled } from '@mui/material'; +import { Grid } from '@mui/material'; import React from 'react'; -import CloudPulseIcon from 'src/assets/icons/entityIcons/monitor.svg'; import { CircleProgress } from 'src/components/CircleProgress'; import { ErrorState } from 'src/components/ErrorState/ErrorState'; import { Paper } from 'src/components/Paper'; -import { Placeholder } from 'src/components/Placeholder/Placeholder'; import { useCloudPulseDashboardByIdQuery } from 'src/queries/cloudpulse/dashboards'; import { CloudPulseDashboardFilterBuilder } from '../shared/CloudPulseDashboardFilterBuilder'; +import { CloudPulseErrorPlaceholder } from '../shared/CloudPulseErrorPlaceholder'; import { CloudPulseTimeRangeSelect } from '../shared/CloudPulseTimeRangeSelect'; import { FILTER_CONFIG } from '../Utils/FilterConfig'; import { @@ -65,7 +64,7 @@ export const CloudPulseDashboardWithFilters = React.memo( const renderPlaceHolder = (title: string) => { return ( - + ); }; @@ -154,10 +153,3 @@ export const CloudPulseDashboardWithFilters = React.memo( ); } ); - -// keeping it here to avoid recreating -const StyledPlaceholder = styled(Placeholder, { - label: 'StyledPlaceholder', -})({ - flex: 'auto', -}); From cdf539131a3d3f91e1a99a0579ba92bedf5f178e Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Wed, 9 Oct 2024 16:06:19 +0530 Subject: [PATCH 159/474] upcoming: [DI-20837] - Added new factory for services --- packages/manager/src/factories/index.ts | 1 + packages/manager/src/factories/services.ts | 8 ++++++++ .../CloudPulse/shared/CloudPulseDashboardSelect.tsx | 4 +++- packages/manager/src/mocks/serverHandlers.ts | 12 +++++++----- 4 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 packages/manager/src/factories/services.ts diff --git a/packages/manager/src/factories/index.ts b/packages/manager/src/factories/index.ts index fc50d4ca726..673c3d1cd4e 100644 --- a/packages/manager/src/factories/index.ts +++ b/packages/manager/src/factories/index.ts @@ -52,6 +52,7 @@ export * from './vlans'; export * from './volume'; export * from './vpcs'; export * from './dashboards'; +export * from './services'; // Convert factory output to our itemsById pattern export const normalizeEntities = (entities: any[]) => { diff --git a/packages/manager/src/factories/services.ts b/packages/manager/src/factories/services.ts new file mode 100644 index 00000000000..d86e225a2d7 --- /dev/null +++ b/packages/manager/src/factories/services.ts @@ -0,0 +1,8 @@ +import Factory from 'src/factories/factoryProxy'; + +import type { ServiceTypes } from '@linode/api-v4'; + +export const serviceTypesFactory = Factory.Sync.makeFactory({ + label: Factory.each((i) => `Factory ServiceType-${i}`), + service_type: Factory.each((i) => `Factory ServiceType-${i}`), +}); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index b992fb6fce9..b1712074036 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -95,7 +95,9 @@ export const CloudPulseDashboardSelect = React.memo( renderGroup={(params) => ( - {serviceTypeMap.get(params.group)} + {serviceTypeMap.has(params.group) + ? serviceTypeMap.get(params.group) + : params.group} {params.children} diff --git a/packages/manager/src/mocks/serverHandlers.ts b/packages/manager/src/mocks/serverHandlers.ts index 42b813aa6d3..fd3163fcc59 100644 --- a/packages/manager/src/mocks/serverHandlers.ts +++ b/packages/manager/src/mocks/serverHandlers.ts @@ -85,6 +85,7 @@ import { promoFactory, regionAvailabilityFactory, securityQuestionsFactory, + serviceTypesFactory, stackScriptFactory, staticObjects, subnetFactory, @@ -115,6 +116,7 @@ import type { NotificationType, ObjectStorageEndpointTypes, SecurityQuestionsPayload, + ServiceTypesList, TokenRequest, UpdateImageRegionsPayload, User, @@ -2306,16 +2308,16 @@ export const handlers = [ return HttpResponse.json(response); }), http.get('*/monitor/services', () => { - const response = { + const response: ServiceTypesList = { data: [ - { + serviceTypesFactory.build({ label: 'Linode', service_type: 'linode', - }, - { + }), + serviceTypesFactory.build({ label: 'Databases', service_type: 'dbaas', - }, + }), ], }; From a33e3d56217297d564ad7da4c78c2415bdc00022 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Thu, 10 Oct 2024 11:39:18 +0530 Subject: [PATCH 160/474] upcoming: [DI-20837] - Updated UT --- .../shared/CloudPulseDashboardSelect.test.tsx | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx index 1da7044a395..664394ebafb 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx @@ -1,7 +1,7 @@ import { fireEvent, screen } from '@testing-library/react'; import React from 'react'; -import { dashboardFactory } from 'src/factories'; +import { dashboardFactory, serviceTypesFactory } from 'src/factories'; import * as utils from 'src/features/CloudPulse/Utils/utils'; import { renderWithTheme } from 'src/utilities/testHelpers'; @@ -19,6 +19,7 @@ const queryMocks = vi.hoisted(() => ({ useCloudPulseServiceTypes: vi.fn().mockReturnValue({}), })); const mockDashboard = dashboardFactory.build(); +const mockServiceTypesList = serviceTypesFactory.build(); vi.mock('src/queries/cloudpulse/dashboards', async () => { const actual = await vi.importActual('src/queries/cloudpulse/dashboards'); @@ -46,16 +47,7 @@ queryMocks.useCloudPulseDashboardsQuery.mockReturnValue({ queryMocks.useCloudPulseServiceTypes.mockReturnValue({ data: { - data: [ - { - label: 'Linode', - service_type: 'linode', - }, - { - label: 'Databases', - service_type: 'dbaas', - }, - ], + data: [mockServiceTypesList], }, }); From 978cbf094404558a6d409a081e3b30f3fd2c6e0d Mon Sep 17 00:00:00 2001 From: vmangalr Date: Thu, 10 Oct 2024 15:30:16 +0530 Subject: [PATCH 161/474] upcoming: [DI-20928] - Filter titles initial changes --- .../src/components/RegionSelect/RegionSelect.tsx | 2 ++ .../src/features/CloudPulse/Utils/FilterBuilder.ts | 9 ++++++--- .../src/features/CloudPulse/Utils/FilterConfig.ts | 4 ++-- .../CloudPulse/shared/CloudPulseCustomSelect.tsx | 8 ++++++-- .../shared/CloudPulseDashboardFilterBuilder.tsx | 4 ++-- .../CloudPulse/shared/CloudPulseRegionSelect.tsx | 13 +++++++++---- .../CloudPulse/shared/CloudPulseResourcesSelect.tsx | 6 ++++-- 7 files changed, 31 insertions(+), 15 deletions(-) diff --git a/packages/manager/src/components/RegionSelect/RegionSelect.tsx b/packages/manager/src/components/RegionSelect/RegionSelect.tsx index cb126df244a..90f3c805ff2 100644 --- a/packages/manager/src/components/RegionSelect/RegionSelect.tsx +++ b/packages/manager/src/components/RegionSelect/RegionSelect.tsx @@ -52,6 +52,7 @@ export const RegionSelect = < helperText, ignoreAccountAvailability, label, + noMarginTop, onChange, placeholder, regionFilter, @@ -175,6 +176,7 @@ export const RegionSelect = < label={label ?? 'Region'} loading={accountAvailabilityLoading} loadingText="Loading regions..." + noMarginTop={noMarginTop} noOptionsText="No results" onChange={onChange} options={regionOptions} diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts index 7e415e6c756..1d02f88cd3f 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts @@ -56,11 +56,12 @@ export const getRegionProperties = ( props: CloudPulseFilterProperties, handleRegionChange: (region: string | undefined, savePref?: boolean) => void ): CloudPulseRegionSelectProps => { - const { placeholder } = props.config.configuration; + const { name, placeholder } = props.config.configuration; const { dashboard, isServiceAnalyticsIntegration, preferences } = props; return { defaultValue: preferences?.[REGION], handleRegionChange, + label: name, placeholder, savePreferences: !isServiceAnalyticsIntegration, selectedDashboard: dashboard, @@ -84,7 +85,7 @@ export const getResourcesProperties = ( savePref?: boolean ) => void ): CloudPulseResourcesSelectProps => { - const { filterKey, placeholder } = props.config.configuration; + const { filterKey, name, placeholder } = props.config.configuration; const { config, dashboard, @@ -100,6 +101,7 @@ export const getResourcesProperties = ( dashboard ), handleResourcesSelection: handleResourceChange, + label: name, placeholder, resourceType: dashboard.service_type, savePreferences: !isServiceAnalyticsIntegration, @@ -129,6 +131,7 @@ export const getCustomSelectProperties = ( filterType, isMultiSelect, maxSelections, + name, options, placeholder, } = props.config.configuration; @@ -156,6 +159,7 @@ export const getCustomSelectProperties = ( filterType, handleSelectionChange: handleCustomSelectChange, isMultiSelect, + label: name, maxSelections, options, placeholder, @@ -374,7 +378,6 @@ const getDependentFiltersByFilterKey = ( ); }; - /** * @param obj1 The first object to be compared * @param obj2 The second object to be compared diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts b/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts index cb2049952c1..62e1ac02cf6 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts @@ -26,7 +26,7 @@ export const LINODE_CONFIG: Readonly = { isFilterable: true, isMetricsFilter: true, isMultiSelect: true, - name: 'Resource', + name: 'Resources', neededInServicePage: false, placeholder: 'Select a Resource', priority: 2, @@ -98,7 +98,7 @@ export const DBAAS_CONFIG: Readonly = { isFilterable: true, isMetricsFilter: true, isMultiSelect: true, - name: 'Resource', + name: 'Resources', neededInServicePage: false, placeholder: 'Select a DB Cluster', priority: 3, diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index 4d25327a3ea..055733f4af8 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -81,6 +81,8 @@ export interface CloudPulseCustomSelectProps { */ isMultiSelect?: boolean; + label: string; + /** * The maximum selections that the user can make incase of multiselect */ @@ -126,6 +128,7 @@ export const CloudPulseCustomSelect = React.memo( filterKey, handleSelectionChange, isMultiSelect, + label, maxSelections, options, placeholder, @@ -228,16 +231,17 @@ export const CloudPulseCustomSelect = React.memo( : placeholder || 'Select a Value' } textFieldProps={{ - hideLabel: true, + // hideLabel: true, }} autoHighlight disabled={isAutoCompleteDisabled} errorText={staticErrorText} isOptionEqualToValue={(option, value) => option.label === value.label} - label={placeholder || 'Select a Value'} + label={label || 'Select a Value'} multiple={isMultiSelect} onChange={handleChange} value={selectedResource ?? (isMultiSelect ? [] : null)} + noMarginTop /> ); }, diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index c4818562563..b0d2bb60092 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -310,9 +310,9 @@ export const CloudPulseDashboardFilterBuilder = React.memo( container display={showFilter ? 'flex' : 'none'} item - maxHeight={'120px'} + maxHeight={theme.spacing(20)} overflow={'auto'} - rowGap={2} + rowGap={1} xs={12} > diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index 7f775d3eb87..6fa3a6622bc 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -8,6 +8,7 @@ import type { Dashboard, FilterValue } from '@linode/api-v4'; export interface CloudPulseRegionSelectProps { defaultValue?: FilterValue; handleRegionChange: (region: string | undefined, savePref?: boolean) => void; + label: string; placeholder?: string; savePreferences?: boolean; selectedDashboard: Dashboard | undefined; @@ -20,6 +21,7 @@ export const CloudPulseRegionSelect = React.memo( const { defaultValue, handleRegionChange, + label, placeholder, savePreferences, selectedDashboard, @@ -44,18 +46,21 @@ export const CloudPulseRegionSelect = React.memo( setSelectedRegion(region?.id); handleRegionChange(region?.id, savePreferences); }} - textFieldProps={{ - hideLabel: true, - }} + textFieldProps={ + { + // hideLabel: true, + } + } currentCapability={undefined} data-testid="region-select" disableClearable={false} disabled={!selectedDashboard || !regions} fullWidth - label="Select a Region" + label={label ?? 'Select a Region'} placeholder={placeholder ?? 'Select a Region'} regions={regions ? regions : []} value={selectedRegion} + noMarginTop /> ); }, diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index 319ab5d3b46..b676d3990f9 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -21,6 +21,7 @@ export interface CloudPulseResourcesSelectProps { resources: CloudPulseResources[], savePref?: boolean ) => void; + label: string; placeholder?: string; region?: string; resourceType: string | undefined; @@ -34,6 +35,7 @@ export const CloudPulseResourcesSelect = React.memo( defaultValue, disabled, handleResourcesSelection, + label, placeholder, region, resourceType, @@ -113,18 +115,18 @@ export const CloudPulseResourcesSelect = React.memo( }, }, }, - hideLabel: true, }} autoHighlight clearOnBlur data-testid="resource-select" disabled={disabled || isLoading} isOptionEqualToValue={(option, value) => option.id === value.id} - label="Select a Resource" + label={label ?? 'Resources'} limitTags={2} multiple options={getResourcesList} value={selectedResources ?? []} + noMarginTop /> ); }, From 7304623ec81c59dada26e4d8fe530b5098381761 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Sat, 12 Oct 2024 10:11:10 +0530 Subject: [PATCH 162/474] upcoming: [DI-20928] - ESLint issue fix --- .../features/CloudPulse/shared/CloudPulseCustomSelect.tsx | 5 +---- .../features/CloudPulse/shared/CloudPulseRegionSelect.tsx | 7 +------ .../CloudPulse/shared/CloudPulseResourcesSelect.tsx | 2 +- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index 055733f4af8..bd527a5c470 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -230,18 +230,15 @@ export const CloudPulseCustomSelect = React.memo( ? '' : placeholder || 'Select a Value' } - textFieldProps={{ - // hideLabel: true, - }} autoHighlight disabled={isAutoCompleteDisabled} errorText={staticErrorText} isOptionEqualToValue={(option, value) => option.label === value.label} label={label || 'Select a Value'} multiple={isMultiSelect} + noMarginTop onChange={handleChange} value={selectedResource ?? (isMultiSelect ? [] : null)} - noMarginTop /> ); }, diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index 6fa3a6622bc..4627215564c 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -46,21 +46,16 @@ export const CloudPulseRegionSelect = React.memo( setSelectedRegion(region?.id); handleRegionChange(region?.id, savePreferences); }} - textFieldProps={ - { - // hideLabel: true, - } - } currentCapability={undefined} data-testid="region-select" disableClearable={false} disabled={!selectedDashboard || !regions} fullWidth label={label ?? 'Select a Region'} + noMarginTop placeholder={placeholder ?? 'Select a Region'} regions={regions ? regions : []} value={selectedRegion} - noMarginTop /> ); }, diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index b676d3990f9..0ae89d86ea5 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -124,9 +124,9 @@ export const CloudPulseResourcesSelect = React.memo( label={label ?? 'Resources'} limitTags={2} multiple + noMarginTop options={getResourcesList} value={selectedResources ?? []} - noMarginTop /> ); }, From fa6a6b7d13a103deed3bf5e244e2ca5b9d4e6b3c Mon Sep 17 00:00:00 2001 From: vmangalr Date: Sat, 12 Oct 2024 10:21:19 +0530 Subject: [PATCH 163/474] upcoming: [DI-20928] - Name to label alias change --- .../src/features/CloudPulse/Utils/FilterBuilder.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts index 1d02f88cd3f..7e8cad885ba 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts @@ -56,12 +56,12 @@ export const getRegionProperties = ( props: CloudPulseFilterProperties, handleRegionChange: (region: string | undefined, savePref?: boolean) => void ): CloudPulseRegionSelectProps => { - const { name, placeholder } = props.config.configuration; + const { name: label, placeholder } = props.config.configuration; const { dashboard, isServiceAnalyticsIntegration, preferences } = props; return { defaultValue: preferences?.[REGION], handleRegionChange, - label: name, + label, placeholder, savePreferences: !isServiceAnalyticsIntegration, selectedDashboard: dashboard, @@ -85,7 +85,7 @@ export const getResourcesProperties = ( savePref?: boolean ) => void ): CloudPulseResourcesSelectProps => { - const { filterKey, name, placeholder } = props.config.configuration; + const { filterKey, name: label, placeholder } = props.config.configuration; const { config, dashboard, @@ -101,7 +101,7 @@ export const getResourcesProperties = ( dashboard ), handleResourcesSelection: handleResourceChange, - label: name, + label, placeholder, resourceType: dashboard.service_type, savePreferences: !isServiceAnalyticsIntegration, @@ -131,7 +131,7 @@ export const getCustomSelectProperties = ( filterType, isMultiSelect, maxSelections, - name, + name: label, options, placeholder, } = props.config.configuration; @@ -159,7 +159,7 @@ export const getCustomSelectProperties = ( filterType, handleSelectionChange: handleCustomSelectChange, isMultiSelect, - label: name, + label, maxSelections, options, placeholder, From 4a090df4aeb52d7c67a4bc1fba1ecbb2c852a588 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Sat, 12 Oct 2024 10:46:03 +0530 Subject: [PATCH 164/474] upcoming: [DI-20928] - Add a margin below filter button to look neat while showing filter --- .../CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index b0d2bb60092..9727fb62579 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -293,6 +293,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( sx={{ justifyContent: 'start', m: 0, + marginBottom: showFilter ? 1 : 0, minHeight: 'auto', minWidth: 'auto', p: 0, @@ -330,6 +331,6 @@ function compareProps( return ( oldProps.dashboard?.id === newProps.dashboard?.id && oldProps.preferences?.[DASHBOARD_ID] === - newProps.preferences?.[DASHBOARD_ID] + newProps.preferences?.[DASHBOARD_ID] ); } From bfde2b7a9c065dee57e5145d43e3ca3b5e91bdec Mon Sep 17 00:00:00 2001 From: vmangalr Date: Sat, 12 Oct 2024 10:50:38 +0530 Subject: [PATCH 165/474] upcoming: [DI-20928] - Fix UT issues --- .../CloudPulse/shared/CloudPulseCustomSelect.test.tsx | 4 ++++ .../CloudPulse/shared/CloudPulseRegionSelect.test.tsx | 1 + .../CloudPulse/shared/CloudPulseResourcesSelect.test.tsx | 6 ++++++ 3 files changed, 11 insertions(+) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.test.tsx index 78ae7c77efe..e07b83138eb 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.test.tsx @@ -56,6 +56,7 @@ describe('CloudPulseCustomSelect component tests', () => { filterKey="testfilter" filterType="number" handleSelectionChange={vi.fn()} + label="Test" options={mockOptions} placeholder={testFilter} type={CloudPulseSelectTypes.static} @@ -76,6 +77,7 @@ describe('CloudPulseCustomSelect component tests', () => { filterType="number" handleSelectionChange={vi.fn()} isMultiSelect={true} + label="Test" options={[...mockOptions]} placeholder={testFilter} type={CloudPulseSelectTypes.static} @@ -105,6 +107,7 @@ describe('CloudPulseCustomSelect component tests', () => { filterKey="testfilter" filterType="number" handleSelectionChange={selectionChnage} + label="Test" placeholder={testFilter} type={CloudPulseSelectTypes.dynamic} /> @@ -131,6 +134,7 @@ describe('CloudPulseCustomSelect component tests', () => { filterType="number" handleSelectionChange={selectionChnage} isMultiSelect={true} + label="Test" placeholder={testFilter} type={CloudPulseSelectTypes.dynamic} /> diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx index fc49edf0f0a..be4f31edf36 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx @@ -10,6 +10,7 @@ import type { Region } from '@linode/api-v4'; const props: CloudPulseRegionSelectProps = { handleRegionChange: vi.fn(), + label: 'Region', selectedDashboard: undefined, }; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx index 019d038369b..d2210f8ddc8 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx @@ -33,6 +33,7 @@ describe('CloudPulseResourcesSelect component tests', () => { const { getByPlaceholderText, getByTestId } = renderWithTheme( @@ -50,6 +51,7 @@ describe('CloudPulseResourcesSelect component tests', () => { renderWithTheme( @@ -77,6 +79,7 @@ describe('CloudPulseResourcesSelect component tests', () => { renderWithTheme( @@ -105,6 +108,7 @@ describe('CloudPulseResourcesSelect component tests', () => { renderWithTheme( @@ -134,6 +138,7 @@ describe('CloudPulseResourcesSelect component tests', () => { renderWithTheme( @@ -175,6 +180,7 @@ describe('CloudPulseResourcesSelect component tests', () => { Date: Sat, 12 Oct 2024 10:51:02 +0530 Subject: [PATCH 166/474] upcoming: [DI-20928] - Remove unused import --- packages/manager/src/MainContent.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/manager/src/MainContent.tsx b/packages/manager/src/MainContent.tsx index 14fc456eee5..4d4698ce965 100644 --- a/packages/manager/src/MainContent.tsx +++ b/packages/manager/src/MainContent.tsx @@ -29,7 +29,6 @@ import { ENABLE_MAINTENANCE_MODE } from './constants'; import { complianceUpdateContext } from './context/complianceUpdateContext'; import { sessionExpirationContext } from './context/sessionExpirationContext'; import { switchAccountSessionContext } from './context/switchAccountSessionContext'; -import { useIsACLPEnabled } from './features/CloudPulse/Utils/utils'; import { useIsDatabasesEnabled } from './features/Databases/utilities'; import { useIsPlacementGroupsEnabled } from './features/PlacementGroups/utils'; import { useGlobalErrors } from './hooks/useGlobalErrors'; From 86171ed0ffc3d3b5e39c8f2be0d27223e2a29c5a Mon Sep 17 00:00:00 2001 From: vmangalr Date: Fri, 11 Oct 2024 18:28:39 +0530 Subject: [PATCH 167/474] upcoming: [DI-20800] - PR review comments initial changes --- .../Widget/components/CloudPulseAggregateFunction.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx index 8abb4392f56..4345fc4ed4d 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx @@ -56,8 +56,10 @@ export const CloudPulseAggregateFunction = React.memo( return ( { - return convertStringToCamelCasesWithSpaces(option.label); // options needed to be display in Caps first + getOptionLabel={(option) => { + return convertStringToCamelCasesWithSpaces( + typeof option === 'string' ? option : option.label + ); // options needed to be display in Caps first }} isOptionEqualToValue={(option, value) => { return option.label === value.label; From 83df7a04015dceea2b66219c71dd1c46493fc416 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Fri, 11 Oct 2024 18:31:28 +0530 Subject: [PATCH 168/474] upcoming: [DI-20800] - PR review comments --- .../features/CloudPulse/shared/CloudPulseResourcesSelect.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index 319ab5d3b46..d80aeb68633 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -83,10 +83,7 @@ export const CloudPulseResourcesSelect = React.memo( return ( { + onChange={(e, resourceSelections) => { setSelectedResources(resourceSelections); if (!isAutocompleteOpen.current) { From 9c25c6fe35ce68633d027198de011d0fbba357fe Mon Sep 17 00:00:00 2001 From: vmangalr Date: Fri, 11 Oct 2024 18:35:20 +0530 Subject: [PATCH 169/474] upcoming: [DI-20800] - PR review comments --- .../features/CloudPulse/shared/CloudPulseResourcesSelect.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index d80aeb68633..dd364901c84 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -41,8 +41,6 @@ export const CloudPulseResourcesSelect = React.memo( xFilter, } = props; - const isAutocompleteOpen = React.useRef(false); - const { data: resources, isLoading } = useResourcesQuery( disabled !== undefined ? !disabled : Boolean(region && resourceType), resourceType, @@ -54,6 +52,9 @@ export const CloudPulseResourcesSelect = React.memo( CloudPulseResources[] >(); + // here we track the open state with ref to avoid unwanted re-renders, as we are any re-rendering while updating the selected values itself + const isAutocompleteOpen = React.useRef(false); // Ref to track the open state of Autocomplete + const getResourcesList = React.useMemo(() => { return resources && resources.length > 0 ? resources : []; }, [resources]); From ae3a43d9340834cbd23095014dc2d4864e80d2ca Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 14 Oct 2024 11:44:12 +0530 Subject: [PATCH 170/474] upcoming: [DI-20844] - Remove height --- .../src/features/CloudPulse/Widget/components/Zoomer.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx b/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx index e52ca9f2b1f..05bde294bf5 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/Zoomer.tsx @@ -27,7 +27,6 @@ export const ZoomIcon = React.memo((props: ZoomIconProperties) => { sx={{ color: theme.color.grey1, fontSize: 'x-large', - height: '34px', padding: '0', }} aria-label="Zoom In" @@ -46,7 +45,6 @@ export const ZoomIcon = React.memo((props: ZoomIconProperties) => { sx={{ color: theme.color.grey1, fontSize: 'x-large', - height: '34px', padding: '0', }} aria-label="Zoom Out" From 3eff36691fd73ca87aad9e2f22e31923f9022e42 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 14 Oct 2024 11:31:05 +0530 Subject: [PATCH 171/474] upcoming: [DI-20844] - Remove comment --- .../features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx index c71ad66ef4d..6a37d417c1a 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx @@ -63,7 +63,7 @@ export const CloudPulseTimeRangeSelect = React.memo( setSelectedTimeRange(item); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [defaultValue]); // need to execute only once, during mounting of this component + }, [defaultValue]); // need to execute when there is change in default value const handleChange = (item: Item) => { setSelectedTimeRange(item); From cfdabf267bc089b6d4a16beb26526ea6292ef4c6 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 14 Oct 2024 12:14:13 +0530 Subject: [PATCH 172/474] upcoming: [DI-20928] - PR comments --- .../src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx | 2 +- .../src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx | 2 +- .../features/CloudPulse/shared/CloudPulseResourcesSelect.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index bd527a5c470..03adc97c684 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -234,7 +234,7 @@ export const CloudPulseCustomSelect = React.memo( disabled={isAutoCompleteDisabled} errorText={staticErrorText} isOptionEqualToValue={(option, value) => option.label === value.label} - label={label || 'Select a Value'} + label={Boolean(label && label.length) ? label : 'Select a Value'} multiple={isMultiSelect} noMarginTop onChange={handleChange} diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index 4627215564c..37a84cfef62 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -51,7 +51,7 @@ export const CloudPulseRegionSelect = React.memo( disableClearable={false} disabled={!selectedDashboard || !regions} fullWidth - label={label ?? 'Select a Region'} + label={Boolean(label && label.length) ? label : 'Region'} noMarginTop placeholder={placeholder ?? 'Select a Region'} regions={regions ? regions : []} diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index 0ae89d86ea5..d4e50e00d2c 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -121,7 +121,7 @@ export const CloudPulseResourcesSelect = React.memo( data-testid="resource-select" disabled={disabled || isLoading} isOptionEqualToValue={(option, value) => option.id === value.id} - label={label ?? 'Resources'} + label={Boolean(label && label.length) ? label : 'Resources'} limitTags={2} multiple noMarginTop From cb54c59ba57977f1990cd0cba06d50f41d7baed1 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 14 Oct 2024 12:29:14 +0530 Subject: [PATCH 173/474] upcoming: [DI-20928] - PR comments --- .../src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx | 2 +- .../src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx | 2 +- .../features/CloudPulse/shared/CloudPulseResourcesSelect.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index 03adc97c684..ec2b043294e 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -234,7 +234,7 @@ export const CloudPulseCustomSelect = React.memo( disabled={isAutoCompleteDisabled} errorText={staticErrorText} isOptionEqualToValue={(option, value) => option.label === value.label} - label={Boolean(label && label.length) ? label : 'Select a Value'} + label={Boolean(label?.length) ? label : 'Select a Value'} multiple={isMultiSelect} noMarginTop onChange={handleChange} diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index 37a84cfef62..e7b121585cc 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -51,7 +51,7 @@ export const CloudPulseRegionSelect = React.memo( disableClearable={false} disabled={!selectedDashboard || !regions} fullWidth - label={Boolean(label && label.length) ? label : 'Region'} + label={Boolean(label?.length) ? label : 'Region'} noMarginTop placeholder={placeholder ?? 'Select a Region'} regions={regions ? regions : []} diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index d4e50e00d2c..2066a1a88bd 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -121,7 +121,7 @@ export const CloudPulseResourcesSelect = React.memo( data-testid="resource-select" disabled={disabled || isLoading} isOptionEqualToValue={(option, value) => option.id === value.id} - label={Boolean(label && label.length) ? label : 'Resources'} + label={Boolean(label?.length) ? label : 'Resources'} limitTags={2} multiple noMarginTop From 9ff5ea1223beb6965fdae150f0fd6147fadb422b Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 14 Oct 2024 20:13:07 +0530 Subject: [PATCH 174/474] upcoming: [DI-20844] - Using reusable sx and removing styled component --- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 11 ++++++----- .../components/CloudPulseAggregateFunction.tsx | 17 ++++++++++------- .../components/CloudPulseIntervalSelect.tsx | 10 +++++++--- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index 29eabd3a7a9..9a43333e3e5 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -24,6 +24,7 @@ import type { TimeDuration, Widgets, } from '@linode/api-v4'; +import type { Theme } from '@mui/material'; import type { DataSet } from 'src/components/LineGraph/LineGraph'; import type { CloudPulseResourceTypeMapFlag, FlagSet } from 'src/featureFlags'; @@ -336,11 +337,11 @@ export const isDataEmpty = (data: DataSet[]): boolean => { }; /** - * Returns an autocomplete with updated styles according to UX, this will be used at widget level + * + * @param theme mui theme + * @returns The style needed for widget level autocomplete filters */ -export const StyledWidgetAutocomplete = styled(Autocomplete, { - label: 'StyledAutocomplete', -})(({ theme }) => ({ +export const getAutocompleteWidgetStyles = (theme: Theme) => ({ '&& .MuiFormControl-root': { minWidth: '90px', [theme.breakpoints.down('sm')]: { @@ -348,4 +349,4 @@ export const StyledWidgetAutocomplete = styled(Autocomplete, { }, width: '90px', }, -})); +}); diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx index 4345fc4ed4d..87db8b89686 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx @@ -1,8 +1,11 @@ +import { useTheme } from '@mui/material'; import React from 'react'; +import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; + import { CloudPulseTooltip } from '../../shared/CloudPulseTooltip'; -import { StyledWidgetAutocomplete } from '../../Utils/CloudPulseWidgetUtils'; import { convertStringToCamelCasesWithSpaces } from '../../Utils/utils'; +import { getAutocompleteWidgetStyles } from '../../Utils/CloudPulseWidgetUtils'; export interface AggregateFunctionProperties { /** @@ -53,18 +56,18 @@ export const CloudPulseAggregateFunction = React.memo( setSelectedAggregateFunction, ] = React.useState(defaultValue); + const theme = useTheme(); + return ( - { - return convertStringToCamelCasesWithSpaces( - typeof option === 'string' ? option : option.label - ); // options needed to be display in Caps first + return convertStringToCamelCasesWithSpaces(option.label); // options needed to be display in Caps first }} isOptionEqualToValue={(option, value) => { return option.label === value.label; }} - onChange={(e, selectedAggregateFunc: AggregateFunction) => { + onChange={(e, selectedAggregateFunc) => { setSelectedAggregateFunction(selectedAggregateFunc); onAggregateFuncChange(selectedAggregateFunc.label); }} @@ -77,7 +80,7 @@ export const CloudPulseAggregateFunction = React.memo( label="Select an Aggregate Function" noMarginTop={true} options={availableAggregateFunc} - sx={{ width: '100%' }} + sx={getAutocompleteWidgetStyles(theme)} value={selectedAggregateFunction} /> diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx index 410b4a6de79..7347cf0c9ed 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx @@ -1,9 +1,11 @@ import React from 'react'; import { CloudPulseTooltip } from '../../shared/CloudPulseTooltip'; -import { StyledWidgetAutocomplete } from '../../Utils/CloudPulseWidgetUtils'; import type { TimeGranularity } from '@linode/api-v4'; +import { useTheme } from '@mui/material'; +import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; +import { getAutocompleteWidgetStyles } from '../../Utils/CloudPulseWidgetUtils'; interface IntervalOptions { label: string; @@ -119,9 +121,11 @@ export const CloudPulseIntervalSelect = React.memo( defaultValue ); + const theme = useTheme(); + return ( - From 70b537d66fdfbfdc9d83553c749d6d9d7e441743 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 15 Oct 2024 09:39:51 +0530 Subject: [PATCH 175/474] upcoming: [DI-20844] - Fix eslint and use common tooltip component --- .../CloudPulseAggregateFunction.tsx | 2 +- .../components/CloudPulseIntervalSelect.tsx | 7 ++++--- .../CloudPulse/shared/CloudPulseTooltip.tsx | 21 ++----------------- 3 files changed, 7 insertions(+), 23 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx index 87db8b89686..d29bbea9e45 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx @@ -4,8 +4,8 @@ import React from 'react'; import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; import { CloudPulseTooltip } from '../../shared/CloudPulseTooltip'; -import { convertStringToCamelCasesWithSpaces } from '../../Utils/utils'; import { getAutocompleteWidgetStyles } from '../../Utils/CloudPulseWidgetUtils'; +import { convertStringToCamelCasesWithSpaces } from '../../Utils/utils'; export interface AggregateFunctionProperties { /** diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx index 7347cf0c9ed..f427e2a4336 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx @@ -1,11 +1,12 @@ +import { useTheme } from '@mui/material'; import React from 'react'; +import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; + import { CloudPulseTooltip } from '../../shared/CloudPulseTooltip'; +import { getAutocompleteWidgetStyles } from '../../Utils/CloudPulseWidgetUtils'; import type { TimeGranularity } from '@linode/api-v4'; -import { useTheme } from '@mui/material'; -import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; -import { getAutocompleteWidgetStyles } from '../../Utils/CloudPulseWidgetUtils'; interface IntervalOptions { label: string; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.tsx index f6afa0a455f..ae9a09eae57 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.tsx @@ -1,4 +1,3 @@ -import { styled, tooltipClasses } from '@mui/material'; import React from 'react'; import { Tooltip } from 'src/components/Tooltip'; @@ -9,7 +8,7 @@ export const CloudPulseTooltip = React.memo((props: TooltipProps) => { const { children, placement, title } = props; return ( - { title={title} > {children} - + ); }); - -const StyledTooltip = styled(({ className, ...props }: TooltipProps) => ( - -))(({ theme }) => ({ - [`& .${tooltipClasses.arrow}`]: { - color: theme.palette.common.black, - }, - [`& .${tooltipClasses.tooltip}`]: { - backgroundColor: theme.palette.common.black, - color: theme.palette.common.white, - fontSize: theme.spacing(1.75), - maxHeight: theme.spacing(3.5), - maxWidth: theme.spacing(30), - padding: theme.spacing(0.75), - }, -})); From 842ee966c0804e49c22cadc8012913b9caf8fa35 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 15 Oct 2024 10:11:26 +0530 Subject: [PATCH 176/474] upcoming: [DI-20844] - Remove unused variables --- packages/manager/src/MainContent.tsx | 1 - .../src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts | 3 --- .../features/CloudPulse/shared/CloudPulseDashboardSelect.tsx | 2 +- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/manager/src/MainContent.tsx b/packages/manager/src/MainContent.tsx index 14fc456eee5..4d4698ce965 100644 --- a/packages/manager/src/MainContent.tsx +++ b/packages/manager/src/MainContent.tsx @@ -29,7 +29,6 @@ import { ENABLE_MAINTENANCE_MODE } from './constants'; import { complianceUpdateContext } from './context/complianceUpdateContext'; import { sessionExpirationContext } from './context/sessionExpirationContext'; import { switchAccountSessionContext } from './context/switchAccountSessionContext'; -import { useIsACLPEnabled } from './features/CloudPulse/Utils/utils'; import { useIsDatabasesEnabled } from './features/Databases/utilities'; import { useIsPlacementGroupsEnabled } from './features/PlacementGroups/utils'; import { useGlobalErrors } from './hooks/useGlobalErrors'; diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index 9a43333e3e5..44b4192fdf4 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -1,6 +1,3 @@ -import { styled } from '@mui/material'; - -import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; import { isToday } from 'src/utilities/isToday'; import { getMetrics } from 'src/utilities/statMetrics'; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index c2a571572f2..5f2c9dfebf4 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -8,7 +8,7 @@ import { useCloudPulseServiceTypes } from 'src/queries/cloudpulse/services'; import { formattedServiceTypes, getAllDashboards } from '../Utils/utils'; -import type { Dashboard, FilterValue, ServiceTypes } from '@linode/api-v4'; +import type { Dashboard, FilterValue } from '@linode/api-v4'; export interface CloudPulseDashboardSelectProps { defaultValue?: Partial; From aa45f52a560d9799e331a989187100a5bd7c61d9 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 15 Oct 2024 10:24:55 +0530 Subject: [PATCH 177/474] upcoming: [DI-20928] - Title name updates --- .../manager/src/features/CloudPulse/Utils/FilterConfig.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts b/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts index 62e1ac02cf6..e9c2939a164 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts @@ -60,7 +60,7 @@ export const DBAAS_CONFIG: Readonly = { isFilterable: false, // isFilterable -- this determines whethere you need to pass it metrics api isMetricsFilter: false, // if it is false, it will go as a part of filter params, else global filter isMultiSelect: false, - name: 'DB Engine', + name: 'Engine', neededInServicePage: false, options: [ { @@ -98,7 +98,7 @@ export const DBAAS_CONFIG: Readonly = { isFilterable: true, isMetricsFilter: true, isMultiSelect: true, - name: 'Resources', + name: 'DB Cluster', neededInServicePage: false, placeholder: 'Select a DB Cluster', priority: 3, From 62aaaf3e78dfa138dd1de5d6a3b2c4439c54d06c Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 15 Oct 2024 10:41:29 +0530 Subject: [PATCH 178/474] upcoming: [DI-20844] - Remove arrow --- .../manager/src/features/CloudPulse/shared/CloudPulseTooltip.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.tsx index ae9a09eae57..a79d37ec299 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTooltip.tsx @@ -19,7 +19,6 @@ export const CloudPulseTooltip = React.memo((props: TooltipProps) => { }, ], }} - arrow data-qa-tooltip={title} data-test-id={title} placement={placement ?? 'top-start'} From 2ab96e8844b2f159beb4f7d7c4a82b2ed71cebbb Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 15 Oct 2024 21:20:57 +0530 Subject: [PATCH 179/474] upcoming: [DI-20844] - PR comments --- .../CloudPulseAggregateFunction.tsx | 6 +----- .../components/CloudPulseIntervalSelect.tsx | 20 +++++++------------ 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx index d29bbea9e45..424bba2288a 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseAggregateFunction.tsx @@ -1,4 +1,3 @@ -import { useTheme } from '@mui/material'; import React from 'react'; import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; @@ -56,8 +55,6 @@ export const CloudPulseAggregateFunction = React.memo( setSelectedAggregateFunction, ] = React.useState(defaultValue); - const theme = useTheme(); - return ( diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx index f427e2a4336..e96abfb95b5 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseIntervalSelect.tsx @@ -1,4 +1,3 @@ -import { useTheme } from '@mui/material'; import React from 'react'; import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; @@ -122,19 +121,15 @@ export const CloudPulseIntervalSelect = React.memo( defaultValue ); - const theme = useTheme(); - return ( option?.value === value?.value && option?.unit === value?.unit} - onChange={( - _: React.SyntheticEvent, - selectedInterval: IntervalOptions - ) => { + isOptionEqualToValue={(option, value) => { + return ( + option?.value === value?.value && option?.unit === value?.unit + ); + }} + onChange={(e, selectedInterval) => { setSelectedInterval(selectedInterval); onIntervalChange({ unit: selectedInterval?.unit, @@ -146,11 +141,10 @@ export const CloudPulseIntervalSelect = React.memo( }} autoHighlight disableClearable - fullWidth={false} label="Select an Interval" noMarginTop={true} options={[autoIntervalOption, ...availableIntervalOptions]} - sx={getAutocompleteWidgetStyles(theme)} + sx={getAutocompleteWidgetStyles} value={selectedInterval} /> From 99878894f11c24246e0d007ee3837097cc9c8c2c Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Tue, 15 Oct 2024 20:52:33 +0530 Subject: [PATCH 180/474] upcoming: [DI-21138] - Dbass node type filter change --- .../src/features/CloudPulse/Utils/FilterConfig.ts | 2 +- .../Utils/ReusableDashboardFilterUtils.test.ts | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts b/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts index cb2049952c1..9034ab46ca8 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts @@ -121,7 +121,7 @@ export const DBAAS_CONFIG: Readonly = { }, { configuration: { - filterKey: 'role', + filterKey: 'node_type', filterType: 'string', isFilterable: true, // isFilterable -- this determines whether you need to pass it metrics api isMetricsFilter: false, // if it is false, it will go as a part of filter params, else global filter diff --git a/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.test.ts b/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.test.ts index 3bdfea69058..56b4e1e060f 100644 --- a/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.test.ts +++ b/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.test.ts @@ -71,7 +71,7 @@ it('test checkMandatoryFiltersSelected method for role', () => { result = checkMandatoryFiltersSelected({ dashboardObj: { ...mockDashboard, service_type: 'dbaas' }, - filterValue: { region: 'us-east', role: 'primary' }, + filterValue: { node_type: 'primary', region: 'us-east' }, resource: 1, timeDuration: { unit: 'min', value: 30 }, }); @@ -83,12 +83,12 @@ it('test constructDimensionFilters method', () => { mockDashboard.service_type = 'dbaas'; const result = constructDimensionFilters({ dashboardObj: mockDashboard, - filterValue: { role: 'primary' }, + filterValue: { node_type: 'primary' }, resource: 1, }); expect(result.length).toEqual(1); - expect(result[0].filterKey).toEqual('role'); + expect(result[0].filterKey).toEqual('node_type'); expect(result[0].filterValue).toEqual('primary'); }); @@ -99,13 +99,13 @@ it('test checkIfFilterNeededInMetricsCall method', () => { result = checkIfFilterNeededInMetricsCall('resource_id', 'linode'); expect(result).toEqual(false); // not needed as dimension filter - result = checkIfFilterNeededInMetricsCall('role', 'dbaas'); + result = checkIfFilterNeededInMetricsCall('node_type', 'dbaas'); expect(result).toEqual(true); result = checkIfFilterNeededInMetricsCall('engine', 'dbaas'); expect(result).toEqual(false); - result = checkIfFilterNeededInMetricsCall('role', 'xyz'); // xyz service type + result = checkIfFilterNeededInMetricsCall('node_type', 'xyz'); // xyz service type expect(result).toEqual(false); }); From b2f205121ba142d86eeeb26a6b1827eaa6ed3566 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 16 Oct 2024 17:38:30 +0530 Subject: [PATCH 181/474] upcoming: [DI-20870] - Migrated chartjs to recharts for ACLP graphs --- packages/api-v4/src/cloudpulse/types.ts | 5 + .../src/components/AreaChart/AreaChart.tsx | 9 +- .../LineGraph/MetricDisplay.styles.ts | 4 +- .../components/LineGraph/MetricsDisplay.tsx | 12 +-- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 97 ++++++++++--------- .../CloudPulse/Widget/CloudPulseWidget.tsx | 34 ++++--- .../Widget/components/CloudPulseLineGraph.tsx | 40 ++------ 7 files changed, 92 insertions(+), 109 deletions(-) diff --git a/packages/api-v4/src/cloudpulse/types.ts b/packages/api-v4/src/cloudpulse/types.ts index 9d24aca5857..3bc92178f95 100644 --- a/packages/api-v4/src/cloudpulse/types.ts +++ b/packages/api-v4/src/cloudpulse/types.ts @@ -131,3 +131,8 @@ export interface ServiceTypes { export interface ServiceTypesList { data: ServiceTypes[]; } + +export interface DataSet { + [label: string]: number; + timestamp: number; +} diff --git a/packages/manager/src/components/AreaChart/AreaChart.tsx b/packages/manager/src/components/AreaChart/AreaChart.tsx index 29ed0c35d23..fb9359bf181 100644 --- a/packages/manager/src/components/AreaChart/AreaChart.tsx +++ b/packages/manager/src/components/AreaChart/AreaChart.tsx @@ -9,7 +9,6 @@ import { Legend, ResponsiveContainer, Tooltip, - TooltipProps, XAxis, YAxis, } from 'recharts'; @@ -17,7 +16,6 @@ import { import { AccessibleAreaChart } from 'src/components/AreaChart/AccessibleAreaChart'; import { Box } from 'src/components/Box'; import MetricsDisplay from 'src/components/LineGraph/MetricsDisplay'; -import { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay'; import { Paper } from 'src/components/Paper'; import { StyledBottomLegend } from 'src/features/NodeBalancers/NodeBalancerDetail/NodeBalancerSummary/TablesPanel'; @@ -27,7 +25,10 @@ import { tooltipValueFormatter, } from './utils'; -interface AreaProps { +import type { TooltipProps } from 'recharts'; +import type { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay'; + +export interface AreaProps { color: string; dataKey: string; } @@ -37,7 +38,7 @@ interface XAxisProps { tickGap: number; } -interface AreaChartProps { +export interface AreaChartProps { areas: AreaProps[]; ariaLabel: string; data: any; diff --git a/packages/manager/src/components/LineGraph/MetricDisplay.styles.ts b/packages/manager/src/components/LineGraph/MetricDisplay.styles.ts index ed4f14d9978..9bf14fe4ea1 100644 --- a/packages/manager/src/components/LineGraph/MetricDisplay.styles.ts +++ b/packages/manager/src/components/LineGraph/MetricDisplay.styles.ts @@ -39,7 +39,9 @@ export const StyledButton = styled(Button, { '&:before': { backgroundColor: hidden ? theme.color.disabledText - : theme.graphs[legendColor], + : theme.graphs[legendColor] + ? theme.graphs[legendColor] + : legendColor, }, }), })); diff --git a/packages/manager/src/components/LineGraph/MetricsDisplay.tsx b/packages/manager/src/components/LineGraph/MetricsDisplay.tsx index 2053aa4aa46..d2a3c0fa2be 100644 --- a/packages/manager/src/components/LineGraph/MetricsDisplay.tsx +++ b/packages/manager/src/components/LineGraph/MetricsDisplay.tsx @@ -5,7 +5,6 @@ import { TableCell } from 'src/components/TableCell'; import { TableHead } from 'src/components/TableHead'; import { TableRow } from 'src/components/TableRow'; import { Typography } from 'src/components/Typography'; -import { Metrics } from 'src/utilities/statMetrics'; import { StyledButton, @@ -13,6 +12,8 @@ import { StyledTableCell, } from './MetricDisplay.styles'; +import type { Metrics } from 'src/utilities/statMetrics'; + interface Props { hiddenRows?: string[]; rows: MetricsDisplayRow[]; @@ -22,14 +23,7 @@ export interface MetricsDisplayRow { data: Metrics; format: (n: number) => string; handleLegendClick?: () => void; - legendColor: - | 'blue' - | 'darkGreen' - | 'green' - | 'lightGreen' - | 'purple' - | 'red' - | 'yellow'; + legendColor: string; legendTitle: string; } diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index 29eabd3a7a9..36e7cf4389c 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -1,11 +1,11 @@ +import { Alias } from '@linode/design-language-system'; import { styled } from '@mui/material'; import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; -import { isToday } from 'src/utilities/isToday'; import { getMetrics } from 'src/utilities/statMetrics'; -import { COLOR_MAP } from './CloudPulseWidgetColorPalette'; import { + convertValueToUnit, formatToolTip, generateUnitByBaseUnit, transformData, @@ -16,15 +16,16 @@ import { } from './utils'; import type { CloudPulseResources } from '../shared/CloudPulseResourcesSelect'; -import type { LegendRow } from '../Widget/CloudPulseWidget'; import type { CloudPulseMetricsList, CloudPulseMetricsRequest, CloudPulseMetricsResponse, + DataSet, TimeDuration, Widgets, } from '@linode/api-v4'; -import type { DataSet } from 'src/components/LineGraph/LineGraph'; +import type { AreaProps } from 'src/components/AreaChart/AreaChart'; +import type { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay'; import type { CloudPulseResourceTypeMapFlag, FlagSet } from 'src/featureFlags'; interface LabelNameOptionsProps { @@ -59,7 +60,7 @@ interface LabelNameOptionsProps { unit: string; } -interface graphDataOptionsProps { +interface GraphDataOptionsProps { /** * flags associated with metricsList */ @@ -149,7 +150,7 @@ interface DimensionNameProperties { * * @returns parameters which will be necessary to populate graph & legends */ -export const generateGraphData = (props: graphDataOptionsProps) => { +export const generateGraphData = (props: GraphDataOptionsProps) => { const { flags, label, @@ -158,28 +159,27 @@ export const generateGraphData = (props: graphDataOptionsProps) => { serviceType, status, unit, - widgetChartType, - widgetColor, + // widgetChartType, + // widgetColor, } = props; - - const dimensions: DataSet[] = []; - const legendRowsData: LegendRow[] = []; - + const legendRowsData: MetricsDisplayRow[] = []; // for now we will use this, but once we decide how to work with coloring, it should be dynamic - const colors = COLOR_MAP.get(widgetColor ?? 'default')!; - let today = false; - + // const colors = COLOR_MAP.get(widgetColor ?? 'default')!; + const dimension: { [timestamp: number]: { [label: string]: number } } = {}; + const areas: AreaProps[] = []; + const colors = Object.values(Alias.Chart.Categorical); if (status === 'success') { metricsList?.data?.result?.forEach( (graphData: CloudPulseMetricsList, index) => { if (!graphData) { return; } + const transformedData = { metric: graphData.metric, values: transformData(graphData.values, unit), }; - const color = colors[index]; + // const color = colors[index]; const { end, start } = convertTimeDurationToStartAndEndTimeRange({ unit: 'min', value: 30, @@ -196,33 +196,52 @@ export const generateGraphData = (props: graphDataOptionsProps) => { serviceType, unit, }; - - const dimension = { - backgroundColor: color, - borderColor: color, - data: seriesDataFormatter(transformedData.values, start, end), - fill: widgetChartType === 'area', - label: getLabelName(labelOptions), - }; + const labelName = getLabelName(labelOptions); + const data = seriesDataFormatter(transformedData.values, start, end); + const color = colors[index]?.Primary ?? Alias.Chart.Neutral; + areas.push({ + color, + dataKey: labelName, + }); + + data.forEach((d) => { + const timestamp = d[0]; + const value = d[1]; + if (value !== null) { + dimension[timestamp] = { + ...dimension[timestamp], + [labelName]: value, + }; + } + }); // construct a legend row with the dimension - const legendRow = { - data: getMetrics(dimension.data as number[][]), + const legendRow: MetricsDisplayRow = { + data: getMetrics(data as number[][]), format: (value: number) => formatToolTip(value, unit), legendColor: color, - legendTitle: dimension.label, + legendTitle: labelName, }; legendRowsData.push(legendRow); - dimensions.push(dimension); - today ||= isToday(start, end); } ); } + const maxUnit = generateMaxUnit(legendRowsData, unit); + const dimensions: DataSet[] = Object.entries(dimension).map( + ([key, value]) => { + const rolledUpData: { [resource: string]: number } = {}; + Object.entries(value).forEach( + ([resource, data]) => + (rolledUpData[resource] = convertValueToUnit(data, maxUnit)) + ); + return { timestamp: Number(key), ...rolledUpData }; + } + ); return { + areas, dimensions, legendRowsData, - today, - unit: generateMaxUnit(legendRowsData, unit), + unit: maxUnit, }; }; @@ -232,7 +251,7 @@ export const generateGraphData = (props: graphDataOptionsProps) => { * @param unit base unit of the values * @returns maximum possible rolled up unit based on the unit */ -const generateMaxUnit = (legendRowsData: LegendRow[], unit: string) => { +const generateMaxUnit = (legendRowsData: MetricsDisplayRow[], unit: string) => { const maxValue = Math.max( 0, ...legendRowsData?.map((row) => row?.data.max ?? 0) @@ -321,20 +340,6 @@ export const mapResourceIdToName = ( return resourcesObj?.label ?? id ?? ''; }; -/** - * - * @param data data set to be checked for empty - * @returns true if data is not empty or contains all the null values otherwise false - */ -export const isDataEmpty = (data: DataSet[]): boolean => { - return data.every( - (thisSeries) => - thisSeries.data.length === 0 || - // If we've padded the data, every y value will be null - thisSeries.data.every((thisPoint) => thisPoint[1] === null) - ); -}; - /** * Returns an autocomplete with updated styles according to UX, this will be used at widget level */ diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 2f0e8d37783..8c0fa92dd85 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -13,7 +13,6 @@ import { } from '../Utils/CloudPulseWidgetUtils'; import { AGGREGATE_FUNCTION, SIZE, TIME_GRANULARITY } from '../Utils/constants'; import { constructAdditionalRequestFilters } from '../Utils/FilterBuilder'; -import { convertValueToUnit, formatToolTip } from '../Utils/unitConversion'; import { useAclpPreference } from '../Utils/UserPreference'; import { convertStringToCamelCasesWithSpaces } from '../Utils/utils'; import { CloudPulseAggregateFunction } from './components/CloudPulseAggregateFunction'; @@ -25,11 +24,13 @@ import type { FilterValueType } from '../Dashboard/CloudPulseDashboardLanding'; import type { CloudPulseResources } from '../shared/CloudPulseResourcesSelect'; import type { AvailableMetrics, + DataSet, TimeDuration, TimeGranularity, } from '@linode/api-v4'; import type { Widgets } from '@linode/api-v4'; -import type { DataSet } from 'src/components/LineGraph/LineGraph'; +import type { AreaProps } from 'src/components/AreaChart/AreaChart'; +import type { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay'; import type { Metrics } from 'src/utilities/statMetrics'; export interface CloudPulseWidgetProperties { @@ -233,11 +234,11 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { url: flags.aclpReadEndpoint!, } ); - let data: DataSet[] = []; - let legendRows: LegendRow[] = []; - let today: boolean = false; + let legendRows: MetricsDisplayRow[] = []; + let currentUnit = unit; + let areas: AreaProps[] = []; if (!isLoading && metricsList) { const generatedData = generateGraphData({ flags, @@ -253,12 +254,17 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { data = generatedData.dimensions; legendRows = generatedData.legendRowsData; - today = generatedData.today; scaledWidgetUnit.current = generatedData.unit; // here state doesn't matter, as this is always the latest re-render + currentUnit = generatedData.unit; + areas = generatedData.areas; } const metricsApiCallError = error?.[0]?.reason; + const tickFormat = + duration.unit === 'min' || duration.unit === 'hr' + ? 'hh:mm a' + : `LLL dd${widget.size === 12 ? ', hh:mm a' : ''}`; return ( @@ -319,20 +325,16 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { ? metricsApiCallError ?? 'Error while rendering graph' : undefined } - formatData={(data: number) => - convertValueToUnit(data, scaledWidgetUnit.current) - } - legendRows={ - legendRows && legendRows.length > 0 ? legendRows : undefined - } + areas={areas} ariaLabel={ariaLabel ? ariaLabel : ''} data={data} - formatTooltip={(value: number) => formatToolTip(value, unit)} - gridSize={widget.size} + height={480} + legendRows={legendRows} loading={isLoading || metricsApiCallError === jweTokenExpiryError} // keep loading until we fetch the refresh token - showToday={today} + showLegend timezone={timezone} - title={widget.label} + unit={currentUnit} + xAxis={{ tickFormat, tickGap: 60 }} /> diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index 5c3ce2fd3fd..a77b06ea01b 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -1,29 +1,19 @@ -import { Box, Typography, useTheme } from '@mui/material'; +import { Box, Typography } from '@mui/material'; import * as React from 'react'; +import { AreaChart } from 'src/components/AreaChart/AreaChart'; import { CircleProgress } from 'src/components/CircleProgress'; import { ErrorState } from 'src/components/ErrorState/ErrorState'; -import { LineGraph } from 'src/components/LineGraph/LineGraph'; -import { isDataEmpty } from '../../Utils/CloudPulseWidgetUtils'; +import type { AreaChartProps } from 'src/components/AreaChart/AreaChart'; -import type { LegendRow } from '../CloudPulseWidget'; -import type { LineGraphProps } from 'src/components/LineGraph/LineGraph'; - -export interface CloudPulseLineGraph extends LineGraphProps { - ariaLabel?: string; +export interface CloudPulseLineGraph extends AreaChartProps { error?: string; - gridSize: number; - legendRows?: LegendRow[]; loading?: boolean; - subtitle?: string; - title: string; } export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { - const { ariaLabel, data, error, legendRows, loading, ...rest } = props; - - const theme = useTheme(); + const { error, loading, ...rest } = props; if (loading) { return ; @@ -42,25 +32,9 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { ) : ( - + )} - {isDataEmpty(data) && ( + {rest.data.length === 0 && ( Date: Wed, 16 Oct 2024 17:49:37 +0530 Subject: [PATCH 182/474] upcoming: [DI-20928] - Title name for dashboard and time range selection too --- .../src/features/CloudPulse/Overview/GlobalFilters.tsx | 1 + .../CloudPulse/shared/CloudPulseDashboardSelect.tsx | 8 +++----- .../CloudPulse/shared/CloudPulseTimeRangeSelect.tsx | 6 ++---- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index 320e8e1280d..793d424a974 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -114,6 +114,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { = new Map( - serviceTypesList?.data.map(item => [item.service_type, item.label]) + serviceTypesList?.data.map((item) => [item.service_type, item.label]) ); const { @@ -102,9 +102,6 @@ export const CloudPulseDashboardSelect = React.memo( {params.children} )} - textFieldProps={{ - hideLabel: true, - }} autoHighlight clearOnBlur data-testid="cloudpulse-dashboard-select" @@ -113,8 +110,9 @@ export const CloudPulseDashboardSelect = React.memo( fullWidth groupBy={(option: Dashboard) => option.service_type} isOptionEqualToValue={(option, value) => option.id === value.id} - label="Select a Dashboard" + label="Dashboard" loading={dashboardsLoading || serviceTypesLoading} + noMarginTop options={getSortedDashboardsList(dashboardsList ?? [])} placeholder={placeHolder} value={selectedDashboard ?? null} // Undefined is not allowed for uncontrolled component diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx index 6a37d417c1a..323141e3bd2 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx @@ -80,15 +80,13 @@ export const CloudPulseTimeRangeSelect = React.memo( onChange={(e, value: Item) => { handleChange(value); }} - textFieldProps={{ - hideLabel: true, - }} autoHighlight data-testid="cloudpulse-time-duration" disableClearable fullWidth isOptionEqualToValue={(option, value) => option.value === value.value} - label="Select a Time Duration" + label="Time Range" + noMarginTop options={options} value={selectedTimeRange} /> From 6f8cee7ec9cce7475c27527563146d9822f383b8 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Wed, 16 Oct 2024 17:50:47 +0530 Subject: [PATCH 183/474] upcoming: [DI-20928] - Title name for dashboard and time range selection too --- .../manager/src/features/CloudPulse/Overview/GlobalFilters.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index 793d424a974..06b1a0a348d 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -114,7 +114,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { Date: Wed, 16 Oct 2024 17:54:27 +0530 Subject: [PATCH 184/474] upcoming: [DI-20870] - Removed unused imports --- .../src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index c5ba77445be..309e43abb87 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -1,7 +1,5 @@ import { Alias } from '@linode/design-language-system'; -import { styled } from '@mui/material'; -import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; import { getMetrics } from 'src/utilities/statMetrics'; import { @@ -24,9 +22,9 @@ import type { TimeDuration, Widgets, } from '@linode/api-v4'; +import type { Theme } from '@mui/material'; import type { AreaProps } from 'src/components/AreaChart/AreaChart'; import type { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay'; -import type { Theme } from '@mui/material'; import type { CloudPulseResourceTypeMapFlag, FlagSet } from 'src/featureFlags'; interface LabelNameOptionsProps { From 69f1e3332c281e3e64fd1bb08f96e2b67befd75b Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 16 Oct 2024 18:13:17 +0530 Subject: [PATCH 185/474] upcoming: [DI-20870] - Removed CloudPulseWidgetColorPalette file --- .../Utils/CloudPulseWidgetColorPalette.ts | 111 ------------------ .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 3 - 2 files changed, 114 deletions(-) delete mode 100644 packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetColorPalette.ts diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetColorPalette.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetColorPalette.ts deleted file mode 100644 index 3b9325521d0..00000000000 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetColorPalette.ts +++ /dev/null @@ -1,111 +0,0 @@ -export const RED = [ - '#ee2c2c80', - '#ff633d80', - '#F27E7E80', - '#EA7C7280', - '#E2796580', - '#D9775980', - '#D1744D80', - '#C9724080', - '#C16F3480', - '3B86D2880', - '#B06A1B80', - '#A8680F80', -]; - -export const GREEN = [ - '#10a21d80', - '#31ce3e80', - '#d9b0d980', - '#ffdc7d80', - '#7EF29D80', - '#72E39E80', - '#65D3A080', - '#59C4A180', - '#4DB5A280', - '#40A5A480', - '#3496A580', - '#2887A680', - '#1B77A880', - '#0F68A980', -]; - -export const BLUE = [ - '#3683dc80', - '#0F91A880', - '#1B9CAC80', - '#28A7AF80', - '#34B1B380', - '#40BCB680', - '#4DC7BA80', - '#59D2BD80', - '#65DCC180', - '#72E7C480', - '#7EF2C880', -]; - -export const YELLOW = [ - '#ffb34d80', - '#F2EE7E80', - '#E6E67280', - '#DBDE6580', - '#CFD75980', - '#C4CF4D80', - '#B8C74080', - '#ADBF3480', - '#A1B82880', - '#96B01B80', - '#8AA80F80', -]; - -export const PINK = [ - '#F27EE180', - '#EA72D180', - '#E265C280', - '#D959B280', - '#D14DA280', - '#C9409380', - '#C1348380', - '#B8287380', - '#B01B6480', - '#A80F5480', -]; - -export const DEFAULT = [ - // thick colors from each... - '#4067E580', - '#FE993380', - '#12A59480', - '#AB4ABA80', - '#D63C4280', - '#05A2C280', - '#E043A780', - '#00B05080', - '#7259D680', - '#99D52A80', - '#71717880', - '#FFD70080', - '#40E0D080', - '#8DA4EF80', - '#C25D0580', - '#067A6F80', - '#CF91D880', - '#EB909180', - '#0C779280', - '#E38EC380', - '#97CF9C80', - '#AA99EC80', - '#94BA2C80', - '#4B4B5180', - '#FFE76680', - '#33B2A680', -]; - -export const COLOR_MAP = new Map([ - ['blue', BLUE], - ['default', DEFAULT], - ['green', GREEN], - ['pink', PINK], - ['red', RED], - ['yellow', YELLOW], -]); diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index 309e43abb87..cc5e8faa948 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -158,12 +158,9 @@ export const generateGraphData = (props: GraphDataOptionsProps) => { serviceType, status, unit, - // widgetChartType, - // widgetColor, } = props; const legendRowsData: MetricsDisplayRow[] = []; // for now we will use this, but once we decide how to work with coloring, it should be dynamic - // const colors = COLOR_MAP.get(widgetColor ?? 'default')!; const dimension: { [timestamp: number]: { [label: string]: number } } = {}; const areas: AreaProps[] = []; const colors = Object.values(Alias.Chart.Categorical); From 36bc02546ea7eacdd0db35604a5bff0090a1a167 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Wed, 16 Oct 2024 18:41:36 +0530 Subject: [PATCH 186/474] upcoming: [DI-20928] - Test fixes --- .../src/features/CloudPulse/Overview/GlobalFilters.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.test.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.test.tsx index bdb9bc34884..286c95377e1 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.test.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.test.tsx @@ -35,7 +35,7 @@ describe('Global filters component test', () => { expect(timeRangeSelect).toBeInTheDocument(); expect( - screen.getByRole('combobox', { name: 'Select a Time Duration' }) + screen.getByRole('combobox', { name: 'Time Range' }) ).toHaveAttribute('value', 'Last 30 Minutes'); }); }); From 25cd49094d4c92a5016a2927076534f5cffb3bca Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 16 Oct 2024 19:23:44 +0530 Subject: [PATCH 187/474] upcoming: [DI-20870] - Optimized code --- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 51 ++++++++++++++----- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index cc5e8faa948..e0a821edbfc 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -145,11 +145,33 @@ interface DimensionNameProperties { resources: CloudPulseResources[]; } +interface GraphData { + /** + * array of area props to be shown on graph + */ + areas: AreaProps[]; + + /** + * plots to be shown of each dimension + */ + dimensions: DataSet[]; + + /** + * legends rows available for each dimension + */ + legendRowsData: MetricsDisplayRow[]; + + /** + * maximum possible rolled up unit for the data + */ + unit: string; +} + /** * * @returns parameters which will be necessary to populate graph & legends */ -export const generateGraphData = (props: GraphDataOptionsProps) => { +export const generateGraphData = (props: GraphDataOptionsProps): GraphData => { const { flags, label, @@ -194,15 +216,15 @@ export const generateGraphData = (props: GraphDataOptionsProps) => { }; const labelName = getLabelName(labelOptions); const data = seriesDataFormatter(transformedData.values, start, end); - const color = colors[index]?.Primary ?? Alias.Chart.Neutral; + const color = colors[index].Primary; areas.push({ color, dataKey: labelName, }); - data.forEach((d) => { - const timestamp = d[0]; - const value = d[1]; + data.forEach((dataPoint) => { + const timestamp = dataPoint[0]; + const value = dataPoint[1]; if (value !== null) { dimension[timestamp] = { ...dimension[timestamp], @@ -223,14 +245,19 @@ export const generateGraphData = (props: GraphDataOptionsProps) => { } const maxUnit = generateMaxUnit(legendRowsData, unit); - const dimensions: DataSet[] = Object.entries(dimension).map( - ([key, value]) => { - const rolledUpData: { [resource: string]: number } = {}; - Object.entries(value).forEach( - ([resource, data]) => - (rolledUpData[resource] = convertValueToUnit(data, maxUnit)) + const dimensions = Object.entries(dimension).map( + ([timestamp, resource]): DataSet => { + const rolledUpData = Object.entries(resource).reduce( + (previousValue, newValue) => { + return { + ...previousValue, + [newValue[0]]: convertValueToUnit(newValue[1], maxUnit), + }; + }, + {} ); - return { timestamp: Number(key), ...rolledUpData }; + + return { timestamp: Number(timestamp), ...rolledUpData }; } ); return { From f7711541873fd5923a1005cf9835c668a02ac163 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Thu, 17 Oct 2024 10:10:52 +0530 Subject: [PATCH 188/474] upcoming: [DI-20928] - Flip issue fixes --- .../src/components/Autocomplete/Autocomplete.styles.tsx | 8 ++++++-- .../features/CloudPulse/shared/CloudPulseCustomSelect.tsx | 5 +++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/components/Autocomplete/Autocomplete.styles.tsx b/packages/manager/src/components/Autocomplete/Autocomplete.styles.tsx index 9f31b39af99..36707ff7181 100644 --- a/packages/manager/src/components/Autocomplete/Autocomplete.styles.tsx +++ b/packages/manager/src/components/Autocomplete/Autocomplete.styles.tsx @@ -44,7 +44,7 @@ export const SelectedIcon = styled(DoneIcon, { })); export const CustomPopper = (props: PopperProps) => { - const { style, ...rest } = props; + const { placement, style, ...rest } = props; const updatedStyle = { ...style, @@ -58,9 +58,13 @@ export const CustomPopper = (props: PopperProps) => { return ( ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index ec2b043294e..6a136770704 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; +import { CustomPopper } from 'src/components/Autocomplete/Autocomplete.styles'; import { useGetCustomFiltersQuery } from 'src/queries/cloudpulse/customfilters'; import { @@ -14,6 +15,7 @@ import type { QueryFunctionAndKey, } from '../Utils/models'; import type { AclpConfig, FilterValue } from '@linode/api-v4'; +import type { PopperProps } from '@mui/material'; /** * These are the properties requires for CloudPulseCustomSelect Components @@ -219,6 +221,9 @@ export const CloudPulseCustomSelect = React.memo( return ( ( + + )} options={ type === CloudPulseSelectTypes.static ? options ?? [] From aa7d44231637892d57274a12cf764fb333955e6c Mon Sep 17 00:00:00 2001 From: vmangalr Date: Thu, 17 Oct 2024 12:46:28 +0530 Subject: [PATCH 189/474] upcoming: [DI-20928] - Code refactoring and UT additions --- .../components/RegionSelect/RegionSelect.tsx | 2 +- .../CloudPulse/Utils/FilterBuilder.test.ts | 100 ++++++++++++------ .../CloudPulse/Utils/FilterBuilder.ts | 3 +- .../features/CloudPulse/Utils/FilterConfig.ts | 2 +- .../shared/CloudPulseCustomSelect.test.tsx | 6 +- .../shared/CloudPulseCustomSelect.tsx | 2 +- .../shared/CloudPulseRegionSelect.tsx | 2 +- .../shared/CloudPulseResourcesSelect.test.tsx | 5 + .../shared/CloudPulseResourcesSelect.tsx | 2 +- .../shared/CloudPulseTimeRangeSelect.tsx | 4 +- 10 files changed, 87 insertions(+), 41 deletions(-) diff --git a/packages/manager/src/components/RegionSelect/RegionSelect.tsx b/packages/manager/src/components/RegionSelect/RegionSelect.tsx index 90f3c805ff2..62466762b5a 100644 --- a/packages/manager/src/components/RegionSelect/RegionSelect.tsx +++ b/packages/manager/src/components/RegionSelect/RegionSelect.tsx @@ -176,7 +176,7 @@ export const RegionSelect = < label={label ?? 'Region'} loading={accountAvailabilityLoading} loadingText="Loading regions..." - noMarginTop={noMarginTop} + noMarginTop={noMarginTop || false} noOptionsText="No results" onChange={onChange} options={regionOptions} diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.test.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.test.ts index 6687ebbb561..8b95abb53de 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.test.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.test.ts @@ -31,7 +31,11 @@ it('test getRegionProperties method', () => { expect(regionConfig).toBeDefined(); if (regionConfig) { - const result = getRegionProperties( + const { + handleRegionChange, + label, + selectedDashboard, + } = getRegionProperties( { config: regionConfig, dashboard: mockDashboard, @@ -39,20 +43,25 @@ it('test getRegionProperties method', () => { }, vi.fn() ); - expect(result['handleRegionChange']).toBeDefined(); - expect(result['selectedDashboard']).toEqual(mockDashboard); + expect(handleRegionChange).toBeDefined(); + expect(selectedDashboard).toEqual(mockDashboard); + expect(label).toEqual(regionConfig.configuration.name); } }); it('test getTimeDuratonProperties method', () => { const timeDurationConfig = linodeConfig?.filters.find( - (filterObj) => filterObj.name === 'Time Duration' + (filterObj) => filterObj.name === 'Time Range' ); expect(timeDurationConfig).toBeDefined(); if (timeDurationConfig) { - const result = getTimeDurationProperties( + const { + handleStatsChange, + label, + savePreferences, + } = getTimeDurationProperties( { config: timeDurationConfig, dashboard: mockDashboard, @@ -60,8 +69,9 @@ it('test getTimeDuratonProperties method', () => { }, vi.fn() ); - expect(result['handleStatsChange']).toBeDefined(); - expect(result['savePreferences']).toEqual(true); + expect(handleStatsChange).toBeDefined(); + expect(savePreferences).toEqual(true); + expect(label).toEqual(timeDurationConfig.configuration.name); } }); @@ -73,7 +83,13 @@ it('test getResourceSelectionProperties method', () => { expect(resourceSelectionConfig).toBeDefined(); if (resourceSelectionConfig) { - const result = getResourcesProperties( + const { + disabled, + handleResourcesSelection, + label, + savePreferences, + xFilter, + } = getResourcesProperties( { config: resourceSelectionConfig, dashboard: mockDashboard, @@ -82,12 +98,11 @@ it('test getResourceSelectionProperties method', () => { }, vi.fn() ); - expect(result['handleResourcesSelection']).toBeDefined(); - expect(result['savePreferences']).toEqual(false); - expect(result['disabled']).toEqual(false); - expect(JSON.stringify(result['xFilter'])).toEqual( - '{"+and":[{"region":"us-east"}]}' - ); + expect(handleResourcesSelection).toBeDefined(); + expect(savePreferences).toEqual(false); + expect(disabled).toEqual(false); + expect(JSON.stringify(xFilter)).toEqual('{"+and":[{"region":"us-east"}]}'); + expect(label).toEqual(resourceSelectionConfig.configuration.name); } }); @@ -99,7 +114,13 @@ it('test getResourceSelectionProperties method with disabled true', () => { expect(resourceSelectionConfig).toBeDefined(); if (resourceSelectionConfig) { - const result = getResourcesProperties( + const { + disabled, + handleResourcesSelection, + label, + savePreferences, + xFilter, + } = getResourcesProperties( { config: resourceSelectionConfig, dashboard: mockDashboard, @@ -108,10 +129,11 @@ it('test getResourceSelectionProperties method with disabled true', () => { }, vi.fn() ); - expect(result['handleResourcesSelection']).toBeDefined(); - expect(result['savePreferences']).toEqual(false); - expect(result['disabled']).toEqual(true); - expect(JSON.stringify(result['xFilter'])).toEqual('{"+and":[]}'); + expect(handleResourcesSelection).toBeDefined(); + expect(savePreferences).toEqual(false); + expect(disabled).toEqual(true); + expect(JSON.stringify(xFilter)).toEqual('{"+and":[]}'); + expect(label).toEqual(resourceSelectionConfig.configuration.name); } }); @@ -201,7 +223,14 @@ it('test getCustomSelectProperties method', () => { expect(customSelectEngineConfig).toBeDefined(); if (customSelectEngineConfig) { - let result = getCustomSelectProperties( + const { + clearDependentSelections, + disabled, + isMultiSelect, + label, + options, + savePreferences, + } = getCustomSelectProperties( { config: customSelectEngineConfig, dashboard: { ...mockDashboard, service_type: 'dbaas' }, @@ -210,13 +239,14 @@ it('test getCustomSelectProperties method', () => { vi.fn() ); - expect(result.options).toBeDefined(); - expect(result.options?.length).toEqual(2); - expect(result.savePreferences).toEqual(false); - expect(result.isMultiSelect).toEqual(false); - expect(result.disabled).toEqual(false); - expect(result.clearDependentSelections).toBeDefined(); - expect(result.clearDependentSelections?.includes(RESOURCES)).toBe(true); + expect(options).toBeDefined(); + expect(options?.length).toEqual(2); + expect(savePreferences).toEqual(false); + expect(isMultiSelect).toEqual(false); + expect(label).toEqual(customSelectEngineConfig.configuration.name); + expect(disabled).toEqual(false); + expect(clearDependentSelections).toBeDefined(); + expect(clearDependentSelections?.includes(RESOURCES)).toBe(true); customSelectEngineConfig.configuration.type = CloudPulseSelectTypes.dynamic; customSelectEngineConfig.configuration.apiV4QueryKey = @@ -224,7 +254,12 @@ it('test getCustomSelectProperties method', () => { customSelectEngineConfig.configuration.isMultiSelect = true; customSelectEngineConfig.configuration.options = undefined; - result = getCustomSelectProperties( + const { + apiV4QueryKey, + isMultiSelect: isMultiSelectApi, + savePreferences: savePreferencesApi, + type, + } = getCustomSelectProperties( { config: customSelectEngineConfig, dashboard: mockDashboard, @@ -233,10 +268,11 @@ it('test getCustomSelectProperties method', () => { vi.fn() ); - expect(result.apiV4QueryKey).toEqual(databaseQueries.engines); - expect(result.type).toEqual(CloudPulseSelectTypes.dynamic); - expect(result.savePreferences).toEqual(false); - expect(result.isMultiSelect).toEqual(true); + expect(apiV4QueryKey).toEqual(databaseQueries.engines); + expect(type).toEqual(CloudPulseSelectTypes.dynamic); + expect(savePreferencesApi).toEqual(false); + expect(isMultiSelectApi).toEqual(true); + expect(label).toEqual(customSelectEngineConfig.configuration.name); } }); diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts index 7e8cad885ba..e058b2e3d03 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts @@ -187,13 +187,14 @@ export const getTimeDurationProperties = ( savePref?: boolean ) => void ): CloudPulseTimeRangeSelectProps => { - const { placeholder } = props.config.configuration; + const { name: label, placeholder } = props.config.configuration; const { isServiceAnalyticsIntegration, preferences } = props; const timeDuration = preferences?.timeDuration; return { defaultValue: timeDuration, handleStatsChange: handleTimeRangeChange, + label, placeholder, savePreferences: !isServiceAnalyticsIntegration, }; diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts b/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts index af7e0f8d91b..c44e25256d5 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts @@ -2,7 +2,7 @@ import { CloudPulseSelectTypes } from './models'; import type { CloudPulseServiceTypeFilterMap } from './models'; -const TIME_DURATION = 'Time Duration'; +const TIME_DURATION = 'Time Range'; export const LINODE_CONFIG: Readonly = { filters: [ diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.test.tsx index e07b83138eb..59f92338cf9 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.test.tsx @@ -63,6 +63,7 @@ describe('CloudPulseCustomSelect component tests', () => { /> ); expect(screen.queryByPlaceholderText(testFilter)).toBeNull(); + expect(screen.getByLabelText('Test')).toBeInTheDocument(); const keyDown = screen.getByTestId(keyboardArrowDownIcon); fireEvent.click(keyDown); fireEvent.click(screen.getByText('Test1')); @@ -77,13 +78,14 @@ describe('CloudPulseCustomSelect component tests', () => { filterType="number" handleSelectionChange={vi.fn()} isMultiSelect={true} - label="Test" + label="CustomTest" options={[...mockOptions]} placeholder={testFilter} type={CloudPulseSelectTypes.static} /> ); expect(screen.queryByPlaceholderText(testFilter)).toBeNull(); + expect(screen.getByLabelText('CustomTest')).toBeInTheDocument(); const keyDown = screen.getByTestId(keyboardArrowDownIcon); fireEvent.click(keyDown); expect(screen.getAllByText('Test1').length).toEqual(2); // here it should be 2 @@ -113,6 +115,7 @@ describe('CloudPulseCustomSelect component tests', () => { /> ); expect(screen.queryByPlaceholderText(testFilter)).toBeNull(); + expect(screen.getByLabelText('Test')).toBeInTheDocument(); const keyDown = screen.getByTestId(keyboardArrowDownIcon); fireEvent.click(keyDown); fireEvent.click(screen.getByText('Test1')); @@ -140,6 +143,7 @@ describe('CloudPulseCustomSelect component tests', () => { /> ); expect(screen.queryByPlaceholderText(testFilter)).toBeNull(); + expect(screen.getByLabelText('Test')).toBeInTheDocument(); const keyDown = screen.getByTestId(keyboardArrowDownIcon); fireEvent.click(keyDown); expect(screen.getAllByText('Test1').length).toEqual(2); // here it should be 2 diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index 6a136770704..3ffa5b537c7 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -239,7 +239,7 @@ export const CloudPulseCustomSelect = React.memo( disabled={isAutoCompleteDisabled} errorText={staticErrorText} isOptionEqualToValue={(option, value) => option.label === value.label} - label={Boolean(label?.length) ? label : 'Select a Value'} + label={label || 'Select a Value'} multiple={isMultiSelect} noMarginTop onChange={handleChange} diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index e7b121585cc..6a6b7bc388c 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -51,7 +51,7 @@ export const CloudPulseRegionSelect = React.memo( disableClearable={false} disabled={!selectedDashboard || !regions} fullWidth - label={Boolean(label?.length) ? label : 'Region'} + label={label || 'Region'} noMarginTop placeholder={placeholder ?? 'Select a Region'} regions={regions ? regions : []} diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx index d2210f8ddc8..ec2f6c04ef8 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx @@ -39,6 +39,7 @@ describe('CloudPulseResourcesSelect component tests', () => { /> ); expect(getByTestId('resource-select')).toBeInTheDocument(); + expect(screen.getByLabelText('Resources')).toBeInTheDocument(); expect(getByPlaceholderText('Select a Resource')).toBeInTheDocument(); }), it('should render resources happy path', () => { @@ -57,6 +58,7 @@ describe('CloudPulseResourcesSelect component tests', () => { /> ); fireEvent.click(screen.getByRole('button', { name: 'Open' })); + expect(screen.getByLabelText('Resources')).toBeInTheDocument(); expect( screen.getByRole('option', { name: 'linode-3', @@ -86,6 +88,7 @@ describe('CloudPulseResourcesSelect component tests', () => { ); fireEvent.click(screen.getByRole('button', { name: 'Open' })); fireEvent.click(screen.getByRole('option', { name: SELECT_ALL })); + expect(screen.getByLabelText('Resources')).toBeInTheDocument(); expect( screen.getByRole('option', { name: 'linode-5', @@ -116,6 +119,7 @@ describe('CloudPulseResourcesSelect component tests', () => { fireEvent.click(screen.getByRole('button', { name: 'Open' })); fireEvent.click(screen.getByRole('option', { name: SELECT_ALL })); fireEvent.click(screen.getByRole('option', { name: 'Deselect All' })); + expect(screen.getByLabelText('Resources')).toBeInTheDocument(); expect( screen.getByRole('option', { name: 'linode-7', @@ -146,6 +150,7 @@ describe('CloudPulseResourcesSelect component tests', () => { fireEvent.click(screen.getByRole('button', { name: 'Open' })); fireEvent.click(screen.getByRole('option', { name: 'linode-9' })); fireEvent.click(screen.getByRole('option', { name: 'linode-10' })); + expect(screen.getByLabelText('Resources')).toBeInTheDocument(); expect( screen.getByRole('option', { diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index 1a3aed382d2..e2c46fb611c 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -119,7 +119,7 @@ export const CloudPulseResourcesSelect = React.memo( data-testid="resource-select" disabled={disabled || isLoading} isOptionEqualToValue={(option, value) => option.id === value.id} - label={Boolean(label?.length) ? label : 'Resources'} + label={label || 'Resources'} limitTags={2} multiple noMarginTop diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx index 323141e3bd2..c0e74b2d2b6 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx @@ -36,7 +36,7 @@ export type Labels = export const CloudPulseTimeRangeSelect = React.memo( (props: CloudPulseTimeRangeSelectProps) => { - const { defaultValue, handleStatsChange, savePreferences } = props; + const { defaultValue, handleStatsChange, label, savePreferences } = props; const options = generateSelectOptions(); const getDefaultValue = React.useCallback((): Item => { if (!savePreferences) { @@ -85,7 +85,7 @@ export const CloudPulseTimeRangeSelect = React.memo( disableClearable fullWidth isOptionEqualToValue={(option, value) => option.value === value.value} - label="Time Range" + label={label || 'Time Range'} noMarginTop options={options} value={selectedTimeRange} From ba9a533356cfa5dc6af6d395243eac46fa0463f8 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Thu, 17 Oct 2024 13:05:53 +0530 Subject: [PATCH 190/474] upcoming: [DI-20928] - Code refactoring and edits --- .../manager/src/features/CloudPulse/Overview/GlobalFilters.tsx | 2 +- .../features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index 06b1a0a348d..5da22919834 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -107,7 +107,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { defaultValue={preferences?.timeDuration} handleStatsChange={handleTimeRangeChange} hideLabel - label="Select Time Range" + label="Time Range" savePreferences /> diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx index be4f31edf36..5d85ad3156c 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx @@ -20,9 +20,10 @@ describe('CloudPulseRegionSelect', () => { } as ReturnType); it('should render a Region Select component', () => { - const { getByTestId } = renderWithTheme( + const { getByLabelText, getByTestId } = renderWithTheme( ); + expect(getByLabelText(props.label)).toBeInTheDocument(); expect(getByTestId('region-select')).toBeInTheDocument(); }); }); From 0b478c0522fd5183e4c796f5c8f88d2bbb1709c9 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Thu, 17 Oct 2024 13:13:15 +0530 Subject: [PATCH 191/474] upcoming: [DI-20928] - Destructure properties from objects and use --- .../CloudPulse/Utils/FilterBuilder.test.ts | 16 +++++++++++----- .../shared/CloudPulseRegionSelect.test.tsx | 3 ++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.test.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.test.ts index 8b95abb53de..963d804147c 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.test.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.test.ts @@ -43,9 +43,10 @@ it('test getRegionProperties method', () => { }, vi.fn() ); + const { name } = regionConfig.configuration; expect(handleRegionChange).toBeDefined(); expect(selectedDashboard).toEqual(mockDashboard); - expect(label).toEqual(regionConfig.configuration.name); + expect(label).toEqual(name); } }); @@ -69,9 +70,10 @@ it('test getTimeDuratonProperties method', () => { }, vi.fn() ); + const { name } = timeDurationConfig.configuration; expect(handleStatsChange).toBeDefined(); expect(savePreferences).toEqual(true); - expect(label).toEqual(timeDurationConfig.configuration.name); + expect(label).toEqual(name); } }); @@ -98,11 +100,12 @@ it('test getResourceSelectionProperties method', () => { }, vi.fn() ); + const { name } = resourceSelectionConfig.configuration; expect(handleResourcesSelection).toBeDefined(); expect(savePreferences).toEqual(false); expect(disabled).toEqual(false); expect(JSON.stringify(xFilter)).toEqual('{"+and":[{"region":"us-east"}]}'); - expect(label).toEqual(resourceSelectionConfig.configuration.name); + expect(label).toEqual(name); } }); @@ -129,11 +132,12 @@ it('test getResourceSelectionProperties method with disabled true', () => { }, vi.fn() ); + const { name } = resourceSelectionConfig.configuration; expect(handleResourcesSelection).toBeDefined(); expect(savePreferences).toEqual(false); expect(disabled).toEqual(true); expect(JSON.stringify(xFilter)).toEqual('{"+and":[]}'); - expect(label).toEqual(resourceSelectionConfig.configuration.name); + expect(label).toEqual(name); } }); @@ -268,11 +272,13 @@ it('test getCustomSelectProperties method', () => { vi.fn() ); + const { name } = customSelectEngineConfig.configuration; + expect(apiV4QueryKey).toEqual(databaseQueries.engines); expect(type).toEqual(CloudPulseSelectTypes.dynamic); expect(savePreferencesApi).toEqual(false); expect(isMultiSelectApi).toEqual(true); - expect(label).toEqual(customSelectEngineConfig.configuration.name); + expect(label).toEqual(name); } }); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx index 5d85ad3156c..3b571880994 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx @@ -23,7 +23,8 @@ describe('CloudPulseRegionSelect', () => { const { getByLabelText, getByTestId } = renderWithTheme( ); - expect(getByLabelText(props.label)).toBeInTheDocument(); + const { label } = props; + expect(getByLabelText(label)).toBeInTheDocument(); expect(getByTestId('region-select')).toBeInTheDocument(); }); }); From 0ccaa1dc1f08da40a2a5776cee3f5fbe462d26e7 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Thu, 17 Oct 2024 15:29:45 +0530 Subject: [PATCH 192/474] upcoming: [DI-20928] - Resource to Resources --- .../manager/src/features/CloudPulse/Utils/FilterConfig.ts | 6 +++--- .../CloudPulse/shared/CloudPulseComponentRenderer.test.tsx | 2 +- .../CloudPulse/shared/CloudPulseResourcesSelect.test.tsx | 2 +- .../CloudPulse/shared/CloudPulseResourcesSelect.tsx | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts b/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts index c44e25256d5..43838df9efc 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts @@ -28,7 +28,7 @@ export const LINODE_CONFIG: Readonly = { isMultiSelect: true, name: 'Resources', neededInServicePage: false, - placeholder: 'Select a Resource', + placeholder: 'Select Resources', priority: 2, }, name: 'Resources', @@ -98,9 +98,9 @@ export const DBAAS_CONFIG: Readonly = { isFilterable: true, isMetricsFilter: true, isMultiSelect: true, - name: 'DB Cluster', + name: 'DB Clusters', neededInServicePage: false, - placeholder: 'Select a DB Cluster', + placeholder: 'Select DB Clusters', priority: 3, }, name: 'Resources', diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseComponentRenderer.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseComponentRenderer.test.tsx index 1b907419a46..dd74c70a1ef 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseComponentRenderer.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseComponentRenderer.test.tsx @@ -81,6 +81,6 @@ describe('ComponentRenderer component tests', () => { })} ); - expect(getByPlaceholderText('Select a Resource')).toBeDefined(); + expect(getByPlaceholderText('Select Resources')).toBeDefined(); }); }); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx index ec2f6c04ef8..23aaecb35ac 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx @@ -40,7 +40,7 @@ describe('CloudPulseResourcesSelect component tests', () => { ); expect(getByTestId('resource-select')).toBeInTheDocument(); expect(screen.getByLabelText('Resources')).toBeInTheDocument(); - expect(getByPlaceholderText('Select a Resource')).toBeInTheDocument(); + expect(getByPlaceholderText('Select Resources')).toBeInTheDocument(); }), it('should render resources happy path', () => { queryMocks.useResourcesQuery.mockReturnValue({ diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index e2c46fb611c..af107fbc18c 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -101,7 +101,7 @@ export const CloudPulseResourcesSelect = React.memo( isAutocompleteOpen.current = true; }} placeholder={ - selectedResources?.length ? '' : placeholder || 'Select a Resource' + selectedResources?.length ? '' : placeholder || 'Select Resources' } textFieldProps={{ InputProps: { From 00d2d74281db8a3c855f181be3cdd9a97abcd511 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Thu, 17 Oct 2024 18:26:13 +0530 Subject: [PATCH 193/474] upcoming: [DI-20928] - Popper placement changes --- .../.changeset/pr-11118-upcoming-features-1729147903845.md | 5 +++++ .../src/components/Autocomplete/Autocomplete.styles.tsx | 4 ++-- .../features/CloudPulse/shared/CloudPulseCustomSelect.tsx | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 packages/manager/.changeset/pr-11118-upcoming-features-1729147903845.md diff --git a/packages/manager/.changeset/pr-11118-upcoming-features-1729147903845.md b/packages/manager/.changeset/pr-11118-upcoming-features-1729147903845.md new file mode 100644 index 00000000000..e8a09469fac --- /dev/null +++ b/packages/manager/.changeset/pr-11118-upcoming-features-1729147903845.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Upcoming Features +--- + +Add labels / titles for all global filters in aclp ([#11118](https://github.com/linode/manager/pull/11118)) diff --git a/packages/manager/src/components/Autocomplete/Autocomplete.styles.tsx b/packages/manager/src/components/Autocomplete/Autocomplete.styles.tsx index 36707ff7181..d36c2be8fc9 100644 --- a/packages/manager/src/components/Autocomplete/Autocomplete.styles.tsx +++ b/packages/manager/src/components/Autocomplete/Autocomplete.styles.tsx @@ -60,11 +60,11 @@ export const CustomPopper = (props: PopperProps) => { {...rest} modifiers={[ { enabled: false, name: 'preventOverflow' }, - { enabled: !placement, name: 'flip' }, // if explicit placement is passed, no need to flip + { enabled: !placement, name: 'flip' }, ]} data-qa-autocomplete-popper data-testid="autocomplete-popper" - placement={placement ?? 'bottom'} + placement={placement || undefined} style={updatedStyle} /> ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index 3ffa5b537c7..16cddc35741 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -222,7 +222,7 @@ export const CloudPulseCustomSelect = React.memo( return ( ( - + )} options={ type === CloudPulseSelectTypes.static From a6d2e96f9e239a5f6c3afc7bafe80af0c0f0047f Mon Sep 17 00:00:00 2001 From: vmangalr Date: Thu, 17 Oct 2024 20:58:39 +0530 Subject: [PATCH 194/474] upcoming: [DI-20928] - PR comments --- .../manager/src/components/Autocomplete/Autocomplete.styles.tsx | 2 +- packages/manager/src/components/RegionSelect/RegionSelect.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/components/Autocomplete/Autocomplete.styles.tsx b/packages/manager/src/components/Autocomplete/Autocomplete.styles.tsx index d36c2be8fc9..5e4c9989e51 100644 --- a/packages/manager/src/components/Autocomplete/Autocomplete.styles.tsx +++ b/packages/manager/src/components/Autocomplete/Autocomplete.styles.tsx @@ -64,7 +64,7 @@ export const CustomPopper = (props: PopperProps) => { ]} data-qa-autocomplete-popper data-testid="autocomplete-popper" - placement={placement || undefined} + placement={placement} style={updatedStyle} /> ); diff --git a/packages/manager/src/components/RegionSelect/RegionSelect.tsx b/packages/manager/src/components/RegionSelect/RegionSelect.tsx index 62466762b5a..c6628df3821 100644 --- a/packages/manager/src/components/RegionSelect/RegionSelect.tsx +++ b/packages/manager/src/components/RegionSelect/RegionSelect.tsx @@ -176,7 +176,7 @@ export const RegionSelect = < label={label ?? 'Region'} loading={accountAvailabilityLoading} loadingText="Loading regions..." - noMarginTop={noMarginTop || false} + noMarginTop={noMarginTop ?? false} noOptionsText="No results" onChange={onChange} options={regionOptions} From 67d9cafdc197cc8aa2a5393d64ac1508f2f4b5b8 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 21 Oct 2024 11:42:43 +0530 Subject: [PATCH 195/474] upcoming: [DI-20928] - initial changes --- .../Dashboard/CloudPulseDashboard.tsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index 220c8b2813b..e106b8516b4 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -73,11 +73,13 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { const { data: dashboard, + isError: isDashboardApiError, isLoading: isDashboardLoading, } = useCloudPulseDashboardByIdQuery(dashboardId); const { data: resourceList, + isError: isResourceLoadingError, isLoading: isResourcesLoading, } = useResourcesQuery( Boolean(dashboard?.service_type), @@ -105,6 +107,22 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { Boolean(resourceList) ); + if (isDashboardApiError) { + return ( + + + + ); + } + + if (isResourceLoadingError) { + return ( + + + + ); + } + if (isJweTokenError) { return ( From 7aed67525f8a73664e57235b62b6af4921fc8308 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 21 Oct 2024 11:43:58 +0530 Subject: [PATCH 196/474] upcoming: [DI-20928] - merge issue fixes --- .../src/features/Databases/DatabaseDetail/index.tsx | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/packages/manager/src/features/Databases/DatabaseDetail/index.tsx b/packages/manager/src/features/Databases/DatabaseDetail/index.tsx index ca2fefc89c5..cf862c1613a 100644 --- a/packages/manager/src/features/Databases/DatabaseDetail/index.tsx +++ b/packages/manager/src/features/Databases/DatabaseDetail/index.tsx @@ -134,11 +134,6 @@ export const DatabaseDetail = () => { }); } - tabs.push({ - routeName: `/databases/${engine}/${id}/monitor`, - title: 'Monitor', - }); - const getTabIndex = () => { const tabChoice = tabs.findIndex((tab) => Boolean(matchPath(tab.routeName, { path: location.pathname })) @@ -242,12 +237,6 @@ export const DatabaseDetail = () => { disabled={isDatabasesGrantReadOnly} /> - - - {isDefault && } From 4fa4884e107639ad74026d4c74371909c732b490 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 21 Oct 2024 14:39:47 +0530 Subject: [PATCH 197/474] upcoming: [DI-18419] - more changes --- .../src/features/CloudPulse/Widget/CloudPulseWidget.tsx | 4 ++-- .../features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 44d5dbcdb39..1a6aa6b107f 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -251,8 +251,8 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { serviceType, status, unit, - widgetChartType: widget.chart_type, - widgetColor: widget.color, + widgetChartType: widget.chart_type || 'area', + widgetColor: widget.color || 'default', }); data = generatedData.dimensions; diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx index b8aa623ddba..79da5137b54 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx @@ -1,9 +1,7 @@ import { Grid, Paper } from '@mui/material'; import React from 'react'; -import CloudPulseIcon from 'src/assets/icons/entityIcons/monitor.svg'; -import { Placeholder } from 'src/components/Placeholder/Placeholder'; - +import { CloudPulseErrorPlaceholder } from '../shared/CloudPulseErrorPlaceholder'; import { createObjectCopy } from '../Utils/utils'; import { CloudPulseWidget } from './CloudPulseWidget'; import { @@ -45,7 +43,7 @@ const renderPlaceHolder = (subtitle: string) => { return ( - + ); From 3f1974846c8975cfe58c91447037188af39b7355 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Mon, 21 Oct 2024 18:40:57 +0530 Subject: [PATCH 198/474] upcoming: [DI-21520] - Added default xFilter for fetching aiven clusters --- .../CloudPulse/shared/CloudPulseResourcesSelect.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index 4b43d137019..8b57edd0287 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -45,7 +45,13 @@ export const CloudPulseResourcesSelect = React.memo( disabled !== undefined ? !disabled : Boolean(region && resourceType), resourceType, {}, - xFilter ? xFilter : { region } + resourceType === 'dbaas' + ? xFilter + ? { platform: 'rdbms-default', ...xFilter } + : { platform: 'rdbms-default', region } + : xFilter + ? xFilter + : { region } ); const [selectedResources, setSelectedResources] = React.useState< From 03f16adeabccac5a9bf2d8cd2feecf2d2a9f0e18 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 22 Oct 2024 12:54:50 +0530 Subject: [PATCH 199/474] upcoming: [DI-20928] - Changes --- .../CloudPulse/Widget/CloudPulseWidget.tsx | 2 +- .../shared/CloudPulseRegionSelect.tsx | 4 +- .../shared/CloudPulseResourcesSelect.tsx | 16 +++++-- packages/manager/src/mocks/serverHandlers.ts | 47 ++++++++++--------- 4 files changed, 42 insertions(+), 27 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 1a6aa6b107f..b6e1044afb4 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -295,7 +295,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { )} {Boolean( diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index 6a6b7bc388c..6a1f86339f8 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -16,7 +16,7 @@ export interface CloudPulseRegionSelectProps { export const CloudPulseRegionSelect = React.memo( (props: CloudPulseRegionSelectProps) => { - const { data: regions } = useRegionsQuery(); + const { data: regions, isError, isLoading: loading } = useRegionsQuery(); const { defaultValue, @@ -50,8 +50,10 @@ export const CloudPulseRegionSelect = React.memo( data-testid="region-select" disableClearable={false} disabled={!selectedDashboard || !regions} + errorText={isError ? `Failed to get ${label ?? 'Region'}` : ''} fullWidth label={label || 'Region'} + loading={loading} noMarginTop placeholder={placeholder ?? 'Select a Region'} regions={regions ? regions : []} diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index 9ee85d4cd6e..2ad3c86f901 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -43,11 +43,19 @@ export const CloudPulseResourcesSelect = React.memo( xFilter, } = props; - const { data: resources, isLoading } = useResourcesQuery( + const { data: resources, isError, isLoading } = useResourcesQuery( disabled !== undefined ? !disabled : Boolean(region && resourceType), resourceType, {}, - xFilter ? xFilter : { region } + xFilter + ? { + ...(resourceType === 'dbaas' ? { platform: 'rdbms-default' } : {}), + ...xFilter, + } + : { + ...(resourceType === 'dbaas' ? { platform: 'rdbms-default' } : {}), + region, + } ); const [selectedResources, setSelectedResources] = React.useState< @@ -121,10 +129,12 @@ export const CloudPulseResourcesSelect = React.memo( autoHighlight clearOnBlur data-testid="resource-select" - disabled={disabled || isLoading} + disabled={disabled} + errorText={isError ? `Failed to fetch ${label || 'Resources'}` : ''} isOptionEqualToValue={(option, value) => option.id === value.id} label={label || 'Resources'} limitTags={2} + loading={isLoading} multiple noMarginTop options={getResourcesList} diff --git a/packages/manager/src/mocks/serverHandlers.ts b/packages/manager/src/mocks/serverHandlers.ts index 2d092465043..03606302fae 100644 --- a/packages/manager/src/mocks/serverHandlers.ts +++ b/packages/manager/src/mocks/serverHandlers.ts @@ -204,6 +204,7 @@ const databases = [ http.get('*/databases/instances', () => { const databases = databaseInstanceFactory.buildList(9); return HttpResponse.json(makeResourcePage(databases)); + // return HttpResponse.error(); }), http.get('*/databases/types', () => { @@ -465,6 +466,7 @@ export const handlers = [ ), http.get('*/regions', async () => { return HttpResponse.json(makeResourcePage(regions)); + // return HttpResponse.error(); }), http.get<{ id: string }>('*/v4/images/:id', ({ params }) => { const distributedImage = imageFactory.build({ @@ -2068,26 +2070,27 @@ export const handlers = [ return HttpResponse.json({}, { status: 404 }); }), http.get('*regions/availability', () => { - return HttpResponse.json( - makeResourcePage([ - regionAvailabilityFactory.build({ - plan: 'g6-standard-6', - region: 'us-east', - }), - regionAvailabilityFactory.build({ - plan: 'g6-standard-7', - region: 'us-east', - }), - regionAvailabilityFactory.build({ - plan: 'g6-dedicated-5', - region: 'us-central', - }), - regionAvailabilityFactory.build({ - plan: 'g6-dedicated-6', - region: 'us-central', - }), - ]) - ); + // return HttpResponse.json( + // makeResourcePage([ + // regionAvailabilityFactory.build({ + // plan: 'g6-standard-6', + // region: 'us-east', + // }), + // regionAvailabilityFactory.build({ + // plan: 'g6-standard-7', + // region: 'us-east', + // }), + // regionAvailabilityFactory.build({ + // plan: 'g6-dedicated-5', + // region: 'us-central', + // }), + // regionAvailabilityFactory.build({ + // plan: 'g6-dedicated-6', + // region: 'us-central', + // }), + // ]) + // ); + return HttpResponse.error(); }), http.get('*regions/:regionId/availability', () => { return HttpResponse.json([ @@ -2313,11 +2316,11 @@ export const handlers = [ const response: ServiceTypesList = { data: [ serviceTypesFactory.build({ - label: 'Linode', + label: undefined, service_type: 'linode', }), serviceTypesFactory.build({ - label: 'Databases', + label: undefined, service_type: 'dbaas', }), ], From 0d8bf10ebd045807be66057088cf8b06c004034a Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 22 Oct 2024 12:59:26 +0530 Subject: [PATCH 200/474] upcoming: [DI-20928] - contextual view enabling --- .../DatabaseDetail/DatabaseMonitor/DatabaseMonitor.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseMonitor/DatabaseMonitor.tsx b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseMonitor/DatabaseMonitor.tsx index 5a255785977..ef47e2f34d0 100644 --- a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseMonitor/DatabaseMonitor.tsx +++ b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseMonitor/DatabaseMonitor.tsx @@ -8,7 +8,7 @@ interface Props { export const DatabaseMonitor = ({ database }: Props) => { const databaseId = database?.id; - const dbaasDashboardId = 1; + const dbaasDashboardId = 2; return ( Date: Tue, 22 Oct 2024 13:10:48 +0530 Subject: [PATCH 201/474] upcoming: [DI-20928] - contextual view enabling --- .../manager/src/features/Databases/DatabaseDetail/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/Databases/DatabaseDetail/index.tsx b/packages/manager/src/features/Databases/DatabaseDetail/index.tsx index cf862c1613a..f43e743e032 100644 --- a/packages/manager/src/features/Databases/DatabaseDetail/index.tsx +++ b/packages/manager/src/features/Databases/DatabaseDetail/index.tsx @@ -99,7 +99,7 @@ export const DatabaseDetail = () => { } const isDefault = database.platform === 'rdbms-default'; - const isMonitorEnabled = isDefault && isDatabasesMonitorEnabled; + const isMonitorEnabled = isDatabasesMonitorEnabled; const tabs: Tab[] = [ { From 4e80da4096c6a8e64283b89891a5f19ea5fabf13 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Tue, 22 Oct 2024 14:39:50 +0530 Subject: [PATCH 202/474] upcoming: [DI-21520] - Bug fix for service type label --- .../CloudPulse/shared/CloudPulseDashboardSelect.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index 81526099c4d..fcde0ed481f 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -31,7 +31,10 @@ export const CloudPulseDashboardSelect = React.memo( const serviceTypes: string[] = formattedServiceTypes(serviceTypesList); const serviceTypeMap: Map = new Map( - serviceTypesList?.data.map((item) => [item.service_type, item.label]) + (serviceTypesList?.data || []).map((item) => [ + item?.service_type ?? '', + item?.label ?? '', + ]) ); const { @@ -95,9 +98,7 @@ export const CloudPulseDashboardSelect = React.memo( renderGroup={(params) => ( - {serviceTypeMap.has(params.group) - ? serviceTypeMap.get(params.group) - : params.group} + {serviceTypeMap.get(params.group) || params.group} {params.children} From e3697ad5b700bdd806c9cf1c461e21be10ccd5ff Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Tue, 22 Oct 2024 16:01:44 +0530 Subject: [PATCH 203/474] upcoming: [DI-21520] - PR Comments --- .../shared/CloudPulseDashboardSelect.tsx | 7 +++---- .../shared/CloudPulseResourcesSelect.tsx | 19 ++++++++++++------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index fcde0ed481f..0a2e66781de 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -31,10 +31,9 @@ export const CloudPulseDashboardSelect = React.memo( const serviceTypes: string[] = formattedServiceTypes(serviceTypesList); const serviceTypeMap: Map = new Map( - (serviceTypesList?.data || []).map((item) => [ - item?.service_type ?? '', - item?.label ?? '', - ]) + (serviceTypesList?.data || []) + .filter((item) => item?.service_type !== undefined) + .map((item) => [item.service_type, item.label ?? '']) ); const { diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index 8b57edd0287..03f7c93caf7 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -41,17 +41,22 @@ export const CloudPulseResourcesSelect = React.memo( xFilter, } = props; + const platformFilter = + resourceType === 'dbaas' ? { platform: 'rdbms-default' } : {}; + const { data: resources, isLoading } = useResourcesQuery( disabled !== undefined ? !disabled : Boolean(region && resourceType), resourceType, {}, - resourceType === 'dbaas' - ? xFilter - ? { platform: 'rdbms-default', ...xFilter } - : { platform: 'rdbms-default', region } - : xFilter - ? xFilter - : { region } + xFilter + ? { + ...platformFilter, + ...xFilter, + } + : { + ...platformFilter, + region, + } ); const [selectedResources, setSelectedResources] = React.useState< From 3cb5edd5b911421db87db80e1e79a390a744f1a3 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Tue, 22 Oct 2024 18:03:51 +0530 Subject: [PATCH 204/474] Recharts reverted --- .../Utils/CloudPulseWidgetColorPalette.ts | 111 ++++++++++++++++ .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 122 +++++++----------- .../CloudPulse/Widget/CloudPulseWidget.tsx | 35 +++-- .../Widget/components/CloudPulseLineGraph.tsx | 40 +++++- 4 files changed, 207 insertions(+), 101 deletions(-) create mode 100644 packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetColorPalette.ts diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetColorPalette.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetColorPalette.ts new file mode 100644 index 00000000000..3b9325521d0 --- /dev/null +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetColorPalette.ts @@ -0,0 +1,111 @@ +export const RED = [ + '#ee2c2c80', + '#ff633d80', + '#F27E7E80', + '#EA7C7280', + '#E2796580', + '#D9775980', + '#D1744D80', + '#C9724080', + '#C16F3480', + '3B86D2880', + '#B06A1B80', + '#A8680F80', +]; + +export const GREEN = [ + '#10a21d80', + '#31ce3e80', + '#d9b0d980', + '#ffdc7d80', + '#7EF29D80', + '#72E39E80', + '#65D3A080', + '#59C4A180', + '#4DB5A280', + '#40A5A480', + '#3496A580', + '#2887A680', + '#1B77A880', + '#0F68A980', +]; + +export const BLUE = [ + '#3683dc80', + '#0F91A880', + '#1B9CAC80', + '#28A7AF80', + '#34B1B380', + '#40BCB680', + '#4DC7BA80', + '#59D2BD80', + '#65DCC180', + '#72E7C480', + '#7EF2C880', +]; + +export const YELLOW = [ + '#ffb34d80', + '#F2EE7E80', + '#E6E67280', + '#DBDE6580', + '#CFD75980', + '#C4CF4D80', + '#B8C74080', + '#ADBF3480', + '#A1B82880', + '#96B01B80', + '#8AA80F80', +]; + +export const PINK = [ + '#F27EE180', + '#EA72D180', + '#E265C280', + '#D959B280', + '#D14DA280', + '#C9409380', + '#C1348380', + '#B8287380', + '#B01B6480', + '#A80F5480', +]; + +export const DEFAULT = [ + // thick colors from each... + '#4067E580', + '#FE993380', + '#12A59480', + '#AB4ABA80', + '#D63C4280', + '#05A2C280', + '#E043A780', + '#00B05080', + '#7259D680', + '#99D52A80', + '#71717880', + '#FFD70080', + '#40E0D080', + '#8DA4EF80', + '#C25D0580', + '#067A6F80', + '#CF91D880', + '#EB909180', + '#0C779280', + '#E38EC380', + '#97CF9C80', + '#AA99EC80', + '#94BA2C80', + '#4B4B5180', + '#FFE76680', + '#33B2A680', +]; + +export const COLOR_MAP = new Map([ + ['blue', BLUE], + ['default', DEFAULT], + ['green', GREEN], + ['pink', PINK], + ['red', RED], + ['yellow', YELLOW], +]); diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index e0a821edbfc..44b4192fdf4 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -1,9 +1,8 @@ -import { Alias } from '@linode/design-language-system'; - +import { isToday } from 'src/utilities/isToday'; import { getMetrics } from 'src/utilities/statMetrics'; +import { COLOR_MAP } from './CloudPulseWidgetColorPalette'; import { - convertValueToUnit, formatToolTip, generateUnitByBaseUnit, transformData, @@ -14,17 +13,16 @@ import { } from './utils'; import type { CloudPulseResources } from '../shared/CloudPulseResourcesSelect'; +import type { LegendRow } from '../Widget/CloudPulseWidget'; import type { CloudPulseMetricsList, CloudPulseMetricsRequest, CloudPulseMetricsResponse, - DataSet, TimeDuration, Widgets, } from '@linode/api-v4'; import type { Theme } from '@mui/material'; -import type { AreaProps } from 'src/components/AreaChart/AreaChart'; -import type { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay'; +import type { DataSet } from 'src/components/LineGraph/LineGraph'; import type { CloudPulseResourceTypeMapFlag, FlagSet } from 'src/featureFlags'; interface LabelNameOptionsProps { @@ -59,7 +57,7 @@ interface LabelNameOptionsProps { unit: string; } -interface GraphDataOptionsProps { +interface graphDataOptionsProps { /** * flags associated with metricsList */ @@ -145,33 +143,11 @@ interface DimensionNameProperties { resources: CloudPulseResources[]; } -interface GraphData { - /** - * array of area props to be shown on graph - */ - areas: AreaProps[]; - - /** - * plots to be shown of each dimension - */ - dimensions: DataSet[]; - - /** - * legends rows available for each dimension - */ - legendRowsData: MetricsDisplayRow[]; - - /** - * maximum possible rolled up unit for the data - */ - unit: string; -} - /** * * @returns parameters which will be necessary to populate graph & legends */ -export const generateGraphData = (props: GraphDataOptionsProps): GraphData => { +export const generateGraphData = (props: graphDataOptionsProps) => { const { flags, label, @@ -180,24 +156,28 @@ export const generateGraphData = (props: GraphDataOptionsProps): GraphData => { serviceType, status, unit, + widgetChartType, + widgetColor, } = props; - const legendRowsData: MetricsDisplayRow[] = []; + + const dimensions: DataSet[] = []; + const legendRowsData: LegendRow[] = []; + // for now we will use this, but once we decide how to work with coloring, it should be dynamic - const dimension: { [timestamp: number]: { [label: string]: number } } = {}; - const areas: AreaProps[] = []; - const colors = Object.values(Alias.Chart.Categorical); + const colors = COLOR_MAP.get(widgetColor ?? 'default')!; + let today = false; + if (status === 'success') { metricsList?.data?.result?.forEach( (graphData: CloudPulseMetricsList, index) => { if (!graphData) { return; } - const transformedData = { metric: graphData.metric, values: transformData(graphData.values, unit), }; - // const color = colors[index]; + const color = colors[index]; const { end, start } = convertTimeDurationToStartAndEndTimeRange({ unit: 'min', value: 30, @@ -214,57 +194,33 @@ export const generateGraphData = (props: GraphDataOptionsProps): GraphData => { serviceType, unit, }; - const labelName = getLabelName(labelOptions); - const data = seriesDataFormatter(transformedData.values, start, end); - const color = colors[index].Primary; - areas.push({ - color, - dataKey: labelName, - }); - - data.forEach((dataPoint) => { - const timestamp = dataPoint[0]; - const value = dataPoint[1]; - if (value !== null) { - dimension[timestamp] = { - ...dimension[timestamp], - [labelName]: value, - }; - } - }); + + const dimension = { + backgroundColor: color, + borderColor: color, + data: seriesDataFormatter(transformedData.values, start, end), + fill: widgetChartType === 'area', + label: getLabelName(labelOptions), + }; // construct a legend row with the dimension - const legendRow: MetricsDisplayRow = { - data: getMetrics(data as number[][]), + const legendRow = { + data: getMetrics(dimension.data as number[][]), format: (value: number) => formatToolTip(value, unit), legendColor: color, - legendTitle: labelName, + legendTitle: dimension.label, }; legendRowsData.push(legendRow); + dimensions.push(dimension); + today ||= isToday(start, end); } ); } - const maxUnit = generateMaxUnit(legendRowsData, unit); - const dimensions = Object.entries(dimension).map( - ([timestamp, resource]): DataSet => { - const rolledUpData = Object.entries(resource).reduce( - (previousValue, newValue) => { - return { - ...previousValue, - [newValue[0]]: convertValueToUnit(newValue[1], maxUnit), - }; - }, - {} - ); - - return { timestamp: Number(timestamp), ...rolledUpData }; - } - ); return { - areas, dimensions, legendRowsData, - unit: maxUnit, + today, + unit: generateMaxUnit(legendRowsData, unit), }; }; @@ -274,7 +230,7 @@ export const generateGraphData = (props: GraphDataOptionsProps): GraphData => { * @param unit base unit of the values * @returns maximum possible rolled up unit based on the unit */ -const generateMaxUnit = (legendRowsData: MetricsDisplayRow[], unit: string) => { +const generateMaxUnit = (legendRowsData: LegendRow[], unit: string) => { const maxValue = Math.max( 0, ...legendRowsData?.map((row) => row?.data.max ?? 0) @@ -363,6 +319,20 @@ export const mapResourceIdToName = ( return resourcesObj?.label ?? id ?? ''; }; +/** + * + * @param data data set to be checked for empty + * @returns true if data is not empty or contains all the null values otherwise false + */ +export const isDataEmpty = (data: DataSet[]): boolean => { + return data.every( + (thisSeries) => + thisSeries.data.length === 0 || + // If we've padded the data, every y value will be null + thisSeries.data.every((thisPoint) => thisPoint[1] === null) + ); +}; + /** * * @param theme mui theme diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index f51b73108ed..44d5dbcdb39 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -14,6 +14,8 @@ import { import { AGGREGATE_FUNCTION, SIZE, TIME_GRANULARITY } from '../Utils/constants'; import { constructAdditionalRequestFilters } from '../Utils/FilterBuilder'; import { + convertValueToUnit, + formatToolTip, generateCurrentUnit, } from '../Utils/unitConversion'; import { useAclpPreference } from '../Utils/UserPreference'; @@ -27,13 +29,11 @@ import type { FilterValueType } from '../Dashboard/CloudPulseDashboardLanding'; import type { CloudPulseResources } from '../shared/CloudPulseResourcesSelect'; import type { AvailableMetrics, - DataSet, TimeDuration, TimeGranularity, } from '@linode/api-v4'; import type { Widgets } from '@linode/api-v4'; -import type { AreaProps } from 'src/components/AreaChart/AreaChart'; -import type { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay'; +import type { DataSet } from 'src/components/LineGraph/LineGraph'; import type { Metrics } from 'src/utilities/statMetrics'; export interface CloudPulseWidgetProperties { @@ -237,11 +237,11 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { url: flags.aclpReadEndpoint!, } ); + let data: DataSet[] = []; - let legendRows: MetricsDisplayRow[] = []; - let currentUnit = unit; - let areas: AreaProps[] = []; + let legendRows: LegendRow[] = []; + let today: boolean = false; if (!isLoading && metricsList) { const generatedData = generateGraphData({ flags, @@ -257,17 +257,12 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { data = generatedData.dimensions; legendRows = generatedData.legendRowsData; + today = generatedData.today; scaledWidgetUnit.current = generatedData.unit; // here state doesn't matter, as this is always the latest re-render - currentUnit = generatedData.unit; - areas = generatedData.areas; } const metricsApiCallError = error?.[0]?.reason; - const tickFormat = - duration.unit === 'min' || duration.unit === 'hr' - ? 'hh:mm a' - : `LLL dd${widget.size === 12 ? ', hh:mm a' : ''}`; return ( @@ -328,16 +323,20 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { ? metricsApiCallError ?? 'Error while rendering graph' : undefined } - areas={areas} + formatData={(data: number) => + convertValueToUnit(data, scaledWidgetUnit.current) + } + legendRows={ + legendRows && legendRows.length > 0 ? legendRows : undefined + } ariaLabel={ariaLabel ? ariaLabel : ''} data={data} - height={480} - legendRows={legendRows} + formatTooltip={(value: number) => formatToolTip(value, unit)} + gridSize={widget.size} loading={isLoading || metricsApiCallError === jweTokenExpiryError} // keep loading until we fetch the refresh token - showLegend + showToday={today} timezone={timezone} - unit={currentUnit} - xAxis={{ tickFormat, tickGap: 60 }} + title={widget.label} /> diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index a77b06ea01b..5c3ce2fd3fd 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -1,19 +1,29 @@ -import { Box, Typography } from '@mui/material'; +import { Box, Typography, useTheme } from '@mui/material'; import * as React from 'react'; -import { AreaChart } from 'src/components/AreaChart/AreaChart'; import { CircleProgress } from 'src/components/CircleProgress'; import { ErrorState } from 'src/components/ErrorState/ErrorState'; +import { LineGraph } from 'src/components/LineGraph/LineGraph'; -import type { AreaChartProps } from 'src/components/AreaChart/AreaChart'; +import { isDataEmpty } from '../../Utils/CloudPulseWidgetUtils'; -export interface CloudPulseLineGraph extends AreaChartProps { +import type { LegendRow } from '../CloudPulseWidget'; +import type { LineGraphProps } from 'src/components/LineGraph/LineGraph'; + +export interface CloudPulseLineGraph extends LineGraphProps { + ariaLabel?: string; error?: string; + gridSize: number; + legendRows?: LegendRow[]; loading?: boolean; + subtitle?: string; + title: string; } export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { - const { error, loading, ...rest } = props; + const { ariaLabel, data, error, legendRows, loading, ...rest } = props; + + const theme = useTheme(); if (loading) { return ; @@ -32,9 +42,25 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { ) : ( - + )} - {rest.data.length === 0 && ( + {isDataEmpty(data) && ( Date: Tue, 22 Oct 2024 18:22:53 +0530 Subject: [PATCH 205/474] upcoming: [DI-20928] - DB to Databases --- .../manager/src/features/CloudPulse/Utils/FilterConfig.ts | 8 ++++---- .../shared/CloudPulseDashboardFilterBuilder.test.tsx | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts b/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts index 43838df9efc..55c96678749 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts @@ -60,7 +60,7 @@ export const DBAAS_CONFIG: Readonly = { isFilterable: false, // isFilterable -- this determines whethere you need to pass it metrics api isMetricsFilter: false, // if it is false, it will go as a part of filter params, else global filter isMultiSelect: false, - name: 'Engine', + name: 'Database Engine', neededInServicePage: false, options: [ { @@ -72,7 +72,7 @@ export const DBAAS_CONFIG: Readonly = { label: 'PostgreSQL', }, ], - placeholder: 'Select an Engine', + placeholder: 'Select a Database Engine', priority: 2, type: CloudPulseSelectTypes.static, }, @@ -98,9 +98,9 @@ export const DBAAS_CONFIG: Readonly = { isFilterable: true, isMetricsFilter: true, isMultiSelect: true, - name: 'DB Clusters', + name: 'Database Clusters', neededInServicePage: false, - placeholder: 'Select DB Clusters', + placeholder: 'Select Database Clusters', priority: 3, }, name: 'Resources', diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.test.tsx index 006dc05afb6..ec2c10bacc5 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.test.tsx @@ -32,7 +32,7 @@ describe('CloudPulseDashboardFilterBuilder component tests', () => { /> ); - expect(getByPlaceholderText('Select an Engine')).toBeDefined(); + expect(getByPlaceholderText('Select a Database Engine')).toBeDefined(); expect(getByPlaceholderText('Select a Region')).toBeDefined(); }); }); From a69ddd4cbaea8396e803d073524ced97212aff51 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 22 Oct 2024 21:02:10 +0530 Subject: [PATCH 206/474] upcoming: [DI-20928] - Minor PR comments --- .../src/components/Autocomplete/Autocomplete.styles.tsx | 8 ++------ .../manager/src/components/RegionSelect/RegionSelect.tsx | 2 +- .../features/CloudPulse/shared/CloudPulseCustomSelect.tsx | 8 +++++--- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/manager/src/components/Autocomplete/Autocomplete.styles.tsx b/packages/manager/src/components/Autocomplete/Autocomplete.styles.tsx index 5e4c9989e51..9f31b39af99 100644 --- a/packages/manager/src/components/Autocomplete/Autocomplete.styles.tsx +++ b/packages/manager/src/components/Autocomplete/Autocomplete.styles.tsx @@ -44,7 +44,7 @@ export const SelectedIcon = styled(DoneIcon, { })); export const CustomPopper = (props: PopperProps) => { - const { placement, style, ...rest } = props; + const { style, ...rest } = props; const updatedStyle = { ...style, @@ -58,13 +58,9 @@ export const CustomPopper = (props: PopperProps) => { return ( ); diff --git a/packages/manager/src/components/RegionSelect/RegionSelect.tsx b/packages/manager/src/components/RegionSelect/RegionSelect.tsx index 3cd42b3dc33..1a107f1aa3f 100644 --- a/packages/manager/src/components/RegionSelect/RegionSelect.tsx +++ b/packages/manager/src/components/RegionSelect/RegionSelect.tsx @@ -173,7 +173,7 @@ export const RegionSelect = < label={label ?? 'Region'} loading={accountAvailabilityLoading} loadingText="Loading regions..." - noMarginTop={noMarginTop ?? false} + noMarginTop={noMarginTop} noOptionsText="No results" onChange={onChange} options={regionOptions} diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index 16cddc35741..0b90438036e 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -221,9 +221,6 @@ export const CloudPulseCustomSelect = React.memo( return ( ( - - )} options={ type === CloudPulseSelectTypes.static ? options ?? [] @@ -235,6 +232,11 @@ export const CloudPulseCustomSelect = React.memo( ? '' : placeholder || 'Select a Value' } + slotProps={{ + popper: { + placement: 'bottom', + }, + }} autoHighlight disabled={isAutoCompleteDisabled} errorText={staticErrorText} From 435cf5f9dd28a953542410c34d3fc8cefba3c42c Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 22 Oct 2024 21:05:09 +0530 Subject: [PATCH 207/474] upcoming: [DI-20928] - Minor PR comments --- .../src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index 0b90438036e..95c413c4adc 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; -import { CustomPopper } from 'src/components/Autocomplete/Autocomplete.styles'; import { useGetCustomFiltersQuery } from 'src/queries/cloudpulse/customfilters'; import { @@ -15,7 +14,6 @@ import type { QueryFunctionAndKey, } from '../Utils/models'; import type { AclpConfig, FilterValue } from '@linode/api-v4'; -import type { PopperProps } from '@mui/material'; /** * These are the properties requires for CloudPulseCustomSelect Components From f265b1a530d5c1f53327f173c3b49aa7ca5ef7e8 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 22 Oct 2024 21:15:18 +0530 Subject: [PATCH 208/474] upcoming: [DI-20928] - Minor PR comments --- .../src/components/Autocomplete/Autocomplete.styles.tsx | 8 ++++++-- .../features/CloudPulse/shared/CloudPulseCustomSelect.tsx | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/components/Autocomplete/Autocomplete.styles.tsx b/packages/manager/src/components/Autocomplete/Autocomplete.styles.tsx index 9f31b39af99..5e4c9989e51 100644 --- a/packages/manager/src/components/Autocomplete/Autocomplete.styles.tsx +++ b/packages/manager/src/components/Autocomplete/Autocomplete.styles.tsx @@ -44,7 +44,7 @@ export const SelectedIcon = styled(DoneIcon, { })); export const CustomPopper = (props: PopperProps) => { - const { style, ...rest } = props; + const { placement, style, ...rest } = props; const updatedStyle = { ...style, @@ -58,9 +58,13 @@ export const CustomPopper = (props: PopperProps) => { return ( ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index 95c413c4adc..0b90438036e 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; +import { CustomPopper } from 'src/components/Autocomplete/Autocomplete.styles'; import { useGetCustomFiltersQuery } from 'src/queries/cloudpulse/customfilters'; import { @@ -14,6 +15,7 @@ import type { QueryFunctionAndKey, } from '../Utils/models'; import type { AclpConfig, FilterValue } from '@linode/api-v4'; +import type { PopperProps } from '@mui/material'; /** * These are the properties requires for CloudPulseCustomSelect Components From 042a92da645a4d54251291f5ede6cd46e48442b4 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 22 Oct 2024 21:17:02 +0530 Subject: [PATCH 209/474] upcoming: [DI-20928] - Delete unused imports --- .../src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index 0b90438036e..95c413c4adc 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; -import { CustomPopper } from 'src/components/Autocomplete/Autocomplete.styles'; import { useGetCustomFiltersQuery } from 'src/queries/cloudpulse/customfilters'; import { @@ -15,7 +14,6 @@ import type { QueryFunctionAndKey, } from '../Utils/models'; import type { AclpConfig, FilterValue } from '@linode/api-v4'; -import type { PopperProps } from '@mui/material'; /** * These are the properties requires for CloudPulseCustomSelect Components From 9cb1b4529b4257fcf1bbf359d21545e2a26a86c4 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Wed, 23 Oct 2024 11:19:47 +0530 Subject: [PATCH 210/474] upcoming: [DI-18419] - remove unwanted changes --- .../features/CloudPulse/Widget/CloudPulseWidget.tsx | 2 +- .../CloudPulse/shared/CloudPulseRegionSelect.tsx | 2 +- .../CloudPulse/shared/CloudPulseResourcesSelect.tsx | 10 +--------- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index b6e1044afb4..1a6aa6b107f 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -295,7 +295,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { )} {Boolean( diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index 6a1f86339f8..7a505024703 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -50,7 +50,7 @@ export const CloudPulseRegionSelect = React.memo( data-testid="region-select" disableClearable={false} disabled={!selectedDashboard || !regions} - errorText={isError ? `Failed to get ${label ?? 'Region'}` : ''} + errorText={isError ? `Failed to get ${label || 'Region'}` : ''} fullWidth label={label || 'Region'} loading={loading} diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index 2ad3c86f901..2195547828e 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -47,15 +47,7 @@ export const CloudPulseResourcesSelect = React.memo( disabled !== undefined ? !disabled : Boolean(region && resourceType), resourceType, {}, - xFilter - ? { - ...(resourceType === 'dbaas' ? { platform: 'rdbms-default' } : {}), - ...xFilter, - } - : { - ...(resourceType === 'dbaas' ? { platform: 'rdbms-default' } : {}), - region, - } + xFilter ? xFilter : { region } ); const [selectedResources, setSelectedResources] = React.useState< From fe7fe04dfa6bf0581174bdb9f55e2c7bb93021a4 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Wed, 23 Oct 2024 11:55:11 +0530 Subject: [PATCH 211/474] upcoming: [DI-18419] - Error message updates --- .../src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index 7a505024703..a573f779483 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -50,7 +50,7 @@ export const CloudPulseRegionSelect = React.memo( data-testid="region-select" disableClearable={false} disabled={!selectedDashboard || !regions} - errorText={isError ? `Failed to get ${label || 'Region'}` : ''} + errorText={isError ? `Failed to get ${label || 'Regions'}` : ''} fullWidth label={label || 'Region'} loading={loading} From 00d6afa9b2f41b1df3409f7df946908d0cabe885 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Wed, 23 Oct 2024 11:57:17 +0530 Subject: [PATCH 212/474] upcoming: [DI-18419] - As per dev --- packages/manager/src/mocks/serverHandlers.ts | 47 +++++++++----------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/packages/manager/src/mocks/serverHandlers.ts b/packages/manager/src/mocks/serverHandlers.ts index 03606302fae..2d092465043 100644 --- a/packages/manager/src/mocks/serverHandlers.ts +++ b/packages/manager/src/mocks/serverHandlers.ts @@ -204,7 +204,6 @@ const databases = [ http.get('*/databases/instances', () => { const databases = databaseInstanceFactory.buildList(9); return HttpResponse.json(makeResourcePage(databases)); - // return HttpResponse.error(); }), http.get('*/databases/types', () => { @@ -466,7 +465,6 @@ export const handlers = [ ), http.get('*/regions', async () => { return HttpResponse.json(makeResourcePage(regions)); - // return HttpResponse.error(); }), http.get<{ id: string }>('*/v4/images/:id', ({ params }) => { const distributedImage = imageFactory.build({ @@ -2070,27 +2068,26 @@ export const handlers = [ return HttpResponse.json({}, { status: 404 }); }), http.get('*regions/availability', () => { - // return HttpResponse.json( - // makeResourcePage([ - // regionAvailabilityFactory.build({ - // plan: 'g6-standard-6', - // region: 'us-east', - // }), - // regionAvailabilityFactory.build({ - // plan: 'g6-standard-7', - // region: 'us-east', - // }), - // regionAvailabilityFactory.build({ - // plan: 'g6-dedicated-5', - // region: 'us-central', - // }), - // regionAvailabilityFactory.build({ - // plan: 'g6-dedicated-6', - // region: 'us-central', - // }), - // ]) - // ); - return HttpResponse.error(); + return HttpResponse.json( + makeResourcePage([ + regionAvailabilityFactory.build({ + plan: 'g6-standard-6', + region: 'us-east', + }), + regionAvailabilityFactory.build({ + plan: 'g6-standard-7', + region: 'us-east', + }), + regionAvailabilityFactory.build({ + plan: 'g6-dedicated-5', + region: 'us-central', + }), + regionAvailabilityFactory.build({ + plan: 'g6-dedicated-6', + region: 'us-central', + }), + ]) + ); }), http.get('*regions/:regionId/availability', () => { return HttpResponse.json([ @@ -2316,11 +2313,11 @@ export const handlers = [ const response: ServiceTypesList = { data: [ serviceTypesFactory.build({ - label: undefined, + label: 'Linode', service_type: 'linode', }), serviceTypesFactory.build({ - label: undefined, + label: 'Databases', service_type: 'dbaas', }), ], From 73853d6586f66ecdd8a2be7e427d9b3186351218 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Wed, 23 Oct 2024 13:49:55 +0530 Subject: [PATCH 213/474] upcoming: [DI-18419] - Dashboard selection issue fix --- .../features/CloudPulse/shared/CloudPulseDashboardSelect.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index 19828bc4328..c7cc53fdcc7 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -106,7 +106,7 @@ export const CloudPulseDashboardSelect = React.memo( clearOnBlur data-testid="cloudpulse-dashboard-select" disabled={!dashboardsList} - errorText={dashboardsList ? '' : errorText} + errorText={Boolean(dashboardsList?.length) ? '' : errorText} fullWidth groupBy={(option: Dashboard) => option.service_type} isOptionEqualToValue={(option, value) => option.id === value.id} From cd8d8c093c18119089faa9ca29374b2a9b060694 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Wed, 23 Oct 2024 13:53:14 +0530 Subject: [PATCH 214/474] upcoming: [DI-18419] - Using fetch in the error messages --- .../features/CloudPulse/shared/CloudPulseDashboardSelect.tsx | 4 ++-- .../src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index c7cc53fdcc7..438f9a05d36 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -49,11 +49,11 @@ export const CloudPulseDashboardSelect = React.memo( const getErrorText = () => { if (serviceTypesError) { - return 'Unable to load service types'; + return 'Failed to fetch service types'; } if (dashboardsError.length > 0) { - return `Unable to load ${dashboardsError.slice(0, -1)}`; + return `Failed to fetch dashboards for ${dashboardsError.slice(0, -1)}`; } return ''; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index a573f779483..3b3739e5ed5 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -50,7 +50,7 @@ export const CloudPulseRegionSelect = React.memo( data-testid="region-select" disableClearable={false} disabled={!selectedDashboard || !regions} - errorText={isError ? `Failed to get ${label || 'Regions'}` : ''} + errorText={isError ? `Failed to fetch ${label || 'Regions'}` : ''} fullWidth label={label || 'Region'} loading={loading} From 915dc9e725224cbc99abbb5a68af5a8ec4fede7d Mon Sep 17 00:00:00 2001 From: vmangalr Date: Wed, 23 Oct 2024 13:57:15 +0530 Subject: [PATCH 215/474] upcoming: [DI-18419] - Using fetch in the error messages --- .../src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index e106b8516b4..1d056d94204 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -110,7 +110,7 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { if (isDashboardApiError) { return ( - + ); } @@ -118,7 +118,7 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { if (isResourceLoadingError) { return ( - + ); } From 679bd3bb6d88bb4d44f5e39f0e2ba1f86711e1e6 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Wed, 23 Oct 2024 15:08:22 +0530 Subject: [PATCH 216/474] upcoming: [DI-18419] - Error fixes --- .../features/CloudPulse/shared/CloudPulseResourcesSelect.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index d18112604d5..bb4816252ac 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -42,11 +42,11 @@ export const CloudPulseResourcesSelect = React.memo( savePreferences, xFilter, } = props; - + const platformFilter = resourceType === 'dbaas' ? { platform: 'rdbms-default' } : {}; - const { data: resources, isLoading } = useResourcesQuery( + const { data: resources, isError, isLoading } = useResourcesQuery( disabled !== undefined ? !disabled : Boolean(region && resourceType), resourceType, {}, From 00f8efccd43aa6f46672084873562796dc2ec442 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Wed, 23 Oct 2024 15:49:24 +0530 Subject: [PATCH 217/474] upcoming: [DI-18419] - More code refactoring --- .../src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx | 4 ++-- .../features/CloudPulse/shared/CloudPulseDashboardSelect.tsx | 2 +- .../src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index 1d056d94204..2d53646230f 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -79,7 +79,7 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { const { data: resourceList, - isError: isResourceLoadingError, + isError: isResourcesApiError, isLoading: isResourcesLoading, } = useResourcesQuery( Boolean(dashboard?.service_type), @@ -115,7 +115,7 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { ); } - if (isResourceLoadingError) { + if (isResourcesApiError) { return ( diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index 66c08519ab4..7c15e313ba3 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -51,7 +51,7 @@ export const CloudPulseDashboardSelect = React.memo( const getErrorText = () => { if (serviceTypesError) { - return 'Failed to fetch service types'; + return 'Failed to fetch supported services for CloudPulse'; } if (dashboardsError.length > 0) { diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index 3b3739e5ed5..d9faa9862b2 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -16,7 +16,7 @@ export interface CloudPulseRegionSelectProps { export const CloudPulseRegionSelect = React.memo( (props: CloudPulseRegionSelectProps) => { - const { data: regions, isError, isLoading: loading } = useRegionsQuery(); + const { data: regions, isError, isLoading } = useRegionsQuery(); const { defaultValue, @@ -53,7 +53,7 @@ export const CloudPulseRegionSelect = React.memo( errorText={isError ? `Failed to fetch ${label || 'Regions'}` : ''} fullWidth label={label || 'Region'} - loading={loading} + loading={isLoading} noMarginTop placeholder={placeholder ?? 'Select a Region'} regions={regions ? regions : []} From f00d3a9de1c79e5d456e3c5e6166e2cef4f5032d Mon Sep 17 00:00:00 2001 From: vmangalr Date: Wed, 23 Oct 2024 15:58:14 +0530 Subject: [PATCH 218/474] upcoming: [DI-18419] - Error text validation --- .../features/CloudPulse/shared/CloudPulseDashboardSelect.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index 7c15e313ba3..8eb579528e0 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -90,6 +90,9 @@ export const CloudPulseDashboardSelect = React.memo( }, [dashboardsList]); return ( { setSelectedDashboard(dashboard); handleDashboardChange(dashboard, savePreferences); @@ -106,7 +109,6 @@ export const CloudPulseDashboardSelect = React.memo( clearOnBlur data-testid="cloudpulse-dashboard-select" disabled={!dashboardsList} - errorText={Boolean(dashboardsList?.length) ? '' : errorText} fullWidth groupBy={(option: Dashboard) => option.service_type} isOptionEqualToValue={(option, value) => option.id === value.id} From ffbc09d0640be4837bcb216aaf580a69dc1aefe7 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Wed, 23 Oct 2024 17:59:08 +0530 Subject: [PATCH 219/474] upcoming: [DI-18419] - Addressed the comments --- .../Dashboard/CloudPulseDashboard.tsx | 22 +++++++++---------- .../shared/CloudPulseDashboardSelect.tsx | 6 ++--- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index 2d53646230f..0ffae985652 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -110,23 +110,23 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { if (isDashboardApiError) { return ( - + ); } - if (isResourcesApiError) { + if (isResourcesApiError || isJweTokenError) { return ( - - - ); - } - - if (isJweTokenError) { - return ( - - + ); } diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index 8eb579528e0..78413851450 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -51,7 +51,7 @@ export const CloudPulseDashboardSelect = React.memo( const getErrorText = () => { if (serviceTypesError) { - return 'Failed to fetch supported services for CloudPulse'; + return 'Failed to fetch services'; } if (dashboardsError.length > 0) { @@ -90,9 +90,6 @@ export const CloudPulseDashboardSelect = React.memo( }, [dashboardsList]); return ( { setSelectedDashboard(dashboard); handleDashboardChange(dashboard, savePreferences); @@ -109,6 +106,7 @@ export const CloudPulseDashboardSelect = React.memo( clearOnBlur data-testid="cloudpulse-dashboard-select" disabled={!dashboardsList} + errorText={Boolean(dashboardsList?.length) ? '' : errorText} fullWidth groupBy={(option: Dashboard) => option.service_type} isOptionEqualToValue={(option, value) => option.id === value.id} From 552744493455b195e0b2514376a45175cbd4e73d Mon Sep 17 00:00:00 2001 From: vmangalr Date: Wed, 23 Oct 2024 18:01:16 +0530 Subject: [PATCH 220/474] upcoming: [DI-18419] - Addressed the comments --- .../Dashboard/CloudPulseDashboard.tsx | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index 0ffae985652..af39550c32c 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -107,26 +107,24 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { Boolean(resourceList) ); - if (isDashboardApiError) { + if (isResourcesApiError || isDashboardApiError) { return ( ); } - if (isResourcesApiError || isJweTokenError) { + if (isJweTokenError) { return ( - + ); } From dacd1e13bd2470c7bd27f07b4768da4af6a12b87 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Thu, 24 Oct 2024 12:04:54 +0530 Subject: [PATCH 221/474] upcoming: [DI-21520] - Add platform filter for jwe token fetch for aiven clusters in DBasS --- .../features/CloudPulse/Dashboard/CloudPulseDashboard.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index 220c8b2813b..cd8d2ceffa1 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -76,6 +76,9 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { isLoading: isDashboardLoading, } = useCloudPulseDashboardByIdQuery(dashboardId); + const platformFilter = + dashboard?.service_type === 'dbaas' ? { platform: 'rdbms-default' } : {}; + const { data: resourceList, isLoading: isResourcesLoading, @@ -83,7 +86,9 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { Boolean(dashboard?.service_type), dashboard?.service_type, {}, - {} + { + ...platformFilter, + } ); const { From 4fda4c63b66912e9f7a59dae59d0c36654d956b4 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Thu, 24 Oct 2024 12:35:01 +0530 Subject: [PATCH 222/474] upcoming: [DI-21520] - PR Comments --- .../src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index cd8d2ceffa1..5ab0a561327 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -87,7 +87,7 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { dashboard?.service_type, {}, { - ...platformFilter, + platformFilter, } ); From f17c7028fa8995fb768935824ee32436b9165076 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Thu, 24 Oct 2024 12:45:03 +0530 Subject: [PATCH 223/474] upcoming: [DI-21520] - PR Comments --- .../features/CloudPulse/Dashboard/CloudPulseDashboard.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index 5ab0a561327..a333a379858 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -76,9 +76,6 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { isLoading: isDashboardLoading, } = useCloudPulseDashboardByIdQuery(dashboardId); - const platformFilter = - dashboard?.service_type === 'dbaas' ? { platform: 'rdbms-default' } : {}; - const { data: resourceList, isLoading: isResourcesLoading, @@ -86,9 +83,7 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { Boolean(dashboard?.service_type), dashboard?.service_type, {}, - { - platformFilter, - } + dashboard?.service_type === 'dbaas' ? { platform: 'rdbms-default' } : {} ); const { From 7e18e2e30395c3de7e4dfb7768dc0911b2e94ef0 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Thu, 24 Oct 2024 16:06:38 +0530 Subject: [PATCH 224/474] upcoming: [DI-18419] - Revert error message changes for dashboards selection --- .../features/CloudPulse/shared/CloudPulseDashboardSelect.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index 78413851450..7b11c5e5cd7 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -51,11 +51,11 @@ export const CloudPulseDashboardSelect = React.memo( const getErrorText = () => { if (serviceTypesError) { - return 'Failed to fetch services'; + return 'Unable to load service types'; } if (dashboardsError.length > 0) { - return `Failed to fetch dashboards for ${dashboardsError.slice(0, -1)}`; + return `Unable to load ${dashboardsError.slice(0, -1)}`; } return ''; From 63ee2421953bab91f84e3620371f243ec2dd0eda Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Thu, 24 Oct 2024 15:30:28 +0530 Subject: [PATCH 225/474] upcoming: [DI-21118] - ACLP scope as part of PAT token --- .../APITokens/ViewAPITokenDrawer.test.tsx | 3 ++- .../features/Profile/APITokens/utils.test.ts | 18 +++++++++++++++++- .../src/features/Profile/APITokens/utils.ts | 2 ++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/Profile/APITokens/ViewAPITokenDrawer.test.tsx b/packages/manager/src/features/Profile/APITokens/ViewAPITokenDrawer.test.tsx index 7b1b44387e7..d1d7c9b0cee 100644 --- a/packages/manager/src/features/Profile/APITokens/ViewAPITokenDrawer.test.tsx +++ b/packages/manager/src/features/Profile/APITokens/ViewAPITokenDrawer.test.tsx @@ -111,13 +111,14 @@ describe('View API Token Drawer', () => { {...props} token={appTokenFactory.build({ scopes: - 'databases:read_only domains:read_write child_account:read_write events:read_write firewall:read_write images:read_write ips:read_write linodes:read_only lke:read_only longview:read_write nodebalancers:read_write object_storage:read_only stackscripts:read_write volumes:read_only vpc:read_write', + 'aclp:read_write databases:read_only domains:read_write child_account:read_write events:read_write firewall:read_write images:read_write ips:read_write linodes:read_only lke:read_only longview:read_write nodebalancers:read_write object_storage:read_only stackscripts:read_write volumes:read_only vpc:read_write', })} /> ); const expectedScopeLevels = { account: 0, + aclp: 2, child_account: 2, databases: 1, domains: 2, diff --git a/packages/manager/src/features/Profile/APITokens/utils.test.ts b/packages/manager/src/features/Profile/APITokens/utils.test.ts index ae7b23ce05c..628c5b1fdec 100644 --- a/packages/manager/src/features/Profile/APITokens/utils.test.ts +++ b/packages/manager/src/features/Profile/APITokens/utils.test.ts @@ -28,6 +28,7 @@ describe('APIToken utils', () => { const result = scopeStringToPermTuples('*'); const expected = [ ['account', 2], + ['aclp', 2], ['child_account', 2], ['databases', 2], ['domains', 2], @@ -53,6 +54,7 @@ describe('APIToken utils', () => { const result = scopeStringToPermTuples(''); const expected = [ ['account', 0], + ['aclp', 0], ['child_account', 0], ['databases', 0], ['domains', 0], @@ -79,6 +81,7 @@ describe('APIToken utils', () => { const result = scopeStringToPermTuples('account:none'); const expected = [ ['account', 0], + ['aclp', 0], ['child_account', 0], ['databases', 0], ['domains', 0], @@ -105,6 +108,7 @@ describe('APIToken utils', () => { const result = scopeStringToPermTuples('account:read_only'); const expected = [ ['account', 1], + ['aclp', 0], ['child_account', 0], ['databases', 0], ['domains', 0], @@ -131,6 +135,7 @@ describe('APIToken utils', () => { const result = scopeStringToPermTuples('account:read_write'); const expected = [ ['account', 2], + ['aclp', 0], ['child_account', 0], ['databases', 0], ['domains', 0], @@ -159,6 +164,7 @@ describe('APIToken utils', () => { ); const expected = [ ['account', 0], + ['aclp', 0], ['child_account', 0], ['databases', 0], ['domains', 1], @@ -189,6 +195,7 @@ describe('APIToken utils', () => { const result = scopeStringToPermTuples('account:none,tokens:read_write'); const expected = [ ['account', 2], + ['aclp', 0], ['child_account', 0], ['databases', 0], ['domains', 0], @@ -219,6 +226,7 @@ describe('APIToken utils', () => { const result = scopeStringToPermTuples('account:read_only,tokens:none'); const expected = [ ['account', 1], + ['aclp', 0], ['child_account', 0], ['databases', 0], ['domains', 0], @@ -245,6 +253,7 @@ describe('APIToken utils', () => { it('should return 0 if all scopes are 0', () => { const scopes: Permission[] = [ ['account', 0], + ['aclp', 0], ['child_account', 0], ['databases', 0], ['domains', 0], @@ -266,6 +275,7 @@ describe('APIToken utils', () => { it('should return 1 if all scopes are 1', () => { const scopes: Permission[] = [ ['account', 1], + ['aclp', 1], ['child_account', 1], ['databases', 1], ['domains', 1], @@ -286,6 +296,7 @@ describe('APIToken utils', () => { it('should return 2 if all scopes are 2', () => { const scopes: Permission[] = [ ['account', 2], + ['aclp', 2], ['child_account', 2], ['databases', 2], ['domains', 2], @@ -304,9 +315,10 @@ describe('APIToken utils', () => { ]; expect(allScopesAreTheSame(scopes)).toBe(2); }); - it('should return null if all scopes are different', () => { + it('should return null if all scopes are not same', () => { const scopes: Permission[] = [ ['account', 1], + ['aclp', 2], ['child_account', 0], ['databases', 0], ['domains', 2], @@ -329,6 +341,7 @@ describe('APIToken utils', () => { it('should return 1 if all scopes, except any exclusions, are 1', () => { const scopes: Permission[] = [ ['account', 1], + ['aclp', 1], ['child_account', 1], ['databases', 1], ['domains', 1], @@ -365,6 +378,7 @@ describe('APIToken utils', () => { describe('hasAccessBeenSelectedForAllScopes', () => { const defaultScopes: Permission[] = [ ['account', -1], + ['aclp', -1], ['child_account', -1], ['databases', -1], ['domains', -1], @@ -384,6 +398,7 @@ describe('hasAccessBeenSelectedForAllScopes', () => { const missingSelectionScopes: Permission[] = [ ['account', -1], + ['aclp', -1], ['child_account', -1], ['databases', -1], ['domains', -1], @@ -403,6 +418,7 @@ describe('hasAccessBeenSelectedForAllScopes', () => { const allSelectedScopes: Permission[] = [ ['account', 1], + ['aclp', 0], ['child_account', 0], ['databases', 0], ['domains', 0], diff --git a/packages/manager/src/features/Profile/APITokens/utils.ts b/packages/manager/src/features/Profile/APITokens/utils.ts index 4256637f84d..992cc8e57d3 100644 --- a/packages/manager/src/features/Profile/APITokens/utils.ts +++ b/packages/manager/src/features/Profile/APITokens/utils.ts @@ -8,6 +8,7 @@ export type Permission = [keyof typeof basePermNameMap, number]; export const basePerms = [ 'account', + 'aclp', 'child_account', 'databases', 'domains', @@ -27,6 +28,7 @@ export const basePerms = [ export const basePermNameMap = { account: 'Account', + aclp: 'ACLP', child_account: 'Child Account Access', databases: 'Databases', domains: 'Domains', From 8b2959b4892f430e34b9ac7d1a5f291ba8c13336 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 28 Oct 2024 11:18:39 +0530 Subject: [PATCH 226/474] upcoming: [DI-18419] - Error message updates --- .../src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx | 4 ++-- .../features/CloudPulse/shared/CloudPulseDashboardSelect.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index af39550c32c..1d8d3d292c3 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -113,8 +113,8 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index 7b11c5e5cd7..0f888d84d73 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -51,11 +51,11 @@ export const CloudPulseDashboardSelect = React.memo( const getErrorText = () => { if (serviceTypesError) { - return 'Unable to load service types'; + return 'Failed to fetch the services'; } if (dashboardsError.length > 0) { - return `Unable to load ${dashboardsError.slice(0, -1)}`; + return `Failed to fetch the dashboards`; } return ''; From 5b905a52afc90b3547bea66c418f97d2ac5f23c1 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 28 Oct 2024 13:06:45 +0530 Subject: [PATCH 227/474] upcoming: [DI-18419] - UT and code reusability updates --- .../Dashboard/CloudPulseDashboard.tsx | 34 +++++++------- .../shared/CloudPulseDashboardSelect.test.tsx | 33 +++++++++++++ .../shared/CloudPulseRegionSelect.test.tsx | 29 ++++++++++-- .../shared/CloudPulseResourcesSelect.test.tsx | 46 +++++++++++++++++++ 4 files changed, 120 insertions(+), 22 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index 1d8d3d292c3..be229412365 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -107,26 +107,16 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { Boolean(resourceList) ); - if (isResourcesApiError || isDashboardApiError) { - return ( - - - - ); + if (isResourcesApiError) { + return renderErrorState('Failed to fetch Resources'); + } + + if (isDashboardApiError) { + return renderErrorState('Failed to fetch the dashboard details'); } if (isJweTokenError) { - return ( - - - - ); + return renderErrorState('Failed to get jwe token'); } if ( @@ -139,7 +129,7 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { } if (isMetricDefinitionError) { - return ; + return renderErrorState('Error loading metric definitions'); } return ( @@ -157,3 +147,11 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { /> ); }; + +export const renderErrorState = (errorMessage: string) => { + return ( + + + + ); +}; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx index 664394ebafb..333399b6a62 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx @@ -100,4 +100,37 @@ describe('CloudPulse Dashboard select', () => { dashboardLabel ); }); + + it('Should show error message when only dashboard call fails', () => { + vi.spyOn(utils, 'getAllDashboards').mockReturnValue({ + data: [], + error: 'some error', + isLoading: false, + }); + + renderWithTheme(); + + expect( + screen.getByText('Failed to fetch the dashboards') + ).toBeInTheDocument(); + }); + it('Should show error message when services call fails', () => { + queryMocks.useCloudPulseServiceTypes.mockReturnValue({ + data: undefined, + error: 'an error happened', + isLoading: false, + }); + + vi.spyOn(utils, 'getAllDashboards').mockReturnValue({ + data: [], + error: 'some error', + isLoading: false, + }); + + renderWithTheme(); + + expect( + screen.getByText('Failed to fetch the services') + ).toBeInTheDocument(); + }); }); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx index 3b571880994..277d3b24ad7 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx @@ -14,11 +14,19 @@ const props: CloudPulseRegionSelectProps = { selectedDashboard: undefined, }; -describe('CloudPulseRegionSelect', () => { - vi.spyOn(regions, 'useRegionsQuery').mockReturnValue({ - data: Array(), - } as ReturnType); +const queryMocks = vi.hoisted(() => ({ + useRegionsQuery: vi.fn().mockReturnValue({}), +})); + +vi.mock('src/queries/regions/regions', () => ({ + useRegionsQuery: queryMocks.useRegionsQuery, +})); +queryMocks.useRegionsQuery.mockReturnValue({ + data: Array(), +}); + +describe('CloudPulseRegionSelect', () => { it('should render a Region Select component', () => { const { getByLabelText, getByTestId } = renderWithTheme( @@ -27,4 +35,17 @@ describe('CloudPulseRegionSelect', () => { expect(getByLabelText(label)).toBeInTheDocument(); expect(getByTestId('region-select')).toBeInTheDocument(); }); + + it('should render a Region Select component with proper error message on api call failure', () => { + queryMocks.useRegionsQuery.mockReturnValue({ + data: undefined, + isError: true, + isLoading: false, + }); + const { getByText } = renderWithTheme( + + ); + + expect(getByText('Failed to fetch Region')); + }); }); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx index 23aaecb35ac..38f43fb019d 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx @@ -206,4 +206,50 @@ describe('CloudPulseResourcesSelect component tests', () => { }) ).toHaveAttribute(ARIA_SELECTED, 'false'); }); + + it('Should show appropriate error message on resources call failure', async () => { + queryMocks.useResourcesQuery.mockReturnValue({ + data: undefined, + isError: true, + isLoading: false, + status: 'error', + }); + renderWithTheme( + + ); + expect(screen.getByText('Failed to fetch Resource')).toBeInTheDocument(); + + // if the label is ABC, error message should be Failed to fetch ABC + renderWithTheme( + + ); + expect(screen.getByText('Failed to fetch ABC')).toBeInTheDocument(); + + // if the label is empty , error message should be Failed to fetch Resources + renderWithTheme( + + ); + expect(screen.getByText('Failed to fetch Resources')).toBeInTheDocument(); + }); }); From b2e61a49e1f2e294890de247cad75555dcfd12aa Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 28 Oct 2024 13:29:16 +0530 Subject: [PATCH 228/474] upcoming: [DI-18419] - UT and code reusability updates --- .../CloudPulse/Dashboard/CloudPulseDashboard.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index be229412365..d09024e26d6 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -119,6 +119,10 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { return renderErrorState('Failed to get jwe token'); } + if (isMetricDefinitionError) { + return renderErrorState('Error loading metric definitions'); + } + if ( isMetricDefinitionLoading || isDashboardLoading || @@ -128,10 +132,6 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { return ; } - if (isMetricDefinitionError) { - return renderErrorState('Error loading metric definitions'); - } - return ( { ); }; -export const renderErrorState = (errorMessage: string) => { +const renderErrorState = (errorMessage: string) => { return ( From 55dcfbf23ae60e8e75fb2513fe12230d4383bc4d Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 28 Oct 2024 13:30:22 +0530 Subject: [PATCH 229/474] upcoming: [DI-18419] - JSDoc comments --- .../src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index d09024e26d6..951fe0fd3fa 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -148,6 +148,10 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { ); }; +/** + * @param errorMessage The error message to be displayed + * @returns The error state component with error message passed + */ const renderErrorState = (errorMessage: string) => { return ( From 77332aef8890ee9d0b0809b6fa2a5779c31d0e77 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 28 Oct 2024 13:41:47 +0530 Subject: [PATCH 230/474] upcoming: [DI-18419] - PR comments --- .../features/CloudPulse/Dashboard/CloudPulseDashboard.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index 951fe0fd3fa..c16c0523d0e 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -107,14 +107,14 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { Boolean(resourceList) ); - if (isResourcesApiError) { - return renderErrorState('Failed to fetch Resources'); - } - if (isDashboardApiError) { return renderErrorState('Failed to fetch the dashboard details'); } + if (isResourcesApiError) { + return renderErrorState('Failed to fetch Resources'); + } + if (isJweTokenError) { return renderErrorState('Failed to get jwe token'); } From 23fbf368a0db9d08503355ddf3d0b4e0a34c56c2 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 28 Oct 2024 13:47:00 +0530 Subject: [PATCH 231/474] upcoming: [DI-18419] - Reuse existing spy setup --- .../shared/CloudPulseRegionSelect.test.tsx | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx index 277d3b24ad7..fcdbe1b808b 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx @@ -14,19 +14,11 @@ const props: CloudPulseRegionSelectProps = { selectedDashboard: undefined, }; -const queryMocks = vi.hoisted(() => ({ - useRegionsQuery: vi.fn().mockReturnValue({}), -})); - -vi.mock('src/queries/regions/regions', () => ({ - useRegionsQuery: queryMocks.useRegionsQuery, -})); - -queryMocks.useRegionsQuery.mockReturnValue({ - data: Array(), -}); - describe('CloudPulseRegionSelect', () => { + vi.spyOn(regions, 'useRegionsQuery').mockReturnValue({ + data: Array(), + } as ReturnType); + it('should render a Region Select component', () => { const { getByLabelText, getByTestId } = renderWithTheme( @@ -37,11 +29,11 @@ describe('CloudPulseRegionSelect', () => { }); it('should render a Region Select component with proper error message on api call failure', () => { - queryMocks.useRegionsQuery.mockReturnValue({ + vi.spyOn(regions, 'useRegionsQuery').mockReturnValue({ data: undefined, isError: true, isLoading: false, - }); + } as ReturnType); const { getByText } = renderWithTheme( ); From 30951d8e84f02385627fc4d7af889e9bbab75f98 Mon Sep 17 00:00:00 2001 From: agorthi Date: Mon, 28 Oct 2024 14:31:06 +0530 Subject: [PATCH 232/474] upcoming:[DI-21483]- Added code review comments --- .../cloudpulse/cloudpulse-navigation.spec.ts | 4 +- .../cloudpulse/cloudpulse-validation.spec.ts | 468 ++++++++++++++++++ .../dbaas-widgets-verification.spec.ts | 1 + .../linode-widget-verification.spec.ts | 10 +- 4 files changed, 473 insertions(+), 10 deletions(-) create mode 100644 packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts index 8196496aca3..dce2e6dbae7 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts @@ -36,7 +36,7 @@ describe('CloudPulse navigation', () => { /* * - Confirms that Cloudpulse navigation item is not shown when feature flag is disabled. */ - it('does not show Cloudpulse navigation item when feature is disabled', () => { + it.skip('does not show Cloudpulse navigation item when feature is disabled', () => { mockAppendFeatureFlags({ aclp: { beta: true, @@ -55,7 +55,7 @@ describe('CloudPulse navigation', () => { /* * - Confirms that manual navigation to Cloudpulse landing page with feature is disabled displays Not Found to user. */ - it('displays Not Found when manually navigating to /cloudpulse with feature flag disabled', () => { + it.skip('displays Not Found when manually navigating to /cloudpulse with feature flag disabled', () => { mockAppendFeatureFlags({ aclp: { beta: true, diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts new file mode 100644 index 00000000000..e131326ad82 --- /dev/null +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts @@ -0,0 +1,468 @@ +/** + * @file Error Handling Tests for CloudPulse DBaaS Dashboard. + */ +import { mockAppendFeatureFlags } from 'support/intercepts/feature-flags'; +import { + mockCreateCloudPulseJWEToken, + mockGetCloudPulseDashboard, + mockCreateCloudPulseMetrics, + mockGetCloudPulseDashboards, + mockGetCloudPulseMetricDefinitions, + mockGetCloudPulseServices, +} from 'support/intercepts/cloudpulse'; +import { ui } from 'support/ui'; +import { widgetDetails } from 'support/constants/widgets'; +import { + accountFactory, + cloudPulseMetricsResponseFactory, + dashboardFactory, + dashboardMetricFactory, + databaseFactory, + kubeLinodeFactory, + linodeFactory, + regionFactory, + widgetFactory, +} from 'src/factories'; +import { mockGetAccount } from 'support/intercepts/account'; +import { mockGetLinodes } from 'support/intercepts/linodes'; +import { mockGetUserPreferences } from 'support/intercepts/profile'; +import { mockGetRegions } from 'support/intercepts/regions'; +import { extendRegion } from 'support/util/regions'; +import { generateRandomMetricsData } from 'support/util/cloudpulse'; +import { mockGetDatabases } from 'support/intercepts/databases'; +import { apiMatcher } from 'support/util/intercepts'; +import { Database } from '@linode/api-v4'; + +/** + * This suite tests error handling on the CloudPulse DBaaS dashboard. + * Verifies: + * - Widget loading, title accuracy, and data values. + * - Error handling for failed API requests. + * - Widget interactivity (e.g., zoom and filter behavior). + */ +const timeDurationToSelect = 'Last 24 Hours'; + +const { + metrics, + id, + serviceType, + dashboardName, + region, + engine, + clusterName, + nodeType, +} = widgetDetails.dbaas; + +const dashboard = dashboardFactory.build({ + label: dashboardName, + service_type: serviceType, + widgets: metrics.map(({ title, yLabel, name, unit }) => { + return widgetFactory.build({ + label: title, + y_label: yLabel, + metric: name, + unit, + }); + }), +}); + +const metricDefinitions = { + data: metrics.map(({ title, name, unit }) => + dashboardMetricFactory.build({ + label: title, + metric: name, + unit, + }) + ), +}; + +const mockLinode = linodeFactory.build({ + label: clusterName, + id: kubeLinodeFactory.build().instance_id ?? undefined, +}); + +const mockAccount = accountFactory.build(); +const mockRegion = extendRegion( + regionFactory.build({ + capabilities: ['Linodes'], + id: 'us-ord', + label: 'Chicago, IL', + country: 'us', + }) +); +const metricsAPIResponsePayload = cloudPulseMetricsResponseFactory.build({ + data: generateRandomMetricsData(timeDurationToSelect, '5 min'), +}); + +/** + * Verifies the presence and values of specific properties within the aclpPreference object + * of the request payload. This function checks that the expected properties exist + * and have the expected values, allowing for validation of user preferences in the application. + * + * @param requestPayload - The payload received from the request, containing the aclpPreference object. + * @param expectedValues - An object containing the expected values for properties to validate against the requestPayload. + * Expected properties may include: + * - dashboardId: The ID of the dashboard. + * - timeDuration: The selected time duration for metrics. + * - engine: The database engine used. + * - region: The selected region for the dashboard. + * - resources: An array of resource identifiers. + * - role: The role associated with the dashboard user. + */ + +const databaseMock: Database = databaseFactory.build({ + label: widgetDetails.dbaas.clusterName, + type: widgetDetails.dbaas.engine, + region: widgetDetails.dbaas.region, + version: '1', + status: 'provisioning', + cluster_size: 1, + engine: 'mysql', + platform: 'rdbms-default', + hosts: { + primary: undefined, + secondary: undefined, + }, +}); + +describe('DbasS API Error Handling', () => { + beforeEach(() => { + mockAppendFeatureFlags({ + aclp: { beta: true, enabled: true }, + }); + mockGetAccount(mockAccount); + mockGetLinodes([mockLinode]); + mockGetUserPreferences({}); + }); + + const statusCodes = [400]; + statusCodes.forEach((statusCode) => { + it(`should return ${statusCode} error response when fetching metric definitions API Request`, () => { + // Step 1: Intercept the API call for fetching metric definitions and simulate an error response. + cy.intercept( + 'GET', + apiMatcher(`/monitor/services/${serviceType}/metric-definitions`), + { + statusCode: statusCode, // Use the specified status code (e.g., 400) + body: { + errors: [ + { + reason: 'Bad Request', // Specify the reason for the error + }, + ], + }, + } + ).as('getMetricDefinitions'); // Alias for the intercepted API call + + // Step 2: Mock the required API responses for dashboards and services. + mockGetCloudPulseDashboards(serviceType, [dashboard]).as( + 'fetchDashboard' + ); + mockGetCloudPulseServices(serviceType).as('fetchServices'); + mockGetCloudPulseDashboard(id, dashboard); + mockCreateCloudPulseJWEToken(serviceType); + mockCreateCloudPulseMetrics(serviceType, metricsAPIResponsePayload).as( + 'getMetrics' + ); + mockGetRegions([mockRegion]); + mockGetDatabases([databaseMock]).as('getDatabases'); + + // Step 3: Navigate to the CloudPulse page after logging in. + cy.visitWithLogin('monitor/cloudpulse'); + + // Step 4: Wait for the services and dashboard API calls to complete before proceeding. + cy.wait(['@fetchServices', '@fetchDashboard']); + + // Step 5: Selecting a dashboard from the autocomplete input. + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') // Ensure the dashboard input is visible + .type(`${dashboardName}{enter}`) // Type the dashboard name and select it + .should('be.visible'); // Confirm the selection is visible + + // Step 6: Select a Database Engine from the autocomplete input. + ui.autocomplete + .findByLabel('Database Engine') + .should('be.visible') // Ensure the input is visible + .type(`${engine}{enter}`) // Type the engine name and select it + .should('be.visible'); // Confirm the selection is visible + + // Step 7: Select a region from the dropdown. + ui.regionSelect.find().click().type(`${region}{enter}`); // Click and select the region + + // Step 8: Select a resource (Database Clusters) from the autocomplete input. + ui.autocomplete + .findByLabel('Database Clusters') + .should('be.visible') // Ensure the input is visible + .type(`${clusterName}{enter}`) // Type the cluster name and select it + .click(); // Click to confirm selection + cy.findByText(clusterName).should('be.visible'); // Verify the selected cluster is visible + + // Step 9: Select a Node from the autocomplete input. + ui.autocomplete + .findByLabel('Node Type') + .should('be.visible') // Ensure the input is visible + .type(`${nodeType}{enter}`); // Type the node type and select it + + // Step 10: Wait for the metric definitions API call to resolve. + cy.wait('@getMetricDefinitions'); // Wait for the API call to complete + + // Step 11: Assert that the appropriate error message is displayed on the UI. + cy.get('[data-qa-error-msg="true"]') // Select the error message element + .should('be.visible') // Ensure the error message element is visible + .and('have.text', 'Error loading metric definitions'); // Validate the displayed error message + }); + + it(`should return ${statusCode} error response when fetching Services API Request`, () => { + // Step 1: Intercept the API call for fetching services and simulate a specific error response. + cy.intercept('GET', apiMatcher(`/monitor/services`), { + statusCode: statusCode, // Use the provided status code (e.g., 400) + body: { + errors: [ + { + reason: 'Bad Request', // Define the reason for the error + }, + ], + }, + }).as('fetchServices'); // Alias for the intercepted API call + + // Step 2: Visit the CloudPulse page after logging in. + cy.visitWithLogin('monitor/cloudpulse'); // Simulate user navigation to the relevant page + + // Step 3: Wait for the API call to complete and capture the response. + cy.wait('@fetchServices'); // Wait for the services API call to complete + + // Step 4: Check for any loading indicators or placeholder texts (optional). + cy.get('[data-qa-loading-indicator]').should('not.exist'); // Ensure no loading indicators are present + + // Step 5: Assert that the appropriate error message for the services fetch is displayed on the UI. + cy.get('[data-qa-textfield-error-text="Dashboard"]') // Select the error message element for the services + .should('be.visible') // Verify that the error message element is visible + .invoke('text') // Retrieve the text content of the error message element + .then((text) => { + // Step 6: Check if the text matches the expected error message. + expect(text.trim()).to.equal(`Failed to fetch the services`); // Validate the displayed error message + }); + }); + + it(`should return ${statusCode} error response when fetching Dashboards API Request`, () => { + // Step 1: Mock the API response for fetching cloud pulse services. + mockGetCloudPulseServices(serviceType).as('fetchServices'); // Mock API call for services + + // Step 2: Intercept the API call for fetching dashboards and simulate a 400 Bad Request response. + cy.intercept( + 'GET', + apiMatcher(`/monitor/services/${serviceType}/dashboards`), + { + statusCode: statusCode, // Use the status code defined in the test + body: { + errors: [ + { + reason: 'Bad Request', // Specify the error reason + }, + ], + }, + } + ).as('fetchDashboard'); // Alias for the intercepted API call + + // Step 3: Navigate to the CloudPulse monitoring page after logging in. + cy.visitWithLogin('monitor/cloudpulse'); + + // Step 4: Wait for both the fetch services and fetch dashboard API calls to complete. + cy.wait(['@fetchServices', '@fetchDashboard']); // Wait for the mocked API calls + + // Step 5: Assert that the error message for fetching the dashboards is displayed correctly. + cy.get('[data-qa-textfield-error-text="Dashboard"]') // Select the error message element + .should('be.visible') // Ensure the error message element is visible + .invoke('text') // Get the text content of the element + .then((text) => { + expect(text.trim()).to.equal(`Failed to fetch the dashboards`); // Check if the message matches the expected error + }); + }); + + it(`should return ${statusCode} error message when the Dashboard details API request fails`, () => { + // Step 1: Set up mock responses for fetching services and dashboards to prepare the test environment. + mockGetCloudPulseServices(serviceType).as('fetchServices'); // Mock fetching services + mockGetCloudPulseDashboards(serviceType, [dashboard]).as( + 'fetchDashboard' + ); // Mock fetching the dashboard + + // Step 2: Intercept the API call for fetching dashboard details by ID and simulate a 400 Bad Request error response. + cy.intercept('GET', apiMatcher(`/monitor/dashboards/${id}`), { + statusCode: statusCode, // Use the status code defined in the test + body: { + errors: [ + { + reason: 'Bad Request', // Specify the error reason + }, + ], + }, + }).as('fetchDashboardById'); // Alias for the intercept to be used later + + // Step 3: Mock additional necessary responses for regions and databases. + mockGetRegions([mockRegion]); // Mock fetching regions + mockGetDatabases([databaseMock]).as('getDatabases'); // Mock fetching databases + + // Step 4: Navigate to the CloudPulse monitoring page after logging in. + cy.visitWithLogin('monitor/cloudpulse'); + + // Step 5: Select a dashboard from the autocomplete input. Verify that the input is visible before typing. + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') // Check that the dashboard input is visible + .type(`${dashboardName}{enter}`) // Type the dashboard name and press enter + .should('be.visible'); // Ensure the dashboard input remains visible + + // Step 6: Select a time duration from the autocomplete input. Verify visibility before interaction. + ui.autocomplete + .findByLabel('Time Range') + .should('be.visible') // Check that the time range input is visible + .type(`${timeDurationToSelect}{enter}`) // Type the time duration and press enter + .should('be.visible'); // Ensure the time range input remains visible + + // Step 7: Select a database engine from the autocomplete input. Verify visibility before interaction. + ui.autocomplete + .findByLabel('Database Engine') + .should('be.visible') // Check that the database engine input is visible + .type(`${engine}{enter}`) // Type the database engine and press enter + .should('be.visible'); // Ensure the database engine input remains visible + + // Step 8: Select a region from the dropdown. Verify visibility before interaction. + ui.regionSelect.find().click().type(`${region}{enter}`); // Click and select the region from the dropdown + + // Step 9: Select a database cluster from the autocomplete input. Verify visibility before interaction. + ui.autocomplete + .findByLabel('Database Clusters') + .should('be.visible') // Check that the database clusters input is visible + .type(`${clusterName}{enter}`) // Type the cluster name and press enter + .click(); // Click to select the cluster + cy.findByText(clusterName).should('be.visible'); // Ensure the selected cluster is visible + + // Step 10: Select a node type from the autocomplete input. Verify visibility before interaction. + ui.autocomplete + .findByLabel('Node Type') + .should('be.visible') // Check that the node type input is visible + .type(`${nodeType}{enter}`); // Type the node type and press enter + + // Step 11: Wait for the API calls to fetch services and dashboard to resolve. + cy.wait(['@fetchServices', '@fetchDashboard']); + + // Step 12: Assert that the error message for fetching the dashboard details is displayed correctly. + cy.get('[data-qa-error-msg="true"]') // Select the error message element + .should('be.visible') // Ensure the error message is visible + .and('have.text', 'Failed to fetch the dashboard details'); // Check if the message matches the expected error + }); + + it(`should return ${statusCode} error message when the Regions API request fails`, () => { + // Step 1: Set up mock responses for various API endpoints to prepare the test environment. + mockGetCloudPulseMetricDefinitions(serviceType, metricDefinitions); // Mock metric definitions + mockGetCloudPulseDashboards(serviceType, [dashboard]).as( + 'fetchDashboard' + ); // Mock fetching the dashboard + mockGetCloudPulseServices(serviceType).as('fetchServices'); // Mock fetching the services + mockGetCloudPulseDashboard(id, dashboard); // Mock fetching a specific dashboard by ID + mockCreateCloudPulseJWEToken(serviceType); // Mock creating a JWE token for authentication + mockCreateCloudPulseMetrics(serviceType, metricsAPIResponsePayload).as( + 'getMetrics' + ); // Mock fetching metrics + + // Step 2: Intercept the API call for fetching regions and simulate a 400 Bad Request error response. + cy.intercept('GET', apiMatcher(`regions*`), { + statusCode: statusCode, // Use the status code defined in the test + body: { + errors: [ + { + reason: 'Bad Request', // Specify the error reason + }, + ], + }, + }).as('fetchRegion'); // Alias for the intercept to be used later + + // Step 3: Navigate to the CloudPulse monitoring page after logging in. + cy.visitWithLogin('monitor/cloudpulse'); + + // Step 4: Wait for the services and dashboard API calls to resolve before proceeding. + cy.wait(['@fetchServices', '@fetchDashboard']); + + // Step 5: Select a dashboard from the autocomplete input. Verify that the input is visible before typing. + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') // Check that the dashboard input is visible + .type(`${dashboardName}{enter}`) // Type the dashboard name and press enter + .should('be.visible'); // Ensure the dashboard input remains visible + + // Step 6: Assert that the error message for fetching Regions is displayed correctly. + cy.get('[data-qa-textfield-error-text="Region"]') // Select the error message element + .should('be.visible') // Check that the error message is visible + .invoke('text') // Get the text content of the error message + .then((text) => { + // Step 7: Verify that the displayed error message matches the expected message. + expect(text.trim()).to.equal(`Failed to fetch Region`); // Check if the message is as expected + }); + }); + + it(`should return ${statusCode} error response when fetching DB Cluster API Request`, () => { + // Step 1: Set up mock responses for various API endpoints to prepare the test environment. + mockGetCloudPulseMetricDefinitions(serviceType, metricDefinitions).as( + 'fetchMetricDefinitions' + ); // Mock metric definitions + mockGetCloudPulseDashboards(serviceType, [dashboard]).as( + 'fetchDashboard' + ); // Mock fetching the dashboard + mockGetCloudPulseServices(serviceType).as('fetchServices'); // Mock fetching the services + mockGetCloudPulseDashboard(id, dashboard); // Mock fetching a specific dashboard by ID + mockCreateCloudPulseJWEToken(serviceType); // Mock creating a JWE token for authentication + mockGetRegions([mockRegion]); // Mock fetching the regions available + + // Step 2: Intercept the API call for fetching DB clusters and simulate a 400 Bad Request error response. + cy.intercept('GET', apiMatcher(`databases/instances*`), { + statusCode: statusCode, // Use the status code defined in the loop + body: { + errors: [ + { + reason: 'Bad Request', // Specify the error reason + }, + ], + }, + }).as('fetchCluster'); // Alias for the intercept to be used later + + // Step 3: Navigate to the CloudPulse monitoring page after logging in. + cy.visitWithLogin('monitor/cloudpulse'); + + // Step 4: Wait for the services and dashboard API calls to resolve before proceeding. + cy.wait(['@fetchServices', '@fetchDashboard']); + + // Step 5: Select a dashboard from the autocomplete input. Verify that the input is visible before typing. + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') // Check that the dashboard input is visible + .type(`${dashboardName}{enter}`) // Type the dashboard name and press enter + .should('be.visible'); // Ensure the dashboard input remains visible + + // Step 6: Select a Node Type from the autocomplete input. Verify visibility before typing. + ui.autocomplete + .findByLabel('Node Type') + .should('be.visible') // Check that the Node Type input is visible + .type(`${nodeType}{enter}`); // Type the node type and press enter + + // Step 7: Select a region from the dropdown. Click and type the region name. + ui.regionSelect.find().click().type(`${region}{enter}`); // Click on the region dropdown and select the region + + // Step 8: Select a Database Engine from the autocomplete input. Verify visibility before typing. + ui.autocomplete + .findByLabel('Database Engine') + .should('be.visible') // Check that the Database Engine input is visible + .type(`${engine}{enter}`) // Type the engine name and press enter + .should('be.visible'); // Ensure the engine input remains visible + + // Step 9: Assert that the error message for fetching Database Clusters is displayed correctly. + cy.get('[data-qa-textfield-error-text="Database Clusters"]') // Select the error message element + .should('be.visible') // Check that the error message is visible + .invoke('text') // Get the text content of the error message + .then((text) => { + // Step 10: Verify that the displayed error message matches the expected message. + expect(text.trim()).to.equal(`Failed to fetch Database Clusters`); // Check if the message is as expected + }); + }); + }); +}); diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts index d1f1181337d..4512ceb27ad 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts @@ -134,6 +134,7 @@ const databaseMock: Database = databaseFactory.build({ status: 'provisioning', cluster_size: 1, engine: 'mysql', + platform: 'rdbms-default', hosts: { primary: undefined, secondary: undefined, diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index b0620e4148e..11106e45858 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -46,14 +46,8 @@ import { Interception } from 'cypress/types/net-stubbing'; const expectedGranularityArray = ['Auto', '1 day', '1 hr', '5 min']; const timeDurationToSelect = 'Last 24 Hours'; -const { - metrics, - id, - serviceType, - dashboardName, - region, - resource, -} = widgetDetails.linode; +const { metrics, id, serviceType, dashboardName, region, resource } = + widgetDetails.linode; const dashboard = dashboardFactory.build({ label: dashboardName, From 0e8751d488537670d2e60b2965b78516d64b1e84 Mon Sep 17 00:00:00 2001 From: agorthi Date: Mon, 28 Oct 2024 14:59:36 +0530 Subject: [PATCH 233/474] upcoming:[DI-21483]- Added code review comments --- .../e2e/core/cloudpulse/cloudpulse-navigation.spec.ts | 4 ++-- .../core/cloudpulse/linode-widget-verification.spec.ts | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts index dce2e6dbae7..8196496aca3 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts @@ -36,7 +36,7 @@ describe('CloudPulse navigation', () => { /* * - Confirms that Cloudpulse navigation item is not shown when feature flag is disabled. */ - it.skip('does not show Cloudpulse navigation item when feature is disabled', () => { + it('does not show Cloudpulse navigation item when feature is disabled', () => { mockAppendFeatureFlags({ aclp: { beta: true, @@ -55,7 +55,7 @@ describe('CloudPulse navigation', () => { /* * - Confirms that manual navigation to Cloudpulse landing page with feature is disabled displays Not Found to user. */ - it.skip('displays Not Found when manually navigating to /cloudpulse with feature flag disabled', () => { + it('displays Not Found when manually navigating to /cloudpulse with feature flag disabled', () => { mockAppendFeatureFlags({ aclp: { beta: true, diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 11106e45858..b0620e4148e 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -46,8 +46,14 @@ import { Interception } from 'cypress/types/net-stubbing'; const expectedGranularityArray = ['Auto', '1 day', '1 hr', '5 min']; const timeDurationToSelect = 'Last 24 Hours'; -const { metrics, id, serviceType, dashboardName, region, resource } = - widgetDetails.linode; +const { + metrics, + id, + serviceType, + dashboardName, + region, + resource, +} = widgetDetails.linode; const dashboard = dashboardFactory.build({ label: dashboardName, From 10f1958042ff14a4a863ca73a37e682d23ab255d Mon Sep 17 00:00:00 2001 From: agorthi Date: Mon, 28 Oct 2024 15:01:11 +0530 Subject: [PATCH 234/474] upcoming:[DI-21483]- Added code review comments --- .../e2e/core/cloudpulse/cloudpulse-navigation.spec.ts | 4 ++-- .../core/cloudpulse/linode-widget-verification.spec.ts | 10 ++-------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts index 8196496aca3..dce2e6dbae7 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts @@ -36,7 +36,7 @@ describe('CloudPulse navigation', () => { /* * - Confirms that Cloudpulse navigation item is not shown when feature flag is disabled. */ - it('does not show Cloudpulse navigation item when feature is disabled', () => { + it.skip('does not show Cloudpulse navigation item when feature is disabled', () => { mockAppendFeatureFlags({ aclp: { beta: true, @@ -55,7 +55,7 @@ describe('CloudPulse navigation', () => { /* * - Confirms that manual navigation to Cloudpulse landing page with feature is disabled displays Not Found to user. */ - it('displays Not Found when manually navigating to /cloudpulse with feature flag disabled', () => { + it.skip('displays Not Found when manually navigating to /cloudpulse with feature flag disabled', () => { mockAppendFeatureFlags({ aclp: { beta: true, diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index b0620e4148e..11106e45858 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -46,14 +46,8 @@ import { Interception } from 'cypress/types/net-stubbing'; const expectedGranularityArray = ['Auto', '1 day', '1 hr', '5 min']; const timeDurationToSelect = 'Last 24 Hours'; -const { - metrics, - id, - serviceType, - dashboardName, - region, - resource, -} = widgetDetails.linode; +const { metrics, id, serviceType, dashboardName, region, resource } = + widgetDetails.linode; const dashboard = dashboardFactory.build({ label: dashboardName, From 7c26a0d746fed4bc33eef06419a56d6187663c65 Mon Sep 17 00:00:00 2001 From: agorthi Date: Mon, 28 Oct 2024 15:06:46 +0530 Subject: [PATCH 235/474] upcoming:[DI-21483]- Added code review comments --- .../cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts index e131326ad82..535193335a9 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts @@ -135,7 +135,7 @@ describe('DbasS API Error Handling', () => { mockGetUserPreferences({}); }); - const statusCodes = [400]; + const statusCodes = [400,500]; statusCodes.forEach((statusCode) => { it(`should return ${statusCode} error response when fetching metric definitions API Request`, () => { // Step 1: Intercept the API call for fetching metric definitions and simulate an error response. From 358ec6898bbff3801c7606e046169fbc1ba339e2 Mon Sep 17 00:00:00 2001 From: agorthi Date: Mon, 28 Oct 2024 15:10:22 +0530 Subject: [PATCH 236/474] upcoming:[DI-21483]- Added code review comments --- .../e2e/core/cloudpulse/cloudpulse-navigation.spec.ts | 4 ++-- .../core/cloudpulse/linode-widget-verification.spec.ts | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts index dce2e6dbae7..8196496aca3 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts @@ -36,7 +36,7 @@ describe('CloudPulse navigation', () => { /* * - Confirms that Cloudpulse navigation item is not shown when feature flag is disabled. */ - it.skip('does not show Cloudpulse navigation item when feature is disabled', () => { + it('does not show Cloudpulse navigation item when feature is disabled', () => { mockAppendFeatureFlags({ aclp: { beta: true, @@ -55,7 +55,7 @@ describe('CloudPulse navigation', () => { /* * - Confirms that manual navigation to Cloudpulse landing page with feature is disabled displays Not Found to user. */ - it.skip('displays Not Found when manually navigating to /cloudpulse with feature flag disabled', () => { + it('displays Not Found when manually navigating to /cloudpulse with feature flag disabled', () => { mockAppendFeatureFlags({ aclp: { beta: true, diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 11106e45858..b0620e4148e 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -46,8 +46,14 @@ import { Interception } from 'cypress/types/net-stubbing'; const expectedGranularityArray = ['Auto', '1 day', '1 hr', '5 min']; const timeDurationToSelect = 'Last 24 Hours'; -const { metrics, id, serviceType, dashboardName, region, resource } = - widgetDetails.linode; +const { + metrics, + id, + serviceType, + dashboardName, + region, + resource, +} = widgetDetails.linode; const dashboard = dashboardFactory.build({ label: dashboardName, From 26431fe0396a4264ea33cb96251c5b75f8c40c16 Mon Sep 17 00:00:00 2001 From: agorthi Date: Mon, 28 Oct 2024 17:06:46 +0530 Subject: [PATCH 237/474] upcoming:[DI-21483]- Added code review comments --- .../cloudpulse/cloudpulse-validation.spec.ts | 559 ++++++++---------- .../dbaas-widgets-verification.spec.ts | 1 - 2 files changed, 231 insertions(+), 329 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts index 535193335a9..c3eabc4522e 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts @@ -5,7 +5,6 @@ import { mockAppendFeatureFlags } from 'support/intercepts/feature-flags'; import { mockCreateCloudPulseJWEToken, mockGetCloudPulseDashboard, - mockCreateCloudPulseMetrics, mockGetCloudPulseDashboards, mockGetCloudPulseMetricDefinitions, mockGetCloudPulseServices, @@ -14,7 +13,6 @@ import { ui } from 'support/ui'; import { widgetDetails } from 'support/constants/widgets'; import { accountFactory, - cloudPulseMetricsResponseFactory, dashboardFactory, dashboardMetricFactory, databaseFactory, @@ -28,20 +26,17 @@ import { mockGetLinodes } from 'support/intercepts/linodes'; import { mockGetUserPreferences } from 'support/intercepts/profile'; import { mockGetRegions } from 'support/intercepts/regions'; import { extendRegion } from 'support/util/regions'; -import { generateRandomMetricsData } from 'support/util/cloudpulse'; import { mockGetDatabases } from 'support/intercepts/databases'; import { apiMatcher } from 'support/util/intercepts'; import { Database } from '@linode/api-v4'; - /** - * This suite tests error handling on the CloudPulse DBaaS dashboard. - * Verifies: - * - Widget loading, title accuracy, and data values. - * - Error handling for failed API requests. - * - Widget interactivity (e.g., zoom and filter behavior). + * Verifies the presence and values of specific properties within the aclpPreference object + * of the request payload. This function checks that the expected properties exist + * and have the expected values, allowing for validation of user preferences in the application. + * + * @param requestPayload - The payload received from the request, containing the aclpPreference object. + * @param expectedValues - An object containing the expected values for properties to validate against the requestPayload. */ -const timeDurationToSelect = 'Last 24 Hours'; - const { metrics, id, @@ -90,26 +85,6 @@ const mockRegion = extendRegion( country: 'us', }) ); -const metricsAPIResponsePayload = cloudPulseMetricsResponseFactory.build({ - data: generateRandomMetricsData(timeDurationToSelect, '5 min'), -}); - -/** - * Verifies the presence and values of specific properties within the aclpPreference object - * of the request payload. This function checks that the expected properties exist - * and have the expected values, allowing for validation of user preferences in the application. - * - * @param requestPayload - The payload received from the request, containing the aclpPreference object. - * @param expectedValues - An object containing the expected values for properties to validate against the requestPayload. - * Expected properties may include: - * - dashboardId: The ID of the dashboard. - * - timeDuration: The selected time duration for metrics. - * - engine: The database engine used. - * - region: The selected region for the dashboard. - * - resources: An array of resource identifiers. - * - role: The role associated with the dashboard user. - */ - const databaseMock: Database = databaseFactory.build({ label: widgetDetails.dbaas.clusterName, type: widgetDetails.dbaas.engine, @@ -118,11 +93,6 @@ const databaseMock: Database = databaseFactory.build({ status: 'provisioning', cluster_size: 1, engine: 'mysql', - platform: 'rdbms-default', - hosts: { - primary: undefined, - secondary: undefined, - }, }); describe('DbasS API Error Handling', () => { @@ -132,337 +102,270 @@ describe('DbasS API Error Handling', () => { }); mockGetAccount(mockAccount); mockGetLinodes([mockLinode]); + mockGetAccount(mockAccount); + mockGetLinodes([mockLinode]); + mockGetCloudPulseMetricDefinitions(serviceType, metricDefinitions); + mockGetCloudPulseDashboards(serviceType, [dashboard]).as('fetchDashboard'); + mockGetCloudPulseServices(serviceType).as('fetchServices'); + mockCreateCloudPulseJWEToken(serviceType); + mockGetCloudPulseDashboard(id, dashboard); + mockGetRegions([mockRegion]); mockGetUserPreferences({}); + mockGetDatabases([databaseMock]).as('getDatabases'); }); - const statusCodes = [400,500]; + const statusCodes = [400]; statusCodes.forEach((statusCode) => { - it(`should return ${statusCode} error response when fetching metric definitions API Request`, () => { - // Step 1: Intercept the API call for fetching metric definitions and simulate an error response. - cy.intercept( - 'GET', - apiMatcher(`/monitor/services/${serviceType}/metric-definitions`), - { - statusCode: statusCode, // Use the specified status code (e.g., 400) + it('should return ' + statusCode + ' error response when fetching metric definitions API Request', () => { + cy.intercept( + 'GET', + apiMatcher(`/monitor/services/${serviceType}/metric-definitions`), + { + statusCode: statusCode, + body: { + errors: [ + { + reason: 'Bad Request', + }, + ], + }, + } + ).as('getMetricDefinitions'); + + cy.visitWithLogin('monitor/cloudpulse'); + + // Wait for the services and dashboard API calls to complete before proceeding. + cy.wait(['@fetchServices', '@fetchDashboard']); + + // Selecting a dashboard from the autocomplete input. + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') + .type(`${dashboardName}{enter}`) + .should('be.visible'); + + // Select a Database Engine from the autocomplete input. + ui.autocomplete + .findByLabel('Database Engine') + .should('be.visible') + .type(`${engine}{enter}`) + .should('be.visible'); + + // Select a region from the dropdown. + ui.regionSelect.find().click().type(`${region}{enter}`); + + // Select a resource (Database Clusters) from the autocomplete input. + ui.autocomplete + .findByLabel('Database Clusters') + .should('be.visible') + .type(`${clusterName}{enter}`) + .click(); + cy.findByText(clusterName).should('be.visible'); + + // Select a Node from the autocomplete input. + ui.autocomplete + .findByLabel('Node Type') + .should('be.visible') + .type(`${nodeType}{enter}`); + + // Wait for the metric definitions API call to resolve. + cy.wait('@getMetricDefinitions'); + cy.get('[data-qa-error-msg="true"]') + .should('be.visible') + .and('have.text', 'Error loading metric definitions'); + } + ); + + it( 'should return ' + statusCode +' error response when fetching Services API Request',() => { + cy.intercept('GET', apiMatcher(`/monitor/services`), { + statusCode: statusCode, body: { errors: [ { - reason: 'Bad Request', // Specify the reason for the error + reason: 'Bad Request', }, ], }, - } - ).as('getMetricDefinitions'); // Alias for the intercepted API call - - // Step 2: Mock the required API responses for dashboards and services. - mockGetCloudPulseDashboards(serviceType, [dashboard]).as( - 'fetchDashboard' - ); - mockGetCloudPulseServices(serviceType).as('fetchServices'); - mockGetCloudPulseDashboard(id, dashboard); - mockCreateCloudPulseJWEToken(serviceType); - mockCreateCloudPulseMetrics(serviceType, metricsAPIResponsePayload).as( - 'getMetrics' - ); - mockGetRegions([mockRegion]); - mockGetDatabases([databaseMock]).as('getDatabases'); - - // Step 3: Navigate to the CloudPulse page after logging in. - cy.visitWithLogin('monitor/cloudpulse'); - - // Step 4: Wait for the services and dashboard API calls to complete before proceeding. - cy.wait(['@fetchServices', '@fetchDashboard']); - - // Step 5: Selecting a dashboard from the autocomplete input. - ui.autocomplete - .findByLabel('Dashboard') - .should('be.visible') // Ensure the dashboard input is visible - .type(`${dashboardName}{enter}`) // Type the dashboard name and select it - .should('be.visible'); // Confirm the selection is visible - - // Step 6: Select a Database Engine from the autocomplete input. - ui.autocomplete - .findByLabel('Database Engine') - .should('be.visible') // Ensure the input is visible - .type(`${engine}{enter}`) // Type the engine name and select it - .should('be.visible'); // Confirm the selection is visible - - // Step 7: Select a region from the dropdown. - ui.regionSelect.find().click().type(`${region}{enter}`); // Click and select the region - - // Step 8: Select a resource (Database Clusters) from the autocomplete input. - ui.autocomplete - .findByLabel('Database Clusters') - .should('be.visible') // Ensure the input is visible - .type(`${clusterName}{enter}`) // Type the cluster name and select it - .click(); // Click to confirm selection - cy.findByText(clusterName).should('be.visible'); // Verify the selected cluster is visible - - // Step 9: Select a Node from the autocomplete input. - ui.autocomplete - .findByLabel('Node Type') - .should('be.visible') // Ensure the input is visible - .type(`${nodeType}{enter}`); // Type the node type and select it - - // Step 10: Wait for the metric definitions API call to resolve. - cy.wait('@getMetricDefinitions'); // Wait for the API call to complete - - // Step 11: Assert that the appropriate error message is displayed on the UI. - cy.get('[data-qa-error-msg="true"]') // Select the error message element - .should('be.visible') // Ensure the error message element is visible - .and('have.text', 'Error loading metric definitions'); // Validate the displayed error message - }); - - it(`should return ${statusCode} error response when fetching Services API Request`, () => { - // Step 1: Intercept the API call for fetching services and simulate a specific error response. - cy.intercept('GET', apiMatcher(`/monitor/services`), { - statusCode: statusCode, // Use the provided status code (e.g., 400) - body: { - errors: [ - { - reason: 'Bad Request', // Define the reason for the error + }).as('fetchServices'); + cy.visitWithLogin('monitor/cloudpulse'); + + // Wait for the API call to complete and capture the response. + cy.wait('@fetchServices'); + + cy.get('[data-qa-textfield-error-text="Dashboard"]') + .should('be.visible') + .invoke('text') + .then((text) => { + expect(text).to.equal('Failed to fetch the services'); + }); + } + ); + + it( 'should return ' + statusCode + ' error response when fetching Dashboards API Request',() => { + mockGetCloudPulseServices(serviceType).as('fetchServices'); + cy.intercept( + 'GET', + apiMatcher(`/monitor/services/${serviceType}/dashboards`), + { + statusCode: statusCode, + body: { + errors: [ + { + reason: 'Bad Request', + }, + ], }, - ], - }, - }).as('fetchServices'); // Alias for the intercepted API call - - // Step 2: Visit the CloudPulse page after logging in. - cy.visitWithLogin('monitor/cloudpulse'); // Simulate user navigation to the relevant page - - // Step 3: Wait for the API call to complete and capture the response. - cy.wait('@fetchServices'); // Wait for the services API call to complete - - // Step 4: Check for any loading indicators or placeholder texts (optional). - cy.get('[data-qa-loading-indicator]').should('not.exist'); // Ensure no loading indicators are present - - // Step 5: Assert that the appropriate error message for the services fetch is displayed on the UI. - cy.get('[data-qa-textfield-error-text="Dashboard"]') // Select the error message element for the services - .should('be.visible') // Verify that the error message element is visible - .invoke('text') // Retrieve the text content of the error message element - .then((text) => { - // Step 6: Check if the text matches the expected error message. - expect(text.trim()).to.equal(`Failed to fetch the services`); // Validate the displayed error message - }); - }); - - it(`should return ${statusCode} error response when fetching Dashboards API Request`, () => { - // Step 1: Mock the API response for fetching cloud pulse services. - mockGetCloudPulseServices(serviceType).as('fetchServices'); // Mock API call for services - - // Step 2: Intercept the API call for fetching dashboards and simulate a 400 Bad Request response. - cy.intercept( - 'GET', - apiMatcher(`/monitor/services/${serviceType}/dashboards`), - { - statusCode: statusCode, // Use the status code defined in the test + } + ).as('fetchDashboard'); + + cy.visitWithLogin('monitor/cloudpulse'); + // Wait for both the fetch services and fetch dashboard API calls to complete. + cy.wait(['@fetchServices', '@fetchDashboard']); + + // Assert that the error message for fetching the dashboards is displayed correctly. + cy.get('[data-qa-textfield-error-text="Dashboard"]') + .should('be.visible') + .invoke('text') + .then((text) => { + expect(text).to.equal('Failed to fetch the dashboards'); + }); + } + ); + + it('should return ' + statusCode + ' error message when the Dashboard details API request fails',() => { + cy.intercept('GET', apiMatcher(`/monitor/dashboards/${id}`), { + statusCode: statusCode, body: { errors: [ { - reason: 'Bad Request', // Specify the error reason + reason: 'Bad Request', }, ], }, - } - ).as('fetchDashboard'); // Alias for the intercepted API call - - // Step 3: Navigate to the CloudPulse monitoring page after logging in. - cy.visitWithLogin('monitor/cloudpulse'); - - // Step 4: Wait for both the fetch services and fetch dashboard API calls to complete. - cy.wait(['@fetchServices', '@fetchDashboard']); // Wait for the mocked API calls - - // Step 5: Assert that the error message for fetching the dashboards is displayed correctly. - cy.get('[data-qa-textfield-error-text="Dashboard"]') // Select the error message element - .should('be.visible') // Ensure the error message element is visible - .invoke('text') // Get the text content of the element - .then((text) => { - expect(text.trim()).to.equal(`Failed to fetch the dashboards`); // Check if the message matches the expected error - }); - }); - - it(`should return ${statusCode} error message when the Dashboard details API request fails`, () => { - // Step 1: Set up mock responses for fetching services and dashboards to prepare the test environment. - mockGetCloudPulseServices(serviceType).as('fetchServices'); // Mock fetching services - mockGetCloudPulseDashboards(serviceType, [dashboard]).as( - 'fetchDashboard' - ); // Mock fetching the dashboard - - // Step 2: Intercept the API call for fetching dashboard details by ID and simulate a 400 Bad Request error response. - cy.intercept('GET', apiMatcher(`/monitor/dashboards/${id}`), { - statusCode: statusCode, // Use the status code defined in the test - body: { - errors: [ - { - reason: 'Bad Request', // Specify the error reason - }, - ], - }, - }).as('fetchDashboardById'); // Alias for the intercept to be used later - - // Step 3: Mock additional necessary responses for regions and databases. - mockGetRegions([mockRegion]); // Mock fetching regions - mockGetDatabases([databaseMock]).as('getDatabases'); // Mock fetching databases - - // Step 4: Navigate to the CloudPulse monitoring page after logging in. - cy.visitWithLogin('monitor/cloudpulse'); - - // Step 5: Select a dashboard from the autocomplete input. Verify that the input is visible before typing. - ui.autocomplete - .findByLabel('Dashboard') - .should('be.visible') // Check that the dashboard input is visible - .type(`${dashboardName}{enter}`) // Type the dashboard name and press enter - .should('be.visible'); // Ensure the dashboard input remains visible - - // Step 6: Select a time duration from the autocomplete input. Verify visibility before interaction. - ui.autocomplete - .findByLabel('Time Range') - .should('be.visible') // Check that the time range input is visible - .type(`${timeDurationToSelect}{enter}`) // Type the time duration and press enter - .should('be.visible'); // Ensure the time range input remains visible - - // Step 7: Select a database engine from the autocomplete input. Verify visibility before interaction. - ui.autocomplete - .findByLabel('Database Engine') - .should('be.visible') // Check that the database engine input is visible - .type(`${engine}{enter}`) // Type the database engine and press enter - .should('be.visible'); // Ensure the database engine input remains visible - - // Step 8: Select a region from the dropdown. Verify visibility before interaction. - ui.regionSelect.find().click().type(`${region}{enter}`); // Click and select the region from the dropdown - - // Step 9: Select a database cluster from the autocomplete input. Verify visibility before interaction. - ui.autocomplete - .findByLabel('Database Clusters') - .should('be.visible') // Check that the database clusters input is visible - .type(`${clusterName}{enter}`) // Type the cluster name and press enter - .click(); // Click to select the cluster - cy.findByText(clusterName).should('be.visible'); // Ensure the selected cluster is visible - - // Step 10: Select a node type from the autocomplete input. Verify visibility before interaction. - ui.autocomplete - .findByLabel('Node Type') - .should('be.visible') // Check that the node type input is visible - .type(`${nodeType}{enter}`); // Type the node type and press enter - - // Step 11: Wait for the API calls to fetch services and dashboard to resolve. - cy.wait(['@fetchServices', '@fetchDashboard']); - - // Step 12: Assert that the error message for fetching the dashboard details is displayed correctly. - cy.get('[data-qa-error-msg="true"]') // Select the error message element - .should('be.visible') // Ensure the error message is visible - .and('have.text', 'Failed to fetch the dashboard details'); // Check if the message matches the expected error - }); + }).as('fetchDashboardById'); + + cy.visitWithLogin('monitor/cloudpulse'); + + // Select a dashboard from the autocomplete input. Verify that the input is visible before typing. + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') + .type(`${dashboardName}{enter}`) + .should('be.visible'); + + // Select a database engine from the autocomplete input. Verify visibility before interaction. + ui.autocomplete + .findByLabel('Database Engine') + .should('be.visible') + .type(`${engine}{enter}`) + .should('be.visible'); + + // Select a region from the dropdown. Verify visibility before interaction. + ui.regionSelect.find().click().type(`${region}{enter}`); + + // Select a database cluster from the autocomplete input. Verify visibility before interaction. + ui.autocomplete + .findByLabel('Database Clusters') + .should('be.visible') + .type(`${clusterName}{enter}`) + .click(); + cy.findByText(clusterName).should('be.visible'); + + // Select a node type from the autocomplete input. Verify visibility before interaction. + ui.autocomplete + .findByLabel('Node Type') + .should('be.visible') + .type(`${nodeType}{enter}`); + + // Wait for the API calls to fetch services and dashboard to resolve. + cy.wait(['@fetchServices', '@fetchDashboard']); + + cy.get('[data-qa-error-msg="true"]') + .should('be.visible') + .and('have.text', 'Failed to fetch the dashboard details'); + } + ); it(`should return ${statusCode} error message when the Regions API request fails`, () => { - // Step 1: Set up mock responses for various API endpoints to prepare the test environment. - mockGetCloudPulseMetricDefinitions(serviceType, metricDefinitions); // Mock metric definitions - mockGetCloudPulseDashboards(serviceType, [dashboard]).as( - 'fetchDashboard' - ); // Mock fetching the dashboard - mockGetCloudPulseServices(serviceType).as('fetchServices'); // Mock fetching the services - mockGetCloudPulseDashboard(id, dashboard); // Mock fetching a specific dashboard by ID - mockCreateCloudPulseJWEToken(serviceType); // Mock creating a JWE token for authentication - mockCreateCloudPulseMetrics(serviceType, metricsAPIResponsePayload).as( - 'getMetrics' - ); // Mock fetching metrics - - // Step 2: Intercept the API call for fetching regions and simulate a 400 Bad Request error response. cy.intercept('GET', apiMatcher(`regions*`), { statusCode: statusCode, // Use the status code defined in the test body: { errors: [ { - reason: 'Bad Request', // Specify the error reason + reason: 'Bad Request', }, ], }, - }).as('fetchRegion'); // Alias for the intercept to be used later + }).as('fetchRegion'); - // Step 3: Navigate to the CloudPulse monitoring page after logging in. + // Navigate to the CloudPulse monitoring page after logging in. cy.visitWithLogin('monitor/cloudpulse'); - // Step 4: Wait for the services and dashboard API calls to resolve before proceeding. + // Wait for the services and dashboard API calls to resolve before proceeding. cy.wait(['@fetchServices', '@fetchDashboard']); - // Step 5: Select a dashboard from the autocomplete input. Verify that the input is visible before typing. + // Select a dashboard from the autocomplete input. Verify that the input is visible before typing. ui.autocomplete .findByLabel('Dashboard') - .should('be.visible') // Check that the dashboard input is visible - .type(`${dashboardName}{enter}`) // Type the dashboard name and press enter - .should('be.visible'); // Ensure the dashboard input remains visible + .should('be.visible') + .type(`${dashboardName}{enter}`) + .should('be.visible'); - // Step 6: Assert that the error message for fetching Regions is displayed correctly. cy.get('[data-qa-textfield-error-text="Region"]') // Select the error message element - .should('be.visible') // Check that the error message is visible - .invoke('text') // Get the text content of the error message + .should('be.visible') + .invoke('text') .then((text) => { - // Step 7: Verify that the displayed error message matches the expected message. - expect(text.trim()).to.equal(`Failed to fetch Region`); // Check if the message is as expected + expect(text).to.equal('Failed to fetch Region'); }); }); - it(`should return ${statusCode} error response when fetching DB Cluster API Request`, () => { - // Step 1: Set up mock responses for various API endpoints to prepare the test environment. - mockGetCloudPulseMetricDefinitions(serviceType, metricDefinitions).as( - 'fetchMetricDefinitions' - ); // Mock metric definitions - mockGetCloudPulseDashboards(serviceType, [dashboard]).as( - 'fetchDashboard' - ); // Mock fetching the dashboard - mockGetCloudPulseServices(serviceType).as('fetchServices'); // Mock fetching the services - mockGetCloudPulseDashboard(id, dashboard); // Mock fetching a specific dashboard by ID - mockCreateCloudPulseJWEToken(serviceType); // Mock creating a JWE token for authentication - mockGetRegions([mockRegion]); // Mock fetching the regions available - - // Step 2: Intercept the API call for fetching DB clusters and simulate a 400 Bad Request error response. - cy.intercept('GET', apiMatcher(`databases/instances*`), { - statusCode: statusCode, // Use the status code defined in the loop - body: { - errors: [ - { - reason: 'Bad Request', // Specify the error reason - }, - ], - }, - }).as('fetchCluster'); // Alias for the intercept to be used later - - // Step 3: Navigate to the CloudPulse monitoring page after logging in. - cy.visitWithLogin('monitor/cloudpulse'); - - // Step 4: Wait for the services and dashboard API calls to resolve before proceeding. - cy.wait(['@fetchServices', '@fetchDashboard']); - - // Step 5: Select a dashboard from the autocomplete input. Verify that the input is visible before typing. - ui.autocomplete - .findByLabel('Dashboard') - .should('be.visible') // Check that the dashboard input is visible - .type(`${dashboardName}{enter}`) // Type the dashboard name and press enter - .should('be.visible'); // Ensure the dashboard input remains visible - - // Step 6: Select a Node Type from the autocomplete input. Verify visibility before typing. - ui.autocomplete - .findByLabel('Node Type') - .should('be.visible') // Check that the Node Type input is visible - .type(`${nodeType}{enter}`); // Type the node type and press enter - - // Step 7: Select a region from the dropdown. Click and type the region name. - ui.regionSelect.find().click().type(`${region}{enter}`); // Click on the region dropdown and select the region - - // Step 8: Select a Database Engine from the autocomplete input. Verify visibility before typing. - ui.autocomplete - .findByLabel('Database Engine') - .should('be.visible') // Check that the Database Engine input is visible - .type(`${engine}{enter}`) // Type the engine name and press enter - .should('be.visible'); // Ensure the engine input remains visible - - // Step 9: Assert that the error message for fetching Database Clusters is displayed correctly. - cy.get('[data-qa-textfield-error-text="Database Clusters"]') // Select the error message element - .should('be.visible') // Check that the error message is visible - .invoke('text') // Get the text content of the error message - .then((text) => { - // Step 10: Verify that the displayed error message matches the expected message. - expect(text.trim()).to.equal(`Failed to fetch Database Clusters`); // Check if the message is as expected - }); - }); + it('should return ' + statusCode +' error response when fetching DB Cluster API Request',() => { + cy.intercept('GET', apiMatcher(`databases/instances*`), { + statusCode: statusCode, + body: { + errors: [ + { + reason: 'Bad Request', + }, + ], + }, + }).as('fetchCluster'); + + cy.visitWithLogin('monitor/cloudpulse'); + + //Wait for the services and dashboard API calls to resolve before proceeding. + cy.wait(['@fetchServices', '@fetchDashboard']); + + // Select a dashboard from the autocomplete input + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') + .type(`${dashboardName}{enter}`) + .should('be.visible'); + + // Select a Node Type from the autocomplete input. Verify visibility before typing. + ui.autocomplete + .findByLabel('Node Type') + .should('be.visible') + .type(`${nodeType}{enter}`); + + // Select a region from the dropdown. Click and type the region name. + ui.regionSelect.find().click().type(`${region}{enter}`); + + // Select a Database Engine from the autocomplete input. Verify visibility before typing. + ui.autocomplete + .findByLabel('Database Engine') + .should('be.visible') + .type(`${engine}{enter}`) + .should('be.visible'); + + cy.get('[data-qa-textfield-error-text="Database Clusters"]') + .should('be.visible') + .invoke('text') + .then((text) => { + expect(text).to.equal('Failed to fetch Database Clusters'); + }); + } + ); }); }); diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts index 4512ceb27ad..d1f1181337d 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts @@ -134,7 +134,6 @@ const databaseMock: Database = databaseFactory.build({ status: 'provisioning', cluster_size: 1, engine: 'mysql', - platform: 'rdbms-default', hosts: { primary: undefined, secondary: undefined, From 91c9ae0427909d118b3d313d0bd586cf61e55c34 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 28 Oct 2024 16:57:55 +0530 Subject: [PATCH 238/474] upcoming: [DI-18419] - Zeroth state update and invalid response handling --- .../Dashboard/CloudPulseDashboardRenderer.tsx | 2 +- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 6 +++--- .../CloudPulse/Widget/CloudPulseWidget.tsx | 20 +++++++++---------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx index 83abd618a98..5fb6097af25 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx @@ -16,7 +16,7 @@ export const CloudPulseDashboardRenderer = React.memo( const { dashboard, filterValue, timeDuration } = props; const selectDashboardAndFilterMessage = - 'Select Dashboard and filters to visualize metrics.'; + 'Select dashboard and filters to visualize metrics.'; const getMetricsCall = React.useMemo( () => getMetricsCallCustomFilters(filterValue, dashboard?.service_type), diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index 44b4192fdf4..e5618019074 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -1,7 +1,7 @@ import { isToday } from 'src/utilities/isToday'; import { getMetrics } from 'src/utilities/statMetrics'; -import { COLOR_MAP } from './CloudPulseWidgetColorPalette'; +import { COLOR_MAP, DEFAULT } from './CloudPulseWidgetColorPalette'; import { formatToolTip, generateUnitByBaseUnit, @@ -101,7 +101,7 @@ interface graphDataOptionsProps { /** * preferred color for the widget's graph */ - widgetColor: string | undefined; + widgetColor: string; } interface MetricRequestProps { @@ -164,7 +164,7 @@ export const generateGraphData = (props: graphDataOptionsProps) => { const legendRowsData: LegendRow[] = []; // for now we will use this, but once we decide how to work with coloring, it should be dynamic - const colors = COLOR_MAP.get(widgetColor ?? 'default')!; + const colors = COLOR_MAP.get(widgetColor) ?? DEFAULT; let today = false; if (status === 'success') { diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 1a6aa6b107f..6672c1f9441 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -251,8 +251,8 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { serviceType, status, unit, - widgetChartType: widget.chart_type || 'area', - widgetColor: widget.color || 'default', + widgetChartType: widget.chart_type, + widgetColor: widget.color, }); data = generatedData.dimensions; @@ -301,14 +301,14 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { {Boolean( availableMetrics?.available_aggregate_functions?.length ) && ( - - )} + + )} Date: Mon, 28 Oct 2024 17:23:35 +0530 Subject: [PATCH 239/474] upcoming: [DI-18419] - As per dev --- .../CloudPulse/Widget/CloudPulseWidget.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 6672c1f9441..44d5dbcdb39 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -301,14 +301,14 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { {Boolean( availableMetrics?.available_aggregate_functions?.length ) && ( - - )} + + )} Date: Mon, 28 Oct 2024 17:59:52 +0530 Subject: [PATCH 240/474] upcoming: [DI-18419] - Error message updates --- .../CloudPulse/Dashboard/CloudPulseDashboardLanding.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.test.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.test.tsx index d54a52a0500..0a8509f9e5a 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.test.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.test.tsx @@ -56,7 +56,7 @@ describe('CloudPulseDashboardFilterBuilder component tests', () => { ); expect( - screen.getByText('Select Dashboard and filters to visualize metrics.') + screen.getByText('Select dashboard and filters to visualize metrics.') ).toBeDefined(); }); @@ -103,7 +103,7 @@ describe('CloudPulseDashboardFilterBuilder component tests', () => { ); expect( - screen.getByText('Select Dashboard and filters to visualize metrics.') + screen.getByText('Select dashboard and filters to visualize metrics.') ).toBeDefined(); }); }); From c8268abd0bddcd28019d7ceeda7edfbd49e53d61 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 28 Oct 2024 20:14:41 +0530 Subject: [PATCH 241/474] upcoming: [DI-18419] - Valid comments --- .../features/CloudPulse/Utils/CloudPulseWidgetUtils.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index e5618019074..83757cf5151 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -163,7 +163,7 @@ export const generateGraphData = (props: graphDataOptionsProps) => { const dimensions: DataSet[] = []; const legendRowsData: LegendRow[] = []; - // for now we will use this, but once we decide how to work with coloring, it should be dynamic + // if the color is not found in the map, we will fallback to default color theme const colors = COLOR_MAP.get(widgetColor) ?? DEFAULT; let today = false; @@ -260,9 +260,9 @@ export const getCloudPulseMetricRequest = ( widget.time_granularity.unit === 'Auto' ? undefined : { - unit: widget.time_granularity.unit, - value: widget.time_granularity.value, - }, + unit: widget.time_granularity.unit, + value: widget.time_granularity.value, + }, }; }; From 0bf56b6208c6490fcd84abf26bcbb322dfee2d31 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 29 Oct 2024 10:03:04 +0530 Subject: [PATCH 242/474] upcoming: [DI-18419] - Normal string instead of interpolation --- .../features/CloudPulse/shared/CloudPulseDashboardSelect.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index 0f888d84d73..ae36c55ff19 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -55,7 +55,7 @@ export const CloudPulseDashboardSelect = React.memo( } if (dashboardsError.length > 0) { - return `Failed to fetch the dashboards`; + return 'Failed to fetch the dashboards'; } return ''; From 8067d62020cf494f5b777a1ee32122fad0ce736b Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 29 Oct 2024 12:39:52 +0530 Subject: [PATCH 243/474] upcoming: [DI-18419] - Added period for error messages --- .../features/CloudPulse/Dashboard/CloudPulseDashboard.tsx | 8 ++++---- .../CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx | 2 +- .../CloudPulse/Widget/CloudPulseWidgetRenderer.tsx | 4 ++-- .../CloudPulse/shared/CloudPulseDashboardSelect.test.tsx | 4 ++-- .../CloudPulse/shared/CloudPulseDashboardSelect.tsx | 5 +++-- .../CloudPulse/shared/CloudPulseRegionSelect.test.tsx | 2 +- .../features/CloudPulse/shared/CloudPulseRegionSelect.tsx | 2 +- .../CloudPulse/shared/CloudPulseResourcesSelect.test.tsx | 6 +++--- .../CloudPulse/shared/CloudPulseResourcesSelect.tsx | 2 +- 9 files changed, 18 insertions(+), 17 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index c16c0523d0e..bed2ec6c7b7 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -108,19 +108,19 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { ); if (isDashboardApiError) { - return renderErrorState('Failed to fetch the dashboard details'); + return renderErrorState('Failed to fetch the dashboard details.'); } if (isResourcesApiError) { - return renderErrorState('Failed to fetch Resources'); + return renderErrorState('Failed to fetch Resources.'); } if (isJweTokenError) { - return renderErrorState('Failed to get jwe token'); + return renderErrorState('Failed to get the token.'); } if (isMetricDefinitionError) { - return renderErrorState('Error loading metric definitions'); + return renderErrorState('Error loading metric definitions.'); } if ( diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx index 5fb6097af25..91924a6c632 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx @@ -33,7 +33,7 @@ export const CloudPulseDashboardRenderer = React.memo( if (!FILTER_CONFIG.get(dashboard.service_type)) { return ( - + ); } diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx index 79da5137b54..d13d3efe97a 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx @@ -73,7 +73,7 @@ export const RenderWidgets = React.memo( authToken: '', availableMetrics: undefined, duration, - errorLabel: 'Error While Loading Data', + errorLabel: 'Error while loading data.', resourceIds: resources, resources: [], serviceType: dashboard?.service_type ?? '', @@ -127,7 +127,7 @@ export const RenderWidgets = React.memo( !Boolean(resourceList?.length) ) { return renderPlaceHolder( - 'Select Dashboard, Region and Resource to visualize metrics' + 'Select Dashboard, Region and Resource to visualize metrics.' ); } diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx index 333399b6a62..9ac49f8f032 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.test.tsx @@ -111,7 +111,7 @@ describe('CloudPulse Dashboard select', () => { renderWithTheme(); expect( - screen.getByText('Failed to fetch the dashboards') + screen.getByText('Failed to fetch the dashboards.') ).toBeInTheDocument(); }); it('Should show error message when services call fails', () => { @@ -130,7 +130,7 @@ describe('CloudPulse Dashboard select', () => { renderWithTheme(); expect( - screen.getByText('Failed to fetch the services') + screen.getByText('Failed to fetch the services.') ).toBeInTheDocument(); }); }); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index ae36c55ff19..a0bc932c980 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -51,11 +51,11 @@ export const CloudPulseDashboardSelect = React.memo( const getErrorText = () => { if (serviceTypesError) { - return 'Failed to fetch the services'; + return 'Failed to fetch the services.'; } if (dashboardsError.length > 0) { - return 'Failed to fetch the dashboards'; + return 'Failed to fetch the dashboards.'; } return ''; @@ -116,6 +116,7 @@ export const CloudPulseDashboardSelect = React.memo( options={getSortedDashboardsList(dashboardsList ?? [])} placeholder={placeHolder} value={selectedDashboard ?? null} // Undefined is not allowed for uncontrolled component + aria-required /> ); } diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx index fcdbe1b808b..9372ec32ead 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx @@ -38,6 +38,6 @@ describe('CloudPulseRegionSelect', () => { ); - expect(getByText('Failed to fetch Region')); + expect(getByText('Failed to fetch Region.')); }); }); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index d9faa9862b2..bb8a1c25f03 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -50,7 +50,7 @@ export const CloudPulseRegionSelect = React.memo( data-testid="region-select" disableClearable={false} disabled={!selectedDashboard || !regions} - errorText={isError ? `Failed to fetch ${label || 'Regions'}` : ''} + errorText={isError ? `Failed to fetch ${label || 'Regions'}.` : ''} fullWidth label={label || 'Region'} loading={isLoading} diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx index 38f43fb019d..7249de52a16 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx @@ -224,7 +224,7 @@ describe('CloudPulseResourcesSelect component tests', () => { savePreferences /> ); - expect(screen.getByText('Failed to fetch Resource')).toBeInTheDocument(); + expect(screen.getByText('Failed to fetch Resource.')).toBeInTheDocument(); // if the label is ABC, error message should be Failed to fetch ABC renderWithTheme( @@ -237,7 +237,7 @@ describe('CloudPulseResourcesSelect component tests', () => { savePreferences /> ); - expect(screen.getByText('Failed to fetch ABC')).toBeInTheDocument(); + expect(screen.getByText('Failed to fetch ABC.')).toBeInTheDocument(); // if the label is empty , error message should be Failed to fetch Resources renderWithTheme( @@ -250,6 +250,6 @@ describe('CloudPulseResourcesSelect component tests', () => { savePreferences /> ); - expect(screen.getByText('Failed to fetch Resources')).toBeInTheDocument(); + expect(screen.getByText('Failed to fetch Resources.')).toBeInTheDocument(); }); }); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index bb4816252ac..62a7f44ad87 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -133,7 +133,7 @@ export const CloudPulseResourcesSelect = React.memo( clearOnBlur data-testid="resource-select" disabled={disabled} - errorText={isError ? `Failed to fetch ${label || 'Resources'}` : ''} + errorText={isError ? `Failed to fetch ${label || 'Resources'}.` : ''} isOptionEqualToValue={(option, value) => option.id === value.id} label={label || 'Resources'} limitTags={2} From cc39c6b9a2f8064e067849effce3657c6d589c70 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 29 Oct 2024 13:18:59 +0530 Subject: [PATCH 244/474] upcoming: [DI-18419] - remove whitespace --- .../src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index 83757cf5151..20a44f11f59 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -260,9 +260,9 @@ export const getCloudPulseMetricRequest = ( widget.time_granularity.unit === 'Auto' ? undefined : { - unit: widget.time_granularity.unit, - value: widget.time_granularity.value, - }, + unit: widget.time_granularity.unit, + value: widget.time_granularity.value, + }, }; }; From 86a958512786e5f37bcc2e83d0497b07abe0dfa7 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 29 Oct 2024 13:23:00 +0530 Subject: [PATCH 245/474] upcoming: [DI-18419] - remove unwanted --- .../src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index a0bc932c980..62d18388f5a 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -116,7 +116,6 @@ export const CloudPulseDashboardSelect = React.memo( options={getSortedDashboardsList(dashboardsList ?? [])} placeholder={placeHolder} value={selectedDashboard ?? null} // Undefined is not allowed for uncontrolled component - aria-required /> ); } From 054854d490a4ad26242727fc1ebda1e12cbb0509 Mon Sep 17 00:00:00 2001 From: agorthi Date: Tue, 29 Oct 2024 14:19:16 +0530 Subject: [PATCH 246/474] upcoming:[DI-21483]- Added code review comments --- .../cloudpulse/cloudpulse-validation.spec.ts | 528 ++++++++++-------- 1 file changed, 284 insertions(+), 244 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts index c3eabc4522e..8021d7c148c 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts @@ -29,6 +29,7 @@ import { extendRegion } from 'support/util/regions'; import { mockGetDatabases } from 'support/intercepts/databases'; import { apiMatcher } from 'support/util/intercepts'; import { Database } from '@linode/api-v4'; + /** * Verifies the presence and values of specific properties within the aclpPreference object * of the request payload. This function checks that the expected properties exist @@ -102,8 +103,6 @@ describe('DbasS API Error Handling', () => { }); mockGetAccount(mockAccount); mockGetLinodes([mockLinode]); - mockGetAccount(mockAccount); - mockGetLinodes([mockLinode]); mockGetCloudPulseMetricDefinitions(serviceType, metricDefinitions); mockGetCloudPulseDashboards(serviceType, [dashboard]).as('fetchDashboard'); mockGetCloudPulseServices(serviceType).as('fetchServices'); @@ -113,182 +112,89 @@ describe('DbasS API Error Handling', () => { mockGetUserPreferences({}); mockGetDatabases([databaseMock]).as('getDatabases'); }); - - const statusCodes = [400]; - statusCodes.forEach((statusCode) => { - it('should return ' + statusCode + ' error response when fetching metric definitions API Request', () => { - cy.intercept( - 'GET', - apiMatcher(`/monitor/services/${serviceType}/metric-definitions`), - { - statusCode: statusCode, - body: { - errors: [ - { - reason: 'Bad Request', - }, - ], - }, - } - ).as('getMetricDefinitions'); - - cy.visitWithLogin('monitor/cloudpulse'); - - // Wait for the services and dashboard API calls to complete before proceeding. - cy.wait(['@fetchServices', '@fetchDashboard']); - - // Selecting a dashboard from the autocomplete input. - ui.autocomplete - .findByLabel('Dashboard') - .should('be.visible') - .type(`${dashboardName}{enter}`) - .should('be.visible'); - - // Select a Database Engine from the autocomplete input. - ui.autocomplete - .findByLabel('Database Engine') - .should('be.visible') - .type(`${engine}{enter}`) - .should('be.visible'); - - // Select a region from the dropdown. - ui.regionSelect.find().click().type(`${region}{enter}`); - - // Select a resource (Database Clusters) from the autocomplete input. - ui.autocomplete - .findByLabel('Database Clusters') - .should('be.visible') - .type(`${clusterName}{enter}`) - .click(); - cy.findByText(clusterName).should('be.visible'); - - // Select a Node from the autocomplete input. - ui.autocomplete - .findByLabel('Node Type') - .should('be.visible') - .type(`${nodeType}{enter}`); - - // Wait for the metric definitions API call to resolve. - cy.wait('@getMetricDefinitions'); - cy.get('[data-qa-error-msg="true"]') - .should('be.visible') - .and('have.text', 'Error loading metric definitions'); - } - ); - - it( 'should return ' + statusCode +' error response when fetching Services API Request',() => { - cy.intercept('GET', apiMatcher(`/monitor/services`), { - statusCode: statusCode, - body: { - errors: [ - { - reason: 'Bad Request', - }, - ], - }, - }).as('fetchServices'); - cy.visitWithLogin('monitor/cloudpulse'); - - // Wait for the API call to complete and capture the response. - cy.wait('@fetchServices'); - - cy.get('[data-qa-textfield-error-text="Dashboard"]') - .should('be.visible') - .invoke('text') - .then((text) => { - expect(text).to.equal('Failed to fetch the services'); - }); + + it('should return error response when fetching metric definitions API request', () => { + cy.intercept( + 'GET', + apiMatcher(`/monitor/services/${serviceType}/metric-definitions`), + { + statusCode: 400, + body: {errors: [ { reason: 'Bad Request',},], + }, } - ); + ).as('getMetricDefinitions'); + + cy.visitWithLogin('monitor/cloudpulse'); + + // Wait for the services and dashboard API calls to complete before proceeding. + cy.wait(['@fetchServices', '@fetchDashboard']); + + // Selecting a dashboard from the autocomplete input. + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') + .type(`${dashboardName}{enter}`) + .should('be.visible'); + + // Select a Database Engine from the autocomplete input. + ui.autocomplete + .findByLabel('Database Engine') + .should('be.visible') + .type(`${engine}{enter}`) + .should('be.visible'); + + // Select a region from the dropdown. + ui.regionSelect.find().click().type(`${region}{enter}`); + + // Select a resource (Database Clusters) from the autocomplete input. + ui.autocomplete + .findByLabel('Database Clusters') + .should('be.visible') + .type(`${clusterName}{enter}`) + .click(); + cy.findByText(clusterName).should('be.visible'); + + // Select a Node from the autocomplete input. + ui.autocomplete + .findByLabel('Node Type') + .should('be.visible') + .type(`${nodeType}{enter}`); + + // Wait for the metric definitions API call to resolve. + cy.wait('@getMetricDefinitions'); + cy.get('[data-qa-error-msg="true"]') + .should('be.visible') + .and('have.text', 'Error loading metric definitions.'); + }); - it( 'should return ' + statusCode + ' error response when fetching Dashboards API Request',() => { - mockGetCloudPulseServices(serviceType).as('fetchServices'); - cy.intercept( - 'GET', - apiMatcher(`/monitor/services/${serviceType}/dashboards`), + it( 'should return error response when fetching services API request',() => { + cy.intercept('GET', apiMatcher(`/monitor/services`), { + statusCode: 400, + body: {errors: [ { - statusCode: statusCode, - body: { - errors: [ - { - reason: 'Bad Request', - }, - ], - }, - } - ).as('fetchDashboard'); - - cy.visitWithLogin('monitor/cloudpulse'); - // Wait for both the fetch services and fetch dashboard API calls to complete. - cy.wait(['@fetchServices', '@fetchDashboard']); - - // Assert that the error message for fetching the dashboards is displayed correctly. - cy.get('[data-qa-textfield-error-text="Dashboard"]') - .should('be.visible') - .invoke('text') - .then((text) => { - expect(text).to.equal('Failed to fetch the dashboards'); - }); - } - ); - - it('should return ' + statusCode + ' error message when the Dashboard details API request fails',() => { - cy.intercept('GET', apiMatcher(`/monitor/dashboards/${id}`), { - statusCode: statusCode, - body: { - errors: [ - { - reason: 'Bad Request', - }, - ], + reason: 'Bad Request', }, - }).as('fetchDashboardById'); - - cy.visitWithLogin('monitor/cloudpulse'); - - // Select a dashboard from the autocomplete input. Verify that the input is visible before typing. - ui.autocomplete - .findByLabel('Dashboard') - .should('be.visible') - .type(`${dashboardName}{enter}`) - .should('be.visible'); - - // Select a database engine from the autocomplete input. Verify visibility before interaction. - ui.autocomplete - .findByLabel('Database Engine') - .should('be.visible') - .type(`${engine}{enter}`) - .should('be.visible'); - - // Select a region from the dropdown. Verify visibility before interaction. - ui.regionSelect.find().click().type(`${region}{enter}`); - - // Select a database cluster from the autocomplete input. Verify visibility before interaction. - ui.autocomplete - .findByLabel('Database Clusters') - .should('be.visible') - .type(`${clusterName}{enter}`) - .click(); - cy.findByText(clusterName).should('be.visible'); - - // Select a node type from the autocomplete input. Verify visibility before interaction. - ui.autocomplete - .findByLabel('Node Type') - .should('be.visible') - .type(`${nodeType}{enter}`); - - // Wait for the API calls to fetch services and dashboard to resolve. - cy.wait(['@fetchServices', '@fetchDashboard']); - - cy.get('[data-qa-error-msg="true"]') - .should('be.visible') - .and('have.text', 'Failed to fetch the dashboard details'); - } - ); - - it(`should return ${statusCode} error message when the Regions API request fails`, () => { - cy.intercept('GET', apiMatcher(`regions*`), { - statusCode: statusCode, // Use the status code defined in the test + ], + }, + }).as('fetchServices'); + cy.visitWithLogin('monitor/cloudpulse'); + + // Wait for the API call to complete and capture the response. + cy.wait('@fetchServices'); + + cy.get('[data-qa-textfield-error-text="Dashboard"]') + .should('be.visible') + .invoke('text') + .then((text) => { + expect(text).to.equal('Failed to fetch the services.'); + }); + }); + it( 'should return error response when fetching Token API Request',() => { + cy.intercept( + 'POST', + apiMatcher(`/monitor/services/${serviceType}/token`), + { + statusCode: 400, body: { errors: [ { @@ -296,76 +202,210 @@ describe('DbasS API Error Handling', () => { }, ], }, - }).as('fetchRegion'); - - // Navigate to the CloudPulse monitoring page after logging in. - cy.visitWithLogin('monitor/cloudpulse'); - - // Wait for the services and dashboard API calls to resolve before proceeding. - cy.wait(['@fetchServices', '@fetchDashboard']); - - // Select a dashboard from the autocomplete input. Verify that the input is visible before typing. - ui.autocomplete - .findByLabel('Dashboard') - .should('be.visible') - .type(`${dashboardName}{enter}`) - .should('be.visible'); - - cy.get('[data-qa-textfield-error-text="Region"]') // Select the error message element - .should('be.visible') - .invoke('text') - .then((text) => { - expect(text).to.equal('Failed to fetch Region'); - }); + } + ).as('fetchToken'); + + cy.visitWithLogin('monitor/cloudpulse'); + // Wait for both the fetch services and fetch dashboard API calls to complete. + cy.wait(['@fetchServices', '@fetchDashboard']); + + // Selecting a dashboard from the autocomplete input. + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') + .type(`${dashboardName}{enter}`) + .should('be.visible'); + + // Select a Database Engine from the autocomplete input. + ui.autocomplete + .findByLabel('Database Engine') + .should('be.visible') + .type(`${engine}{enter}`) + .should('be.visible'); + + // Select a region from the dropdown. + ui.regionSelect.find().click().type(`${region}{enter}`); + + // Select a resource (Database Clusters) from the autocomplete input. + ui.autocomplete + .findByLabel('Database Clusters') + .should('be.visible') + .type(`${clusterName}{enter}`) + .click(); + cy.findByText(clusterName).should('be.visible'); + + // Select a Node from the autocomplete input. + ui.autocomplete + .findByLabel('Node Type') + .should('be.visible') + .type(`${nodeType}{enter}`); + + cy.get('[data-qa-error-msg="true"]') + .should('be.visible') + .and('have.text', 'Failed to get the token.'); + }); + + it( 'should return error response when fetching Dashboards API Request',() => { + mockGetCloudPulseServices(serviceType).as('fetchServices'); + cy.intercept( + 'GET', + apiMatcher(`/monitor/services/${serviceType}/dashboards`), + { + statusCode: 400, + body: { + errors: [ + { + reason: 'Bad Request', + }, + ], + }, + } + ).as('fetchDashboard'); + + cy.visitWithLogin('monitor/cloudpulse'); + // Wait for both the fetch services and fetch dashboard API calls to complete. + cy.wait(['@fetchServices', '@fetchDashboard']); + + // Assert that the error message for fetching the dashboards is displayed correctly. + cy.get('[data-qa-textfield-error-text="Dashboard"]') + .should('be.visible') + .invoke('text') + .then((text) => { + expect(text).to.equal('Failed to fetch the dashboards.'); }); +} ); + +it('should return error message when the Dashboard details API request fails',() => { + cy.intercept('GET', apiMatcher(`/monitor/dashboards/${id}`), { + statusCode: 400, + body: { + errors: [ + { + reason: 'Bad Request', + }, + ], + }, + }).as('fetchDashboardById'); + + cy.visitWithLogin('monitor/cloudpulse'); + + // Select a dashboard from the autocomplete input. Verify that the input is visible before typing. + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') + .type(`${dashboardName}{enter}`) + .should('be.visible'); + + // Select a database engine from the autocomplete input. Verify visibility before interaction. + ui.autocomplete + .findByLabel('Database Engine') + .should('be.visible') + .type(`${engine}{enter}`) + .should('be.visible'); + + // Select a region from the dropdown. Verify visibility before interaction. + ui.regionSelect.find().click().type(`${region}{enter}`); + + // Select a database cluster from the autocomplete input. Verify visibility before interaction. + ui.autocomplete + .findByLabel('Database Clusters') + .should('be.visible') + .type(`${clusterName}{enter}`) + .click(); + cy.findByText(clusterName).should('be.visible'); + + // Select a node type from the autocomplete input. Verify visibility before interaction. + ui.autocomplete + .findByLabel('Node Type') + .should('be.visible') + .type(`${nodeType}{enter}`); + + // Wait for the API calls to fetch services and dashboard to resolve. + cy.wait(['@fetchServices', '@fetchDashboard']); + + cy.get('[data-qa-error-msg="true"]') + .should('be.visible') + .and('have.text', 'Failed to fetch the dashboard details.'); +}); - it('should return ' + statusCode +' error response when fetching DB Cluster API Request',() => { - cy.intercept('GET', apiMatcher(`databases/instances*`), { - statusCode: statusCode, - body: { - errors: [ - { - reason: 'Bad Request', - }, - ], - }, - }).as('fetchCluster'); - - cy.visitWithLogin('monitor/cloudpulse'); - - //Wait for the services and dashboard API calls to resolve before proceeding. - cy.wait(['@fetchServices', '@fetchDashboard']); - - // Select a dashboard from the autocomplete input - ui.autocomplete - .findByLabel('Dashboard') - .should('be.visible') - .type(`${dashboardName}{enter}`) - .should('be.visible'); - - // Select a Node Type from the autocomplete input. Verify visibility before typing. - ui.autocomplete - .findByLabel('Node Type') - .should('be.visible') - .type(`${nodeType}{enter}`); - - // Select a region from the dropdown. Click and type the region name. - ui.regionSelect.find().click().type(`${region}{enter}`); - - // Select a Database Engine from the autocomplete input. Verify visibility before typing. - ui.autocomplete - .findByLabel('Database Engine') - .should('be.visible') - .type(`${engine}{enter}`) - .should('be.visible'); - - cy.get('[data-qa-textfield-error-text="Database Clusters"]') - .should('be.visible') - .invoke('text') - .then((text) => { - expect(text).to.equal('Failed to fetch Database Clusters'); - }); - } - ); - }); +it(`should return error message when the Regions API request fails`, () => { + cy.intercept('GET', apiMatcher(`regions*`), { + statusCode: 400, // Use the status code defined in the test + body: { + errors: [ + { + reason: 'Bad Request', + }, + ], + }, + }).as('fetchRegion'); + + cy.visitWithLogin('monitor/cloudpulse'); + + // Wait for the services and dashboard API calls to resolve before proceeding. + cy.wait(['@fetchServices', '@fetchDashboard']); + + // Select a dashboard from the autocomplete input. Verify that the input is visible before typing. + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') + .type(`${dashboardName}{enter}`) + .should('be.visible'); + + cy.get('[data-qa-textfield-error-text="Region"]') // Select the error message element + .should('be.visible') + .invoke('text') + .then((text) => { + expect(text).to.equal('Failed to fetch Region.'); + }); +}); + +it('should return error response when fetching DB Cluster API Request',() => { + cy.intercept('GET', apiMatcher(`databases/instances*`), { + statusCode: 400, + body: { + errors: [ + { + reason: 'Bad Request', + }, + ], + }, + }).as('fetchCluster'); + + cy.visitWithLogin('monitor/cloudpulse'); + + //Wait for the services and dashboard API calls to resolve before proceeding. + cy.wait(['@fetchServices', '@fetchDashboard']); + + // Select a dashboard from the autocomplete input + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') + .type(`${dashboardName}{enter}`) + .should('be.visible'); + + // Select a Node Type from the autocomplete input. Verify visibility before typing. + ui.autocomplete + .findByLabel('Node Type') + .should('be.visible') + .type(`${nodeType}{enter}`); + + // Select a region from the dropdown. Click and type the region name. + ui.regionSelect.find().click().type(`${region}{enter}`); + + // Select a Database Engine from the autocomplete input. Verify visibility before typing. + ui.autocomplete + .findByLabel('Database Engine') + .should('be.visible') + .type(`${engine}{enter}`) + .should('be.visible'); + + cy.get('[data-qa-textfield-error-text="Database Clusters"]') + .should('be.visible') + .invoke('text') + .then((text) => { + expect(text).to.equal('Failed to fetch Database Clusters.'); + }); + +}); }); From 35d5a76d34bccfa3daebff86814b08625049a95e Mon Sep 17 00:00:00 2001 From: agorthi Date: Tue, 29 Oct 2024 14:20:34 +0530 Subject: [PATCH 247/474] upcoming:[DI-21483]- Added code review comments --- .../cloudpulse/cloudpulse-validation.spec.ts | 387 +++++++++--------- 1 file changed, 191 insertions(+), 196 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts index 8021d7c148c..64904468019 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts @@ -112,15 +112,14 @@ describe('DbasS API Error Handling', () => { mockGetUserPreferences({}); mockGetDatabases([databaseMock]).as('getDatabases'); }); - + it('should return error response when fetching metric definitions API request', () => { cy.intercept( 'GET', apiMatcher(`/monitor/services/${serviceType}/metric-definitions`), { statusCode: 400, - body: {errors: [ { reason: 'Bad Request',},], - }, + body: { errors: [{ reason: 'Bad Request' }] }, } ).as('getMetricDefinitions'); @@ -167,10 +166,11 @@ describe('DbasS API Error Handling', () => { .and('have.text', 'Error loading metric definitions.'); }); - it( 'should return error response when fetching services API request',() => { + it('should return error response when fetching services API request', () => { cy.intercept('GET', apiMatcher(`/monitor/services`), { statusCode: 400, - body: {errors: [ + body: { + errors: [ { reason: 'Bad Request', }, @@ -189,10 +189,63 @@ describe('DbasS API Error Handling', () => { expect(text).to.equal('Failed to fetch the services.'); }); }); - it( 'should return error response when fetching Token API Request',() => { + it('should return error response when fetching Token API Request', () => { + cy.intercept('POST', apiMatcher(`/monitor/services/${serviceType}/token`), { + statusCode: 400, + body: { + errors: [ + { + reason: 'Bad Request', + }, + ], + }, + }).as('fetchToken'); + + cy.visitWithLogin('monitor/cloudpulse'); + // Wait for both the fetch services and fetch dashboard API calls to complete. + cy.wait(['@fetchServices', '@fetchDashboard']); + + // Selecting a dashboard from the autocomplete input. + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') + .type(`${dashboardName}{enter}`) + .should('be.visible'); + + // Select a Database Engine from the autocomplete input. + ui.autocomplete + .findByLabel('Database Engine') + .should('be.visible') + .type(`${engine}{enter}`) + .should('be.visible'); + + // Select a region from the dropdown. + ui.regionSelect.find().click().type(`${region}{enter}`); + + // Select a resource (Database Clusters) from the autocomplete input. + ui.autocomplete + .findByLabel('Database Clusters') + .should('be.visible') + .type(`${clusterName}{enter}`) + .click(); + cy.findByText(clusterName).should('be.visible'); + + // Select a Node from the autocomplete input. + ui.autocomplete + .findByLabel('Node Type') + .should('be.visible') + .type(`${nodeType}{enter}`); + + cy.get('[data-qa-error-msg="true"]') + .should('be.visible') + .and('have.text', 'Failed to get the token.'); + }); + + it('should return error response when fetching Dashboards API Request', () => { + mockGetCloudPulseServices(serviceType).as('fetchServices'); cy.intercept( - 'POST', - apiMatcher(`/monitor/services/${serviceType}/token`), + 'GET', + apiMatcher(`/monitor/services/${serviceType}/dashboards`), { statusCode: 400, body: { @@ -203,54 +256,23 @@ describe('DbasS API Error Handling', () => { ], }, } - ).as('fetchToken'); + ).as('fetchDashboard'); cy.visitWithLogin('monitor/cloudpulse'); // Wait for both the fetch services and fetch dashboard API calls to complete. cy.wait(['@fetchServices', '@fetchDashboard']); - // Selecting a dashboard from the autocomplete input. - ui.autocomplete - .findByLabel('Dashboard') - .should('be.visible') - .type(`${dashboardName}{enter}`) - .should('be.visible'); - - // Select a Database Engine from the autocomplete input. - ui.autocomplete - .findByLabel('Database Engine') - .should('be.visible') - .type(`${engine}{enter}`) - .should('be.visible'); - - // Select a region from the dropdown. - ui.regionSelect.find().click().type(`${region}{enter}`); - - // Select a resource (Database Clusters) from the autocomplete input. - ui.autocomplete - .findByLabel('Database Clusters') - .should('be.visible') - .type(`${clusterName}{enter}`) - .click(); - cy.findByText(clusterName).should('be.visible'); - - // Select a Node from the autocomplete input. - ui.autocomplete - .findByLabel('Node Type') - .should('be.visible') - .type(`${nodeType}{enter}`); - - cy.get('[data-qa-error-msg="true"]') + // Assert that the error message for fetching the dashboards is displayed correctly. + cy.get('[data-qa-textfield-error-text="Dashboard"]') .should('be.visible') - .and('have.text', 'Failed to get the token.'); - }); - - it( 'should return error response when fetching Dashboards API Request',() => { - mockGetCloudPulseServices(serviceType).as('fetchServices'); - cy.intercept( - 'GET', - apiMatcher(`/monitor/services/${serviceType}/dashboards`), - { + .invoke('text') + .then((text) => { + expect(text).to.equal('Failed to fetch the dashboards.'); + }); + }); + + it('should return error message when the Dashboard details API request fails', () => { + cy.intercept('GET', apiMatcher(`/monitor/dashboards/${id}`), { statusCode: 400, body: { errors: [ @@ -259,153 +281,126 @@ describe('DbasS API Error Handling', () => { }, ], }, - } - ).as('fetchDashboard'); - - cy.visitWithLogin('monitor/cloudpulse'); - // Wait for both the fetch services and fetch dashboard API calls to complete. - cy.wait(['@fetchServices', '@fetchDashboard']); - - // Assert that the error message for fetching the dashboards is displayed correctly. - cy.get('[data-qa-textfield-error-text="Dashboard"]') - .should('be.visible') - .invoke('text') - .then((text) => { - expect(text).to.equal('Failed to fetch the dashboards.'); - }); -} ); - -it('should return error message when the Dashboard details API request fails',() => { - cy.intercept('GET', apiMatcher(`/monitor/dashboards/${id}`), { - statusCode: 400, - body: { - errors: [ - { - reason: 'Bad Request', - }, - ], - }, - }).as('fetchDashboardById'); - - cy.visitWithLogin('monitor/cloudpulse'); - - // Select a dashboard from the autocomplete input. Verify that the input is visible before typing. - ui.autocomplete - .findByLabel('Dashboard') - .should('be.visible') - .type(`${dashboardName}{enter}`) - .should('be.visible'); - - // Select a database engine from the autocomplete input. Verify visibility before interaction. - ui.autocomplete - .findByLabel('Database Engine') - .should('be.visible') - .type(`${engine}{enter}`) - .should('be.visible'); - - // Select a region from the dropdown. Verify visibility before interaction. - ui.regionSelect.find().click().type(`${region}{enter}`); - - // Select a database cluster from the autocomplete input. Verify visibility before interaction. - ui.autocomplete - .findByLabel('Database Clusters') - .should('be.visible') - .type(`${clusterName}{enter}`) - .click(); - cy.findByText(clusterName).should('be.visible'); - - // Select a node type from the autocomplete input. Verify visibility before interaction. - ui.autocomplete - .findByLabel('Node Type') - .should('be.visible') - .type(`${nodeType}{enter}`); - - // Wait for the API calls to fetch services and dashboard to resolve. - cy.wait(['@fetchServices', '@fetchDashboard']); - - cy.get('[data-qa-error-msg="true"]') - .should('be.visible') - .and('have.text', 'Failed to fetch the dashboard details.'); -}); + }).as('fetchDashboardById'); -it(`should return error message when the Regions API request fails`, () => { - cy.intercept('GET', apiMatcher(`regions*`), { - statusCode: 400, // Use the status code defined in the test - body: { - errors: [ - { - reason: 'Bad Request', - }, - ], - }, - }).as('fetchRegion'); - - cy.visitWithLogin('monitor/cloudpulse'); - - // Wait for the services and dashboard API calls to resolve before proceeding. - cy.wait(['@fetchServices', '@fetchDashboard']); - - // Select a dashboard from the autocomplete input. Verify that the input is visible before typing. - ui.autocomplete - .findByLabel('Dashboard') - .should('be.visible') - .type(`${dashboardName}{enter}`) - .should('be.visible'); - - cy.get('[data-qa-textfield-error-text="Region"]') // Select the error message element - .should('be.visible') - .invoke('text') - .then((text) => { - expect(text).to.equal('Failed to fetch Region.'); - }); -}); + cy.visitWithLogin('monitor/cloudpulse'); -it('should return error response when fetching DB Cluster API Request',() => { - cy.intercept('GET', apiMatcher(`databases/instances*`), { - statusCode: 400, - body: { - errors: [ - { - reason: 'Bad Request', - }, - ], - }, - }).as('fetchCluster'); - - cy.visitWithLogin('monitor/cloudpulse'); - - //Wait for the services and dashboard API calls to resolve before proceeding. - cy.wait(['@fetchServices', '@fetchDashboard']); - - // Select a dashboard from the autocomplete input - ui.autocomplete - .findByLabel('Dashboard') - .should('be.visible') - .type(`${dashboardName}{enter}`) - .should('be.visible'); - - // Select a Node Type from the autocomplete input. Verify visibility before typing. - ui.autocomplete - .findByLabel('Node Type') - .should('be.visible') - .type(`${nodeType}{enter}`); - - // Select a region from the dropdown. Click and type the region name. - ui.regionSelect.find().click().type(`${region}{enter}`); - - // Select a Database Engine from the autocomplete input. Verify visibility before typing. - ui.autocomplete - .findByLabel('Database Engine') - .should('be.visible') - .type(`${engine}{enter}`) - .should('be.visible'); - - cy.get('[data-qa-textfield-error-text="Database Clusters"]') - .should('be.visible') - .invoke('text') - .then((text) => { - expect(text).to.equal('Failed to fetch Database Clusters.'); - }); + // Select a dashboard from the autocomplete input. Verify that the input is visible before typing. + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') + .type(`${dashboardName}{enter}`) + .should('be.visible'); -}); + // Select a database engine from the autocomplete input. Verify visibility before interaction. + ui.autocomplete + .findByLabel('Database Engine') + .should('be.visible') + .type(`${engine}{enter}`) + .should('be.visible'); + + // Select a region from the dropdown. Verify visibility before interaction. + ui.regionSelect.find().click().type(`${region}{enter}`); + + // Select a database cluster from the autocomplete input. Verify visibility before interaction. + ui.autocomplete + .findByLabel('Database Clusters') + .should('be.visible') + .type(`${clusterName}{enter}`) + .click(); + cy.findByText(clusterName).should('be.visible'); + + // Select a node type from the autocomplete input. Verify visibility before interaction. + ui.autocomplete + .findByLabel('Node Type') + .should('be.visible') + .type(`${nodeType}{enter}`); + + // Wait for the API calls to fetch services and dashboard to resolve. + cy.wait(['@fetchServices', '@fetchDashboard']); + + cy.get('[data-qa-error-msg="true"]') + .should('be.visible') + .and('have.text', 'Failed to fetch the dashboard details.'); + }); + + it(`should return error message when the Regions API request fails`, () => { + cy.intercept('GET', apiMatcher(`regions*`), { + statusCode: 400, // Use the status code defined in the test + body: { + errors: [ + { + reason: 'Bad Request', + }, + ], + }, + }).as('fetchRegion'); + + cy.visitWithLogin('monitor/cloudpulse'); + + // Wait for the services and dashboard API calls to resolve before proceeding. + cy.wait(['@fetchServices', '@fetchDashboard']); + + // Select a dashboard from the autocomplete input. Verify that the input is visible before typing. + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') + .type(`${dashboardName}{enter}`) + .should('be.visible'); + + cy.get('[data-qa-textfield-error-text="Region"]') // Select the error message element + .should('be.visible') + .invoke('text') + .then((text) => { + expect(text).to.equal('Failed to fetch Region.'); + }); + }); + + it('should return error response when fetching DB Cluster API Request', () => { + cy.intercept('GET', apiMatcher(`databases/instances*`), { + statusCode: 400, + body: { + errors: [ + { + reason: 'Bad Request', + }, + ], + }, + }).as('fetchCluster'); + + cy.visitWithLogin('monitor/cloudpulse'); + + //Wait for the services and dashboard API calls to resolve before proceeding. + cy.wait(['@fetchServices', '@fetchDashboard']); + + // Select a dashboard from the autocomplete input + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') + .type(`${dashboardName}{enter}`) + .should('be.visible'); + + // Select a Node Type from the autocomplete input. Verify visibility before typing. + ui.autocomplete + .findByLabel('Node Type') + .should('be.visible') + .type(`${nodeType}{enter}`); + + // Select a region from the dropdown. Click and type the region name. + ui.regionSelect.find().click().type(`${region}{enter}`); + + // Select a Database Engine from the autocomplete input. Verify visibility before typing. + ui.autocomplete + .findByLabel('Database Engine') + .should('be.visible') + .type(`${engine}{enter}`) + .should('be.visible'); + + cy.get('[data-qa-textfield-error-text="Database Clusters"]') + .should('be.visible') + .invoke('text') + .then((text) => { + expect(text).to.equal('Failed to fetch Database Clusters.'); + }); + }); }); From e65918ef3c1f8b1eb102764a1be7ac4b6b641d3d Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 29 Oct 2024 15:05:16 +0530 Subject: [PATCH 248/474] upcoming: [DI-18419] - updated error messages across files --- .../src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx | 4 ++-- .../CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx | 2 +- .../features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index bed2ec6c7b7..7af33471c4d 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -116,11 +116,11 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { } if (isJweTokenError) { - return renderErrorState('Failed to get the token.'); + return renderErrorState('Failed to get the authentication token.'); } if (isMetricDefinitionError) { - return renderErrorState('Error loading metric definitions.'); + return renderErrorState('Error loading the definitions of metrics.'); } if ( diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx index 91924a6c632..6b6d679f3a3 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx @@ -33,7 +33,7 @@ export const CloudPulseDashboardRenderer = React.memo( if (!FILTER_CONFIG.get(dashboard.service_type)) { return ( - + ); } diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx index d13d3efe97a..11d3c97204c 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx @@ -73,7 +73,7 @@ export const RenderWidgets = React.memo( authToken: '', availableMetrics: undefined, duration, - errorLabel: 'Error while loading data.', + errorLabel: 'Error occurred while loading data.', resourceIds: resources, resources: [], serviceType: dashboard?.service_type ?? '', @@ -127,7 +127,7 @@ export const RenderWidgets = React.memo( !Boolean(resourceList?.length) ) { return renderPlaceHolder( - 'Select Dashboard, Region and Resource to visualize metrics.' + 'Select dashboard and filters to visualize metrics.' ); } From 7c01edbbf05e7de05511410f7e33476d0f1876fd Mon Sep 17 00:00:00 2001 From: agorthi Date: Tue, 29 Oct 2024 15:31:04 +0530 Subject: [PATCH 249/474] upcoming:[DI-21483]- Added code review comments with message update --- .../core/cloudpulse/cloudpulse-validation.spec.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts index 64904468019..519386130d5 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts @@ -163,7 +163,7 @@ describe('DbasS API Error Handling', () => { cy.wait('@getMetricDefinitions'); cy.get('[data-qa-error-msg="true"]') .should('be.visible') - .and('have.text', 'Error loading metric definitions.'); + .and('have.text', 'Error loading the definitions of metrics.'); }); it('should return error response when fetching services API request', () => { @@ -189,7 +189,7 @@ describe('DbasS API Error Handling', () => { expect(text).to.equal('Failed to fetch the services.'); }); }); - it('should return error response when fetching Token API Request', () => { + it('should return error response when fetching Token API Request', () => { cy.intercept('POST', apiMatcher(`/monitor/services/${serviceType}/token`), { statusCode: 400, body: { @@ -238,10 +238,10 @@ describe('DbasS API Error Handling', () => { cy.get('[data-qa-error-msg="true"]') .should('be.visible') - .and('have.text', 'Failed to get the token.'); + .and('have.text', 'Failed to get the authentication token.'); }); - it('should return error response when fetching Dashboards API Request', () => { + it('should return error response when fetching Dashboards API Request', () => { mockGetCloudPulseServices(serviceType).as('fetchServices'); cy.intercept( 'GET', @@ -324,7 +324,7 @@ describe('DbasS API Error Handling', () => { .and('have.text', 'Failed to fetch the dashboard details.'); }); - it(`should return error message when the Regions API request fails`, () => { + it(`should return error message when the Regions API request fails`, () => { cy.intercept('GET', apiMatcher(`regions*`), { statusCode: 400, // Use the status code defined in the test body: { @@ -356,7 +356,7 @@ describe('DbasS API Error Handling', () => { }); }); - it('should return error response when fetching DB Cluster API Request', () => { + it('should return error response when fetching DB Cluster API Request', () => { cy.intercept('GET', apiMatcher(`databases/instances*`), { statusCode: 400, body: { From ca73277f6a0e688930c848940c3d06e4e4afbedf Mon Sep 17 00:00:00 2001 From: agorthi Date: Tue, 29 Oct 2024 16:27:05 +0530 Subject: [PATCH 250/474] upcoming:[DI-21483]- Added code review comments with message update --- .../cloudpulse/cloudpulse-validation.spec.ts | 40 +++---------------- 1 file changed, 6 insertions(+), 34 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts index 519386130d5..641fc2f0f4c 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts @@ -170,11 +170,7 @@ describe('DbasS API Error Handling', () => { cy.intercept('GET', apiMatcher(`/monitor/services`), { statusCode: 400, body: { - errors: [ - { - reason: 'Bad Request', - }, - ], + errors: [{ reason: 'Bad Request' }], }, }).as('fetchServices'); cy.visitWithLogin('monitor/cloudpulse'); @@ -193,11 +189,7 @@ describe('DbasS API Error Handling', () => { cy.intercept('POST', apiMatcher(`/monitor/services/${serviceType}/token`), { statusCode: 400, body: { - errors: [ - { - reason: 'Bad Request', - }, - ], + errors: [{ reason: 'Bad Request' }], }, }).as('fetchToken'); @@ -249,11 +241,7 @@ describe('DbasS API Error Handling', () => { { statusCode: 400, body: { - errors: [ - { - reason: 'Bad Request', - }, - ], + errors: [{ reason: 'Bad Request' }], }, } ).as('fetchDashboard'); @@ -274,13 +262,7 @@ describe('DbasS API Error Handling', () => { it('should return error message when the Dashboard details API request fails', () => { cy.intercept('GET', apiMatcher(`/monitor/dashboards/${id}`), { statusCode: 400, - body: { - errors: [ - { - reason: 'Bad Request', - }, - ], - }, + body: { errors: [{ reason: 'Bad Request' }] }, }).as('fetchDashboardById'); cy.visitWithLogin('monitor/cloudpulse'); @@ -327,13 +309,7 @@ describe('DbasS API Error Handling', () => { it(`should return error message when the Regions API request fails`, () => { cy.intercept('GET', apiMatcher(`regions*`), { statusCode: 400, // Use the status code defined in the test - body: { - errors: [ - { - reason: 'Bad Request', - }, - ], - }, + body: { errors: [{ reason: 'Bad Request' }] }, }).as('fetchRegion'); cy.visitWithLogin('monitor/cloudpulse'); @@ -360,11 +336,7 @@ describe('DbasS API Error Handling', () => { cy.intercept('GET', apiMatcher(`databases/instances*`), { statusCode: 400, body: { - errors: [ - { - reason: 'Bad Request', - }, - ], + errors: [{ reason: 'Bad Request' }], }, }).as('fetchCluster'); From 3e3be92de05971ffb73cc86f2cc07b699099f958 Mon Sep 17 00:00:00 2001 From: agorthi Date: Tue, 29 Oct 2024 16:34:13 +0530 Subject: [PATCH 251/474] upcoming:[DI-21483]- Added code review comments with message update --- .../cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts index 641fc2f0f4c..e81e7df1bf1 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts @@ -259,7 +259,7 @@ describe('DbasS API Error Handling', () => { }); }); - it('should return error message when the Dashboard details API request fails', () => { + it('should return error message when the Dashboard details API request fails', () => { cy.intercept('GET', apiMatcher(`/monitor/dashboards/${id}`), { statusCode: 400, body: { errors: [{ reason: 'Bad Request' }] }, From 403b4388275f3c571244e901b2179eccb1f6ef54 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Tue, 29 Oct 2024 19:50:05 +0530 Subject: [PATCH 252/474] upcoming: [DI-21118] - Monitor scope as part of PAT token --- .../APITokens/ViewAPITokenDrawer.test.tsx | 4 +-- .../features/Profile/APITokens/utils.test.ts | 32 +++++++++---------- .../src/features/Profile/APITokens/utils.ts | 4 +-- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/packages/manager/src/features/Profile/APITokens/ViewAPITokenDrawer.test.tsx b/packages/manager/src/features/Profile/APITokens/ViewAPITokenDrawer.test.tsx index d1d7c9b0cee..cb1c38e4f40 100644 --- a/packages/manager/src/features/Profile/APITokens/ViewAPITokenDrawer.test.tsx +++ b/packages/manager/src/features/Profile/APITokens/ViewAPITokenDrawer.test.tsx @@ -111,14 +111,13 @@ describe('View API Token Drawer', () => { {...props} token={appTokenFactory.build({ scopes: - 'aclp:read_write databases:read_only domains:read_write child_account:read_write events:read_write firewall:read_write images:read_write ips:read_write linodes:read_only lke:read_only longview:read_write nodebalancers:read_write object_storage:read_only stackscripts:read_write volumes:read_only vpc:read_write', + 'databases:read_only domains:read_write child_account:read_write events:read_write firewall:read_write images:read_write ips:read_write linodes:read_only lke:read_only longview:read_write monitor:read_only nodebalancers:read_write object_storage:read_only stackscripts:read_write volumes:read_only vpc:read_write', })} /> ); const expectedScopeLevels = { account: 0, - aclp: 2, child_account: 2, databases: 1, domains: 2, @@ -129,6 +128,7 @@ describe('View API Token Drawer', () => { linodes: 1, lke: 1, longview: 2, + monitor: 1, nodebalancers: 2, object_storage: 1, stackscripts: 2, diff --git a/packages/manager/src/features/Profile/APITokens/utils.test.ts b/packages/manager/src/features/Profile/APITokens/utils.test.ts index 628c5b1fdec..6b20ff573f0 100644 --- a/packages/manager/src/features/Profile/APITokens/utils.test.ts +++ b/packages/manager/src/features/Profile/APITokens/utils.test.ts @@ -28,7 +28,6 @@ describe('APIToken utils', () => { const result = scopeStringToPermTuples('*'); const expected = [ ['account', 2], - ['aclp', 2], ['child_account', 2], ['databases', 2], ['domains', 2], @@ -39,6 +38,7 @@ describe('APIToken utils', () => { ['linodes', 2], ['lke', 2], ['longview', 2], + ['monitor', 2], ['nodebalancers', 2], ['object_storage', 2], ['stackscripts', 2], @@ -54,7 +54,6 @@ describe('APIToken utils', () => { const result = scopeStringToPermTuples(''); const expected = [ ['account', 0], - ['aclp', 0], ['child_account', 0], ['databases', 0], ['domains', 0], @@ -65,6 +64,7 @@ describe('APIToken utils', () => { ['linodes', 0], ['lke', 0], ['longview', 0], + ['monitor', 0], ['nodebalancers', 0], ['object_storage', 0], ['stackscripts', 0], @@ -81,7 +81,6 @@ describe('APIToken utils', () => { const result = scopeStringToPermTuples('account:none'); const expected = [ ['account', 0], - ['aclp', 0], ['child_account', 0], ['databases', 0], ['domains', 0], @@ -92,6 +91,7 @@ describe('APIToken utils', () => { ['linodes', 0], ['lke', 0], ['longview', 0], + ['monitor', 0], ['nodebalancers', 0], ['object_storage', 0], ['stackscripts', 0], @@ -108,7 +108,6 @@ describe('APIToken utils', () => { const result = scopeStringToPermTuples('account:read_only'); const expected = [ ['account', 1], - ['aclp', 0], ['child_account', 0], ['databases', 0], ['domains', 0], @@ -119,6 +118,7 @@ describe('APIToken utils', () => { ['linodes', 0], ['lke', 0], ['longview', 0], + ['monitor', 0], ['nodebalancers', 0], ['object_storage', 0], ['stackscripts', 0], @@ -135,7 +135,6 @@ describe('APIToken utils', () => { const result = scopeStringToPermTuples('account:read_write'); const expected = [ ['account', 2], - ['aclp', 0], ['child_account', 0], ['databases', 0], ['domains', 0], @@ -146,6 +145,7 @@ describe('APIToken utils', () => { ['linodes', 0], ['lke', 0], ['longview', 0], + ['monitor', 0], ['nodebalancers', 0], ['object_storage', 0], ['stackscripts', 0], @@ -164,7 +164,6 @@ describe('APIToken utils', () => { ); const expected = [ ['account', 0], - ['aclp', 0], ['child_account', 0], ['databases', 0], ['domains', 1], @@ -175,6 +174,7 @@ describe('APIToken utils', () => { ['linodes', 0], ['lke', 0], ['longview', 2], + ['monitor', 0], ['nodebalancers', 0], ['object_storage', 0], ['stackscripts', 0], @@ -195,7 +195,6 @@ describe('APIToken utils', () => { const result = scopeStringToPermTuples('account:none,tokens:read_write'); const expected = [ ['account', 2], - ['aclp', 0], ['child_account', 0], ['databases', 0], ['domains', 0], @@ -206,6 +205,7 @@ describe('APIToken utils', () => { ['linodes', 0], ['lke', 0], ['longview', 0], + ['monitor', 0], ['nodebalancers', 0], ['object_storage', 0], ['stackscripts', 0], @@ -226,7 +226,6 @@ describe('APIToken utils', () => { const result = scopeStringToPermTuples('account:read_only,tokens:none'); const expected = [ ['account', 1], - ['aclp', 0], ['child_account', 0], ['databases', 0], ['domains', 0], @@ -237,6 +236,7 @@ describe('APIToken utils', () => { ['linodes', 0], ['lke', 0], ['longview', 0], + ['monitor', 0], ['nodebalancers', 0], ['object_storage', 0], ['stackscripts', 0], @@ -253,7 +253,6 @@ describe('APIToken utils', () => { it('should return 0 if all scopes are 0', () => { const scopes: Permission[] = [ ['account', 0], - ['aclp', 0], ['child_account', 0], ['databases', 0], ['domains', 0], @@ -264,6 +263,7 @@ describe('APIToken utils', () => { ['linodes', 0], ['lke', 0], ['longview', 0], + ['monitor', 0], ['nodebalancers', 0], ['object_storage', 0], ['stackscripts', 0], @@ -275,7 +275,6 @@ describe('APIToken utils', () => { it('should return 1 if all scopes are 1', () => { const scopes: Permission[] = [ ['account', 1], - ['aclp', 1], ['child_account', 1], ['databases', 1], ['domains', 1], @@ -286,6 +285,7 @@ describe('APIToken utils', () => { ['linodes', 1], ['lke', 1], ['longview', 1], + ['monitor', 1], ['nodebalancers', 1], ['object_storage', 1], ['stackscripts', 1], @@ -296,7 +296,6 @@ describe('APIToken utils', () => { it('should return 2 if all scopes are 2', () => { const scopes: Permission[] = [ ['account', 2], - ['aclp', 2], ['child_account', 2], ['databases', 2], ['domains', 2], @@ -307,6 +306,7 @@ describe('APIToken utils', () => { ['linodes', 2], ['lke', 2], ['longview', 2], + ['monitor', 2], ['nodebalancers', 2], ['object_storage', 2], ['stackscripts', 2], @@ -318,7 +318,6 @@ describe('APIToken utils', () => { it('should return null if all scopes are not same', () => { const scopes: Permission[] = [ ['account', 1], - ['aclp', 2], ['child_account', 0], ['databases', 0], ['domains', 2], @@ -329,6 +328,7 @@ describe('APIToken utils', () => { ['linodes', 1], ['lke', 2], ['longview', 2], + ['monitor', 2], ['nodebalancers', 0], ['object_storage', 2], ['stackscripts', 2], @@ -341,7 +341,6 @@ describe('APIToken utils', () => { it('should return 1 if all scopes, except any exclusions, are 1', () => { const scopes: Permission[] = [ ['account', 1], - ['aclp', 1], ['child_account', 1], ['databases', 1], ['domains', 1], @@ -352,6 +351,7 @@ describe('APIToken utils', () => { ['linodes', 1], ['lke', 1], ['longview', 2], + ['monitor', 1], ['nodebalancers', 1], ['object_storage', 1], ['stackscripts', 1], @@ -378,7 +378,6 @@ describe('APIToken utils', () => { describe('hasAccessBeenSelectedForAllScopes', () => { const defaultScopes: Permission[] = [ ['account', -1], - ['aclp', -1], ['child_account', -1], ['databases', -1], ['domains', -1], @@ -389,6 +388,7 @@ describe('hasAccessBeenSelectedForAllScopes', () => { ['linodes', -1], ['lke', -1], ['longview', -1], + ['monitor', -1], ['nodebalancers', -1], ['object_storage', -1], ['stackscripts', -1], @@ -398,7 +398,6 @@ describe('hasAccessBeenSelectedForAllScopes', () => { const missingSelectionScopes: Permission[] = [ ['account', -1], - ['aclp', -1], ['child_account', -1], ['databases', -1], ['domains', -1], @@ -409,6 +408,7 @@ describe('hasAccessBeenSelectedForAllScopes', () => { ['linodes', -1], ['lke', -1], ['longview', -1], + ['monitor', -1], ['nodebalancers', -1], ['object_storage', -1], ['stackscripts', -1], @@ -418,7 +418,6 @@ describe('hasAccessBeenSelectedForAllScopes', () => { const allSelectedScopes: Permission[] = [ ['account', 1], - ['aclp', 0], ['child_account', 0], ['databases', 0], ['domains', 0], @@ -429,6 +428,7 @@ describe('hasAccessBeenSelectedForAllScopes', () => { ['linodes', 2], ['lke', 0], ['longview', 0], + ['monitor', 0], ['nodebalancers', 0], ['object_storage', 0], ['stackscripts', 0], diff --git a/packages/manager/src/features/Profile/APITokens/utils.ts b/packages/manager/src/features/Profile/APITokens/utils.ts index 992cc8e57d3..6ba792065e4 100644 --- a/packages/manager/src/features/Profile/APITokens/utils.ts +++ b/packages/manager/src/features/Profile/APITokens/utils.ts @@ -8,7 +8,6 @@ export type Permission = [keyof typeof basePermNameMap, number]; export const basePerms = [ 'account', - 'aclp', 'child_account', 'databases', 'domains', @@ -19,6 +18,7 @@ export const basePerms = [ 'linodes', 'lke', 'longview', + 'monitor', 'nodebalancers', 'object_storage', 'stackscripts', @@ -28,7 +28,6 @@ export const basePerms = [ export const basePermNameMap = { account: 'Account', - aclp: 'ACLP', child_account: 'Child Account Access', databases: 'Databases', domains: 'Domains', @@ -39,6 +38,7 @@ export const basePermNameMap = { linodes: 'Linodes', lke: 'Kubernetes', longview: 'Longview', + monitor: 'Monitor', nodebalancers: 'NodeBalancers', object_storage: 'Object Storage', stackscripts: 'StackScripts', From 03118256fa7fc15c305d4e18fe5b9315997bbb99 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Tue, 29 Oct 2024 19:53:54 +0530 Subject: [PATCH 253/474] upcoming: [DI-21118] - PR comment --- packages/manager/src/features/Profile/APITokens/utils.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/Profile/APITokens/utils.test.ts b/packages/manager/src/features/Profile/APITokens/utils.test.ts index 6b20ff573f0..634baa93c5c 100644 --- a/packages/manager/src/features/Profile/APITokens/utils.test.ts +++ b/packages/manager/src/features/Profile/APITokens/utils.test.ts @@ -315,7 +315,7 @@ describe('APIToken utils', () => { ]; expect(allScopesAreTheSame(scopes)).toBe(2); }); - it('should return null if all scopes are not same', () => { + it('should return null if all scopes are different', () => { const scopes: Permission[] = [ ['account', 1], ['child_account', 0], From 473702de4a8f205160a2a8f23f8912459650284b Mon Sep 17 00:00:00 2001 From: vmangalr Date: Wed, 30 Oct 2024 12:12:34 +0530 Subject: [PATCH 254/474] upcoming: [DI-18419] - PR comments --- .../CloudPulse/Dashboard/CloudPulseDashboardLanding.test.tsx | 4 ++-- .../CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx | 2 +- .../features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.test.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.test.tsx index 0a8509f9e5a..78661b048a8 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.test.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.test.tsx @@ -56,7 +56,7 @@ describe('CloudPulseDashboardFilterBuilder component tests', () => { ); expect( - screen.getByText('Select dashboard and filters to visualize metrics.') + screen.getByText('Select a dashboard and filters to visualize metrics.') ).toBeDefined(); }); @@ -103,7 +103,7 @@ describe('CloudPulseDashboardFilterBuilder component tests', () => { ); expect( - screen.getByText('Select dashboard and filters to visualize metrics.') + screen.getByText('Select a dashboard and filters to visualize metrics.') ).toBeDefined(); }); }); diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx index 6b6d679f3a3..a1cb03e235b 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx @@ -16,7 +16,7 @@ export const CloudPulseDashboardRenderer = React.memo( const { dashboard, filterValue, timeDuration } = props; const selectDashboardAndFilterMessage = - 'Select dashboard and filters to visualize metrics.'; + 'Select a dashboard and filters to visualize metrics.'; const getMetricsCall = React.useMemo( () => getMetricsCallCustomFilters(filterValue, dashboard?.service_type), diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx index 11d3c97204c..56d27e950a2 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx @@ -127,7 +127,7 @@ export const RenderWidgets = React.memo( !Boolean(resourceList?.length) ) { return renderPlaceHolder( - 'Select dashboard and filters to visualize metrics.' + 'Select a dashboard and filters to visualize metrics.' ); } From e91c46e0988844bddeba2a9b6e979a9127625b70 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 16 Oct 2024 17:38:30 +0530 Subject: [PATCH 255/474] upcoming: [DI-20870] - Migrated chartjs to recharts for ACLP graphs --- .../src/components/AreaChart/AreaChart.tsx | 2 +- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 101 ++++++++++-------- .../CloudPulse/Widget/CloudPulseWidget.tsx | 38 ++++--- .../Widget/components/CloudPulseLineGraph.tsx | 40 ++----- 4 files changed, 81 insertions(+), 100 deletions(-) diff --git a/packages/manager/src/components/AreaChart/AreaChart.tsx b/packages/manager/src/components/AreaChart/AreaChart.tsx index 9416c620701..755aad64e45 100644 --- a/packages/manager/src/components/AreaChart/AreaChart.tsx +++ b/packages/manager/src/components/AreaChart/AreaChart.tsx @@ -53,7 +53,7 @@ interface XAxisProps { tickGap: number; } -interface AreaChartProps { +export interface AreaChartProps { /** * list of areas to be displayed */ diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index 20a44f11f59..2d02687d849 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -1,8 +1,11 @@ -import { isToday } from 'src/utilities/isToday'; +import { Alias } from '@linode/design-language-system'; +import { styled } from '@mui/material'; + +import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; import { getMetrics } from 'src/utilities/statMetrics'; -import { COLOR_MAP, DEFAULT } from './CloudPulseWidgetColorPalette'; import { + convertValueToUnit, formatToolTip, generateUnitByBaseUnit, transformData, @@ -13,16 +16,17 @@ import { } from './utils'; import type { CloudPulseResources } from '../shared/CloudPulseResourcesSelect'; -import type { LegendRow } from '../Widget/CloudPulseWidget'; import type { CloudPulseMetricsList, CloudPulseMetricsRequest, CloudPulseMetricsResponse, + DataSet, TimeDuration, Widgets, } from '@linode/api-v4'; +import type { AreaProps } from 'src/components/AreaChart/AreaChart'; +import type { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay'; import type { Theme } from '@mui/material'; -import type { DataSet } from 'src/components/LineGraph/LineGraph'; import type { CloudPulseResourceTypeMapFlag, FlagSet } from 'src/featureFlags'; interface LabelNameOptionsProps { @@ -57,7 +61,7 @@ interface LabelNameOptionsProps { unit: string; } -interface graphDataOptionsProps { +interface GraphDataOptionsProps { /** * flags associated with metricsList */ @@ -147,7 +151,7 @@ interface DimensionNameProperties { * * @returns parameters which will be necessary to populate graph & legends */ -export const generateGraphData = (props: graphDataOptionsProps) => { +export const generateGraphData = (props: GraphDataOptionsProps) => { const { flags, label, @@ -156,28 +160,27 @@ export const generateGraphData = (props: graphDataOptionsProps) => { serviceType, status, unit, - widgetChartType, - widgetColor, + // widgetChartType, + // widgetColor, } = props; - - const dimensions: DataSet[] = []; - const legendRowsData: LegendRow[] = []; - - // if the color is not found in the map, we will fallback to default color theme - const colors = COLOR_MAP.get(widgetColor) ?? DEFAULT; - let today = false; - + const legendRowsData: MetricsDisplayRow[] = []; + // for now we will use this, but once we decide how to work with coloring, it should be dynamic + // const colors = COLOR_MAP.get(widgetColor ?? 'default')!; + const dimension: { [timestamp: number]: { [label: string]: number } } = {}; + const areas: AreaProps[] = []; + const colors = Object.values(Alias.Chart.Categorical); if (status === 'success') { metricsList?.data?.result?.forEach( (graphData: CloudPulseMetricsList, index) => { if (!graphData) { return; } + const transformedData = { metric: graphData.metric, values: transformData(graphData.values, unit), }; - const color = colors[index]; + // const color = colors[index]; const { end, start } = convertTimeDurationToStartAndEndTimeRange({ unit: 'min', value: 30, @@ -194,33 +197,52 @@ export const generateGraphData = (props: graphDataOptionsProps) => { serviceType, unit, }; - - const dimension = { - backgroundColor: color, - borderColor: color, - data: seriesDataFormatter(transformedData.values, start, end), - fill: widgetChartType === 'area', - label: getLabelName(labelOptions), - }; + const labelName = getLabelName(labelOptions); + const data = seriesDataFormatter(transformedData.values, start, end); + const color = colors[index]?.Primary ?? Alias.Chart.Neutral; + areas.push({ + color, + dataKey: labelName, + }); + + data.forEach((d) => { + const timestamp = d[0]; + const value = d[1]; + if (value !== null) { + dimension[timestamp] = { + ...dimension[timestamp], + [labelName]: value, + }; + } + }); // construct a legend row with the dimension - const legendRow = { - data: getMetrics(dimension.data as number[][]), + const legendRow: MetricsDisplayRow = { + data: getMetrics(data as number[][]), format: (value: number) => formatToolTip(value, unit), legendColor: color, - legendTitle: dimension.label, + legendTitle: labelName, }; legendRowsData.push(legendRow); - dimensions.push(dimension); - today ||= isToday(start, end); } ); } + const maxUnit = generateMaxUnit(legendRowsData, unit); + const dimensions: DataSet[] = Object.entries(dimension).map( + ([key, value]) => { + const rolledUpData: { [resource: string]: number } = {}; + Object.entries(value).forEach( + ([resource, data]) => + (rolledUpData[resource] = convertValueToUnit(data, maxUnit)) + ); + return { timestamp: Number(key), ...rolledUpData }; + } + ); return { + areas, dimensions, legendRowsData, - today, - unit: generateMaxUnit(legendRowsData, unit), + unit: maxUnit, }; }; @@ -230,7 +252,7 @@ export const generateGraphData = (props: graphDataOptionsProps) => { * @param unit base unit of the values * @returns maximum possible rolled up unit based on the unit */ -const generateMaxUnit = (legendRowsData: LegendRow[], unit: string) => { +const generateMaxUnit = (legendRowsData: MetricsDisplayRow[], unit: string) => { const maxValue = Math.max( 0, ...legendRowsData?.map((row) => row?.data.max ?? 0) @@ -319,19 +341,6 @@ export const mapResourceIdToName = ( return resourcesObj?.label ?? id ?? ''; }; -/** - * - * @param data data set to be checked for empty - * @returns true if data is not empty or contains all the null values otherwise false - */ -export const isDataEmpty = (data: DataSet[]): boolean => { - return data.every( - (thisSeries) => - thisSeries.data.length === 0 || - // If we've padded the data, every y value will be null - thisSeries.data.every((thisPoint) => thisPoint[1] === null) - ); -}; /** * diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 44d5dbcdb39..7a2e16a3293 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -13,11 +13,6 @@ import { } from '../Utils/CloudPulseWidgetUtils'; import { AGGREGATE_FUNCTION, SIZE, TIME_GRANULARITY } from '../Utils/constants'; import { constructAdditionalRequestFilters } from '../Utils/FilterBuilder'; -import { - convertValueToUnit, - formatToolTip, - generateCurrentUnit, -} from '../Utils/unitConversion'; import { useAclpPreference } from '../Utils/UserPreference'; import { convertStringToCamelCasesWithSpaces } from '../Utils/utils'; import { CloudPulseAggregateFunction } from './components/CloudPulseAggregateFunction'; @@ -29,11 +24,13 @@ import type { FilterValueType } from '../Dashboard/CloudPulseDashboardLanding'; import type { CloudPulseResources } from '../shared/CloudPulseResourcesSelect'; import type { AvailableMetrics, + DataSet, TimeDuration, TimeGranularity, } from '@linode/api-v4'; import type { Widgets } from '@linode/api-v4'; -import type { DataSet } from 'src/components/LineGraph/LineGraph'; +import type { AreaProps } from 'src/components/AreaChart/AreaChart'; +import type { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay'; import type { Metrics } from 'src/utilities/statMetrics'; export interface CloudPulseWidgetProperties { @@ -237,11 +234,11 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { url: flags.aclpReadEndpoint!, } ); - let data: DataSet[] = []; - let legendRows: LegendRow[] = []; - let today: boolean = false; + let legendRows: MetricsDisplayRow[] = []; + let currentUnit = unit; + let areas: AreaProps[] = []; if (!isLoading && metricsList) { const generatedData = generateGraphData({ flags, @@ -257,12 +254,17 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { data = generatedData.dimensions; legendRows = generatedData.legendRowsData; - today = generatedData.today; scaledWidgetUnit.current = generatedData.unit; // here state doesn't matter, as this is always the latest re-render + currentUnit = generatedData.unit; + areas = generatedData.areas; } const metricsApiCallError = error?.[0]?.reason; + const tickFormat = + duration.unit === 'min' || duration.unit === 'hr' + ? 'hh:mm a' + : `LLL dd${widget.size === 12 ? ', hh:mm a' : ''}`; return ( @@ -323,20 +325,16 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { ? metricsApiCallError ?? 'Error while rendering graph' : undefined } - formatData={(data: number) => - convertValueToUnit(data, scaledWidgetUnit.current) - } - legendRows={ - legendRows && legendRows.length > 0 ? legendRows : undefined - } + areas={areas} ariaLabel={ariaLabel ? ariaLabel : ''} data={data} - formatTooltip={(value: number) => formatToolTip(value, unit)} - gridSize={widget.size} + height={480} + legendRows={legendRows} loading={isLoading || metricsApiCallError === jweTokenExpiryError} // keep loading until we fetch the refresh token - showToday={today} + showLegend timezone={timezone} - title={widget.label} + unit={currentUnit} + xAxis={{ tickFormat, tickGap: 60 }} /> diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index 5c3ce2fd3fd..a77b06ea01b 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -1,29 +1,19 @@ -import { Box, Typography, useTheme } from '@mui/material'; +import { Box, Typography } from '@mui/material'; import * as React from 'react'; +import { AreaChart } from 'src/components/AreaChart/AreaChart'; import { CircleProgress } from 'src/components/CircleProgress'; import { ErrorState } from 'src/components/ErrorState/ErrorState'; -import { LineGraph } from 'src/components/LineGraph/LineGraph'; -import { isDataEmpty } from '../../Utils/CloudPulseWidgetUtils'; +import type { AreaChartProps } from 'src/components/AreaChart/AreaChart'; -import type { LegendRow } from '../CloudPulseWidget'; -import type { LineGraphProps } from 'src/components/LineGraph/LineGraph'; - -export interface CloudPulseLineGraph extends LineGraphProps { - ariaLabel?: string; +export interface CloudPulseLineGraph extends AreaChartProps { error?: string; - gridSize: number; - legendRows?: LegendRow[]; loading?: boolean; - subtitle?: string; - title: string; } export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { - const { ariaLabel, data, error, legendRows, loading, ...rest } = props; - - const theme = useTheme(); + const { error, loading, ...rest } = props; if (loading) { return ; @@ -42,25 +32,9 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { ) : ( - + )} - {isDataEmpty(data) && ( + {rest.data.length === 0 && ( Date: Wed, 16 Oct 2024 17:54:27 +0530 Subject: [PATCH 256/474] upcoming: [DI-20870] - Removed unused imports --- .../src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index 2d02687d849..ab6f7fb01a2 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -1,7 +1,5 @@ import { Alias } from '@linode/design-language-system'; -import { styled } from '@mui/material'; -import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; import { getMetrics } from 'src/utilities/statMetrics'; import { @@ -24,9 +22,9 @@ import type { TimeDuration, Widgets, } from '@linode/api-v4'; +import type { Theme } from '@mui/material'; import type { AreaProps } from 'src/components/AreaChart/AreaChart'; import type { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay'; -import type { Theme } from '@mui/material'; import type { CloudPulseResourceTypeMapFlag, FlagSet } from 'src/featureFlags'; interface LabelNameOptionsProps { From fae2fc8194b4296908aa976b51cfac2e93f68a1c Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 16 Oct 2024 18:13:17 +0530 Subject: [PATCH 257/474] upcoming: [DI-20870] - Removed CloudPulseWidgetColorPalette file --- .../Utils/CloudPulseWidgetColorPalette.ts | 111 ------------------ .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 3 - 2 files changed, 114 deletions(-) delete mode 100644 packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetColorPalette.ts diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetColorPalette.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetColorPalette.ts deleted file mode 100644 index 3b9325521d0..00000000000 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetColorPalette.ts +++ /dev/null @@ -1,111 +0,0 @@ -export const RED = [ - '#ee2c2c80', - '#ff633d80', - '#F27E7E80', - '#EA7C7280', - '#E2796580', - '#D9775980', - '#D1744D80', - '#C9724080', - '#C16F3480', - '3B86D2880', - '#B06A1B80', - '#A8680F80', -]; - -export const GREEN = [ - '#10a21d80', - '#31ce3e80', - '#d9b0d980', - '#ffdc7d80', - '#7EF29D80', - '#72E39E80', - '#65D3A080', - '#59C4A180', - '#4DB5A280', - '#40A5A480', - '#3496A580', - '#2887A680', - '#1B77A880', - '#0F68A980', -]; - -export const BLUE = [ - '#3683dc80', - '#0F91A880', - '#1B9CAC80', - '#28A7AF80', - '#34B1B380', - '#40BCB680', - '#4DC7BA80', - '#59D2BD80', - '#65DCC180', - '#72E7C480', - '#7EF2C880', -]; - -export const YELLOW = [ - '#ffb34d80', - '#F2EE7E80', - '#E6E67280', - '#DBDE6580', - '#CFD75980', - '#C4CF4D80', - '#B8C74080', - '#ADBF3480', - '#A1B82880', - '#96B01B80', - '#8AA80F80', -]; - -export const PINK = [ - '#F27EE180', - '#EA72D180', - '#E265C280', - '#D959B280', - '#D14DA280', - '#C9409380', - '#C1348380', - '#B8287380', - '#B01B6480', - '#A80F5480', -]; - -export const DEFAULT = [ - // thick colors from each... - '#4067E580', - '#FE993380', - '#12A59480', - '#AB4ABA80', - '#D63C4280', - '#05A2C280', - '#E043A780', - '#00B05080', - '#7259D680', - '#99D52A80', - '#71717880', - '#FFD70080', - '#40E0D080', - '#8DA4EF80', - '#C25D0580', - '#067A6F80', - '#CF91D880', - '#EB909180', - '#0C779280', - '#E38EC380', - '#97CF9C80', - '#AA99EC80', - '#94BA2C80', - '#4B4B5180', - '#FFE76680', - '#33B2A680', -]; - -export const COLOR_MAP = new Map([ - ['blue', BLUE], - ['default', DEFAULT], - ['green', GREEN], - ['pink', PINK], - ['red', RED], - ['yellow', YELLOW], -]); diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index ab6f7fb01a2..af8915bbb08 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -158,12 +158,9 @@ export const generateGraphData = (props: GraphDataOptionsProps) => { serviceType, status, unit, - // widgetChartType, - // widgetColor, } = props; const legendRowsData: MetricsDisplayRow[] = []; // for now we will use this, but once we decide how to work with coloring, it should be dynamic - // const colors = COLOR_MAP.get(widgetColor ?? 'default')!; const dimension: { [timestamp: number]: { [label: string]: number } } = {}; const areas: AreaProps[] = []; const colors = Object.values(Alias.Chart.Categorical); From ea99d49a08df357d9f58e9c5c3d442c4667c16c1 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 16 Oct 2024 19:23:44 +0530 Subject: [PATCH 258/474] upcoming: [DI-20870] - Optimized code --- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 51 ++++++++++++++----- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index af8915bbb08..24b29f8a50b 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -145,11 +145,33 @@ interface DimensionNameProperties { resources: CloudPulseResources[]; } +interface GraphData { + /** + * array of area props to be shown on graph + */ + areas: AreaProps[]; + + /** + * plots to be shown of each dimension + */ + dimensions: DataSet[]; + + /** + * legends rows available for each dimension + */ + legendRowsData: MetricsDisplayRow[]; + + /** + * maximum possible rolled up unit for the data + */ + unit: string; +} + /** * * @returns parameters which will be necessary to populate graph & legends */ -export const generateGraphData = (props: GraphDataOptionsProps) => { +export const generateGraphData = (props: GraphDataOptionsProps): GraphData => { const { flags, label, @@ -194,15 +216,15 @@ export const generateGraphData = (props: GraphDataOptionsProps) => { }; const labelName = getLabelName(labelOptions); const data = seriesDataFormatter(transformedData.values, start, end); - const color = colors[index]?.Primary ?? Alias.Chart.Neutral; + const color = colors[index].Primary; areas.push({ color, dataKey: labelName, }); - data.forEach((d) => { - const timestamp = d[0]; - const value = d[1]; + data.forEach((dataPoint) => { + const timestamp = dataPoint[0]; + const value = dataPoint[1]; if (value !== null) { dimension[timestamp] = { ...dimension[timestamp], @@ -223,14 +245,19 @@ export const generateGraphData = (props: GraphDataOptionsProps) => { } const maxUnit = generateMaxUnit(legendRowsData, unit); - const dimensions: DataSet[] = Object.entries(dimension).map( - ([key, value]) => { - const rolledUpData: { [resource: string]: number } = {}; - Object.entries(value).forEach( - ([resource, data]) => - (rolledUpData[resource] = convertValueToUnit(data, maxUnit)) + const dimensions = Object.entries(dimension).map( + ([timestamp, resource]): DataSet => { + const rolledUpData = Object.entries(resource).reduce( + (previousValue, newValue) => { + return { + ...previousValue, + [newValue[0]]: convertValueToUnit(newValue[1], maxUnit), + }; + }, + {} ); - return { timestamp: Number(key), ...rolledUpData }; + + return { timestamp: Number(timestamp), ...rolledUpData }; } ); return { From 9eac33d96bf6ae4fb2425f8b31e318291446693c Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 30 Oct 2024 14:21:39 +0530 Subject: [PATCH 259/474] upcoming: [DI-21200] - Added connectNulls & color properties --- .../manager/src/components/AreaChart/AreaChart.tsx | 13 +++++++++++-- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 1 - .../features/CloudPulse/Widget/CloudPulseWidget.tsx | 5 ++++- .../Widget/components/CloudPulseLineGraph.tsx | 2 +- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/manager/src/components/AreaChart/AreaChart.tsx b/packages/manager/src/components/AreaChart/AreaChart.tsx index 755aad64e45..273374856ce 100644 --- a/packages/manager/src/components/AreaChart/AreaChart.tsx +++ b/packages/manager/src/components/AreaChart/AreaChart.tsx @@ -28,7 +28,9 @@ import { import type { TooltipProps } from 'recharts'; import type { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay'; -interface AreaProps { +export type ChartVariant = 'line' | 'area'; + +export interface AreaProps { /** * color for the area */ @@ -64,6 +66,11 @@ export interface AreaChartProps { */ ariaLabel: string; + /** + * connect nulls value between two data points + */ + connectNulls? :boolean; + /** * data to be displayed on the graph */ @@ -104,7 +111,7 @@ export interface AreaChartProps { * make chart appear as a line or area chart * @default area */ - variant?: 'area' | 'line'; + variant?: ChartVariant; /** * x-axis properties @@ -125,6 +132,7 @@ export const AreaChart = (props: AreaChartProps) => { unit, variant, xAxis, + connectNulls } = props; const theme = useTheme(); @@ -253,6 +261,7 @@ export const AreaChart = (props: AreaChartProps) => { )} {areas.map(({ color, dataKey }) => ( { metric: graphData.metric, values: transformData(graphData.values, unit), }; - // const color = colors[index]; const { end, start } = convertTimeDurationToStartAndEndTimeRange({ unit: 'min', value: 30, diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 7a2e16a3293..1c417d35ee5 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -29,9 +29,10 @@ import type { TimeGranularity, } from '@linode/api-v4'; import type { Widgets } from '@linode/api-v4'; -import type { AreaProps } from 'src/components/AreaChart/AreaChart'; +import type { AreaProps, ChartVariant } from 'src/components/AreaChart/AreaChart'; import type { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay'; import type { Metrics } from 'src/utilities/statMetrics'; +import { generateCurrentUnit } from '../Utils/unitConversion'; export interface CloudPulseWidgetProperties { /** @@ -239,6 +240,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { let legendRows: MetricsDisplayRow[] = []; let currentUnit = unit; let areas: AreaProps[] = []; + const variant : ChartVariant= widget.chart_type === 'line' ? 'line' : 'area'; if (!isLoading && metricsList) { const generatedData = generateGraphData({ flags, @@ -335,6 +337,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { timezone={timezone} unit={currentUnit} xAxis={{ tickFormat, tickGap: 60 }} + variant={variant} /> diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index a77b06ea01b..a7afc44a9c6 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -32,7 +32,7 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { ) : ( - + )} {rest.data.length === 0 && ( Date: Wed, 30 Oct 2024 14:32:23 +0530 Subject: [PATCH 260/474] upcoming: [DI-21200] - Added sort data based on timestamp --- .../src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index 4a09d69a715..f4de495f561 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -261,7 +261,7 @@ export const generateGraphData = (props: GraphDataOptionsProps): GraphData => { ); return { areas, - dimensions, + dimensions : dimensions.sort((dim1, dim2) => dim1.timestamp - dim2.timestamp), legendRowsData, unit: maxUnit, }; From 33606974d9dbdb72e49b5e8fe9b583f98574be14 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 30 Oct 2024 14:34:40 +0530 Subject: [PATCH 261/474] upcoming: [DI-21200] - Updated x-axis tick format --- .../manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 1c417d35ee5..5ec14c7fdad 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -266,7 +266,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { const tickFormat = duration.unit === 'min' || duration.unit === 'hr' ? 'hh:mm a' - : `LLL dd${widget.size === 12 ? ', hh:mm a' : ''}`; + : 'LLL dd, hh:mm a'; return ( From fd3431732cf5cb22a2436710eb848504ecd9b551 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 30 Oct 2024 16:30:08 +0530 Subject: [PATCH 262/474] upcoming: [DI-21200] - Updated PR comments --- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 15 ++------------- .../CloudPulse/Widget/CloudPulseWidget.tsx | 4 +--- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index f4de495f561..4c91f1ee8f1 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -94,16 +94,6 @@ interface GraphDataOptionsProps { * unit of the data */ unit: string; - - /** - * widget chart type - */ - widgetChartType: string; - - /** - * preferred color for the widget's graph - */ - widgetColor: string; } interface MetricRequestProps { @@ -182,7 +172,6 @@ export const generateGraphData = (props: GraphDataOptionsProps): GraphData => { unit, } = props; const legendRowsData: MetricsDisplayRow[] = []; - // for now we will use this, but once we decide how to work with coloring, it should be dynamic const dimension: { [timestamp: number]: { [label: string]: number } } = {}; const areas: AreaProps[] = []; const colors = Object.values(Alias.Chart.Categorical); @@ -258,10 +247,10 @@ export const generateGraphData = (props: GraphDataOptionsProps): GraphData => { return { timestamp: Number(timestamp), ...rolledUpData }; } - ); + ).sort((dimension1, dimension2) => dimension1.timestamp - dimension2.timestamp); return { areas, - dimensions : dimensions.sort((dim1, dim2) => dim1.timestamp - dim2.timestamp), + dimensions, legendRowsData, unit: maxUnit, }; diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 5ec14c7fdad..437a6326b39 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -249,9 +249,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { resources, serviceType, status, - unit, - widgetChartType: widget.chart_type, - widgetColor: widget.color, + unit }); data = generatedData.dimensions; From 22d778862f7678255a7cce0fc6a53b278be6b66e Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 30 Oct 2024 16:36:07 +0530 Subject: [PATCH 263/474] upcoming: [DI-21200] - Hide legends if not data present --- .../manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 437a6326b39..eb55349e3c7 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -331,7 +331,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { height={480} legendRows={legendRows} loading={isLoading || metricsApiCallError === jweTokenExpiryError} // keep loading until we fetch the refresh token - showLegend + showLegend={data.length !== 0} timezone={timezone} unit={currentUnit} xAxis={{ tickFormat, tickGap: 60 }} From 1c12a3fe224c6ff40f0945829d5d6932b42c536e Mon Sep 17 00:00:00 2001 From: agorthi Date: Wed, 30 Oct 2024 18:23:31 +0530 Subject: [PATCH 264/474] upcoming:[DI-21483]- Added code review comments with message update --- .../cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts index e81e7df1bf1..f80021f952c 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts @@ -185,7 +185,7 @@ describe('DbasS API Error Handling', () => { expect(text).to.equal('Failed to fetch the services.'); }); }); - it('should return error response when fetching Token API Request', () => { + it('should return error response when fetching token api request', () => { cy.intercept('POST', apiMatcher(`/monitor/services/${serviceType}/token`), { statusCode: 400, body: { @@ -332,7 +332,7 @@ describe('DbasS API Error Handling', () => { }); }); - it('should return error response when fetching DB Cluster API Request', () => { + it('should return error response when fetching db cluster api request', () => { cy.intercept('GET', apiMatcher(`databases/instances*`), { statusCode: 400, body: { From d579607aa4ed9f619e8235516fc05e32f6915a5a Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 4 Nov 2024 10:38:39 +0530 Subject: [PATCH 265/474] DI-21706 - Use alpha env going forward for testing --- packages/api-v4/src/cloudpulse/dashboards.ts | 14 +++----------- packages/api-v4/src/cloudpulse/services.ts | 20 ++++---------------- 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/packages/api-v4/src/cloudpulse/dashboards.ts b/packages/api-v4/src/cloudpulse/dashboards.ts index 08b2ed268e7..2166e5515e4 100644 --- a/packages/api-v4/src/cloudpulse/dashboards.ts +++ b/packages/api-v4/src/cloudpulse/dashboards.ts @@ -1,9 +1,7 @@ import { ResourcePage } from 'src/types'; import Request, { setHeaders, setMethod, setURL } from '../request'; import { Dashboard } from './types'; -// import { BETA_API_ROOT as API_ROOT } from 'src/constants'; - -const API_ROOT = 'https://blr-lhvm1i.bangalore.corp.akamai.com:9000/v4beta'; +import { BETA_API_ROOT as API_ROOT } from 'src/constants'; // Returns the list of all the dashboards available export const getDashboards = (serviceType: string) => @@ -13,17 +11,11 @@ export const getDashboards = (serviceType: string) => serviceType )}/dashboards` ), - setMethod('GET'), - setHeaders({ - Authorization: 'Bearer vagrant' - }) + setMethod('GET') ); export const getDashboardById = (dashboardId: number) => Request( setURL(`${API_ROOT}/monitor/dashboards/${encodeURIComponent(dashboardId)}`), - setMethod('GET'), - setHeaders({ - Authorization: 'Bearer vagrant' - }) + setMethod('GET') ); diff --git a/packages/api-v4/src/cloudpulse/services.ts b/packages/api-v4/src/cloudpulse/services.ts index 8258d048052..954020b9590 100644 --- a/packages/api-v4/src/cloudpulse/services.ts +++ b/packages/api-v4/src/cloudpulse/services.ts @@ -1,4 +1,4 @@ -// import { BETA_API_ROOT as API_ROOT } from 'src/constants'; +import { BETA_API_ROOT as API_ROOT } from 'src/constants'; import Request, { setData, setHeaders, setMethod, setURL } from '../request'; import { JWEToken, @@ -8,9 +8,6 @@ import { } from './types'; import { ResourcePage as Page } from 'src/types'; - -const API_ROOT = 'https://blr-lhvm1i.bangalore.corp.akamai.com:9000/v4beta'; - export const getMetricDefinitionsByServiceType = (serviceType: string) => { return Request>( setURL( @@ -18,10 +15,7 @@ export const getMetricDefinitionsByServiceType = (serviceType: string) => { serviceType )}/metric-definitions` ), - setMethod('GET'), - setHeaders({ - Authorization: 'Bearer vagrant' - }) + setMethod('GET') ); }; @@ -31,18 +25,12 @@ export const getJWEToken = (data: JWETokenPayLoad, serviceType: string) => `${API_ROOT}/monitor/services/${encodeURIComponent(serviceType)}/token` ), setMethod('POST'), - setData(data), - setHeaders({ - Authorization: 'Bearer mlishuser' - }) + setData(data) ); // Returns the list of service types available export const getCloudPulseServiceTypes = () => Request( setURL(`${API_ROOT}/monitor/services`), - setMethod('GET'), - setHeaders({ - Authorization: 'Bearer vagrant' - }) + setMethod('GET') ); From 666c994e8add42722f4a3760cfcbeb4b6b964c25 Mon Sep 17 00:00:00 2001 From: agorthi Date: Mon, 4 Nov 2024 10:40:15 +0530 Subject: [PATCH 266/474] upcoming:[DI-21483]- Added code review comments with message update --- .../cloudpulse/cloudpulse-validation.spec.ts | 64 ++++++------------- 1 file changed, 18 insertions(+), 46 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts index f80021f952c..514b8de01bb 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts @@ -12,17 +12,12 @@ import { import { ui } from 'support/ui'; import { widgetDetails } from 'support/constants/widgets'; import { - accountFactory, dashboardFactory, dashboardMetricFactory, databaseFactory, - kubeLinodeFactory, - linodeFactory, regionFactory, widgetFactory, } from 'src/factories'; -import { mockGetAccount } from 'support/intercepts/account'; -import { mockGetLinodes } from 'support/intercepts/linodes'; import { mockGetUserPreferences } from 'support/intercepts/profile'; import { mockGetRegions } from 'support/intercepts/regions'; import { extendRegion } from 'support/util/regions'; @@ -72,12 +67,6 @@ const metricDefinitions = { ), }; -const mockLinode = linodeFactory.build({ - label: clusterName, - id: kubeLinodeFactory.build().instance_id ?? undefined, -}); - -const mockAccount = accountFactory.build(); const mockRegion = extendRegion( regionFactory.build({ capabilities: ['Linodes'], @@ -101,8 +90,6 @@ describe('DbasS API Error Handling', () => { mockAppendFeatureFlags({ aclp: { beta: true, enabled: true }, }); - mockGetAccount(mockAccount); - mockGetLinodes([mockLinode]); mockGetCloudPulseMetricDefinitions(serviceType, metricDefinitions); mockGetCloudPulseDashboards(serviceType, [dashboard]).as('fetchDashboard'); mockGetCloudPulseServices(serviceType).as('fetchServices'); @@ -117,10 +104,7 @@ describe('DbasS API Error Handling', () => { cy.intercept( 'GET', apiMatcher(`/monitor/services/${serviceType}/metric-definitions`), - { - statusCode: 400, - body: { errors: [{ reason: 'Bad Request' }] }, - } + { statusCode: 500, body: { errors: [{ reason: 'Bad Request' }] }, } ).as('getMetricDefinitions'); cy.visitWithLogin('monitor/cloudpulse'); @@ -151,7 +135,6 @@ describe('DbasS API Error Handling', () => { .should('be.visible') .type(`${clusterName}{enter}`) .click(); - cy.findByText(clusterName).should('be.visible'); // Select a Node from the autocomplete input. ui.autocomplete @@ -168,16 +151,12 @@ describe('DbasS API Error Handling', () => { it('should return error response when fetching services API request', () => { cy.intercept('GET', apiMatcher(`/monitor/services`), { - statusCode: 400, + statusCode: 500, body: { - errors: [{ reason: 'Bad Request' }], - }, + errors: [{ reason: 'Bad Request' }],}, }).as('fetchServices'); cy.visitWithLogin('monitor/cloudpulse'); - // Wait for the API call to complete and capture the response. - cy.wait('@fetchServices'); - cy.get('[data-qa-textfield-error-text="Dashboard"]') .should('be.visible') .invoke('text') @@ -185,13 +164,12 @@ describe('DbasS API Error Handling', () => { expect(text).to.equal('Failed to fetch the services.'); }); }); - it('should return error response when fetching token api request', () => { + it('should return error response when fetching token API request', () => { cy.intercept('POST', apiMatcher(`/monitor/services/${serviceType}/token`), { - statusCode: 400, + statusCode: 500, body: { - errors: [{ reason: 'Bad Request' }], - }, - }).as('fetchToken'); + errors: [{ reason: 'Bad Request' }], }, + }); cy.visitWithLogin('monitor/cloudpulse'); // Wait for both the fetch services and fetch dashboard API calls to complete. @@ -220,7 +198,6 @@ describe('DbasS API Error Handling', () => { .should('be.visible') .type(`${clusterName}{enter}`) .click(); - cy.findByText(clusterName).should('be.visible'); // Select a Node from the autocomplete input. ui.autocomplete @@ -239,10 +216,8 @@ describe('DbasS API Error Handling', () => { 'GET', apiMatcher(`/monitor/services/${serviceType}/dashboards`), { - statusCode: 400, - body: { - errors: [{ reason: 'Bad Request' }], - }, + statusCode: 500, + body: { errors: [{ reason: 'Bad Request' }],}, } ).as('fetchDashboard'); @@ -261,9 +236,9 @@ describe('DbasS API Error Handling', () => { it('should return error message when the Dashboard details API request fails', () => { cy.intercept('GET', apiMatcher(`/monitor/dashboards/${id}`), { - statusCode: 400, + statusCode: 500, body: { errors: [{ reason: 'Bad Request' }] }, - }).as('fetchDashboardById'); + }); cy.visitWithLogin('monitor/cloudpulse'); @@ -290,7 +265,6 @@ describe('DbasS API Error Handling', () => { .should('be.visible') .type(`${clusterName}{enter}`) .click(); - cy.findByText(clusterName).should('be.visible'); // Select a node type from the autocomplete input. Verify visibility before interaction. ui.autocomplete @@ -308,9 +282,9 @@ describe('DbasS API Error Handling', () => { it(`should return error message when the Regions API request fails`, () => { cy.intercept('GET', apiMatcher(`regions*`), { - statusCode: 400, // Use the status code defined in the test + statusCode: 500, body: { errors: [{ reason: 'Bad Request' }] }, - }).as('fetchRegion'); + }); cy.visitWithLogin('monitor/cloudpulse'); @@ -324,7 +298,7 @@ describe('DbasS API Error Handling', () => { .type(`${dashboardName}{enter}`) .should('be.visible'); - cy.get('[data-qa-textfield-error-text="Region"]') // Select the error message element + cy.get('[data-qa-textfield-error-text="Region"]') .should('be.visible') .invoke('text') .then((text) => { @@ -332,13 +306,11 @@ describe('DbasS API Error Handling', () => { }); }); - it('should return error response when fetching db cluster api request', () => { + it('should return error response when fetching db cluster API request', () => { cy.intercept('GET', apiMatcher(`databases/instances*`), { - statusCode: 400, - body: { - errors: [{ reason: 'Bad Request' }], - }, - }).as('fetchCluster'); + statusCode: 500, + body: {errors: [{ reason: 'Bad Request' }],}, + }); cy.visitWithLogin('monitor/cloudpulse'); From db1259ffebfb27e29f4f9dcaaa8cb87fa39c5763 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 4 Nov 2024 10:45:31 +0530 Subject: [PATCH 267/474] DI-21706 - remove unused import and eslint issues fix --- packages/api-v4/src/cloudpulse/dashboards.ts | 2 +- packages/api-v4/src/cloudpulse/services.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/api-v4/src/cloudpulse/dashboards.ts b/packages/api-v4/src/cloudpulse/dashboards.ts index 2166e5515e4..c8802747e52 100644 --- a/packages/api-v4/src/cloudpulse/dashboards.ts +++ b/packages/api-v4/src/cloudpulse/dashboards.ts @@ -1,5 +1,5 @@ import { ResourcePage } from 'src/types'; -import Request, { setHeaders, setMethod, setURL } from '../request'; +import Request, { setMethod, setURL } from '../request'; import { Dashboard } from './types'; import { BETA_API_ROOT as API_ROOT } from 'src/constants'; diff --git a/packages/api-v4/src/cloudpulse/services.ts b/packages/api-v4/src/cloudpulse/services.ts index 954020b9590..5eb06faa0e5 100644 --- a/packages/api-v4/src/cloudpulse/services.ts +++ b/packages/api-v4/src/cloudpulse/services.ts @@ -1,5 +1,5 @@ import { BETA_API_ROOT as API_ROOT } from 'src/constants'; -import Request, { setData, setHeaders, setMethod, setURL } from '../request'; +import Request, { setData, setMethod, setURL } from '../request'; import { JWEToken, JWETokenPayLoad, From cdcda75feb1937dd81778e261b36071b76a14ccf Mon Sep 17 00:00:00 2001 From: agorthi Date: Mon, 4 Nov 2024 11:09:14 +0530 Subject: [PATCH 268/474] upcoming:[DI-21483]- Added code review comments with message update --- .../cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts index 514b8de01bb..a07bb680161 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts @@ -85,7 +85,7 @@ const databaseMock: Database = databaseFactory.build({ engine: 'mysql', }); -describe('DbasS API Error Handling', () => { +describe('Tests for API error handling', () => { beforeEach(() => { mockAppendFeatureFlags({ aclp: { beta: true, enabled: true }, From c749f4253e02cc04cecd14f6f879a5356fe65238 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Mon, 4 Nov 2024 12:02:19 +0530 Subject: [PATCH 269/474] DI-21706 - remove unused import and eslint issues fix --- packages/manager/src/features/Databases/DatabaseDetail/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/manager/src/features/Databases/DatabaseDetail/index.tsx b/packages/manager/src/features/Databases/DatabaseDetail/index.tsx index f43e743e032..ee4f49b9ae7 100644 --- a/packages/manager/src/features/Databases/DatabaseDetail/index.tsx +++ b/packages/manager/src/features/Databases/DatabaseDetail/index.tsx @@ -12,7 +12,6 @@ import { SafeTabPanel } from 'src/components/Tabs/SafeTabPanel'; import { TabLinkList } from 'src/components/Tabs/TabLinkList'; import { TabPanels } from 'src/components/Tabs/TabPanels'; import { Tabs } from 'src/components/Tabs/Tabs'; -import { CloudPulseDashboardWithFilters } from 'src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters'; import DatabaseLogo from 'src/features/Databases/DatabaseLanding/DatabaseLogo'; import { useEditableLabelState } from 'src/hooks/useEditableLabelState'; import { useFlags } from 'src/hooks/useFlags'; From 2d051e0331c69e728002638a0760aa0a69ef0ab3 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Mon, 4 Nov 2024 12:52:00 +0530 Subject: [PATCH 270/474] upcoming: [DI-21200] - Updated legends height --- .../CloudPulse/Widget/components/CloudPulseLineGraph.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index a7afc44a9c6..4f23dd4bbaa 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -32,7 +32,12 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { ) : ( - + )} {rest.data.length === 0 && ( Date: Mon, 4 Nov 2024 13:16:31 +0530 Subject: [PATCH 271/474] upcoming: [DI-21200] - ESLint issues fixed --- .../src/components/AreaChart/AreaChart.tsx | 6 +-- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 39 +++++++++++-------- .../CloudPulse/Widget/CloudPulseWidget.tsx | 13 ++++--- 3 files changed, 34 insertions(+), 24 deletions(-) diff --git a/packages/manager/src/components/AreaChart/AreaChart.tsx b/packages/manager/src/components/AreaChart/AreaChart.tsx index d6df449e4e9..44295dc3ca1 100644 --- a/packages/manager/src/components/AreaChart/AreaChart.tsx +++ b/packages/manager/src/components/AreaChart/AreaChart.tsx @@ -28,7 +28,7 @@ import { import type { TooltipProps } from 'recharts'; import type { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay'; -export type ChartVariant = 'line' | 'area'; +export type ChartVariant = 'area' | 'line'; export interface AreaProps { /** @@ -69,7 +69,7 @@ export interface AreaChartProps { /** * connect nulls value between two data points */ - connectNulls? :boolean; + connectNulls?: boolean; /** * data to be displayed on the graph @@ -138,6 +138,7 @@ export const AreaChart = (props: AreaChartProps) => { const { areas, ariaLabel, + connectNulls, data, fillOpacity, height = '100%', @@ -150,7 +151,6 @@ export const AreaChart = (props: AreaChartProps) => { variant, width = '100%', xAxis, - connectNulls } = props; const theme = useTheme(); diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index 4c91f1ee8f1..58347c81369 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -182,6 +182,10 @@ export const generateGraphData = (props: GraphDataOptionsProps): GraphData => { return; } + if (label.includes('CPU') && index >= 1) { + return; + } + const transformedData = { metric: graphData.metric, values: transformData(graphData.values, unit), @@ -233,21 +237,25 @@ export const generateGraphData = (props: GraphDataOptionsProps): GraphData => { } const maxUnit = generateMaxUnit(legendRowsData, unit); - const dimensions = Object.entries(dimension).map( - ([timestamp, resource]): DataSet => { - const rolledUpData = Object.entries(resource).reduce( - (previousValue, newValue) => { - return { - ...previousValue, - [newValue[0]]: convertValueToUnit(newValue[1], maxUnit), - }; - }, - {} - ); - - return { timestamp: Number(timestamp), ...rolledUpData }; - } - ).sort((dimension1, dimension2) => dimension1.timestamp - dimension2.timestamp); + const dimensions = Object.entries(dimension) + .map( + ([timestamp, resource]): DataSet => { + const rolledUpData = Object.entries(resource).reduce( + (previousValue, newValue) => { + return { + ...previousValue, + [newValue[0]]: convertValueToUnit(newValue[1], maxUnit), + }; + }, + {} + ); + + return { timestamp: Number(timestamp), ...rolledUpData }; + } + ) + .sort( + (dimension1, dimension2) => dimension1.timestamp - dimension2.timestamp + ); return { areas, dimensions, @@ -351,7 +359,6 @@ export const mapResourceIdToName = ( return resourcesObj?.label ?? id ?? ''; }; - /** * * @param theme mui theme diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index eb55349e3c7..2d2b1ba19cc 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -13,6 +13,7 @@ import { } from '../Utils/CloudPulseWidgetUtils'; import { AGGREGATE_FUNCTION, SIZE, TIME_GRANULARITY } from '../Utils/constants'; import { constructAdditionalRequestFilters } from '../Utils/FilterBuilder'; +import { generateCurrentUnit } from '../Utils/unitConversion'; import { useAclpPreference } from '../Utils/UserPreference'; import { convertStringToCamelCasesWithSpaces } from '../Utils/utils'; import { CloudPulseAggregateFunction } from './components/CloudPulseAggregateFunction'; @@ -29,10 +30,12 @@ import type { TimeGranularity, } from '@linode/api-v4'; import type { Widgets } from '@linode/api-v4'; -import type { AreaProps, ChartVariant } from 'src/components/AreaChart/AreaChart'; +import type { + AreaProps, + ChartVariant, +} from 'src/components/AreaChart/AreaChart'; import type { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay'; import type { Metrics } from 'src/utilities/statMetrics'; -import { generateCurrentUnit } from '../Utils/unitConversion'; export interface CloudPulseWidgetProperties { /** @@ -240,7 +243,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { let legendRows: MetricsDisplayRow[] = []; let currentUnit = unit; let areas: AreaProps[] = []; - const variant : ChartVariant= widget.chart_type === 'line' ? 'line' : 'area'; + const variant: ChartVariant = widget.chart_type === 'line' ? 'line' : 'area'; if (!isLoading && metricsList) { const generatedData = generateGraphData({ flags, @@ -249,7 +252,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { resources, serviceType, status, - unit + unit, }); data = generatedData.dimensions; @@ -334,8 +337,8 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { showLegend={data.length !== 0} timezone={timezone} unit={currentUnit} - xAxis={{ tickFormat, tickGap: 60 }} variant={variant} + xAxis={{ tickFormat, tickGap: 60 }} /> From 7be47af7febb6d2e5ac35899bfd61ea7acf503da Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 16 Oct 2024 17:38:30 +0530 Subject: [PATCH 272/474] upcoming: [DI-20870] - Migrated chartjs to recharts for ACLP graphs --- .../src/components/AreaChart/AreaChart.tsx | 2 +- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 101 ++++++++++-------- .../CloudPulse/Widget/CloudPulseWidget.tsx | 38 ++++--- .../Widget/components/CloudPulseLineGraph.tsx | 40 ++----- 4 files changed, 81 insertions(+), 100 deletions(-) diff --git a/packages/manager/src/components/AreaChart/AreaChart.tsx b/packages/manager/src/components/AreaChart/AreaChart.tsx index ea6dd7e08b5..0180f0734b0 100644 --- a/packages/manager/src/components/AreaChart/AreaChart.tsx +++ b/packages/manager/src/components/AreaChart/AreaChart.tsx @@ -53,7 +53,7 @@ interface XAxisProps { tickGap: number; } -interface AreaChartProps { +export interface AreaChartProps { /** * list of areas to be displayed */ diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index 7a4e2a5b671..2d02687d849 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -1,8 +1,11 @@ -import { isToday } from 'src/utilities/isToday'; +import { Alias } from '@linode/design-language-system'; +import { styled } from '@mui/material'; + +import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; import { getMetrics } from 'src/utilities/statMetrics'; -import { COLOR_MAP, DEFAULT } from './CloudPulseWidgetColorPalette'; import { + convertValueToUnit, formatToolTip, generateUnitByBaseUnit, transformData, @@ -13,16 +16,17 @@ import { } from './utils'; import type { CloudPulseResources } from '../shared/CloudPulseResourcesSelect'; -import type { LegendRow } from '../Widget/CloudPulseWidget'; import type { CloudPulseMetricsList, CloudPulseMetricsRequest, CloudPulseMetricsResponse, + DataSet, TimeDuration, Widgets, } from '@linode/api-v4'; +import type { AreaProps } from 'src/components/AreaChart/AreaChart'; +import type { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay'; import type { Theme } from '@mui/material'; -import type { DataSet } from 'src/components/LineGraph/LineGraph'; import type { CloudPulseResourceTypeMapFlag, FlagSet } from 'src/featureFlags'; interface LabelNameOptionsProps { @@ -57,7 +61,7 @@ interface LabelNameOptionsProps { unit: string; } -interface graphDataOptionsProps { +interface GraphDataOptionsProps { /** * flags associated with metricsList */ @@ -147,7 +151,7 @@ interface DimensionNameProperties { * * @returns parameters which will be necessary to populate graph & legends */ -export const generateGraphData = (props: graphDataOptionsProps) => { +export const generateGraphData = (props: GraphDataOptionsProps) => { const { flags, label, @@ -156,28 +160,27 @@ export const generateGraphData = (props: graphDataOptionsProps) => { serviceType, status, unit, - widgetChartType, - widgetColor, + // widgetChartType, + // widgetColor, } = props; - - const dimensions: DataSet[] = []; - const legendRowsData: LegendRow[] = []; - - // If the color is not found in the map, fallback to default color theme - const colors = COLOR_MAP.get(widgetColor) ?? DEFAULT; - let today = false; - + const legendRowsData: MetricsDisplayRow[] = []; + // for now we will use this, but once we decide how to work with coloring, it should be dynamic + // const colors = COLOR_MAP.get(widgetColor ?? 'default')!; + const dimension: { [timestamp: number]: { [label: string]: number } } = {}; + const areas: AreaProps[] = []; + const colors = Object.values(Alias.Chart.Categorical); if (status === 'success') { metricsList?.data?.result?.forEach( (graphData: CloudPulseMetricsList, index) => { if (!graphData) { return; } + const transformedData = { metric: graphData.metric, values: transformData(graphData.values, unit), }; - const color = colors[index]; + // const color = colors[index]; const { end, start } = convertTimeDurationToStartAndEndTimeRange({ unit: 'min', value: 30, @@ -194,33 +197,52 @@ export const generateGraphData = (props: graphDataOptionsProps) => { serviceType, unit, }; - - const dimension = { - backgroundColor: color, - borderColor: color, - data: seriesDataFormatter(transformedData.values, start, end), - fill: widgetChartType === 'area', - label: getLabelName(labelOptions), - }; + const labelName = getLabelName(labelOptions); + const data = seriesDataFormatter(transformedData.values, start, end); + const color = colors[index]?.Primary ?? Alias.Chart.Neutral; + areas.push({ + color, + dataKey: labelName, + }); + + data.forEach((d) => { + const timestamp = d[0]; + const value = d[1]; + if (value !== null) { + dimension[timestamp] = { + ...dimension[timestamp], + [labelName]: value, + }; + } + }); // construct a legend row with the dimension - const legendRow = { - data: getMetrics(dimension.data as number[][]), + const legendRow: MetricsDisplayRow = { + data: getMetrics(data as number[][]), format: (value: number) => formatToolTip(value, unit), legendColor: color, - legendTitle: dimension.label, + legendTitle: labelName, }; legendRowsData.push(legendRow); - dimensions.push(dimension); - today ||= isToday(start, end); } ); } + const maxUnit = generateMaxUnit(legendRowsData, unit); + const dimensions: DataSet[] = Object.entries(dimension).map( + ([key, value]) => { + const rolledUpData: { [resource: string]: number } = {}; + Object.entries(value).forEach( + ([resource, data]) => + (rolledUpData[resource] = convertValueToUnit(data, maxUnit)) + ); + return { timestamp: Number(key), ...rolledUpData }; + } + ); return { + areas, dimensions, legendRowsData, - today, - unit: generateMaxUnit(legendRowsData, unit), + unit: maxUnit, }; }; @@ -230,7 +252,7 @@ export const generateGraphData = (props: graphDataOptionsProps) => { * @param unit base unit of the values * @returns maximum possible rolled up unit based on the unit */ -const generateMaxUnit = (legendRowsData: LegendRow[], unit: string) => { +const generateMaxUnit = (legendRowsData: MetricsDisplayRow[], unit: string) => { const maxValue = Math.max( 0, ...legendRowsData?.map((row) => row?.data.max ?? 0) @@ -319,19 +341,6 @@ export const mapResourceIdToName = ( return resourcesObj?.label ?? id ?? ''; }; -/** - * - * @param data data set to be checked for empty - * @returns true if data is not empty or contains all the null values otherwise false - */ -export const isDataEmpty = (data: DataSet[]): boolean => { - return data.every( - (thisSeries) => - thisSeries.data.length === 0 || - // If we've padded the data, every y value will be null - thisSeries.data.every((thisPoint) => thisPoint[1] === null) - ); -}; /** * diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 44d5dbcdb39..7a2e16a3293 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -13,11 +13,6 @@ import { } from '../Utils/CloudPulseWidgetUtils'; import { AGGREGATE_FUNCTION, SIZE, TIME_GRANULARITY } from '../Utils/constants'; import { constructAdditionalRequestFilters } from '../Utils/FilterBuilder'; -import { - convertValueToUnit, - formatToolTip, - generateCurrentUnit, -} from '../Utils/unitConversion'; import { useAclpPreference } from '../Utils/UserPreference'; import { convertStringToCamelCasesWithSpaces } from '../Utils/utils'; import { CloudPulseAggregateFunction } from './components/CloudPulseAggregateFunction'; @@ -29,11 +24,13 @@ import type { FilterValueType } from '../Dashboard/CloudPulseDashboardLanding'; import type { CloudPulseResources } from '../shared/CloudPulseResourcesSelect'; import type { AvailableMetrics, + DataSet, TimeDuration, TimeGranularity, } from '@linode/api-v4'; import type { Widgets } from '@linode/api-v4'; -import type { DataSet } from 'src/components/LineGraph/LineGraph'; +import type { AreaProps } from 'src/components/AreaChart/AreaChart'; +import type { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay'; import type { Metrics } from 'src/utilities/statMetrics'; export interface CloudPulseWidgetProperties { @@ -237,11 +234,11 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { url: flags.aclpReadEndpoint!, } ); - let data: DataSet[] = []; - let legendRows: LegendRow[] = []; - let today: boolean = false; + let legendRows: MetricsDisplayRow[] = []; + let currentUnit = unit; + let areas: AreaProps[] = []; if (!isLoading && metricsList) { const generatedData = generateGraphData({ flags, @@ -257,12 +254,17 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { data = generatedData.dimensions; legendRows = generatedData.legendRowsData; - today = generatedData.today; scaledWidgetUnit.current = generatedData.unit; // here state doesn't matter, as this is always the latest re-render + currentUnit = generatedData.unit; + areas = generatedData.areas; } const metricsApiCallError = error?.[0]?.reason; + const tickFormat = + duration.unit === 'min' || duration.unit === 'hr' + ? 'hh:mm a' + : `LLL dd${widget.size === 12 ? ', hh:mm a' : ''}`; return ( @@ -323,20 +325,16 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { ? metricsApiCallError ?? 'Error while rendering graph' : undefined } - formatData={(data: number) => - convertValueToUnit(data, scaledWidgetUnit.current) - } - legendRows={ - legendRows && legendRows.length > 0 ? legendRows : undefined - } + areas={areas} ariaLabel={ariaLabel ? ariaLabel : ''} data={data} - formatTooltip={(value: number) => formatToolTip(value, unit)} - gridSize={widget.size} + height={480} + legendRows={legendRows} loading={isLoading || metricsApiCallError === jweTokenExpiryError} // keep loading until we fetch the refresh token - showToday={today} + showLegend timezone={timezone} - title={widget.label} + unit={currentUnit} + xAxis={{ tickFormat, tickGap: 60 }} /> diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index 5c3ce2fd3fd..a77b06ea01b 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -1,29 +1,19 @@ -import { Box, Typography, useTheme } from '@mui/material'; +import { Box, Typography } from '@mui/material'; import * as React from 'react'; +import { AreaChart } from 'src/components/AreaChart/AreaChart'; import { CircleProgress } from 'src/components/CircleProgress'; import { ErrorState } from 'src/components/ErrorState/ErrorState'; -import { LineGraph } from 'src/components/LineGraph/LineGraph'; -import { isDataEmpty } from '../../Utils/CloudPulseWidgetUtils'; +import type { AreaChartProps } from 'src/components/AreaChart/AreaChart'; -import type { LegendRow } from '../CloudPulseWidget'; -import type { LineGraphProps } from 'src/components/LineGraph/LineGraph'; - -export interface CloudPulseLineGraph extends LineGraphProps { - ariaLabel?: string; +export interface CloudPulseLineGraph extends AreaChartProps { error?: string; - gridSize: number; - legendRows?: LegendRow[]; loading?: boolean; - subtitle?: string; - title: string; } export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { - const { ariaLabel, data, error, legendRows, loading, ...rest } = props; - - const theme = useTheme(); + const { error, loading, ...rest } = props; if (loading) { return ; @@ -42,25 +32,9 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { ) : ( - + )} - {isDataEmpty(data) && ( + {rest.data.length === 0 && ( Date: Wed, 16 Oct 2024 17:54:27 +0530 Subject: [PATCH 273/474] upcoming: [DI-20870] - Removed unused imports --- .../src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index 2d02687d849..ab6f7fb01a2 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -1,7 +1,5 @@ import { Alias } from '@linode/design-language-system'; -import { styled } from '@mui/material'; -import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; import { getMetrics } from 'src/utilities/statMetrics'; import { @@ -24,9 +22,9 @@ import type { TimeDuration, Widgets, } from '@linode/api-v4'; +import type { Theme } from '@mui/material'; import type { AreaProps } from 'src/components/AreaChart/AreaChart'; import type { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay'; -import type { Theme } from '@mui/material'; import type { CloudPulseResourceTypeMapFlag, FlagSet } from 'src/featureFlags'; interface LabelNameOptionsProps { From aa9931a2046c06cb4c5fbd1e5df050e07cb7d5db Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 16 Oct 2024 18:13:17 +0530 Subject: [PATCH 274/474] upcoming: [DI-20870] - Removed CloudPulseWidgetColorPalette file --- .../Utils/CloudPulseWidgetColorPalette.ts | 111 ------------------ .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 3 - 2 files changed, 114 deletions(-) delete mode 100644 packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetColorPalette.ts diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetColorPalette.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetColorPalette.ts deleted file mode 100644 index 3b9325521d0..00000000000 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetColorPalette.ts +++ /dev/null @@ -1,111 +0,0 @@ -export const RED = [ - '#ee2c2c80', - '#ff633d80', - '#F27E7E80', - '#EA7C7280', - '#E2796580', - '#D9775980', - '#D1744D80', - '#C9724080', - '#C16F3480', - '3B86D2880', - '#B06A1B80', - '#A8680F80', -]; - -export const GREEN = [ - '#10a21d80', - '#31ce3e80', - '#d9b0d980', - '#ffdc7d80', - '#7EF29D80', - '#72E39E80', - '#65D3A080', - '#59C4A180', - '#4DB5A280', - '#40A5A480', - '#3496A580', - '#2887A680', - '#1B77A880', - '#0F68A980', -]; - -export const BLUE = [ - '#3683dc80', - '#0F91A880', - '#1B9CAC80', - '#28A7AF80', - '#34B1B380', - '#40BCB680', - '#4DC7BA80', - '#59D2BD80', - '#65DCC180', - '#72E7C480', - '#7EF2C880', -]; - -export const YELLOW = [ - '#ffb34d80', - '#F2EE7E80', - '#E6E67280', - '#DBDE6580', - '#CFD75980', - '#C4CF4D80', - '#B8C74080', - '#ADBF3480', - '#A1B82880', - '#96B01B80', - '#8AA80F80', -]; - -export const PINK = [ - '#F27EE180', - '#EA72D180', - '#E265C280', - '#D959B280', - '#D14DA280', - '#C9409380', - '#C1348380', - '#B8287380', - '#B01B6480', - '#A80F5480', -]; - -export const DEFAULT = [ - // thick colors from each... - '#4067E580', - '#FE993380', - '#12A59480', - '#AB4ABA80', - '#D63C4280', - '#05A2C280', - '#E043A780', - '#00B05080', - '#7259D680', - '#99D52A80', - '#71717880', - '#FFD70080', - '#40E0D080', - '#8DA4EF80', - '#C25D0580', - '#067A6F80', - '#CF91D880', - '#EB909180', - '#0C779280', - '#E38EC380', - '#97CF9C80', - '#AA99EC80', - '#94BA2C80', - '#4B4B5180', - '#FFE76680', - '#33B2A680', -]; - -export const COLOR_MAP = new Map([ - ['blue', BLUE], - ['default', DEFAULT], - ['green', GREEN], - ['pink', PINK], - ['red', RED], - ['yellow', YELLOW], -]); diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index ab6f7fb01a2..af8915bbb08 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -158,12 +158,9 @@ export const generateGraphData = (props: GraphDataOptionsProps) => { serviceType, status, unit, - // widgetChartType, - // widgetColor, } = props; const legendRowsData: MetricsDisplayRow[] = []; // for now we will use this, but once we decide how to work with coloring, it should be dynamic - // const colors = COLOR_MAP.get(widgetColor ?? 'default')!; const dimension: { [timestamp: number]: { [label: string]: number } } = {}; const areas: AreaProps[] = []; const colors = Object.values(Alias.Chart.Categorical); From 48fb7bba642c009390e3ea8921ee6b672a9e92e1 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 16 Oct 2024 19:23:44 +0530 Subject: [PATCH 275/474] upcoming: [DI-20870] - Optimized code --- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 51 ++++++++++++++----- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index af8915bbb08..24b29f8a50b 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -145,11 +145,33 @@ interface DimensionNameProperties { resources: CloudPulseResources[]; } +interface GraphData { + /** + * array of area props to be shown on graph + */ + areas: AreaProps[]; + + /** + * plots to be shown of each dimension + */ + dimensions: DataSet[]; + + /** + * legends rows available for each dimension + */ + legendRowsData: MetricsDisplayRow[]; + + /** + * maximum possible rolled up unit for the data + */ + unit: string; +} + /** * * @returns parameters which will be necessary to populate graph & legends */ -export const generateGraphData = (props: GraphDataOptionsProps) => { +export const generateGraphData = (props: GraphDataOptionsProps): GraphData => { const { flags, label, @@ -194,15 +216,15 @@ export const generateGraphData = (props: GraphDataOptionsProps) => { }; const labelName = getLabelName(labelOptions); const data = seriesDataFormatter(transformedData.values, start, end); - const color = colors[index]?.Primary ?? Alias.Chart.Neutral; + const color = colors[index].Primary; areas.push({ color, dataKey: labelName, }); - data.forEach((d) => { - const timestamp = d[0]; - const value = d[1]; + data.forEach((dataPoint) => { + const timestamp = dataPoint[0]; + const value = dataPoint[1]; if (value !== null) { dimension[timestamp] = { ...dimension[timestamp], @@ -223,14 +245,19 @@ export const generateGraphData = (props: GraphDataOptionsProps) => { } const maxUnit = generateMaxUnit(legendRowsData, unit); - const dimensions: DataSet[] = Object.entries(dimension).map( - ([key, value]) => { - const rolledUpData: { [resource: string]: number } = {}; - Object.entries(value).forEach( - ([resource, data]) => - (rolledUpData[resource] = convertValueToUnit(data, maxUnit)) + const dimensions = Object.entries(dimension).map( + ([timestamp, resource]): DataSet => { + const rolledUpData = Object.entries(resource).reduce( + (previousValue, newValue) => { + return { + ...previousValue, + [newValue[0]]: convertValueToUnit(newValue[1], maxUnit), + }; + }, + {} ); - return { timestamp: Number(key), ...rolledUpData }; + + return { timestamp: Number(timestamp), ...rolledUpData }; } ); return { From 8482608fdd44d43ec2e76b20765f5e5caf65a360 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 30 Oct 2024 14:21:39 +0530 Subject: [PATCH 276/474] upcoming: [DI-21200] - Added connectNulls & color properties --- .../manager/src/components/AreaChart/AreaChart.tsx | 13 +++++++++++-- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 1 - .../features/CloudPulse/Widget/CloudPulseWidget.tsx | 5 ++++- .../Widget/components/CloudPulseLineGraph.tsx | 2 +- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/manager/src/components/AreaChart/AreaChart.tsx b/packages/manager/src/components/AreaChart/AreaChart.tsx index 0180f0734b0..d6df449e4e9 100644 --- a/packages/manager/src/components/AreaChart/AreaChart.tsx +++ b/packages/manager/src/components/AreaChart/AreaChart.tsx @@ -28,7 +28,9 @@ import { import type { TooltipProps } from 'recharts'; import type { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay'; -interface AreaProps { +export type ChartVariant = 'line' | 'area'; + +export interface AreaProps { /** * color for the area */ @@ -64,6 +66,11 @@ export interface AreaChartProps { */ ariaLabel: string; + /** + * connect nulls value between two data points + */ + connectNulls? :boolean; + /** * data to be displayed on the graph */ @@ -114,7 +121,7 @@ export interface AreaChartProps { * make chart appear as a line or area chart * @default area */ - variant?: 'area' | 'line'; + variant?: ChartVariant; /** * The width of chart container. @@ -143,6 +150,7 @@ export const AreaChart = (props: AreaChartProps) => { variant, width = '100%', xAxis, + connectNulls } = props; const theme = useTheme(); @@ -274,6 +282,7 @@ export const AreaChart = (props: AreaChartProps) => { )} {areas.map(({ color, dataKey }) => ( { metric: graphData.metric, values: transformData(graphData.values, unit), }; - // const color = colors[index]; const { end, start } = convertTimeDurationToStartAndEndTimeRange({ unit: 'min', value: 30, diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 7a2e16a3293..1c417d35ee5 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -29,9 +29,10 @@ import type { TimeGranularity, } from '@linode/api-v4'; import type { Widgets } from '@linode/api-v4'; -import type { AreaProps } from 'src/components/AreaChart/AreaChart'; +import type { AreaProps, ChartVariant } from 'src/components/AreaChart/AreaChart'; import type { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay'; import type { Metrics } from 'src/utilities/statMetrics'; +import { generateCurrentUnit } from '../Utils/unitConversion'; export interface CloudPulseWidgetProperties { /** @@ -239,6 +240,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { let legendRows: MetricsDisplayRow[] = []; let currentUnit = unit; let areas: AreaProps[] = []; + const variant : ChartVariant= widget.chart_type === 'line' ? 'line' : 'area'; if (!isLoading && metricsList) { const generatedData = generateGraphData({ flags, @@ -335,6 +337,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { timezone={timezone} unit={currentUnit} xAxis={{ tickFormat, tickGap: 60 }} + variant={variant} /> diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index a77b06ea01b..a7afc44a9c6 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -32,7 +32,7 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { ) : ( - + )} {rest.data.length === 0 && ( Date: Wed, 30 Oct 2024 14:32:23 +0530 Subject: [PATCH 277/474] upcoming: [DI-21200] - Added sort data based on timestamp --- .../src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index 4a09d69a715..f4de495f561 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -261,7 +261,7 @@ export const generateGraphData = (props: GraphDataOptionsProps): GraphData => { ); return { areas, - dimensions, + dimensions : dimensions.sort((dim1, dim2) => dim1.timestamp - dim2.timestamp), legendRowsData, unit: maxUnit, }; From 3fc7ba93821d41d6c06ddbb91c7e5e6e54ac0532 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 30 Oct 2024 14:34:40 +0530 Subject: [PATCH 278/474] upcoming: [DI-21200] - Updated x-axis tick format --- .../manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 1c417d35ee5..5ec14c7fdad 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -266,7 +266,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { const tickFormat = duration.unit === 'min' || duration.unit === 'hr' ? 'hh:mm a' - : `LLL dd${widget.size === 12 ? ', hh:mm a' : ''}`; + : 'LLL dd, hh:mm a'; return ( From ef29f34551846aa390d9abe9efa84faf61ab8067 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 30 Oct 2024 16:30:08 +0530 Subject: [PATCH 279/474] upcoming: [DI-21200] - Updated PR comments --- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 15 ++------------- .../CloudPulse/Widget/CloudPulseWidget.tsx | 4 +--- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index f4de495f561..4c91f1ee8f1 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -94,16 +94,6 @@ interface GraphDataOptionsProps { * unit of the data */ unit: string; - - /** - * widget chart type - */ - widgetChartType: string; - - /** - * preferred color for the widget's graph - */ - widgetColor: string; } interface MetricRequestProps { @@ -182,7 +172,6 @@ export const generateGraphData = (props: GraphDataOptionsProps): GraphData => { unit, } = props; const legendRowsData: MetricsDisplayRow[] = []; - // for now we will use this, but once we decide how to work with coloring, it should be dynamic const dimension: { [timestamp: number]: { [label: string]: number } } = {}; const areas: AreaProps[] = []; const colors = Object.values(Alias.Chart.Categorical); @@ -258,10 +247,10 @@ export const generateGraphData = (props: GraphDataOptionsProps): GraphData => { return { timestamp: Number(timestamp), ...rolledUpData }; } - ); + ).sort((dimension1, dimension2) => dimension1.timestamp - dimension2.timestamp); return { areas, - dimensions : dimensions.sort((dim1, dim2) => dim1.timestamp - dim2.timestamp), + dimensions, legendRowsData, unit: maxUnit, }; diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 5ec14c7fdad..437a6326b39 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -249,9 +249,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { resources, serviceType, status, - unit, - widgetChartType: widget.chart_type, - widgetColor: widget.color, + unit }); data = generatedData.dimensions; From 1fda16860bd472672813791872194db90eb69589 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 30 Oct 2024 16:36:07 +0530 Subject: [PATCH 280/474] upcoming: [DI-21200] - Hide legends if not data present --- .../manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 437a6326b39..eb55349e3c7 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -331,7 +331,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { height={480} legendRows={legendRows} loading={isLoading || metricsApiCallError === jweTokenExpiryError} // keep loading until we fetch the refresh token - showLegend + showLegend={data.length !== 0} timezone={timezone} unit={currentUnit} xAxis={{ tickFormat, tickGap: 60 }} From b1b5248c3e13c00cf0abe3ff3a48d4333c1b2b28 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Mon, 4 Nov 2024 12:52:00 +0530 Subject: [PATCH 281/474] upcoming: [DI-21200] - Updated legends height --- .../CloudPulse/Widget/components/CloudPulseLineGraph.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index a7afc44a9c6..4f23dd4bbaa 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -32,7 +32,12 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { ) : ( - + )} {rest.data.length === 0 && ( Date: Mon, 4 Nov 2024 13:40:41 +0530 Subject: [PATCH 282/474] upcoming: [DI-21200] - Updated legend row color type --- packages/api-v4/src/cloudpulse/types.ts | 5 +++ .../LineGraph/MetricDisplay.styles.ts | 4 ++- .../components/LineGraph/MetricsDisplay.tsx | 11 +----- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 35 ++++++++++--------- 4 files changed, 28 insertions(+), 27 deletions(-) diff --git a/packages/api-v4/src/cloudpulse/types.ts b/packages/api-v4/src/cloudpulse/types.ts index 19a5149c76a..53d2e8a027f 100644 --- a/packages/api-v4/src/cloudpulse/types.ts +++ b/packages/api-v4/src/cloudpulse/types.ts @@ -132,3 +132,8 @@ export interface ServiceTypes { export interface ServiceTypesList { data: ServiceTypes[]; } + +export interface DataSet { + [label: string]: number; + timestamp: number; +} diff --git a/packages/manager/src/components/LineGraph/MetricDisplay.styles.ts b/packages/manager/src/components/LineGraph/MetricDisplay.styles.ts index 9870bd9bc2e..98b6fc31438 100644 --- a/packages/manager/src/components/LineGraph/MetricDisplay.styles.ts +++ b/packages/manager/src/components/LineGraph/MetricDisplay.styles.ts @@ -41,7 +41,9 @@ export const StyledButton = styled(Button, { '&:before': { backgroundColor: hidden ? theme.color.disabledText - : theme.graphs[legendColor], + : theme.graphs[legendColor] + ? theme.graphs[legendColor] + : legendColor, flexShrink: 0, }, }), diff --git a/packages/manager/src/components/LineGraph/MetricsDisplay.tsx b/packages/manager/src/components/LineGraph/MetricsDisplay.tsx index c22a3c375e8..ed907bbe638 100644 --- a/packages/manager/src/components/LineGraph/MetricsDisplay.tsx +++ b/packages/manager/src/components/LineGraph/MetricsDisplay.tsx @@ -19,15 +19,6 @@ const ROW_HEADERS = ['Max', 'Avg', 'Last'] as const; type MetricKey = 'average' | 'last' | 'max'; const METRIC_KEYS: MetricKey[] = ['max', 'average', 'last']; -export type LegendColor = - | 'blue' - | 'darkGreen' - | 'green' - | 'lightGreen' - | 'purple' - | 'red' - | 'yellow'; - interface Props { /** * Array of rows to hide. Each row should contain the legend title. @@ -47,7 +38,7 @@ export interface MetricsDisplayRow { data: Metrics; format: (n: number) => string; handleLegendClick?: () => void; - legendColor: LegendColor; + legendColor: string; legendTitle: string; } diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index 4c91f1ee8f1..3ef69fece71 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -233,21 +233,25 @@ export const generateGraphData = (props: GraphDataOptionsProps): GraphData => { } const maxUnit = generateMaxUnit(legendRowsData, unit); - const dimensions = Object.entries(dimension).map( - ([timestamp, resource]): DataSet => { - const rolledUpData = Object.entries(resource).reduce( - (previousValue, newValue) => { - return { - ...previousValue, - [newValue[0]]: convertValueToUnit(newValue[1], maxUnit), - }; - }, - {} - ); - - return { timestamp: Number(timestamp), ...rolledUpData }; - } - ).sort((dimension1, dimension2) => dimension1.timestamp - dimension2.timestamp); + const dimensions = Object.entries(dimension) + .map( + ([timestamp, resource]): DataSet => { + const rolledUpData = Object.entries(resource).reduce( + (previousValue, newValue) => { + return { + ...previousValue, + [newValue[0]]: convertValueToUnit(newValue[1], maxUnit), + }; + }, + {} + ); + + return { timestamp: Number(timestamp), ...rolledUpData }; + } + ) + .sort( + (dimension1, dimension2) => dimension1.timestamp - dimension2.timestamp + ); return { areas, dimensions, @@ -351,7 +355,6 @@ export const mapResourceIdToName = ( return resourcesObj?.label ?? id ?? ''; }; - /** * * @param theme mui theme From e503a29b610c4d9e48e8b84fa38eb9edce687c84 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Mon, 4 Nov 2024 14:49:47 +0530 Subject: [PATCH 283/474] upcoming: [DI-21200] - Code refactor --- .../features/CloudPulse/Utils/CloudPulseWidgetUtils.ts | 8 ++------ .../CloudPulse/Widget/components/CloudPulseLineGraph.tsx | 6 ++++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index 58347c81369..ff166aa16a2 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -182,10 +182,6 @@ export const generateGraphData = (props: GraphDataOptionsProps): GraphData => { return; } - if (label.includes('CPU') && index >= 1) { - return; - } - const transformedData = { metric: graphData.metric, values: transformData(graphData.values, unit), @@ -241,9 +237,9 @@ export const generateGraphData = (props: GraphDataOptionsProps): GraphData => { .map( ([timestamp, resource]): DataSet => { const rolledUpData = Object.entries(resource).reduce( - (previousValue, newValue) => { + (oldValue, newValue) => { return { - ...previousValue, + ...oldValue, [newValue[0]]: convertValueToUnit(newValue[1], maxUnit), }; }, diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index 4f23dd4bbaa..d16e64cde7a 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -1,4 +1,4 @@ -import { Box, Typography } from '@mui/material'; +import { Box, Typography, useTheme } from '@mui/material'; import * as React from 'react'; import { AreaChart } from 'src/components/AreaChart/AreaChart'; @@ -15,6 +15,8 @@ export interface CloudPulseLineGraph extends AreaChartProps { export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { const { error, loading, ...rest } = props; + const theme = useTheme(); + if (loading) { return ; } @@ -36,7 +38,7 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { {...rest} connectNulls fillOpacity={0.5} - legendHeight="150px" + legendHeight={theme.spacing(18.75)} /> )} {rest.data.length === 0 && ( From 62a5f98f43286c2e59e65697c5c36be814238fe1 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Mon, 4 Nov 2024 15:08:52 +0530 Subject: [PATCH 284/474] upcoming: [DI-21200] - Code refactor --- .../src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts | 4 ++-- .../CloudPulse/Widget/components/CloudPulseLineGraph.tsx | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index 3ef69fece71..ff166aa16a2 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -237,9 +237,9 @@ export const generateGraphData = (props: GraphDataOptionsProps): GraphData => { .map( ([timestamp, resource]): DataSet => { const rolledUpData = Object.entries(resource).reduce( - (previousValue, newValue) => { + (oldValue, newValue) => { return { - ...previousValue, + ...oldValue, [newValue[0]]: convertValueToUnit(newValue[1], maxUnit), }; }, diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index 4f23dd4bbaa..946cf7c8d70 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -1,4 +1,4 @@ -import { Box, Typography } from '@mui/material'; +import { Box, Typography, useTheme } from '@mui/material'; import * as React from 'react'; import { AreaChart } from 'src/components/AreaChart/AreaChart'; @@ -15,6 +15,7 @@ export interface CloudPulseLineGraph extends AreaChartProps { export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { const { error, loading, ...rest } = props; + const theme = useTheme(); if (loading) { return ; } @@ -36,7 +37,7 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { {...rest} connectNulls fillOpacity={0.5} - legendHeight="150px" + legendHeight={theme.spacing(18.75)} /> )} {rest.data.length === 0 && ( From a9793115ab06ed521699aff8f688aad77a8cb92f Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Mon, 4 Nov 2024 15:12:19 +0530 Subject: [PATCH 285/474] upcoming: [DI-21200] - Added changeset --- .../.changeset/pr-11204-upcoming-features-1730713240022.md | 5 +++++ .../.changeset/pr-11204-upcoming-features-1730713318901.md | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 packages/api-v4/.changeset/pr-11204-upcoming-features-1730713240022.md create mode 100644 packages/manager/.changeset/pr-11204-upcoming-features-1730713318901.md diff --git a/packages/api-v4/.changeset/pr-11204-upcoming-features-1730713240022.md b/packages/api-v4/.changeset/pr-11204-upcoming-features-1730713240022.md new file mode 100644 index 00000000000..b0d680421b2 --- /dev/null +++ b/packages/api-v4/.changeset/pr-11204-upcoming-features-1730713240022.md @@ -0,0 +1,5 @@ +--- +"@linode/api-v4": Upcoming Features +--- + +Add `DataSet` type in `types.ts` ([#11204](https://github.com/linode/manager/pull/11204)) diff --git a/packages/manager/.changeset/pr-11204-upcoming-features-1730713318901.md b/packages/manager/.changeset/pr-11204-upcoming-features-1730713318901.md new file mode 100644 index 00000000000..523b55f80dc --- /dev/null +++ b/packages/manager/.changeset/pr-11204-upcoming-features-1730713318901.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Upcoming Features +--- + +Replace `LineGraph` with `AreaChart` in `CloudPulseLineGraph` component. Add `connectNulls` property in `AreaChart.ts` ([#11204](https://github.com/linode/manager/pull/11204)) From 75adf4d235a9ae3dc12642e0ea96de502ee5f473 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Tue, 5 Nov 2024 12:18:30 +0530 Subject: [PATCH 286/474] upcoming: [DI-21200] - Moved DataSet type from types to CloudPulseLineGraph --- .../pr-11204-upcoming-features-1730713240022.md | 5 ----- packages/api-v4/src/cloudpulse/types.ts | 5 ----- .../pr-11204-upcoming-features-1730713318901.md | 2 +- .../src/components/AreaChart/AreaChart.tsx | 6 +++--- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 2 +- .../CloudPulse/Widget/CloudPulseWidget.tsx | 15 +++++++++------ .../Widget/components/CloudPulseLineGraph.tsx | 5 +++++ 7 files changed, 19 insertions(+), 21 deletions(-) delete mode 100644 packages/api-v4/.changeset/pr-11204-upcoming-features-1730713240022.md diff --git a/packages/api-v4/.changeset/pr-11204-upcoming-features-1730713240022.md b/packages/api-v4/.changeset/pr-11204-upcoming-features-1730713240022.md deleted file mode 100644 index b0d680421b2..00000000000 --- a/packages/api-v4/.changeset/pr-11204-upcoming-features-1730713240022.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@linode/api-v4": Upcoming Features ---- - -Add `DataSet` type in `types.ts` ([#11204](https://github.com/linode/manager/pull/11204)) diff --git a/packages/api-v4/src/cloudpulse/types.ts b/packages/api-v4/src/cloudpulse/types.ts index 53d2e8a027f..19a5149c76a 100644 --- a/packages/api-v4/src/cloudpulse/types.ts +++ b/packages/api-v4/src/cloudpulse/types.ts @@ -132,8 +132,3 @@ export interface ServiceTypes { export interface ServiceTypesList { data: ServiceTypes[]; } - -export interface DataSet { - [label: string]: number; - timestamp: number; -} diff --git a/packages/manager/.changeset/pr-11204-upcoming-features-1730713318901.md b/packages/manager/.changeset/pr-11204-upcoming-features-1730713318901.md index 523b55f80dc..d35b05d620c 100644 --- a/packages/manager/.changeset/pr-11204-upcoming-features-1730713318901.md +++ b/packages/manager/.changeset/pr-11204-upcoming-features-1730713318901.md @@ -2,4 +2,4 @@ "@linode/manager": Upcoming Features --- -Replace `LineGraph` with `AreaChart` in `CloudPulseLineGraph` component. Add `connectNulls` property in `AreaChart.ts` ([#11204](https://github.com/linode/manager/pull/11204)) +Replace `LineGraph` with `AreaChart` and add `DataSet` type in `CloudPulseLineGraph` component, add `connectNulls` property in `AreaChart.ts` ([#11204](https://github.com/linode/manager/pull/11204)) diff --git a/packages/manager/src/components/AreaChart/AreaChart.tsx b/packages/manager/src/components/AreaChart/AreaChart.tsx index d6df449e4e9..44295dc3ca1 100644 --- a/packages/manager/src/components/AreaChart/AreaChart.tsx +++ b/packages/manager/src/components/AreaChart/AreaChart.tsx @@ -28,7 +28,7 @@ import { import type { TooltipProps } from 'recharts'; import type { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay'; -export type ChartVariant = 'line' | 'area'; +export type ChartVariant = 'area' | 'line'; export interface AreaProps { /** @@ -69,7 +69,7 @@ export interface AreaChartProps { /** * connect nulls value between two data points */ - connectNulls? :boolean; + connectNulls?: boolean; /** * data to be displayed on the graph @@ -138,6 +138,7 @@ export const AreaChart = (props: AreaChartProps) => { const { areas, ariaLabel, + connectNulls, data, fillOpacity, height = '100%', @@ -150,7 +151,6 @@ export const AreaChart = (props: AreaChartProps) => { variant, width = '100%', xAxis, - connectNulls } = props; const theme = useTheme(); diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index ff166aa16a2..29d38e1e776 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -14,11 +14,11 @@ import { } from './utils'; import type { CloudPulseResources } from '../shared/CloudPulseResourcesSelect'; +import type { DataSet } from '../Widget/components/CloudPulseLineGraph'; import type { CloudPulseMetricsList, CloudPulseMetricsRequest, CloudPulseMetricsResponse, - DataSet, TimeDuration, Widgets, } from '@linode/api-v4'; diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index eb55349e3c7..4c27fa0057b 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -13,6 +13,7 @@ import { } from '../Utils/CloudPulseWidgetUtils'; import { AGGREGATE_FUNCTION, SIZE, TIME_GRANULARITY } from '../Utils/constants'; import { constructAdditionalRequestFilters } from '../Utils/FilterBuilder'; +import { generateCurrentUnit } from '../Utils/unitConversion'; import { useAclpPreference } from '../Utils/UserPreference'; import { convertStringToCamelCasesWithSpaces } from '../Utils/utils'; import { CloudPulseAggregateFunction } from './components/CloudPulseAggregateFunction'; @@ -22,17 +23,19 @@ import { ZoomIcon } from './components/Zoomer'; import type { FilterValueType } from '../Dashboard/CloudPulseDashboardLanding'; import type { CloudPulseResources } from '../shared/CloudPulseResourcesSelect'; +import type { DataSet } from './components/CloudPulseLineGraph'; import type { AvailableMetrics, - DataSet, TimeDuration, TimeGranularity, } from '@linode/api-v4'; import type { Widgets } from '@linode/api-v4'; -import type { AreaProps, ChartVariant } from 'src/components/AreaChart/AreaChart'; +import type { + AreaProps, + ChartVariant, +} from 'src/components/AreaChart/AreaChart'; import type { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay'; import type { Metrics } from 'src/utilities/statMetrics'; -import { generateCurrentUnit } from '../Utils/unitConversion'; export interface CloudPulseWidgetProperties { /** @@ -240,7 +243,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { let legendRows: MetricsDisplayRow[] = []; let currentUnit = unit; let areas: AreaProps[] = []; - const variant : ChartVariant= widget.chart_type === 'line' ? 'line' : 'area'; + const variant: ChartVariant = widget.chart_type === 'line' ? 'line' : 'area'; if (!isLoading && metricsList) { const generatedData = generateGraphData({ flags, @@ -249,7 +252,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { resources, serviceType, status, - unit + unit, }); data = generatedData.dimensions; @@ -334,8 +337,8 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { showLegend={data.length !== 0} timezone={timezone} unit={currentUnit} - xAxis={{ tickFormat, tickGap: 60 }} variant={variant} + xAxis={{ tickFormat, tickGap: 60 }} /> diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index 946cf7c8d70..eca82bb09ca 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -7,6 +7,11 @@ import { ErrorState } from 'src/components/ErrorState/ErrorState'; import type { AreaChartProps } from 'src/components/AreaChart/AreaChart'; +export interface DataSet { + [label: string]: number; + timestamp: number; +} + export interface CloudPulseLineGraph extends AreaChartProps { error?: string; loading?: boolean; From 463c044b8483c8ddf4113e9aa8503b966e68a2ea Mon Sep 17 00:00:00 2001 From: agorthi Date: Wed, 6 Nov 2024 15:14:33 +0530 Subject: [PATCH 287/474] [DI-21597]-Automating and testing the migration of Recharts --- .../dbaas-widgets-verification.spec.ts | 180 +++++++++--------- .../linode-widget-verification.spec.ts | 180 ++++++++++-------- .../src/components/AreaChart/AreaChart.tsx | 4 +- .../components/LineGraph/MetricsDisplay.tsx | 5 +- 4 files changed, 196 insertions(+), 173 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts index d1f1181337d..313b394b1e9 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts @@ -29,11 +29,12 @@ import { mockGetUserPreferences } from 'support/intercepts/profile'; import { mockGetRegions } from 'support/intercepts/regions'; import { extendRegion } from 'support/util/regions'; import { CloudPulseMetricsResponse, Database } from '@linode/api-v4'; -import { transformData } from 'src/features/CloudPulse/Utils/unitConversion'; -import { getMetrics } from 'src/utilities/statMetrics'; import { Interception } from 'cypress/types/net-stubbing'; import { generateRandomMetricsData } from 'support/util/cloudpulse'; import { mockGetDatabases } from 'support/intercepts/databases'; +import { generateGraphData } from 'src/features/CloudPulse/Utils/CloudPulseWidgetUtils'; +import type { Flags } from 'src/featureFlags'; +import { formatToolTip } from 'src/features/CloudPulse/Utils/unitConversion'; /** * This test ensures that widget titles are displayed correctly on the dashboard. @@ -101,28 +102,50 @@ const metricsAPIResponsePayload = cloudPulseMetricsResponseFactory.build({ }); /** - * Verifies the presence and values of specific properties within the aclpPreference object - * of the request payload. This function checks that the expected properties exist - * and have the expected values, allowing for validation of user preferences in the application. + * Generates graph data from a given CloudPulse metrics response and + * extracts average, last, and maximum metric values from the first + * legend row. The values are rounded to two decimal places for + * better readability. + * + * @param responsePayload - The metrics response object containing + * the necessary data for graph generation. + * @param label - The label for the graph, used for display purposes. + * + * @returns An object containing rounded values for max average, last, * - * @param requestPayload - The payload received from the request, containing the aclpPreference object. - * @param expectedValues - An object containing the expected values for properties to validate against the requestPayload. - * Expected properties may include: - * - dashboardId: The ID of the dashboard. - * - timeDuration: The selected time duration for metrics. - * - engine: The database engine used. - * - region: The selected region for the dashboard. - * - resources: An array of resource identifiers. - * - role: The role associated with the dashboard user. */ + const getWidgetLegendRowValuesFromResponse = ( - responsePayload: CloudPulseMetricsResponse + responsePayload: CloudPulseMetricsResponse, + label: string, + unit: string ) => { - const data = transformData(responsePayload.data.result[0].values, 'Bytes'); - const { average, last, max } = getMetrics(data); - const roundedAverage = Math.round(average * 100) / 100; - const roundedLast = Math.round(last * 100) / 100; - const roundedMax = Math.round(max * 100) / 100; + // Generate graph data using the provided parameters + const graphData = generateGraphData({ + flags: { enabled: true } as Partial, + label: label, + metricsList: responsePayload, + resources: [ + { + id: '1', + label: clusterName, + region: 'us-ord', + }, + ], + serviceType: serviceType, + status: 'success', + unit: unit, + // widgetColor: 'red', + }); + + // Destructure metrics data from the first legend row + const { average, last, max } = graphData.legendRowsData[0].data; + + // Round the metrics values to two decimal places + const roundedAverage = formatToolTip(average, unit); + const roundedLast = formatToolTip(last, unit); + const roundedMax = formatToolTip(max, unit); + // Return the rounded values in an object return { average: roundedAverage, last: roundedLast, max: roundedMax }; }; @@ -250,33 +273,28 @@ describe('Integration Tests for DBaaS Dashboard ', () => { }); //validate the widget linegrah is present - cy.findByTestId('linegraph-wrapper').within(() => { + cy.findByTestId('areachart-wrapper').within(() => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( - metricsAPIResponsePayload - ); - cy.findByText(`${testData.title} (${testData.unit})`).should( - 'be.visible' + metricsAPIResponsePayload, + testData.title, + testData.unit ); + const graphRowTitle = `[data-qa-graph-row-title="${testData.title} (${testData.unit})"]`; + cy.get(graphRowTitle) + .should('be.visible') + .should('have.text', `${testData.title} (${testData.unit})`); + cy.get(`[data-qa-graph-column-title="Max"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.max} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.max}`); cy.get(`[data-qa-graph-column-title="Avg"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.average} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.average}`); cy.get(`[data-qa-graph-column-title="Last"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.last} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.last}`); }); }); }); @@ -309,33 +327,28 @@ describe('Integration Tests for DBaaS Dashboard ', () => { }); //validate the widget linegrah is present - cy.findByTestId('linegraph-wrapper').within(() => { + cy.findByTestId('areachart-wrapper').within(() => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( - metricsAPIResponsePayload - ); - cy.findByText(`${testData.title} (${testData.unit})`).should( - 'be.visible' + metricsAPIResponsePayload, + testData.title, + testData.unit ); + const graphRowTitle = `[data-qa-graph-row-title="${testData.title} (${testData.unit})"]`; + cy.get(graphRowTitle) + .should('be.visible') + .should('have.text', `${testData.title} (${testData.unit})`); + cy.get(`[data-qa-graph-column-title="Max"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.max} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.max}`); cy.get(`[data-qa-graph-column-title="Avg"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.average} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.average}`); cy.get(`[data-qa-graph-column-title="Last"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.last} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.last}`); }); }); }); @@ -384,33 +397,29 @@ describe('Integration Tests for DBaaS Dashboard ', () => { .should('be.enabled') .click(); cy.get('@widget').should('be.visible'); - cy.findByTestId('linegraph-wrapper').within(() => { + + cy.findByTestId('areachart-wrapper').within(() => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( - metricsAPIResponsePayload - ); - cy.findByText(`${testData.title} (${testData.unit})`).should( - 'be.visible' + metricsAPIResponsePayload, + testData.title, + testData.unit ); + const graphRowTitle = `[data-qa-graph-row-title="${testData.title} (${testData.unit})"]`; + cy.get(graphRowTitle) + .should('be.visible') + .should('have.text', `${testData.title} (${testData.unit})`); + cy.get(`[data-qa-graph-column-title="Max"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.max} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.max}`); cy.get(`[data-qa-graph-column-title="Avg"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.average} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.average}`); cy.get(`[data-qa-graph-column-title="Last"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.last} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.last}`); }); // click zoom out and validate the same @@ -421,33 +430,28 @@ describe('Integration Tests for DBaaS Dashboard ', () => { .scrollIntoView() .click({ force: true }); cy.get('@widget').should('be.visible'); - cy.findByTestId('linegraph-wrapper').within(() => { + cy.findByTestId('areachart-wrapper').within(() => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( - metricsAPIResponsePayload - ); - cy.findByText(`${testData.title} (${testData.unit})`).should( - 'be.visible' + metricsAPIResponsePayload, + testData.title, + testData.unit ); + const graphRowTitle = `[data-qa-graph-row-title="${testData.title} (${testData.unit})"]`; + cy.get(graphRowTitle) + .should('be.visible') + .should('have.text', `${testData.title} (${testData.unit})`); + cy.get(`[data-qa-graph-column-title="Max"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.max} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.max}`); cy.get(`[data-qa-graph-column-title="Avg"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.average} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.average}`); cy.get(`[data-qa-graph-column-title="Last"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.last} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.last}`); }); }); }); diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index b0620e4148e..3fca58d1d5b 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -28,10 +28,11 @@ import { mockGetUserPreferences } from 'support/intercepts/profile'; import { mockGetRegions } from 'support/intercepts/regions'; import { extendRegion } from 'support/util/regions'; import { CloudPulseMetricsResponse } from '@linode/api-v4'; -import { transformData } from 'src/features/CloudPulse/Utils/unitConversion'; -import { getMetrics } from 'src/utilities/statMetrics'; import { generateRandomMetricsData } from 'support/util/cloudpulse'; import { Interception } from 'cypress/types/net-stubbing'; +import { generateGraphData } from 'src/features/CloudPulse/Utils/CloudPulseWidgetUtils'; +import { Flags } from 'src/featureFlags'; +import { formatToolTip } from 'src/features/CloudPulse/Utils/unitConversion'; /** * This test ensures that widget titles are displayed correctly on the dashboard. @@ -97,25 +98,49 @@ const metricsAPIResponsePayload = cloudPulseMetricsResponseFactory.build({ }); /** - * `verifyWidgetValues` processes and verifies the metric values of a widget from the provided response payload. + * Generates graph data from a given CloudPulse metrics response and + * extracts average, last, and maximum metric values from the first + * legend row. The values are rounded to two decimal places for + * better readability. * - * This method performs the following steps: - * 1. Transforms the raw data from the response payload into a more manageable format using `transformData`. - * 2. Extracts key metrics (average, last, and max) from the transformed data using `getMetrics`. - * 3. Rounds these metrics to two decimal places for accuracy. - * 4. Returns an object containing the rounded average, last, and max values for further verification or comparison. + * @param responsePayload - The metrics response object containing + * the necessary data for graph generation. + * @param label - The label for the graph, used for display purposes. + * + * @returns An object containing rounded values for average, last, * - * @param {CloudPulseMetricsResponse} responsePayload - The response payload containing metric data for a widget. - * @returns {Object} An object with the rounded average, last, and max metric values. */ + const getWidgetLegendRowValuesFromResponse = ( - responsePayload: CloudPulseMetricsResponse + responsePayload: CloudPulseMetricsResponse, + label: string, + unit: string ) => { - const data = transformData(responsePayload.data.result[0].values, 'Bytes'); - const { average, last, max } = getMetrics(data); - const roundedAverage = Math.round(average * 100) / 100; - const roundedLast = Math.round(last * 100) / 100; - const roundedMax = Math.round(max * 100) / 100; + // Generate graph data using the provided parameters + const graphData = generateGraphData({ + flags: { enabled: true } as Partial, + label: label, + metricsList: responsePayload, + resources: [ + { + id: '1', + label: resource, + region: 'us-ord', + }, + ], + serviceType: serviceType, + status: 'success', + unit: unit, + }); + + // Destructure metrics data from the first legend row + const { average, last, max } = graphData.legendRowsData[0].data; + + // Round the metrics values to two decimal places + const roundedAverage = formatToolTip(average, unit); + const roundedLast = formatToolTip(last, unit); + const roundedMax = formatToolTip(max, unit); + // Return the rounded values in an object return { average: roundedAverage, last: roundedLast, max: roundedMax }; }; @@ -214,34 +239,32 @@ describe('Integration Tests for Linode Dashboard ', () => { ); }); - //validate the widget linegrah is present - cy.findByTestId('linegraph-wrapper').within(() => { + //validate the widget areachart is present + cy.findByTestId('areachart-wrapper').within(() => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( - metricsAPIResponsePayload - ); - cy.findByText(`${testData.title} (${testData.unit})`).should( - 'be.visible' + metricsAPIResponsePayload, + testData.title, + testData.unit ); + + const graphRowTitle = `[data-qa-graph-row-title="${testData.title} (${testData.unit})"]`; + cy.get(graphRowTitle) + .should('be.visible') + .should('have.text', `${testData.title} (${testData.unit})`); + + cy.log('expectedWidgetValues ', expectedWidgetValues.max); + cy.get(`[data-qa-graph-column-title="Max"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.max} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.max}`); cy.get(`[data-qa-graph-column-title="Avg"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.average} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.average}`); cy.get(`[data-qa-graph-column-title="Last"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.last} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.last}`); }); }); }); @@ -273,34 +296,32 @@ describe('Integration Tests for Linode Dashboard ', () => { ); }); - //validate the widget linegrah is present - cy.findByTestId('linegraph-wrapper').within(() => { + //validate the widget areachart is present + cy.findByTestId('areachart-wrapper').within(() => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( - metricsAPIResponsePayload - ); - cy.findByText(`${testData.title} (${testData.unit})`).should( - 'be.visible' + metricsAPIResponsePayload, + testData.title, + testData.unit ); - cy.get(`[data-qa-graph-column-title="Max"]`) + const graphRowTitle = `[data-qa-graph-row-title="${testData.title} (${testData.unit})"]`; + cy.get(graphRowTitle) .should('be.visible') .should( 'have.text', - `${expectedWidgetValues.max} ${testData.unit}` + `${testData.title} (${testData.unit.trim()})` ); + cy.get(`[data-qa-graph-column-title="Max"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.max}`); + cy.get(`[data-qa-graph-column-title="Avg"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.average} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.average}`); cy.get(`[data-qa-graph-column-title="Last"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.last} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.last}`); }); }); }); @@ -349,33 +370,28 @@ describe('Integration Tests for Linode Dashboard ', () => { .should('be.enabled') .click(); cy.get('@widget').should('be.visible'); - cy.findByTestId('linegraph-wrapper').within(() => { + cy.findByTestId('areachart-wrapper').within(() => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( - metricsAPIResponsePayload - ); - cy.findByText(`${testData.title} (${testData.unit})`).should( - 'be.visible' + metricsAPIResponsePayload, + testData.title, + testData.unit ); + const graphRowTitle = `[data-qa-graph-row-title="${testData.title} (${testData.unit})"]`; + cy.get(graphRowTitle) + .should('be.visible') + .should('have.text', `${testData.title} (${testData.unit})`); + cy.get(`[data-qa-graph-column-title="Max"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.max} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.max}`); cy.get(`[data-qa-graph-column-title="Avg"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.average} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.average}`); cy.get(`[data-qa-graph-column-title="Last"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.last} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.last}`); }); // click zoom out and validate the same @@ -386,33 +402,33 @@ describe('Integration Tests for Linode Dashboard ', () => { .scrollIntoView() .click({ force: true }); cy.get('@widget').should('be.visible'); - cy.findByTestId('linegraph-wrapper').within(() => { + + cy.findByTestId('areachart-wrapper').within(() => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( - metricsAPIResponsePayload - ); - cy.findByText(`${testData.title} (${testData.unit})`).should( - 'be.visible' + metricsAPIResponsePayload, + testData.title, + testData.unit ); - cy.get(`[data-qa-graph-column-title="Max"]`) + + const graphRowTitle = `[data-qa-graph-row-title="${testData.title} (${testData.unit})"]`; + cy.get(graphRowTitle) .should('be.visible') .should( 'have.text', - `${expectedWidgetValues.max} ${testData.unit}` + `${testData.title} (${testData.unit.trim()})` ); + cy.get(`[data-qa-graph-column-title="Max"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.max}`); + cy.get(`[data-qa-graph-column-title="Avg"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.average} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.average}`); cy.get(`[data-qa-graph-column-title="Last"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.last} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.last}`); }); }); }); diff --git a/packages/manager/src/components/AreaChart/AreaChart.tsx b/packages/manager/src/components/AreaChart/AreaChart.tsx index 4128623b913..0674f6d3883 100644 --- a/packages/manager/src/components/AreaChart/AreaChart.tsx +++ b/packages/manager/src/components/AreaChart/AreaChart.tsx @@ -228,7 +228,7 @@ export const AreaChart = (props: AreaChartProps) => { }; return ( - <> + <_AreaChart aria-label={ariaLabel} data={data} margin={margin}> { timezone={timezone} unit={unit} /> - + ); }; diff --git a/packages/manager/src/components/LineGraph/MetricsDisplay.tsx b/packages/manager/src/components/LineGraph/MetricsDisplay.tsx index ed907bbe638..5484c287dd9 100644 --- a/packages/manager/src/components/LineGraph/MetricsDisplay.tsx +++ b/packages/manager/src/components/LineGraph/MetricsDisplay.tsx @@ -86,12 +86,15 @@ const MetricRow = ({ legendColor={legendColor} onClick={handleLegendClick} > - {legendTitle} + + {legendTitle} + {METRIC_KEYS.map((key, idx) => ( Date: Wed, 6 Nov 2024 15:14:44 +0530 Subject: [PATCH 288/474] [DI-21597]-Automating and testing the migration of Recharts --- .../core/cloudpulse/cloudpulse-navigation.spec.ts | 4 ++-- .../core/cloudpulse/cloudpulse-validation.spec.ts | 14 ++++++++------ .../cloudpulse/linode-widget-verification.spec.ts | 10 ++-------- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts index e747af3f3bf..2e304591382 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts @@ -36,7 +36,7 @@ describe('CloudPulse navigation', () => { /* * - Confirms that Cloudpulse navigation item is not shown when feature flag is disabled. */ - it('does not show Cloudpulse navigation item when feature is disabled', () => { + it.skip('does not show Cloudpulse navigation item when feature is disabled', () => { mockAppendFeatureFlags({ aclp: { beta: true, @@ -55,7 +55,7 @@ describe('CloudPulse navigation', () => { /* * - Confirms that manual navigation to Cloudpulse landing page with feature is disabled displays Not Found to user. */ - it('displays Not Found when manually navigating to /cloudpulse with feature flag disabled', () => { + it.skip('displays Not Found when manually navigating to /cloudpulse with feature flag disabled', () => { mockAppendFeatureFlags({ aclp: { beta: true, diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts index a07bb680161..552571d80d8 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts @@ -104,7 +104,7 @@ describe('Tests for API error handling', () => { cy.intercept( 'GET', apiMatcher(`/monitor/services/${serviceType}/metric-definitions`), - { statusCode: 500, body: { errors: [{ reason: 'Bad Request' }] }, } + { statusCode: 500, body: { errors: [{ reason: 'Bad Request' }] } } ).as('getMetricDefinitions'); cy.visitWithLogin('monitor/cloudpulse'); @@ -153,7 +153,8 @@ describe('Tests for API error handling', () => { cy.intercept('GET', apiMatcher(`/monitor/services`), { statusCode: 500, body: { - errors: [{ reason: 'Bad Request' }],}, + errors: [{ reason: 'Bad Request' }], + }, }).as('fetchServices'); cy.visitWithLogin('monitor/cloudpulse'); @@ -168,7 +169,8 @@ describe('Tests for API error handling', () => { cy.intercept('POST', apiMatcher(`/monitor/services/${serviceType}/token`), { statusCode: 500, body: { - errors: [{ reason: 'Bad Request' }], }, + errors: [{ reason: 'Bad Request' }], + }, }); cy.visitWithLogin('monitor/cloudpulse'); @@ -217,7 +219,7 @@ describe('Tests for API error handling', () => { apiMatcher(`/monitor/services/${serviceType}/dashboards`), { statusCode: 500, - body: { errors: [{ reason: 'Bad Request' }],}, + body: { errors: [{ reason: 'Bad Request' }] }, } ).as('fetchDashboard'); @@ -282,7 +284,7 @@ describe('Tests for API error handling', () => { it(`should return error message when the Regions API request fails`, () => { cy.intercept('GET', apiMatcher(`regions*`), { - statusCode: 500, + statusCode: 500, body: { errors: [{ reason: 'Bad Request' }] }, }); @@ -309,7 +311,7 @@ describe('Tests for API error handling', () => { it('should return error response when fetching db cluster API request', () => { cy.intercept('GET', apiMatcher(`databases/instances*`), { statusCode: 500, - body: {errors: [{ reason: 'Bad Request' }],}, + body: { errors: [{ reason: 'Bad Request' }] }, }); cy.visitWithLogin('monitor/cloudpulse'); diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 3fca58d1d5b..dd3c297d364 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -47,14 +47,8 @@ import { formatToolTip } from 'src/features/CloudPulse/Utils/unitConversion'; const expectedGranularityArray = ['Auto', '1 day', '1 hr', '5 min']; const timeDurationToSelect = 'Last 24 Hours'; -const { - metrics, - id, - serviceType, - dashboardName, - region, - resource, -} = widgetDetails.linode; +const { metrics, id, serviceType, dashboardName, region, resource } = + widgetDetails.linode; const dashboard = dashboardFactory.build({ label: dashboardName, From 4c89e128112d94f781a1229768dd79f50e754d08 Mon Sep 17 00:00:00 2001 From: agorthi Date: Wed, 6 Nov 2024 15:19:52 +0530 Subject: [PATCH 289/474] [DI-21597]-Automating and testing the migration of Recharts --- .../core/cloudpulse/cloudpulse-navigation.spec.ts | 4 ++-- .../core/cloudpulse/cloudpulse-validation.spec.ts | 14 ++++++-------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts index 2e304591382..e747af3f3bf 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts @@ -36,7 +36,7 @@ describe('CloudPulse navigation', () => { /* * - Confirms that Cloudpulse navigation item is not shown when feature flag is disabled. */ - it.skip('does not show Cloudpulse navigation item when feature is disabled', () => { + it('does not show Cloudpulse navigation item when feature is disabled', () => { mockAppendFeatureFlags({ aclp: { beta: true, @@ -55,7 +55,7 @@ describe('CloudPulse navigation', () => { /* * - Confirms that manual navigation to Cloudpulse landing page with feature is disabled displays Not Found to user. */ - it.skip('displays Not Found when manually navigating to /cloudpulse with feature flag disabled', () => { + it('displays Not Found when manually navigating to /cloudpulse with feature flag disabled', () => { mockAppendFeatureFlags({ aclp: { beta: true, diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts index 552571d80d8..a07bb680161 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts @@ -104,7 +104,7 @@ describe('Tests for API error handling', () => { cy.intercept( 'GET', apiMatcher(`/monitor/services/${serviceType}/metric-definitions`), - { statusCode: 500, body: { errors: [{ reason: 'Bad Request' }] } } + { statusCode: 500, body: { errors: [{ reason: 'Bad Request' }] }, } ).as('getMetricDefinitions'); cy.visitWithLogin('monitor/cloudpulse'); @@ -153,8 +153,7 @@ describe('Tests for API error handling', () => { cy.intercept('GET', apiMatcher(`/monitor/services`), { statusCode: 500, body: { - errors: [{ reason: 'Bad Request' }], - }, + errors: [{ reason: 'Bad Request' }],}, }).as('fetchServices'); cy.visitWithLogin('monitor/cloudpulse'); @@ -169,8 +168,7 @@ describe('Tests for API error handling', () => { cy.intercept('POST', apiMatcher(`/monitor/services/${serviceType}/token`), { statusCode: 500, body: { - errors: [{ reason: 'Bad Request' }], - }, + errors: [{ reason: 'Bad Request' }], }, }); cy.visitWithLogin('monitor/cloudpulse'); @@ -219,7 +217,7 @@ describe('Tests for API error handling', () => { apiMatcher(`/monitor/services/${serviceType}/dashboards`), { statusCode: 500, - body: { errors: [{ reason: 'Bad Request' }] }, + body: { errors: [{ reason: 'Bad Request' }],}, } ).as('fetchDashboard'); @@ -284,7 +282,7 @@ describe('Tests for API error handling', () => { it(`should return error message when the Regions API request fails`, () => { cy.intercept('GET', apiMatcher(`regions*`), { - statusCode: 500, + statusCode: 500, body: { errors: [{ reason: 'Bad Request' }] }, }); @@ -311,7 +309,7 @@ describe('Tests for API error handling', () => { it('should return error response when fetching db cluster API request', () => { cy.intercept('GET', apiMatcher(`databases/instances*`), { statusCode: 500, - body: { errors: [{ reason: 'Bad Request' }] }, + body: {errors: [{ reason: 'Bad Request' }],}, }); cy.visitWithLogin('monitor/cloudpulse'); From be532c989cfb0ea0abeef87291b8d833eba6656f Mon Sep 17 00:00:00 2001 From: agorthi Date: Wed, 6 Nov 2024 15:28:29 +0530 Subject: [PATCH 290/474] [DI-21597]:Removed commented-out code and explanatory comments related to the line chart in DBaaS test cases --- .../e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts index 313b394b1e9..57c3e5541b5 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts @@ -272,7 +272,7 @@ describe('Integration Tests for DBaaS Dashboard ', () => { ); }); - //validate the widget linegrah is present + //validate the widget areachart is present cy.findByTestId('areachart-wrapper').within(() => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( metricsAPIResponsePayload, @@ -326,7 +326,7 @@ describe('Integration Tests for DBaaS Dashboard ', () => { ); }); - //validate the widget linegrah is present + //validate the widget areachart is present cy.findByTestId('areachart-wrapper').within(() => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( metricsAPIResponsePayload, From 142dcace55e62de733f2a76cd5177326e00017e4 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Thu, 7 Nov 2024 14:30:18 +0530 Subject: [PATCH 291/474] resource order fix --- .../CloudPulse/shared/CloudPulseResourcesSelect.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index 3c6bd803237..c1a0170c5a8 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -46,17 +46,22 @@ export const CloudPulseResourcesSelect = React.memo( const platformFilter = resourceType === 'dbaas' ? { platform: 'rdbms-default' } : {}; + const orderFilter: Partial = + resourceType === 'dbaas' ? { '+order': 'asc', '+order_by': 'id' } : {}; + const { data: resources, isLoading, isError } = useResourcesQuery( disabled !== undefined ? !disabled : Boolean(region && resourceType), resourceType, {}, xFilter ? { - ...platformFilter, - ...xFilter, + ...platformFilter, // platform is a top level filter + ...orderFilter, // order by filter + ...xFilter, // the usual xFilters } : { ...platformFilter, + ...orderFilter, region, } ); From 55efe37f7369a2693d5f7ac5ba664e1ccf0a051f Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Thu, 7 Nov 2024 15:01:50 +0530 Subject: [PATCH 292/474] small fix --- .../features/CloudPulse/shared/CloudPulseResourcesSelect.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index c1a0170c5a8..e2e5cad248d 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -47,7 +47,7 @@ export const CloudPulseResourcesSelect = React.memo( resourceType === 'dbaas' ? { platform: 'rdbms-default' } : {}; const orderFilter: Partial = - resourceType === 'dbaas' ? { '+order': 'asc', '+order_by': 'id' } : {}; + resourceType === 'dbaas' ? { '+order': 'asc', '+order_by': 'label' } : {}; const { data: resources, isLoading, isError } = useResourcesQuery( disabled !== undefined ? !disabled : Boolean(region && resourceType), From 7d7e9337ce245a4e2380f815dcf33751379a3867 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Thu, 7 Nov 2024 16:00:35 +0530 Subject: [PATCH 293/474] small fix --- .../features/CloudPulse/shared/CloudPulseResourcesSelect.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index e2e5cad248d..0db8c43c9c1 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -55,13 +55,13 @@ export const CloudPulseResourcesSelect = React.memo( {}, xFilter ? { - ...platformFilter, // platform is a top level filter ...orderFilter, // order by filter + ...platformFilter, // platform is a top level filter ...xFilter, // the usual xFilters } : { - ...platformFilter, ...orderFilter, + ...platformFilter, region, } ); From 63d3f818e11166f89bce3f9c119a2a3932923f74 Mon Sep 17 00:00:00 2001 From: vmangalr Date: Fri, 8 Nov 2024 09:59:53 +0530 Subject: [PATCH 294/474] DI-21814: use map for better readability and optimisations --- .../shared/CloudPulseResourcesSelect.tsx | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index 0db8c43c9c1..ee2ac13dc0d 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -43,11 +43,9 @@ export const CloudPulseResourcesSelect = React.memo( xFilter, } = props; - const platformFilter = - resourceType === 'dbaas' ? { platform: 'rdbms-default' } : {}; - - const orderFilter: Partial = - resourceType === 'dbaas' ? { '+order': 'asc', '+order_by': 'label' } : {}; + const resourceFilterMap: Record = { + dbaas: { '+order': 'asc', '+order_by': 'label', platform: 'rdbms-default' }, + }; const { data: resources, isLoading, isError } = useResourcesQuery( disabled !== undefined ? !disabled : Boolean(region && resourceType), @@ -55,15 +53,13 @@ export const CloudPulseResourcesSelect = React.memo( {}, xFilter ? { - ...orderFilter, // order by filter - ...platformFilter, // platform is a top level filter - ...xFilter, // the usual xFilters - } + ...(resourceFilterMap[resourceType ?? ''] ?? {}), + ...xFilter, // the usual xFilters + } : { - ...orderFilter, - ...platformFilter, - region, - } + ...(resourceFilterMap[resourceType ?? ''] ?? {}), + region, + } ); const [selectedResources, setSelectedResources] = React.useState< From efc678f09a63bcf9bfd1006fe7d13ff63d99c08b Mon Sep 17 00:00:00 2001 From: vmangalr Date: Fri, 8 Nov 2024 12:17:49 +0530 Subject: [PATCH 295/474] DI-21814: enable contextual view --- .../DatabaseDetail/DatabaseMonitor/DatabaseMonitor.tsx | 2 +- .../manager/src/features/Databases/DatabaseDetail/index.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseMonitor/DatabaseMonitor.tsx b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseMonitor/DatabaseMonitor.tsx index ef47e2f34d0..5a255785977 100644 --- a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseMonitor/DatabaseMonitor.tsx +++ b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseMonitor/DatabaseMonitor.tsx @@ -8,7 +8,7 @@ interface Props { export const DatabaseMonitor = ({ database }: Props) => { const databaseId = database?.id; - const dbaasDashboardId = 2; + const dbaasDashboardId = 1; return ( { } const isDefault = database.platform === 'rdbms-default'; - const isMonitorEnabled = isDatabasesMonitorEnabled; + const isMonitorEnabled = true; const tabs: Tab[] = [ { @@ -120,7 +120,7 @@ export const DatabaseDetail = () => { if (isMonitorEnabled) { tabs.splice(1, 0, { - chip: isDatabasesMonitorBeta ? : null, + chip: (isDatabasesMonitorBeta || true) ? : null, routeName: `/databases/${engine}/${id}/monitor`, title: 'Monitor', }); From 00210055c45f1a3e7a56216e41f1113e6d30571c Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Tue, 12 Nov 2024 09:35:34 +0530 Subject: [PATCH 296/474] upcoming: [DI-20934] - Configurable Max limit on resource selection component --- packages/manager/src/featureFlags.ts | 1 + .../shared/CloudPulseResourcesSelect.test.tsx | 52 ++++++++++++++++--- .../shared/CloudPulseResourcesSelect.tsx | 44 +++++++++++++++- 3 files changed, 89 insertions(+), 8 deletions(-) diff --git a/packages/manager/src/featureFlags.ts b/packages/manager/src/featureFlags.ts index 9a92408132d..24effe13c86 100644 --- a/packages/manager/src/featureFlags.ts +++ b/packages/manager/src/featureFlags.ts @@ -66,6 +66,7 @@ interface AclpFlag { export interface CloudPulseResourceTypeMapFlag { dimensionKey: string; + maxResourceSelections?: number; serviceType: string; } diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx index 7249de52a16..6f05af09315 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx @@ -21,6 +21,8 @@ vi.mock('src/queries/cloudpulse/resources', async () => { const mockResourceHandler = vi.fn(); const SELECT_ALL = 'Select All'; const ARIA_SELECTED = 'aria-selected'; +const ARIA_DISABLED = 'aria-disabled'; +const labelText = 'Resources (10 max)'; describe('CloudPulseResourcesSelect component tests', () => { it('should render disabled component if the the props are undefined or regions and service type does not have any resources', () => { @@ -39,7 +41,7 @@ describe('CloudPulseResourcesSelect component tests', () => { /> ); expect(getByTestId('resource-select')).toBeInTheDocument(); - expect(screen.getByLabelText('Resources')).toBeInTheDocument(); + expect(screen.getByLabelText(labelText)).toBeInTheDocument(); expect(getByPlaceholderText('Select Resources')).toBeInTheDocument(); }), it('should render resources happy path', () => { @@ -58,7 +60,7 @@ describe('CloudPulseResourcesSelect component tests', () => { /> ); fireEvent.click(screen.getByRole('button', { name: 'Open' })); - expect(screen.getByLabelText('Resources')).toBeInTheDocument(); + expect(screen.getByLabelText(labelText)).toBeInTheDocument(); expect( screen.getByRole('option', { name: 'linode-3', @@ -70,8 +72,7 @@ describe('CloudPulseResourcesSelect component tests', () => { }) ).toBeInTheDocument(); }); - - it('should be able to select all resources', () => { + it('should be able to select all resources if resource selection limit is higher than number of resources', () => { queryMocks.useResourcesQuery.mockReturnValue({ data: linodeFactory.buildList(2), isError: false, @@ -88,7 +89,7 @@ describe('CloudPulseResourcesSelect component tests', () => { ); fireEvent.click(screen.getByRole('button', { name: 'Open' })); fireEvent.click(screen.getByRole('option', { name: SELECT_ALL })); - expect(screen.getByLabelText('Resources')).toBeInTheDocument(); + expect(screen.getByLabelText(labelText)).toBeInTheDocument(); expect( screen.getByRole('option', { name: 'linode-5', @@ -119,7 +120,7 @@ describe('CloudPulseResourcesSelect component tests', () => { fireEvent.click(screen.getByRole('button', { name: 'Open' })); fireEvent.click(screen.getByRole('option', { name: SELECT_ALL })); fireEvent.click(screen.getByRole('option', { name: 'Deselect All' })); - expect(screen.getByLabelText('Resources')).toBeInTheDocument(); + expect(screen.getByLabelText(labelText)).toBeInTheDocument(); expect( screen.getByRole('option', { name: 'linode-7', @@ -150,7 +151,7 @@ describe('CloudPulseResourcesSelect component tests', () => { fireEvent.click(screen.getByRole('button', { name: 'Open' })); fireEvent.click(screen.getByRole('option', { name: 'linode-9' })); fireEvent.click(screen.getByRole('option', { name: 'linode-10' })); - expect(screen.getByLabelText('Resources')).toBeInTheDocument(); + expect(screen.getByLabelText(labelText)).toBeInTheDocument(); expect( screen.getByRole('option', { @@ -252,4 +253,41 @@ describe('CloudPulseResourcesSelect component tests', () => { ); expect(screen.getByText('Failed to fetch Resources.')).toBeInTheDocument(); }); + + it('should be able to select limited resources', () => { + queryMocks.useResourcesQuery.mockReturnValue({ + data: linodeFactory.buildList(12), + isError: false, + isLoading: false, + status: 'success', + }); + + const { queryByRole } = renderWithTheme( + + ); + + fireEvent.click(screen.getByRole('button', { name: 'Open' })); + expect(screen.getByLabelText(labelText)).toBeInTheDocument(); + + for (let i = 14; i <= 23; i++) { + fireEvent.click(screen.getByRole('option', { name: `linode-${i}` })); + } + const selectedOptions = screen + .getAllByRole('option') + .filter((option) => option.getAttribute(ARIA_SELECTED) === 'true'); + + expect(selectedOptions.length).toBe(10); + + expect(screen.getByRole('option', { name: `linode-24` })).toHaveAttribute( + ARIA_DISABLED, + 'true' + ); + + expect(queryByRole('option', { name: SELECT_ALL })).not.toBeInTheDocument(); + }); }); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index ee2ac13dc0d..24104b5d51c 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -1,12 +1,16 @@ +import { Box, ListItem } from '@mui/material'; import React from 'react'; import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; +import { SelectedIcon } from 'src/components/Autocomplete/Autocomplete.styles'; +import { useFlags } from 'src/hooks/useFlags'; import { useResourcesQuery } from 'src/queries/cloudpulse/resources'; import { themes } from 'src/utilities/theme'; import { deepEqual } from '../Utils/FilterBuilder'; import type { Filter, FilterValue } from '@linode/api-v4'; +import type { CloudPulseResourceTypeMapFlag } from 'src/featureFlags'; export interface CloudPulseResources { id: string; @@ -43,6 +47,8 @@ export const CloudPulseResourcesSelect = React.memo( xFilter, } = props; + const flags = useFlags(); + const resourceFilterMap: Record = { dbaas: { '+order': 'asc', '+order_by': 'label', platform: 'rdbms-default' }, }; @@ -77,6 +83,18 @@ export const CloudPulseResourcesSelect = React.memo( return resources && resources.length > 0 ? resources : []; }, [resources]); + const setResourceLimit = React.useMemo(() => { + const obj = flags.aclpResourceTypeMap?.find( + (item: CloudPulseResourceTypeMapFlag) => + item.serviceType === resourceType + ); + return obj ? obj.maxResourceSelections || 10 : 10; + }, [resourceType, flags.aclpResourceTypeMap]); + + const resourceLimitReached = React.useMemo(() => { + return getResourcesList.length > setResourceLimit; + }, [getResourcesList.length, setResourceLimit]); + // Once the data is loaded, set the state variable with value stored in preferences React.useEffect(() => { if (resources && savePreferences && !selectedResources) { @@ -119,6 +137,29 @@ export const CloudPulseResourcesSelect = React.memo( placeholder={ selectedResources?.length ? '' : placeholder || 'Select Resources' } + renderOption={(props, option) => { + const { key, ...rest } = props; + const isResourceSelected = selectedResources?.some( + (item) => item.label === option.label + ); + const isOverLimitOption = + selectedResources && + selectedResources?.length >= setResourceLimit && + !isResourceSelected; + return ( + + <> + {option.label} + + + + ); + }} textFieldProps={{ InputProps: { sx: { @@ -133,10 +174,11 @@ export const CloudPulseResourcesSelect = React.memo( autoHighlight clearOnBlur data-testid="resource-select" + disableSelectAll={resourceLimitReached} disabled={disabled} errorText={isError ? `Failed to fetch ${label || 'Resources'}.` : ''} isOptionEqualToValue={(option, value) => option.id === value.id} - label={label || 'Resources'} + label={`${label || 'Resources'} (${setResourceLimit} max)`} limitTags={2} loading={isLoading} multiple From 8215e7c7cc992dfbcb131318d34522cf4426b003 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Tue, 5 Nov 2024 17:27:19 +0530 Subject: [PATCH 297/474] upcoming: [DI-20934] - PR comments --- .../shared/CloudPulseResourcesSelect.test.tsx | 14 +++++++------- .../shared/CloudPulseResourcesSelect.tsx | 15 +++++++++------ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx index 6f05af09315..fa32a97071d 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx @@ -22,7 +22,6 @@ const mockResourceHandler = vi.fn(); const SELECT_ALL = 'Select All'; const ARIA_SELECTED = 'aria-selected'; const ARIA_DISABLED = 'aria-disabled'; -const labelText = 'Resources (10 max)'; describe('CloudPulseResourcesSelect component tests', () => { it('should render disabled component if the the props are undefined or regions and service type does not have any resources', () => { @@ -41,7 +40,7 @@ describe('CloudPulseResourcesSelect component tests', () => { /> ); expect(getByTestId('resource-select')).toBeInTheDocument(); - expect(screen.getByLabelText(labelText)).toBeInTheDocument(); + expect(screen.getByLabelText('Resources')).toBeInTheDocument(); expect(getByPlaceholderText('Select Resources')).toBeInTheDocument(); }), it('should render resources happy path', () => { @@ -60,7 +59,7 @@ describe('CloudPulseResourcesSelect component tests', () => { /> ); fireEvent.click(screen.getByRole('button', { name: 'Open' })); - expect(screen.getByLabelText(labelText)).toBeInTheDocument(); + expect(screen.getByLabelText('Resources')).toBeInTheDocument(); expect( screen.getByRole('option', { name: 'linode-3', @@ -89,7 +88,7 @@ describe('CloudPulseResourcesSelect component tests', () => { ); fireEvent.click(screen.getByRole('button', { name: 'Open' })); fireEvent.click(screen.getByRole('option', { name: SELECT_ALL })); - expect(screen.getByLabelText(labelText)).toBeInTheDocument(); + expect(screen.getByLabelText('Resources')).toBeInTheDocument(); expect( screen.getByRole('option', { name: 'linode-5', @@ -120,7 +119,7 @@ describe('CloudPulseResourcesSelect component tests', () => { fireEvent.click(screen.getByRole('button', { name: 'Open' })); fireEvent.click(screen.getByRole('option', { name: SELECT_ALL })); fireEvent.click(screen.getByRole('option', { name: 'Deselect All' })); - expect(screen.getByLabelText(labelText)).toBeInTheDocument(); + expect(screen.getByLabelText('Resources')).toBeInTheDocument(); expect( screen.getByRole('option', { name: 'linode-7', @@ -151,7 +150,7 @@ describe('CloudPulseResourcesSelect component tests', () => { fireEvent.click(screen.getByRole('button', { name: 'Open' })); fireEvent.click(screen.getByRole('option', { name: 'linode-9' })); fireEvent.click(screen.getByRole('option', { name: 'linode-10' })); - expect(screen.getByLabelText(labelText)).toBeInTheDocument(); + expect(screen.getByLabelText('Resources')).toBeInTheDocument(); expect( screen.getByRole('option', { @@ -272,7 +271,8 @@ describe('CloudPulseResourcesSelect component tests', () => { ); fireEvent.click(screen.getByRole('button', { name: 'Open' })); - expect(screen.getByLabelText(labelText)).toBeInTheDocument(); + expect(screen.getByLabelText('Resources')).toBeInTheDocument(); + expect(screen.getByText('Select up to 10 Resources')).toBeInTheDocument(); for (let i = 14; i <= 23; i++) { fireEvent.click(screen.getByRole('option', { name: `linode-${i}` })); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index 24104b5d51c..a3f55d973de 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -83,7 +83,8 @@ export const CloudPulseResourcesSelect = React.memo( return resources && resources.length > 0 ? resources : []; }, [resources]); - const setResourceLimit = React.useMemo(() => { + // Maximum resource selection limit is fetched from launchdarkly + const ResourceLimit = React.useMemo(() => { const obj = flags.aclpResourceTypeMap?.find( (item: CloudPulseResourceTypeMapFlag) => item.serviceType === resourceType @@ -92,8 +93,8 @@ export const CloudPulseResourcesSelect = React.memo( }, [resourceType, flags.aclpResourceTypeMap]); const resourceLimitReached = React.useMemo(() => { - return getResourcesList.length > setResourceLimit; - }, [getResourcesList.length, setResourceLimit]); + return getResourcesList.length > ResourceLimit; + }, [getResourcesList.length, ResourceLimit]); // Once the data is loaded, set the state variable with value stored in preferences React.useEffect(() => { @@ -138,13 +139,14 @@ export const CloudPulseResourcesSelect = React.memo( selectedResources?.length ? '' : placeholder || 'Select Resources' } renderOption={(props, option) => { + // After selecting resources up to the max resource selection limit, rest of the unselected options will be disabled if there are any const { key, ...rest } = props; const isResourceSelected = selectedResources?.some( (item) => item.label === option.label ); const isOverLimitOption = selectedResources && - selectedResources?.length >= setResourceLimit && + selectedResources.length >= ResourceLimit && !isResourceSelected; return ( option.id === value.id} - label={`${label || 'Resources'} (${setResourceLimit} max)`} + label={label || 'Resources'} limitTags={2} loading={isLoading} multiple From 7383cdcfddaf96c3ea297e67682ab27b24b9a0ee Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Wed, 6 Nov 2024 21:40:19 +0530 Subject: [PATCH 298/474] upcoming: [DI-20934] - Small fix --- .../features/CloudPulse/shared/CloudPulseResourcesSelect.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index a3f55d973de..a8a06e5b9ad 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -179,7 +179,7 @@ export const CloudPulseResourcesSelect = React.memo( disableSelectAll={resourceLimitReached} // Select_All option will not be available if number of resources are higher than resource selection limit disabled={disabled} errorText={isError ? `Failed to fetch ${label || 'Resources'}.` : ''} - helperText={`Select up to ${ResourceLimit} ${label}`} + helperText={!isError ? `Select up to ${ResourceLimit} ${label}` : ''} isOptionEqualToValue={(option, value) => option.id === value.id} label={label || 'Resources'} limitTags={2} From 425dcf8e894232f2fa32006dedb8fe30380642ca Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Mon, 11 Nov 2024 17:42:31 +0530 Subject: [PATCH 299/474] upcoming: [DI-20934] - Added sorting of resources --- .../shared/CloudPulseResourcesSelect.test.tsx | 4 ++-- .../shared/CloudPulseResourcesSelect.tsx | 24 +++++++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx index fa32a97071d..3e670c30889 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx @@ -252,7 +252,7 @@ describe('CloudPulseResourcesSelect component tests', () => { ); expect(screen.getByText('Failed to fetch Resources.')).toBeInTheDocument(); }); - + it('should be able to select limited resources', () => { queryMocks.useResourcesQuery.mockReturnValue({ data: linodeFactory.buildList(12), @@ -282,7 +282,7 @@ describe('CloudPulseResourcesSelect component tests', () => { .filter((option) => option.getAttribute(ARIA_SELECTED) === 'true'); expect(selectedOptions.length).toBe(10); - + expect(selectedOptions[0].textContent).toBe('linode-14'); expect(screen.getByRole('option', { name: `linode-24` })).toHaveAttribute( ARIA_DISABLED, 'true' diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index a8a06e5b9ad..5a3249f41b2 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -95,7 +95,7 @@ export const CloudPulseResourcesSelect = React.memo( const resourceLimitReached = React.useMemo(() => { return getResourcesList.length > ResourceLimit; }, [getResourcesList.length, ResourceLimit]); - + // Once the data is loaded, set the state variable with value stored in preferences React.useEffect(() => { if (resources && savePreferences && !selectedResources) { @@ -119,6 +119,26 @@ export const CloudPulseResourcesSelect = React.memo( // eslint-disable-next-line react-hooks/exhaustive-deps }, [resources, region, xFilter, resourceType]); + // selected resources will appear at the top in the autcomplete popper + const sortedResourcesList = React.useMemo(() => { + return [...getResourcesList].sort((resource_a, resource_b) => { + const aIsSelected = selectedResources?.some( + (item) => item.label === resource_a.label + ); + const bIsSelected = selectedResources?.some( + (item) => item.label === resource_b.label + ); + + if (aIsSelected && !bIsSelected) { + return -1; + } + if (!aIsSelected && bIsSelected) { + return 1; + } + return 0; + }); + }, [getResourcesList, selectedResources]); + return ( { @@ -186,7 +206,7 @@ export const CloudPulseResourcesSelect = React.memo( loading={isLoading} multiple noMarginTop - options={getResourcesList} + options={sortedResourcesList} value={selectedResources ?? []} /> ); From 1edc4a68ee571997902463e71a9fbcacf8caeffb Mon Sep 17 00:00:00 2001 From: vmangalr Date: Tue, 12 Nov 2024 10:14:38 +0530 Subject: [PATCH 300/474] upcoming: [DI-21811] - fix eslint issues --- .../DatabaseDetail/DatabaseMonitor/DatabaseMonitor.tsx | 4 +++- .../src/features/Databases/DatabaseDetail/index.tsx | 9 +-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseMonitor/DatabaseMonitor.tsx b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseMonitor/DatabaseMonitor.tsx index 5a255785977..7f696fc2d0b 100644 --- a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseMonitor/DatabaseMonitor.tsx +++ b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseMonitor/DatabaseMonitor.tsx @@ -1,6 +1,8 @@ import * as React from 'react'; + import { CloudPulseDashboardWithFilters } from 'src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters'; -import { Database } from '@linode/api-v4'; + +import type { Database } from '@linode/api-v4'; interface Props { database: Database; diff --git a/packages/manager/src/features/Databases/DatabaseDetail/index.tsx b/packages/manager/src/features/Databases/DatabaseDetail/index.tsx index 54fe9ce94fe..3d32a14db6c 100644 --- a/packages/manager/src/features/Databases/DatabaseDetail/index.tsx +++ b/packages/manager/src/features/Databases/DatabaseDetail/index.tsx @@ -23,8 +23,6 @@ import { } from 'src/queries/databases/databases'; import { getAPIErrorOrDefault } from 'src/utilities/errorUtils'; -import { useIsDatabasesEnabled } from '../utilities'; - import type { Engine } from '@linode/api-v4/lib/databases/types'; import type { APIError } from '@linode/api-v4/lib/types'; import type { Tab } from 'src/components/Tabs/TabLinkList'; @@ -74,11 +72,6 @@ export const DatabaseDetail = () => { setEditableLabelError, } = useEditableLabelState(); - const { - isDatabasesMonitorBeta, - isDatabasesMonitorEnabled, - } = useIsDatabasesEnabled(); - if (error) { return ( { if (isMonitorEnabled) { tabs.splice(1, 0, { - chip: (isDatabasesMonitorBeta || true) ? : null, + chip: , routeName: `/databases/${engine}/${id}/monitor`, title: 'Monitor', }); From f1ec8e5b06a0552fb4296255593205a0d7d93c78 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Tue, 12 Nov 2024 14:51:07 +0530 Subject: [PATCH 301/474] upcoming: [DI-20934] - PR comments --- .../shared/CloudPulseResourcesSelect.tsx | 51 ++++++++++--------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index 5a3249f41b2..5859ffee3f1 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -84,7 +84,7 @@ export const CloudPulseResourcesSelect = React.memo( }, [resources]); // Maximum resource selection limit is fetched from launchdarkly - const ResourceLimit = React.useMemo(() => { + const maxResourceSelectionLimit = React.useMemo(() => { const obj = flags.aclpResourceTypeMap?.find( (item: CloudPulseResourceTypeMapFlag) => item.serviceType === resourceType @@ -92,10 +92,10 @@ export const CloudPulseResourcesSelect = React.memo( return obj ? obj.maxResourceSelections || 10 : 10; }, [resourceType, flags.aclpResourceTypeMap]); - const resourceLimitReached = React.useMemo(() => { - return getResourcesList.length > ResourceLimit; - }, [getResourcesList.length, ResourceLimit]); - + const isMaxSelectionsReached = React.useMemo(() => { + return getResourcesList.length > maxResourceSelectionLimit; + }, [getResourcesList.length, maxResourceSelectionLimit]); + // Once the data is loaded, set the state variable with value stored in preferences React.useEffect(() => { if (resources && savePreferences && !selectedResources) { @@ -120,23 +120,22 @@ export const CloudPulseResourcesSelect = React.memo( }, [resources, region, xFilter, resourceType]); // selected resources will appear at the top in the autcomplete popper - const sortedResourcesList = React.useMemo(() => { - return [...getResourcesList].sort((resource_a, resource_b) => { - const aIsSelected = selectedResources?.some( - (item) => item.label === resource_a.label - ); - const bIsSelected = selectedResources?.some( - (item) => item.label === resource_b.label - ); + const resourcesWithSelectedFirst = React.useMemo< + CloudPulseResources[] + >(() => { + const selectedResourcesSet = new Set( + selectedResources?.map((item) => item.label) + ); - if (aIsSelected && !bIsSelected) { - return -1; - } - if (!aIsSelected && bIsSelected) { - return 1; - } - return 0; - }); + const selectedResourcesList = getResourcesList.filter((resource) => + selectedResourcesSet.has(resource.label) + ); + + const unselectedResourcesList = getResourcesList.filter( + (resource) => !selectedResourcesSet.has(resource.label) + ); + + return [...selectedResourcesList, ...unselectedResourcesList]; }, [getResourcesList, selectedResources]); return ( @@ -166,7 +165,7 @@ export const CloudPulseResourcesSelect = React.memo( ); const isOverLimitOption = selectedResources && - selectedResources.length >= ResourceLimit && + selectedResources.length >= maxResourceSelectionLimit && !isResourceSelected; return ( option.id === value.id} label={label || 'Resources'} limitTags={2} loading={isLoading} multiple noMarginTop - options={sortedResourcesList} + options={resourcesWithSelectedFirst} value={selectedResources ?? []} /> ); From b8113b3502f6a83b2429e5297e4a0d1adc9dc385 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Tue, 12 Nov 2024 17:37:56 +0530 Subject: [PATCH 302/474] upcoming: [DI-21200] - updated height of chart & legend rows --- .../manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx | 2 +- .../CloudPulse/Widget/components/CloudPulseLineGraph.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 32fb31ad7a7..8e97cb21fe7 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -331,7 +331,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { areas={areas} ariaLabel={ariaLabel ? ariaLabel : ''} data={data} - height={480} + height={424} legendRows={legendRows} loading={isLoading || metricsApiCallError === jweTokenExpiryError} // keep loading until we fetch the refresh token showLegend={data.length !== 0} diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index eca82bb09ca..872cf84d46f 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -42,7 +42,7 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { {...rest} connectNulls fillOpacity={0.5} - legendHeight={theme.spacing(18.75)} + legendHeight={theme.spacing(16)} /> )} {rest.data.length === 0 && ( From ce545093fd14151e4e7ab410535ab8419316dc52 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Wed, 13 Nov 2024 11:24:40 +0530 Subject: [PATCH 303/474] upcoming: [DI-20934] - PR comments --- .../shared/CloudPulseResourcesSelect.test.tsx | 1 - .../shared/CloudPulseResourcesSelect.tsx | 27 +++---------------- 2 files changed, 3 insertions(+), 25 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx index 3e670c30889..7c20da6c349 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx @@ -282,7 +282,6 @@ describe('CloudPulseResourcesSelect component tests', () => { .filter((option) => option.getAttribute(ARIA_SELECTED) === 'true'); expect(selectedOptions.length).toBe(10); - expect(selectedOptions[0].textContent).toBe('linode-14'); expect(screen.getByRole('option', { name: `linode-24` })).toHaveAttribute( ARIA_DISABLED, 'true' diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index 5859ffee3f1..670f5018864 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -10,7 +10,6 @@ import { themes } from 'src/utilities/theme'; import { deepEqual } from '../Utils/FilterBuilder'; import type { Filter, FilterValue } from '@linode/api-v4'; -import type { CloudPulseResourceTypeMapFlag } from 'src/featureFlags'; export interface CloudPulseResources { id: string; @@ -86,10 +85,9 @@ export const CloudPulseResourcesSelect = React.memo( // Maximum resource selection limit is fetched from launchdarkly const maxResourceSelectionLimit = React.useMemo(() => { const obj = flags.aclpResourceTypeMap?.find( - (item: CloudPulseResourceTypeMapFlag) => - item.serviceType === resourceType + (item) => item.serviceType === resourceType ); - return obj ? obj.maxResourceSelections || 10 : 10; + return obj?.maxResourceSelections || 10; }, [resourceType, flags.aclpResourceTypeMap]); const isMaxSelectionsReached = React.useMemo(() => { @@ -119,25 +117,6 @@ export const CloudPulseResourcesSelect = React.memo( // eslint-disable-next-line react-hooks/exhaustive-deps }, [resources, region, xFilter, resourceType]); - // selected resources will appear at the top in the autcomplete popper - const resourcesWithSelectedFirst = React.useMemo< - CloudPulseResources[] - >(() => { - const selectedResourcesSet = new Set( - selectedResources?.map((item) => item.label) - ); - - const selectedResourcesList = getResourcesList.filter((resource) => - selectedResourcesSet.has(resource.label) - ); - - const unselectedResourcesList = getResourcesList.filter( - (resource) => !selectedResourcesSet.has(resource.label) - ); - - return [...selectedResourcesList, ...unselectedResourcesList]; - }, [getResourcesList, selectedResources]); - return ( { @@ -207,7 +186,7 @@ export const CloudPulseResourcesSelect = React.memo( loading={isLoading} multiple noMarginTop - options={resourcesWithSelectedFirst} + options={getResourcesList} value={selectedResources ?? []} /> ); From 8adc17151342f3086baac2efcfb38847908c6f0a Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Wed, 13 Nov 2024 11:44:58 +0530 Subject: [PATCH 304/474] upcoming: [DI-20934] - small fix --- .../CloudPulse/shared/CloudPulseResourcesSelect.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index 670f5018864..b06ab9d9888 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -90,7 +90,7 @@ export const CloudPulseResourcesSelect = React.memo( return obj?.maxResourceSelections || 10; }, [resourceType, flags.aclpResourceTypeMap]); - const isMaxSelectionsReached = React.useMemo(() => { + const resourcesLimitReached = React.useMemo(() => { return getResourcesList.length > maxResourceSelectionLimit; }, [getResourcesList.length, maxResourceSelectionLimit]); @@ -142,14 +142,14 @@ export const CloudPulseResourcesSelect = React.memo( const isResourceSelected = selectedResources?.some( (item) => item.label === option.label ); - const isOverLimitOption = + const isMaxSelectionsReached = selectedResources && selectedResources.length >= maxResourceSelectionLimit && !isResourceSelected; return ( @@ -174,7 +174,7 @@ export const CloudPulseResourcesSelect = React.memo( autoHighlight clearOnBlur data-testid="resource-select" - disableSelectAll={isMaxSelectionsReached} // Select_All option will not be available if number of resources are higher than resource selection limit + disableSelectAll={resourcesLimitReached} // Select_All option will not be available if number of resources are higher than resource selection limit disabled={disabled} errorText={isError ? `Failed to fetch ${label || 'Resources'}.` : ''} helperText={ From effca0460c0308e6420e2613577447902b973bf2 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 13 Nov 2024 12:11:20 +0530 Subject: [PATCH 305/474] upcoming: [DI-21200] - Updated no data display positioning --- packages/manager/src/features/CloudPulse/Utils/utils.ts | 2 +- .../CloudPulse/Widget/components/CloudPulseLineGraph.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/utils.ts b/packages/manager/src/features/CloudPulse/Utils/utils.ts index 7c168f4e487..351d82f884a 100644 --- a/packages/manager/src/features/CloudPulse/Utils/utils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/utils.ts @@ -108,7 +108,7 @@ export const seriesDataFormatter = ( const formattedArray: StatWithDummyPoint[] = data.map(([x, y]) => ({ x: Number(x), - y: y ? Number(y) : null, + y: y != null ? Number(y) : null, })); return convertData(formattedArray, startTime, endTime); diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index 872cf84d46f..67465f86d43 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -48,8 +48,8 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { {rest.data.length === 0 && ( From cdbfa0e6897e2e3a339b3184773da875640a18cf Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Tue, 12 Nov 2024 17:37:56 +0530 Subject: [PATCH 306/474] upcoming: [DI-21200] - updated height of chart & legend rows --- .../manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx | 2 +- .../CloudPulse/Widget/components/CloudPulseLineGraph.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 7e875ae38f6..48c963fdb38 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -331,7 +331,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { areas={areas} ariaLabel={ariaLabel ? ariaLabel : ''} data={data} - height={480} + height={424} legendRows={legendRows} loading={isLoading || metricsApiCallError === jweTokenExpiryError} // keep loading until we fetch the refresh token showLegend={data.length !== 0} diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index d16e64cde7a..7e7a7decf10 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -38,7 +38,7 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { {...rest} connectNulls fillOpacity={0.5} - legendHeight={theme.spacing(18.75)} + legendHeight={theme.spacing(16)} /> )} {rest.data.length === 0 && ( From 573ba860adf7fa67c67fcca2fdf21bfd9982ea49 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 13 Nov 2024 12:11:20 +0530 Subject: [PATCH 307/474] upcoming: [DI-21200] - Updated no data display positioning --- packages/manager/src/features/CloudPulse/Utils/utils.ts | 2 +- .../CloudPulse/Widget/components/CloudPulseLineGraph.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/utils.ts b/packages/manager/src/features/CloudPulse/Utils/utils.ts index 7c168f4e487..351d82f884a 100644 --- a/packages/manager/src/features/CloudPulse/Utils/utils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/utils.ts @@ -108,7 +108,7 @@ export const seriesDataFormatter = ( const formattedArray: StatWithDummyPoint[] = data.map(([x, y]) => ({ x: Number(x), - y: y ? Number(y) : null, + y: y != null ? Number(y) : null, })); return convertData(formattedArray, startTime, endTime); diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index 7e7a7decf10..bc1ce6c215c 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -44,8 +44,8 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { {rest.data.length === 0 && ( From 3be4e12c555e2dc07106fe87a42d7c5af83440bf Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Wed, 13 Nov 2024 15:35:49 +0530 Subject: [PATCH 308/474] upcoming: [DI-21867] - Resources selection tag limit --- .../features/CloudPulse/shared/CloudPulseResourcesSelect.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index b06ab9d9888..8137590ea25 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -182,7 +182,7 @@ export const CloudPulseResourcesSelect = React.memo( } isOptionEqualToValue={(option, value) => option.id === value.id} label={label || 'Resources'} - limitTags={2} + limitTags={1} loading={isLoading} multiple noMarginTop From de10d794ef3210d6ee7a5f25f50e356cae672657 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 13 Nov 2024 17:02:20 +0530 Subject: [PATCH 309/474] upcoming: [DI-21841] - Removed connect nulls --- .../CloudPulse/Widget/components/CloudPulseLineGraph.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index 67465f86d43..6e9adff4464 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -40,7 +40,6 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { ) : ( From a9fce139d28b70cb0739ba6a7dba02bb3bd35a92 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 13 Nov 2024 17:02:20 +0530 Subject: [PATCH 310/474] upcoming: [DI-21841] - Removed connect nulls --- .../CloudPulse/Widget/components/CloudPulseLineGraph.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index bc1ce6c215c..1325073328e 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -36,7 +36,6 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { ) : ( From dbaa8290770bbea3bf8774536b64ab67960d4e92 Mon Sep 17 00:00:00 2001 From: agorthi Date: Wed, 6 Nov 2024 15:14:33 +0530 Subject: [PATCH 311/474] [DI-21597]-Automating and testing the migration of Recharts --- .../dbaas-widgets-verification.spec.ts | 180 +++++++++--------- .../linode-widget-verification.spec.ts | 180 ++++++++++-------- .../src/components/AreaChart/AreaChart.tsx | 4 +- .../components/LineGraph/MetricsDisplay.tsx | 5 +- 4 files changed, 196 insertions(+), 173 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts index d1f1181337d..313b394b1e9 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts @@ -29,11 +29,12 @@ import { mockGetUserPreferences } from 'support/intercepts/profile'; import { mockGetRegions } from 'support/intercepts/regions'; import { extendRegion } from 'support/util/regions'; import { CloudPulseMetricsResponse, Database } from '@linode/api-v4'; -import { transformData } from 'src/features/CloudPulse/Utils/unitConversion'; -import { getMetrics } from 'src/utilities/statMetrics'; import { Interception } from 'cypress/types/net-stubbing'; import { generateRandomMetricsData } from 'support/util/cloudpulse'; import { mockGetDatabases } from 'support/intercepts/databases'; +import { generateGraphData } from 'src/features/CloudPulse/Utils/CloudPulseWidgetUtils'; +import type { Flags } from 'src/featureFlags'; +import { formatToolTip } from 'src/features/CloudPulse/Utils/unitConversion'; /** * This test ensures that widget titles are displayed correctly on the dashboard. @@ -101,28 +102,50 @@ const metricsAPIResponsePayload = cloudPulseMetricsResponseFactory.build({ }); /** - * Verifies the presence and values of specific properties within the aclpPreference object - * of the request payload. This function checks that the expected properties exist - * and have the expected values, allowing for validation of user preferences in the application. + * Generates graph data from a given CloudPulse metrics response and + * extracts average, last, and maximum metric values from the first + * legend row. The values are rounded to two decimal places for + * better readability. + * + * @param responsePayload - The metrics response object containing + * the necessary data for graph generation. + * @param label - The label for the graph, used for display purposes. + * + * @returns An object containing rounded values for max average, last, * - * @param requestPayload - The payload received from the request, containing the aclpPreference object. - * @param expectedValues - An object containing the expected values for properties to validate against the requestPayload. - * Expected properties may include: - * - dashboardId: The ID of the dashboard. - * - timeDuration: The selected time duration for metrics. - * - engine: The database engine used. - * - region: The selected region for the dashboard. - * - resources: An array of resource identifiers. - * - role: The role associated with the dashboard user. */ + const getWidgetLegendRowValuesFromResponse = ( - responsePayload: CloudPulseMetricsResponse + responsePayload: CloudPulseMetricsResponse, + label: string, + unit: string ) => { - const data = transformData(responsePayload.data.result[0].values, 'Bytes'); - const { average, last, max } = getMetrics(data); - const roundedAverage = Math.round(average * 100) / 100; - const roundedLast = Math.round(last * 100) / 100; - const roundedMax = Math.round(max * 100) / 100; + // Generate graph data using the provided parameters + const graphData = generateGraphData({ + flags: { enabled: true } as Partial, + label: label, + metricsList: responsePayload, + resources: [ + { + id: '1', + label: clusterName, + region: 'us-ord', + }, + ], + serviceType: serviceType, + status: 'success', + unit: unit, + // widgetColor: 'red', + }); + + // Destructure metrics data from the first legend row + const { average, last, max } = graphData.legendRowsData[0].data; + + // Round the metrics values to two decimal places + const roundedAverage = formatToolTip(average, unit); + const roundedLast = formatToolTip(last, unit); + const roundedMax = formatToolTip(max, unit); + // Return the rounded values in an object return { average: roundedAverage, last: roundedLast, max: roundedMax }; }; @@ -250,33 +273,28 @@ describe('Integration Tests for DBaaS Dashboard ', () => { }); //validate the widget linegrah is present - cy.findByTestId('linegraph-wrapper').within(() => { + cy.findByTestId('areachart-wrapper').within(() => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( - metricsAPIResponsePayload - ); - cy.findByText(`${testData.title} (${testData.unit})`).should( - 'be.visible' + metricsAPIResponsePayload, + testData.title, + testData.unit ); + const graphRowTitle = `[data-qa-graph-row-title="${testData.title} (${testData.unit})"]`; + cy.get(graphRowTitle) + .should('be.visible') + .should('have.text', `${testData.title} (${testData.unit})`); + cy.get(`[data-qa-graph-column-title="Max"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.max} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.max}`); cy.get(`[data-qa-graph-column-title="Avg"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.average} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.average}`); cy.get(`[data-qa-graph-column-title="Last"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.last} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.last}`); }); }); }); @@ -309,33 +327,28 @@ describe('Integration Tests for DBaaS Dashboard ', () => { }); //validate the widget linegrah is present - cy.findByTestId('linegraph-wrapper').within(() => { + cy.findByTestId('areachart-wrapper').within(() => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( - metricsAPIResponsePayload - ); - cy.findByText(`${testData.title} (${testData.unit})`).should( - 'be.visible' + metricsAPIResponsePayload, + testData.title, + testData.unit ); + const graphRowTitle = `[data-qa-graph-row-title="${testData.title} (${testData.unit})"]`; + cy.get(graphRowTitle) + .should('be.visible') + .should('have.text', `${testData.title} (${testData.unit})`); + cy.get(`[data-qa-graph-column-title="Max"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.max} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.max}`); cy.get(`[data-qa-graph-column-title="Avg"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.average} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.average}`); cy.get(`[data-qa-graph-column-title="Last"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.last} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.last}`); }); }); }); @@ -384,33 +397,29 @@ describe('Integration Tests for DBaaS Dashboard ', () => { .should('be.enabled') .click(); cy.get('@widget').should('be.visible'); - cy.findByTestId('linegraph-wrapper').within(() => { + + cy.findByTestId('areachart-wrapper').within(() => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( - metricsAPIResponsePayload - ); - cy.findByText(`${testData.title} (${testData.unit})`).should( - 'be.visible' + metricsAPIResponsePayload, + testData.title, + testData.unit ); + const graphRowTitle = `[data-qa-graph-row-title="${testData.title} (${testData.unit})"]`; + cy.get(graphRowTitle) + .should('be.visible') + .should('have.text', `${testData.title} (${testData.unit})`); + cy.get(`[data-qa-graph-column-title="Max"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.max} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.max}`); cy.get(`[data-qa-graph-column-title="Avg"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.average} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.average}`); cy.get(`[data-qa-graph-column-title="Last"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.last} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.last}`); }); // click zoom out and validate the same @@ -421,33 +430,28 @@ describe('Integration Tests for DBaaS Dashboard ', () => { .scrollIntoView() .click({ force: true }); cy.get('@widget').should('be.visible'); - cy.findByTestId('linegraph-wrapper').within(() => { + cy.findByTestId('areachart-wrapper').within(() => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( - metricsAPIResponsePayload - ); - cy.findByText(`${testData.title} (${testData.unit})`).should( - 'be.visible' + metricsAPIResponsePayload, + testData.title, + testData.unit ); + const graphRowTitle = `[data-qa-graph-row-title="${testData.title} (${testData.unit})"]`; + cy.get(graphRowTitle) + .should('be.visible') + .should('have.text', `${testData.title} (${testData.unit})`); + cy.get(`[data-qa-graph-column-title="Max"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.max} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.max}`); cy.get(`[data-qa-graph-column-title="Avg"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.average} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.average}`); cy.get(`[data-qa-graph-column-title="Last"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.last} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.last}`); }); }); }); diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index b0620e4148e..3fca58d1d5b 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -28,10 +28,11 @@ import { mockGetUserPreferences } from 'support/intercepts/profile'; import { mockGetRegions } from 'support/intercepts/regions'; import { extendRegion } from 'support/util/regions'; import { CloudPulseMetricsResponse } from '@linode/api-v4'; -import { transformData } from 'src/features/CloudPulse/Utils/unitConversion'; -import { getMetrics } from 'src/utilities/statMetrics'; import { generateRandomMetricsData } from 'support/util/cloudpulse'; import { Interception } from 'cypress/types/net-stubbing'; +import { generateGraphData } from 'src/features/CloudPulse/Utils/CloudPulseWidgetUtils'; +import { Flags } from 'src/featureFlags'; +import { formatToolTip } from 'src/features/CloudPulse/Utils/unitConversion'; /** * This test ensures that widget titles are displayed correctly on the dashboard. @@ -97,25 +98,49 @@ const metricsAPIResponsePayload = cloudPulseMetricsResponseFactory.build({ }); /** - * `verifyWidgetValues` processes and verifies the metric values of a widget from the provided response payload. + * Generates graph data from a given CloudPulse metrics response and + * extracts average, last, and maximum metric values from the first + * legend row. The values are rounded to two decimal places for + * better readability. * - * This method performs the following steps: - * 1. Transforms the raw data from the response payload into a more manageable format using `transformData`. - * 2. Extracts key metrics (average, last, and max) from the transformed data using `getMetrics`. - * 3. Rounds these metrics to two decimal places for accuracy. - * 4. Returns an object containing the rounded average, last, and max values for further verification or comparison. + * @param responsePayload - The metrics response object containing + * the necessary data for graph generation. + * @param label - The label for the graph, used for display purposes. + * + * @returns An object containing rounded values for average, last, * - * @param {CloudPulseMetricsResponse} responsePayload - The response payload containing metric data for a widget. - * @returns {Object} An object with the rounded average, last, and max metric values. */ + const getWidgetLegendRowValuesFromResponse = ( - responsePayload: CloudPulseMetricsResponse + responsePayload: CloudPulseMetricsResponse, + label: string, + unit: string ) => { - const data = transformData(responsePayload.data.result[0].values, 'Bytes'); - const { average, last, max } = getMetrics(data); - const roundedAverage = Math.round(average * 100) / 100; - const roundedLast = Math.round(last * 100) / 100; - const roundedMax = Math.round(max * 100) / 100; + // Generate graph data using the provided parameters + const graphData = generateGraphData({ + flags: { enabled: true } as Partial, + label: label, + metricsList: responsePayload, + resources: [ + { + id: '1', + label: resource, + region: 'us-ord', + }, + ], + serviceType: serviceType, + status: 'success', + unit: unit, + }); + + // Destructure metrics data from the first legend row + const { average, last, max } = graphData.legendRowsData[0].data; + + // Round the metrics values to two decimal places + const roundedAverage = formatToolTip(average, unit); + const roundedLast = formatToolTip(last, unit); + const roundedMax = formatToolTip(max, unit); + // Return the rounded values in an object return { average: roundedAverage, last: roundedLast, max: roundedMax }; }; @@ -214,34 +239,32 @@ describe('Integration Tests for Linode Dashboard ', () => { ); }); - //validate the widget linegrah is present - cy.findByTestId('linegraph-wrapper').within(() => { + //validate the widget areachart is present + cy.findByTestId('areachart-wrapper').within(() => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( - metricsAPIResponsePayload - ); - cy.findByText(`${testData.title} (${testData.unit})`).should( - 'be.visible' + metricsAPIResponsePayload, + testData.title, + testData.unit ); + + const graphRowTitle = `[data-qa-graph-row-title="${testData.title} (${testData.unit})"]`; + cy.get(graphRowTitle) + .should('be.visible') + .should('have.text', `${testData.title} (${testData.unit})`); + + cy.log('expectedWidgetValues ', expectedWidgetValues.max); + cy.get(`[data-qa-graph-column-title="Max"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.max} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.max}`); cy.get(`[data-qa-graph-column-title="Avg"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.average} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.average}`); cy.get(`[data-qa-graph-column-title="Last"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.last} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.last}`); }); }); }); @@ -273,34 +296,32 @@ describe('Integration Tests for Linode Dashboard ', () => { ); }); - //validate the widget linegrah is present - cy.findByTestId('linegraph-wrapper').within(() => { + //validate the widget areachart is present + cy.findByTestId('areachart-wrapper').within(() => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( - metricsAPIResponsePayload - ); - cy.findByText(`${testData.title} (${testData.unit})`).should( - 'be.visible' + metricsAPIResponsePayload, + testData.title, + testData.unit ); - cy.get(`[data-qa-graph-column-title="Max"]`) + const graphRowTitle = `[data-qa-graph-row-title="${testData.title} (${testData.unit})"]`; + cy.get(graphRowTitle) .should('be.visible') .should( 'have.text', - `${expectedWidgetValues.max} ${testData.unit}` + `${testData.title} (${testData.unit.trim()})` ); + cy.get(`[data-qa-graph-column-title="Max"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.max}`); + cy.get(`[data-qa-graph-column-title="Avg"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.average} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.average}`); cy.get(`[data-qa-graph-column-title="Last"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.last} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.last}`); }); }); }); @@ -349,33 +370,28 @@ describe('Integration Tests for Linode Dashboard ', () => { .should('be.enabled') .click(); cy.get('@widget').should('be.visible'); - cy.findByTestId('linegraph-wrapper').within(() => { + cy.findByTestId('areachart-wrapper').within(() => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( - metricsAPIResponsePayload - ); - cy.findByText(`${testData.title} (${testData.unit})`).should( - 'be.visible' + metricsAPIResponsePayload, + testData.title, + testData.unit ); + const graphRowTitle = `[data-qa-graph-row-title="${testData.title} (${testData.unit})"]`; + cy.get(graphRowTitle) + .should('be.visible') + .should('have.text', `${testData.title} (${testData.unit})`); + cy.get(`[data-qa-graph-column-title="Max"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.max} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.max}`); cy.get(`[data-qa-graph-column-title="Avg"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.average} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.average}`); cy.get(`[data-qa-graph-column-title="Last"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.last} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.last}`); }); // click zoom out and validate the same @@ -386,33 +402,33 @@ describe('Integration Tests for Linode Dashboard ', () => { .scrollIntoView() .click({ force: true }); cy.get('@widget').should('be.visible'); - cy.findByTestId('linegraph-wrapper').within(() => { + + cy.findByTestId('areachart-wrapper').within(() => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( - metricsAPIResponsePayload - ); - cy.findByText(`${testData.title} (${testData.unit})`).should( - 'be.visible' + metricsAPIResponsePayload, + testData.title, + testData.unit ); - cy.get(`[data-qa-graph-column-title="Max"]`) + + const graphRowTitle = `[data-qa-graph-row-title="${testData.title} (${testData.unit})"]`; + cy.get(graphRowTitle) .should('be.visible') .should( 'have.text', - `${expectedWidgetValues.max} ${testData.unit}` + `${testData.title} (${testData.unit.trim()})` ); + cy.get(`[data-qa-graph-column-title="Max"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.max}`); + cy.get(`[data-qa-graph-column-title="Avg"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.average} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.average}`); cy.get(`[data-qa-graph-column-title="Last"]`) .should('be.visible') - .should( - 'have.text', - `${expectedWidgetValues.last} ${testData.unit}` - ); + .should('have.text', `${expectedWidgetValues.last}`); }); }); }); diff --git a/packages/manager/src/components/AreaChart/AreaChart.tsx b/packages/manager/src/components/AreaChart/AreaChart.tsx index 4128623b913..0674f6d3883 100644 --- a/packages/manager/src/components/AreaChart/AreaChart.tsx +++ b/packages/manager/src/components/AreaChart/AreaChart.tsx @@ -228,7 +228,7 @@ export const AreaChart = (props: AreaChartProps) => { }; return ( - <> + <_AreaChart aria-label={ariaLabel} data={data} margin={margin}> { timezone={timezone} unit={unit} /> - + ); }; diff --git a/packages/manager/src/components/LineGraph/MetricsDisplay.tsx b/packages/manager/src/components/LineGraph/MetricsDisplay.tsx index ed907bbe638..5484c287dd9 100644 --- a/packages/manager/src/components/LineGraph/MetricsDisplay.tsx +++ b/packages/manager/src/components/LineGraph/MetricsDisplay.tsx @@ -86,12 +86,15 @@ const MetricRow = ({ legendColor={legendColor} onClick={handleLegendClick} > - {legendTitle} + + {legendTitle} + {METRIC_KEYS.map((key, idx) => ( Date: Wed, 6 Nov 2024 15:28:29 +0530 Subject: [PATCH 312/474] [DI-21597]:Removed commented-out code and explanatory comments related to the line chart in DBaaS test cases --- .../e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts index 313b394b1e9..57c3e5541b5 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts @@ -272,7 +272,7 @@ describe('Integration Tests for DBaaS Dashboard ', () => { ); }); - //validate the widget linegrah is present + //validate the widget areachart is present cy.findByTestId('areachart-wrapper').within(() => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( metricsAPIResponsePayload, @@ -326,7 +326,7 @@ describe('Integration Tests for DBaaS Dashboard ', () => { ); }); - //validate the widget linegrah is present + //validate the widget areachart is present cy.findByTestId('areachart-wrapper').within(() => { const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( metricsAPIResponsePayload, From 3510e347c1df5d23950b6dae6ef1f7347ffdad3b Mon Sep 17 00:00:00 2001 From: agorthi Date: Thu, 14 Nov 2024 11:36:49 +0530 Subject: [PATCH 313/474] [DI-21597]-Initial commit: Automating and testing the migration process for Recharts --- .../e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts index 57c3e5541b5..0634d51fdbc 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts @@ -135,7 +135,6 @@ const getWidgetLegendRowValuesFromResponse = ( serviceType: serviceType, status: 'success', unit: unit, - // widgetColor: 'red', }); // Destructure metrics data from the first legend row @@ -237,7 +236,7 @@ describe('Integration Tests for DBaaS Dashboard ', () => { cy.get(widgetSelector) .should('be.visible') .find('h2') - .should('have.text', `${testData.title} (${testData.unit.trim()})`); + .should('have.text', `${testData.title} (${testData.unit})`); cy.get(widgetSelector) .should('be.visible') .within(() => { From 934447705b4714ff2091a11bb0c6d551d913ea36 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Thu, 14 Nov 2024 12:49:27 +0530 Subject: [PATCH 314/474] upcoming: [DI-21926] - Updated ACLP tech docs URL --- packages/manager/src/features/CloudPulse/CloudPulseLanding.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/CloudPulseLanding.tsx b/packages/manager/src/features/CloudPulse/CloudPulseLanding.tsx index 47e13529c3b..1e5052362cf 100644 --- a/packages/manager/src/features/CloudPulse/CloudPulseLanding.tsx +++ b/packages/manager/src/features/CloudPulse/CloudPulseLanding.tsx @@ -12,7 +12,7 @@ export const CloudPulseLanding = () => { }> From 21b598deb7d246b586d95e2c88726d8d7fc69418 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Thu, 14 Nov 2024 18:55:33 +0530 Subject: [PATCH 315/474] upcoming: [DI-21927] - Change ACLP url --- .../cloudpulse/cloudpulse-navigation.spec.ts | 2 +- .../cloudpulse/cloudpulse-validation.spec.ts | 16 ++--- .../dbaas-widgets-verification.spec.ts | 2 +- .../linode-widget-verification.spec.ts | 2 +- packages/manager/src/MainContent.tsx | 5 +- .../src/components/PrimaryNav/PrimaryNav.tsx | 2 +- .../AlertsLanding/AlertsDefinitionLanding.tsx | 4 +- .../Alerts/AlertsLanding/AlertsLanding.tsx | 7 +- .../features/CloudPulse/CloudPulseLanding.tsx | 4 +- .../features/CloudPulse/CloudPulseTabs.tsx | 6 +- packages/manager/src/mocks/serverHandlers.ts | 68 +++++++++---------- .../manager/src/routes/cloudPulse/index.ts | 2 +- 12 files changed, 54 insertions(+), 66 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts index e747af3f3bf..904c2719073 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts @@ -63,7 +63,7 @@ describe('CloudPulse navigation', () => { }, }).as('getFeatureFlags'); - cy.visitWithLogin('monitor/cloudpulse'); + cy.visitWithLogin('monitor'); cy.wait('@getFeatureFlags'); cy.findByText('Not Found').should('be.visible'); diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts index a07bb680161..8d92be44b5e 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts @@ -107,7 +107,7 @@ describe('Tests for API error handling', () => { { statusCode: 500, body: { errors: [{ reason: 'Bad Request' }] }, } ).as('getMetricDefinitions'); - cy.visitWithLogin('monitor/cloudpulse'); + cy.visitWithLogin('monitor'); // Wait for the services and dashboard API calls to complete before proceeding. cy.wait(['@fetchServices', '@fetchDashboard']); @@ -155,7 +155,7 @@ describe('Tests for API error handling', () => { body: { errors: [{ reason: 'Bad Request' }],}, }).as('fetchServices'); - cy.visitWithLogin('monitor/cloudpulse'); + cy.visitWithLogin('monitor'); cy.get('[data-qa-textfield-error-text="Dashboard"]') .should('be.visible') @@ -171,7 +171,7 @@ describe('Tests for API error handling', () => { errors: [{ reason: 'Bad Request' }], }, }); - cy.visitWithLogin('monitor/cloudpulse'); + cy.visitWithLogin('monitor'); // Wait for both the fetch services and fetch dashboard API calls to complete. cy.wait(['@fetchServices', '@fetchDashboard']); @@ -221,7 +221,7 @@ describe('Tests for API error handling', () => { } ).as('fetchDashboard'); - cy.visitWithLogin('monitor/cloudpulse'); + cy.visitWithLogin('monitor'); // Wait for both the fetch services and fetch dashboard API calls to complete. cy.wait(['@fetchServices', '@fetchDashboard']); @@ -240,7 +240,7 @@ describe('Tests for API error handling', () => { body: { errors: [{ reason: 'Bad Request' }] }, }); - cy.visitWithLogin('monitor/cloudpulse'); + cy.visitWithLogin('monitor'); // Select a dashboard from the autocomplete input. Verify that the input is visible before typing. ui.autocomplete @@ -282,11 +282,11 @@ describe('Tests for API error handling', () => { it(`should return error message when the Regions API request fails`, () => { cy.intercept('GET', apiMatcher(`regions*`), { - statusCode: 500, + statusCode: 500, body: { errors: [{ reason: 'Bad Request' }] }, }); - cy.visitWithLogin('monitor/cloudpulse'); + cy.visitWithLogin('monitor'); // Wait for the services and dashboard API calls to resolve before proceeding. cy.wait(['@fetchServices', '@fetchDashboard']); @@ -312,7 +312,7 @@ describe('Tests for API error handling', () => { body: {errors: [{ reason: 'Bad Request' }],}, }); - cy.visitWithLogin('monitor/cloudpulse'); + cy.visitWithLogin('monitor'); //Wait for the services and dashboard API calls to resolve before proceeding. cy.wait(['@fetchServices', '@fetchDashboard']); diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts index d1f1181337d..948ff7fb897 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts @@ -160,7 +160,7 @@ describe('Integration Tests for DBaaS Dashboard ', () => { mockGetDatabases([databaseMock]).as('getDatabases'); // navigate to the cloudpulse page - cy.visitWithLogin('monitor/cloudpulse'); + cy.visitWithLogin('monitor'); // Wait for the services and dashboard API calls to complete before proceeding cy.wait(['@fetchServices', '@fetchDashboard']); diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index b0620e4148e..01406a803ce 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -138,7 +138,7 @@ describe('Integration Tests for Linode Dashboard ', () => { mockGetUserPreferences({}); // navigate to the cloudpulse page - cy.visitWithLogin('monitor/cloudpulse'); + cy.visitWithLogin('monitor'); // Wait for the services and dashboard API calls to complete before proceeding cy.wait(['@fetchServices', '@fetchDashboard']); diff --git a/packages/manager/src/MainContent.tsx b/packages/manager/src/MainContent.tsx index 5f7185fb174..6ca71d524db 100644 --- a/packages/manager/src/MainContent.tsx +++ b/packages/manager/src/MainContent.tsx @@ -354,10 +354,7 @@ export const MainContent = () => { )} {/* {isACLPEnabled && ( */} - + {/* )} */} {/** We don't want to break any bookmarks. This can probably be removed eventually. */} diff --git a/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx b/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx index fd6b10de5c5..49122ffc133 100644 --- a/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx +++ b/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx @@ -196,7 +196,7 @@ export const PrimaryNav = (props: PrimaryNavProps) => { { display: 'Monitor', hide: !isACLPEnabled, - href: '/monitor/cloudpulse', + href: '/monitor', isBeta: flags.aclp?.beta, }, ], diff --git a/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsDefinitionLanding.tsx b/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsDefinitionLanding.tsx index f0c692253ae..7c4bc61754f 100644 --- a/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsDefinitionLanding.tsx +++ b/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsDefinitionLanding.tsx @@ -1,7 +1,7 @@ +import { Paper } from '@linode/ui'; import * as React from 'react'; import { Route, Switch } from 'react-router-dom'; -import { Paper } from '@linode/ui'; import { Typography } from 'src/components/Typography'; export const AlertDefinitionLanding = () => { @@ -10,7 +10,7 @@ export const AlertDefinitionLanding = () => { ); diff --git a/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsLanding.tsx b/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsLanding.tsx index e9511a9c42d..05c44b57195 100644 --- a/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsLanding.tsx +++ b/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsLanding.tsx @@ -61,12 +61,9 @@ export const AlertsLanding = React.memo(() => { - + diff --git a/packages/manager/src/features/CloudPulse/CloudPulseLanding.tsx b/packages/manager/src/features/CloudPulse/CloudPulseLanding.tsx index 1e5052362cf..d303457db05 100644 --- a/packages/manager/src/features/CloudPulse/CloudPulseLanding.tsx +++ b/packages/manager/src/features/CloudPulse/CloudPulseLanding.tsx @@ -23,8 +23,6 @@ export const CloudPulseLanding = () => { ); }; -export const cloudPulseLandingLazyRoute = createLazyRoute( - '/monitor/cloudpulse' -)({ +export const cloudPulseLandingLazyRoute = createLazyRoute('/monitor')({ component: CloudPulseLanding, }); diff --git a/packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx b/packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx index 418bee1322c..63f3642f961 100644 --- a/packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx +++ b/packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx @@ -74,11 +74,7 @@ export const CloudPulseTabs = () => { path={`${url}/dashboards`} /> - + diff --git a/packages/manager/src/mocks/serverHandlers.ts b/packages/manager/src/mocks/serverHandlers.ts index c55a67586e4..e015c46a177 100644 --- a/packages/manager/src/mocks/serverHandlers.ts +++ b/packages/manager/src/mocks/serverHandlers.ts @@ -2550,40 +2550,40 @@ export const handlers = [ const response = { data: { result: [ - { - metric: { - test: 'Test1', - }, - values: [ - [1721854379, '0.2744841110560275'], - [1721857979, '0.2980357104166823'], - [1721861579, '0.3290476561287732'], - [1721865179, '0.32148793964961897'], - [1721868779, '0.3269247326830727'], - [1721872379, '0.3393055885526987'], - [1721875979, '0.3237102833940027'], - [1721879579, '0.3153372503472701'], - [1721883179, '0.26811506053820466'], - [1721886779, '0.25839295774934357'], - [1721890379, '0.26863082415681144'], - [1721893979, '0.26126998689934394'], - [1721897579, '0.26164641539434685'], - ], - }, + // { + // metric: { + // test: 'Test1', + // }, + // values: [ + // [1721854379, '0.2744841110560275'], + // [1721857979, '0.2980357104166823'], + // [1721861579, '0.3290476561287732'], + // [1721865179, '0.32148793964961897'], + // [1721868779, '0.3269247326830727'], + // // [1721872379, '0.3393055885526987'], + // [1721875979, '0.3237102833940027'], + // // [1721879579, '0.3153372503472701'], + // [1721883179, '0.26811506053820466'], + // [1721886779, '0.25839295774934357'], + // [1721890379, '0.26863082415681144'], + // [1721893979, '0.26126998689934394'], + // [1721897579, '0.26164641539434685'], + // ], + // }, { metric: { test2: 'Test2', }, values: [ [1721854379, '0.3744841110560275'], - [1721857979, '0.4980357104166823'], - [1721861579, '0.3290476561287732'], - [1721865179, '0.42148793964961897'], - [1721868779, '0.2269247326830727'], - [1721872379, '0.3393055885526987'], - [1721875979, '0.5237102833940027'], - [1721879579, '0.3153372503472701'], - [1721883179, '0.26811506053820466'], + // [1721857979, '0.4980357104166823'], + // [1721861579, '0.3290476561287732'], + // // [1721865179, '0.42148793964961897'], + // // [1721868779, '0.2269247326830727'], + // // [1721872379, '0.3393055885526987'], + // // [1721875979, '0.5237102833940027'], + // // [1721879579, '0.3153372503472701'], + // // [1721883179, '0.26811506053820466'], [1721886779, '0.35839295774934357'], [1721890379, '0.36863082415681144'], [1721893979, '0.46126998689934394'], @@ -2598,12 +2598,12 @@ export const handlers = [ [1721854379, '0.3744841110560275'], [1721857979, '0.4980357104166823'], [1721861579, '0.3290476561287732'], - [1721865179, '0.4148793964961897'], - [1721868779, '0.4269247326830727'], - [1721872379, '0.3393055885526987'], - [1721875979, '0.6237102833940027'], - [1721879579, '0.3153372503472701'], - [1721883179, '0.26811506053820466'], + // [1721865179, '0.4148793964961897'], + // [1721868779, '0.4269247326830727'], + // [1721872379, '0.3393055885526987'], + // [1721875979, '0.6237102833940027'], + // [1721879579, '0.3153372503472701'], + // [1721883179, '0.26811506053820466'], [1721886779, '0.45839295774934357'], [1721890379, '0.36863082415681144'], [1721893979, '0.56126998689934394'], diff --git a/packages/manager/src/routes/cloudPulse/index.ts b/packages/manager/src/routes/cloudPulse/index.ts index 6f4f3595a7a..c4a228983b9 100644 --- a/packages/manager/src/routes/cloudPulse/index.ts +++ b/packages/manager/src/routes/cloudPulse/index.ts @@ -6,7 +6,7 @@ import { CloudPulseRoute } from './CloudPulseRoute'; const cloudPulseRoute = createRoute({ component: CloudPulseRoute, getParentRoute: () => rootRoute, - path: 'monitor/cloudpulse', + path: 'monitor', }); const cloudPulseLandingRoute = createRoute({ From 9aa8a2ef622518bb18bf37f56b32bd60754e8f7f Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Thu, 14 Nov 2024 19:04:54 +0530 Subject: [PATCH 316/474] upcoming: [DI-21926] - Reverted serverHandler --- packages/manager/src/mocks/serverHandlers.ts | 68 ++++++++++---------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/packages/manager/src/mocks/serverHandlers.ts b/packages/manager/src/mocks/serverHandlers.ts index e015c46a177..c55a67586e4 100644 --- a/packages/manager/src/mocks/serverHandlers.ts +++ b/packages/manager/src/mocks/serverHandlers.ts @@ -2550,40 +2550,40 @@ export const handlers = [ const response = { data: { result: [ - // { - // metric: { - // test: 'Test1', - // }, - // values: [ - // [1721854379, '0.2744841110560275'], - // [1721857979, '0.2980357104166823'], - // [1721861579, '0.3290476561287732'], - // [1721865179, '0.32148793964961897'], - // [1721868779, '0.3269247326830727'], - // // [1721872379, '0.3393055885526987'], - // [1721875979, '0.3237102833940027'], - // // [1721879579, '0.3153372503472701'], - // [1721883179, '0.26811506053820466'], - // [1721886779, '0.25839295774934357'], - // [1721890379, '0.26863082415681144'], - // [1721893979, '0.26126998689934394'], - // [1721897579, '0.26164641539434685'], - // ], - // }, + { + metric: { + test: 'Test1', + }, + values: [ + [1721854379, '0.2744841110560275'], + [1721857979, '0.2980357104166823'], + [1721861579, '0.3290476561287732'], + [1721865179, '0.32148793964961897'], + [1721868779, '0.3269247326830727'], + [1721872379, '0.3393055885526987'], + [1721875979, '0.3237102833940027'], + [1721879579, '0.3153372503472701'], + [1721883179, '0.26811506053820466'], + [1721886779, '0.25839295774934357'], + [1721890379, '0.26863082415681144'], + [1721893979, '0.26126998689934394'], + [1721897579, '0.26164641539434685'], + ], + }, { metric: { test2: 'Test2', }, values: [ [1721854379, '0.3744841110560275'], - // [1721857979, '0.4980357104166823'], - // [1721861579, '0.3290476561287732'], - // // [1721865179, '0.42148793964961897'], - // // [1721868779, '0.2269247326830727'], - // // [1721872379, '0.3393055885526987'], - // // [1721875979, '0.5237102833940027'], - // // [1721879579, '0.3153372503472701'], - // // [1721883179, '0.26811506053820466'], + [1721857979, '0.4980357104166823'], + [1721861579, '0.3290476561287732'], + [1721865179, '0.42148793964961897'], + [1721868779, '0.2269247326830727'], + [1721872379, '0.3393055885526987'], + [1721875979, '0.5237102833940027'], + [1721879579, '0.3153372503472701'], + [1721883179, '0.26811506053820466'], [1721886779, '0.35839295774934357'], [1721890379, '0.36863082415681144'], [1721893979, '0.46126998689934394'], @@ -2598,12 +2598,12 @@ export const handlers = [ [1721854379, '0.3744841110560275'], [1721857979, '0.4980357104166823'], [1721861579, '0.3290476561287732'], - // [1721865179, '0.4148793964961897'], - // [1721868779, '0.4269247326830727'], - // [1721872379, '0.3393055885526987'], - // [1721875979, '0.6237102833940027'], - // [1721879579, '0.3153372503472701'], - // [1721883179, '0.26811506053820466'], + [1721865179, '0.4148793964961897'], + [1721868779, '0.4269247326830727'], + [1721872379, '0.3393055885526987'], + [1721875979, '0.6237102833940027'], + [1721879579, '0.3153372503472701'], + [1721883179, '0.26811506053820466'], [1721886779, '0.45839295774934357'], [1721890379, '0.36863082415681144'], [1721893979, '0.56126998689934394'], From 6f527466d78ae10aa990c841dbe1e684c81fcff9 Mon Sep 17 00:00:00 2001 From: agorthi Date: Thu, 14 Nov 2024 19:05:10 +0530 Subject: [PATCH 317/474] [DI-21597]-Initial commit: Automating and testing the migration process for Recharts --- .../manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index c3861798a0c..8e97cb21fe7 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -8,7 +8,6 @@ import { useCloudPulseMetricsQuery } from 'src/queries/cloudpulse/metrics'; import { useProfile } from 'src/queries/profile/profile'; import { - fillMissingTimeStampsAcrossDimensions, generateGraphData, getCloudPulseMetricRequest, } from '../Utils/CloudPulseWidgetUtils'; From b249080d5b55a4a64f814e4af5a88937326bceaf Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Fri, 15 Nov 2024 16:18:53 +0530 Subject: [PATCH 318/474] upcoming: [DI-21842] - Added capability to toggle dots in AreaChart --- .../src/components/AreaChart/AreaChart.tsx | 17 +++++++++++++++-- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 2 +- .../src/features/CloudPulse/Utils/utils.ts | 2 +- .../CloudPulse/Widget/CloudPulseWidget.tsx | 6 +++--- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/packages/manager/src/components/AreaChart/AreaChart.tsx b/packages/manager/src/components/AreaChart/AreaChart.tsx index 4128623b913..c224db29582 100644 --- a/packages/manager/src/components/AreaChart/AreaChart.tsx +++ b/packages/manager/src/components/AreaChart/AreaChart.tsx @@ -75,6 +75,11 @@ export interface AreaChartProps { */ data: any; + /** + * radius of the dots to be displayed + */ + dotRadius?: number; + /** * */ @@ -100,6 +105,11 @@ export interface AreaChartProps { */ margin?: { bottom: number; left: number; right: number; top: number }; + /** + * control the visibility of dots for each data points + */ + showDot?: boolean; + /** * true to display legends rows else false to hide * @default false @@ -139,11 +149,13 @@ export const AreaChart = (props: AreaChartProps) => { ariaLabel, connectNulls, data, + dotRadius = 3, fillOpacity, height = '100%', legendHeight, legendRows, - margin = { bottom: 0, left: -20, right: 0, top: 0 }, + margin = { bottom: 0, left: -20, right: 30, top: 0 }, + showDot, showLegend, timezone, unit, @@ -239,7 +251,7 @@ export const AreaChart = (props: AreaChartProps) => { { { }; const labelName = getLabelName(labelOptions); const data = seriesDataFormatter(transformedData.values, start, end); - const color = colors[index].Primary; + const color = colors[index % 22].Primary; areas.push({ color, dataKey: labelName, diff --git a/packages/manager/src/features/CloudPulse/Utils/utils.ts b/packages/manager/src/features/CloudPulse/Utils/utils.ts index 351d82f884a..6801fd4b034 100644 --- a/packages/manager/src/features/CloudPulse/Utils/utils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/utils.ts @@ -108,7 +108,7 @@ export const seriesDataFormatter = ( const formattedArray: StatWithDummyPoint[] = data.map(([x, y]) => ({ x: Number(x), - y: y != null ? Number(y) : null, + y: y !== null ? Number(y) : null, })); return convertData(formattedArray, startTime, endTime); diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index c3861798a0c..c044556388e 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -266,9 +266,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { const metricsApiCallError = error?.[0]?.reason; const tickFormat = - duration.unit === 'min' || duration.unit === 'hr' - ? 'hh:mm a' - : 'LLL dd, hh:mm a'; + duration.unit === 'min' || duration.unit === 'hr' ? 'hh:mm a' : 'LLL dd'; return ( @@ -332,9 +330,11 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { areas={areas} ariaLabel={ariaLabel ? ariaLabel : ''} data={data} + dotRadius={1.5} height={424} legendRows={legendRows} loading={isLoading || metricsApiCallError === jweTokenExpiryError} // keep loading until we fetch the refresh token + showDot showLegend={data.length !== 0} timezone={timezone} unit={currentUnit} From a4fbec6f1973e8929ce4a5b64f173d7648d30d1c Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Fri, 15 Nov 2024 16:33:26 +0530 Subject: [PATCH 319/474] upcoming: [DI-21842] - Added logic to generate x-axis ticks --- .../src/components/AreaChart/AreaChart.tsx | 2 ++ .../manager/src/components/AreaChart/utils.ts | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/packages/manager/src/components/AreaChart/AreaChart.tsx b/packages/manager/src/components/AreaChart/AreaChart.tsx index c224db29582..c9e721407ef 100644 --- a/packages/manager/src/components/AreaChart/AreaChart.tsx +++ b/packages/manager/src/components/AreaChart/AreaChart.tsx @@ -19,6 +19,7 @@ import MetricsDisplay from 'src/components/LineGraph/MetricsDisplay'; import { StyledBottomLegend } from 'src/features/NodeBalancers/NodeBalancerDetail/NodeBalancerSummary/TablesPanel'; import { + generate12HourTicks, humanizeLargeData, tooltipLabelFormatter, tooltipValueFormatter, @@ -256,6 +257,7 @@ export const AreaChart = (props: AreaChartProps) => { scale="time" stroke={theme.color.label} tickFormatter={xAxisTickFormatter} + ticks={generate12HourTicks(data, timezone)} type="number" /> diff --git a/packages/manager/src/components/AreaChart/utils.ts b/packages/manager/src/components/AreaChart/utils.ts index 6026169e58a..cf159a55bd6 100644 --- a/packages/manager/src/components/AreaChart/utils.ts +++ b/packages/manager/src/components/AreaChart/utils.ts @@ -36,6 +36,33 @@ export const humanizeLargeData = (value: number) => { return `${value}`; }; +export const generate12HourTicks = (data: any[], timezone: string) => { + if (data.length === 0) { + return []; + } + + // Get start and end time from data + const startTime = data[0].timestamp; + const endTime = data[data.length - 1].timestamp; + + // Calculate duration in hours + const duration = DateTime.fromMillis(endTime, { zone: timezone }).diff( + DateTime.fromMillis(startTime, { zone: timezone }), + 'hours' + ).hours; + + // Generate fixed number of ticks across the 12-hour period + // Use 7 ticks (every 2 hours) to prevent overcrowding + const tickCount = 7; + const interval = duration / (tickCount - 1); + + return Array.from({ length: tickCount }, (_, i) => { + return DateTime.fromMillis(startTime, { zone: timezone }) + .plus({ hours: i * interval }) + .toMillis(); + }); +}; + export const timeData: LinodeNetworkTimeData[] = [ { 'Public Outbound Traffic': 5.434939999999999, From 149a41005b17a06a3c641a0a2888e3ed0da85e91 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Fri, 15 Nov 2024 16:18:53 +0530 Subject: [PATCH 320/474] upcoming: [DI-21842] - Added capability to toggle dots in AreaChart --- .../src/components/AreaChart/AreaChart.tsx | 17 +++++++++++++++-- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 2 +- .../src/features/CloudPulse/Utils/utils.ts | 2 +- .../CloudPulse/Widget/CloudPulseWidget.tsx | 6 +++--- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/packages/manager/src/components/AreaChart/AreaChart.tsx b/packages/manager/src/components/AreaChart/AreaChart.tsx index 4128623b913..c224db29582 100644 --- a/packages/manager/src/components/AreaChart/AreaChart.tsx +++ b/packages/manager/src/components/AreaChart/AreaChart.tsx @@ -75,6 +75,11 @@ export interface AreaChartProps { */ data: any; + /** + * radius of the dots to be displayed + */ + dotRadius?: number; + /** * */ @@ -100,6 +105,11 @@ export interface AreaChartProps { */ margin?: { bottom: number; left: number; right: number; top: number }; + /** + * control the visibility of dots for each data points + */ + showDot?: boolean; + /** * true to display legends rows else false to hide * @default false @@ -139,11 +149,13 @@ export const AreaChart = (props: AreaChartProps) => { ariaLabel, connectNulls, data, + dotRadius = 3, fillOpacity, height = '100%', legendHeight, legendRows, - margin = { bottom: 0, left: -20, right: 0, top: 0 }, + margin = { bottom: 0, left: -20, right: 30, top: 0 }, + showDot, showLegend, timezone, unit, @@ -239,7 +251,7 @@ export const AreaChart = (props: AreaChartProps) => { { { }; const labelName = getLabelName(labelOptions); const data = seriesDataFormatter(transformedData.values, start, end); - const color = colors[index].Primary; + const color = colors[index % 22].Primary; areas.push({ color, dataKey: labelName, diff --git a/packages/manager/src/features/CloudPulse/Utils/utils.ts b/packages/manager/src/features/CloudPulse/Utils/utils.ts index 351d82f884a..6801fd4b034 100644 --- a/packages/manager/src/features/CloudPulse/Utils/utils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/utils.ts @@ -108,7 +108,7 @@ export const seriesDataFormatter = ( const formattedArray: StatWithDummyPoint[] = data.map(([x, y]) => ({ x: Number(x), - y: y != null ? Number(y) : null, + y: y !== null ? Number(y) : null, })); return convertData(formattedArray, startTime, endTime); diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 48c963fdb38..097404aedcf 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -265,9 +265,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { const metricsApiCallError = error?.[0]?.reason; const tickFormat = - duration.unit === 'min' || duration.unit === 'hr' - ? 'hh:mm a' - : 'LLL dd, hh:mm a'; + duration.unit === 'min' || duration.unit === 'hr' ? 'hh:mm a' : 'LLL dd'; return ( @@ -331,9 +329,11 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { areas={areas} ariaLabel={ariaLabel ? ariaLabel : ''} data={data} + dotRadius={1.5} height={424} legendRows={legendRows} loading={isLoading || metricsApiCallError === jweTokenExpiryError} // keep loading until we fetch the refresh token + showDot showLegend={data.length !== 0} timezone={timezone} unit={currentUnit} From cdf590361ec48d7b0dca24a8ecfb2f97b5cee061 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Fri, 15 Nov 2024 16:33:26 +0530 Subject: [PATCH 321/474] upcoming: [DI-21842] - Added logic to generate x-axis ticks --- .../src/components/AreaChart/AreaChart.tsx | 2 ++ .../manager/src/components/AreaChart/utils.ts | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/packages/manager/src/components/AreaChart/AreaChart.tsx b/packages/manager/src/components/AreaChart/AreaChart.tsx index c224db29582..c9e721407ef 100644 --- a/packages/manager/src/components/AreaChart/AreaChart.tsx +++ b/packages/manager/src/components/AreaChart/AreaChart.tsx @@ -19,6 +19,7 @@ import MetricsDisplay from 'src/components/LineGraph/MetricsDisplay'; import { StyledBottomLegend } from 'src/features/NodeBalancers/NodeBalancerDetail/NodeBalancerSummary/TablesPanel'; import { + generate12HourTicks, humanizeLargeData, tooltipLabelFormatter, tooltipValueFormatter, @@ -256,6 +257,7 @@ export const AreaChart = (props: AreaChartProps) => { scale="time" stroke={theme.color.label} tickFormatter={xAxisTickFormatter} + ticks={generate12HourTicks(data, timezone)} type="number" /> diff --git a/packages/manager/src/components/AreaChart/utils.ts b/packages/manager/src/components/AreaChart/utils.ts index 6026169e58a..cf159a55bd6 100644 --- a/packages/manager/src/components/AreaChart/utils.ts +++ b/packages/manager/src/components/AreaChart/utils.ts @@ -36,6 +36,33 @@ export const humanizeLargeData = (value: number) => { return `${value}`; }; +export const generate12HourTicks = (data: any[], timezone: string) => { + if (data.length === 0) { + return []; + } + + // Get start and end time from data + const startTime = data[0].timestamp; + const endTime = data[data.length - 1].timestamp; + + // Calculate duration in hours + const duration = DateTime.fromMillis(endTime, { zone: timezone }).diff( + DateTime.fromMillis(startTime, { zone: timezone }), + 'hours' + ).hours; + + // Generate fixed number of ticks across the 12-hour period + // Use 7 ticks (every 2 hours) to prevent overcrowding + const tickCount = 7; + const interval = duration / (tickCount - 1); + + return Array.from({ length: tickCount }, (_, i) => { + return DateTime.fromMillis(startTime, { zone: timezone }) + .plus({ hours: i * interval }) + .toMillis(); + }); +}; + export const timeData: LinodeNetworkTimeData[] = [ { 'Public Outbound Traffic': 5.434939999999999, From 91acc393e18ae48345c361d7a5ddba608e3d0feb Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Fri, 15 Nov 2024 19:57:32 +0530 Subject: [PATCH 322/474] upcoming: [DI-21842] - Add optional prop for tickCount --- .../manager/src/components/AreaChart/AreaChart.tsx | 14 ++++++++++++-- packages/manager/src/components/AreaChart/utils.ts | 7 +++++-- .../Widget/components/CloudPulseLineGraph.tsx | 1 + 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/packages/manager/src/components/AreaChart/AreaChart.tsx b/packages/manager/src/components/AreaChart/AreaChart.tsx index c9e721407ef..cd97f666bd8 100644 --- a/packages/manager/src/components/AreaChart/AreaChart.tsx +++ b/packages/manager/src/components/AreaChart/AreaChart.tsx @@ -142,6 +142,11 @@ export interface AreaChartProps { * x-axis properties */ xAxis: XAxisProps; + + /** + * number of x-axis ticks should be shown + */ + xAxisTickCount?: number; } export const AreaChart = (props: AreaChartProps) => { @@ -163,6 +168,7 @@ export const AreaChart = (props: AreaChartProps) => { variant, width = '100%', xAxis, + xAxisTickCount, } = props; const theme = useTheme(); @@ -250,14 +256,18 @@ export const AreaChart = (props: AreaChartProps) => { vertical={false} /> diff --git a/packages/manager/src/components/AreaChart/utils.ts b/packages/manager/src/components/AreaChart/utils.ts index cf159a55bd6..34f8ba94e4e 100644 --- a/packages/manager/src/components/AreaChart/utils.ts +++ b/packages/manager/src/components/AreaChart/utils.ts @@ -36,7 +36,11 @@ export const humanizeLargeData = (value: number) => { return `${value}`; }; -export const generate12HourTicks = (data: any[], timezone: string) => { +export const generate12HourTicks = ( + data: any[], + timezone: string, + tickCount: number +) => { if (data.length === 0) { return []; } @@ -53,7 +57,6 @@ export const generate12HourTicks = (data: any[], timezone: string) => { // Generate fixed number of ticks across the 12-hour period // Use 7 ticks (every 2 hours) to prevent overcrowding - const tickCount = 7; const interval = duration / (tickCount - 1); return Array.from({ length: tickCount }, (_, i) => { diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index 1325073328e..31bfd0e33b0 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -38,6 +38,7 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { {...rest} fillOpacity={0.5} legendHeight={theme.spacing(16)} + xAxisTickCount={7} /> )} {rest.data.length === 0 && ( From 0e39a2c199ef1d9c3c36a436094992c52367212f Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Fri, 15 Nov 2024 19:57:32 +0530 Subject: [PATCH 323/474] upcoming: [DI-21842] - Add optional prop for tickCount --- .../manager/src/components/AreaChart/AreaChart.tsx | 14 ++++++++++++-- packages/manager/src/components/AreaChart/utils.ts | 7 +++++-- .../Widget/components/CloudPulseLineGraph.tsx | 1 + 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/packages/manager/src/components/AreaChart/AreaChart.tsx b/packages/manager/src/components/AreaChart/AreaChart.tsx index c9e721407ef..cd97f666bd8 100644 --- a/packages/manager/src/components/AreaChart/AreaChart.tsx +++ b/packages/manager/src/components/AreaChart/AreaChart.tsx @@ -142,6 +142,11 @@ export interface AreaChartProps { * x-axis properties */ xAxis: XAxisProps; + + /** + * number of x-axis ticks should be shown + */ + xAxisTickCount?: number; } export const AreaChart = (props: AreaChartProps) => { @@ -163,6 +168,7 @@ export const AreaChart = (props: AreaChartProps) => { variant, width = '100%', xAxis, + xAxisTickCount, } = props; const theme = useTheme(); @@ -250,14 +256,18 @@ export const AreaChart = (props: AreaChartProps) => { vertical={false} /> diff --git a/packages/manager/src/components/AreaChart/utils.ts b/packages/manager/src/components/AreaChart/utils.ts index cf159a55bd6..34f8ba94e4e 100644 --- a/packages/manager/src/components/AreaChart/utils.ts +++ b/packages/manager/src/components/AreaChart/utils.ts @@ -36,7 +36,11 @@ export const humanizeLargeData = (value: number) => { return `${value}`; }; -export const generate12HourTicks = (data: any[], timezone: string) => { +export const generate12HourTicks = ( + data: any[], + timezone: string, + tickCount: number +) => { if (data.length === 0) { return []; } @@ -53,7 +57,6 @@ export const generate12HourTicks = (data: any[], timezone: string) => { // Generate fixed number of ticks across the 12-hour period // Use 7 ticks (every 2 hours) to prevent overcrowding - const tickCount = 7; const interval = duration / (tickCount - 1); return Array.from({ length: tickCount }, (_, i) => { diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index 6e9adff4464..b3554242a7d 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -42,6 +42,7 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { {...rest} fillOpacity={0.5} legendHeight={theme.spacing(16)} + xAxisTickCount={7} /> )} {rest.data.length === 0 && ( From 181de5b4407e2512df6b3603b9661e14fcfdac4f Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Mon, 18 Nov 2024 17:41:35 +0530 Subject: [PATCH 324/474] upcoming: [DI-21200] - Code refactoring --- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 11 +++++++---- .../src/features/CloudPulse/Utils/unitConversion.ts | 5 ++++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index d3762f62215..5fae267941d 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -210,6 +210,7 @@ export const generateGraphData = (props: GraphDataOptionsProps): GraphData => { dataKey: labelName, }); + // map each label & its data point to its timestamp data.forEach((dataPoint) => { const timestamp = dataPoint[0]; const value = dataPoint[1]; @@ -377,9 +378,11 @@ export const getAutocompleteWidgetStyles = (theme: Theme) => ({ */ // TODO: CloudPulse - delete when recharts migration completed export const fillMissingTimeStampsAcrossDimensions = ( - ...arraysToBeFilled: [number, number | null][][] -): [number, number | null][][] => { - if (arraysToBeFilled.length === 0) return []; + ...arraysToBeFilled: [number, null | number][][] +): [number, null | number][][] => { + if (arraysToBeFilled.length === 0) { + return []; + } // Step 1: Collect all unique keys from all arrays const allTimestamps = new Set(); @@ -400,7 +403,7 @@ export const fillMissingTimeStampsAcrossDimensions = ( // Step 3.2: Build the synchronized array by checking if a key exists return sortedTimestamps.map((key) => { // If the current array has the key, use its value; otherwise, set it to null, so that the gap is properly visible - return [key, map.get(key) ?? null] as [number, number | null]; + return [key, map.get(key) ?? null] as [number, null | number]; }); }); }; diff --git a/packages/manager/src/features/CloudPulse/Utils/unitConversion.ts b/packages/manager/src/features/CloudPulse/Utils/unitConversion.ts index 422607f383a..7dfccb8d7bb 100644 --- a/packages/manager/src/features/CloudPulse/Utils/unitConversion.ts +++ b/packages/manager/src/features/CloudPulse/Utils/unitConversion.ts @@ -244,5 +244,8 @@ export const transformData = ( ): [number, number][] => { const unit: string = generateCurrentUnit(baseUnit); - return data.map((d) => [d[0], Number(d[1]) * (multiplier[unit] ?? 1)]); + return data.map((d) => [ + d[0], + d[1] !== null ? Number(d[1]) * (multiplier[unit] ?? 1) : d[1], + ]); }; From 37522489645bbf8eb88fee4931236611685e1dbe Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Wed, 13 Nov 2024 10:49:15 +0530 Subject: [PATCH 325/474] upcoming: [DI-21119] - Handle jwe token limit in ACLP UI --- .../Dashboard/CloudPulseDashboard.tsx | 25 +++---------- .../Dashboard/CloudPulseDashboardLanding.tsx | 9 ++++- .../Dashboard/CloudPulseDashboardRenderer.tsx | 3 +- .../Widget/CloudPulseWidgetRenderer.tsx | 11 +++--- .../CloudPulseDashboardFilterBuilder.tsx | 35 ++++++++++++------- .../manager/src/queries/cloudpulse/queries.ts | 2 +- 6 files changed, 42 insertions(+), 43 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index 0c7fcb6e4b1..a898bea8a36 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -4,7 +4,6 @@ import React from 'react'; import { CircleProgress } from 'src/components/CircleProgress'; import { ErrorState } from 'src/components/ErrorState/ErrorState'; import { useCloudPulseDashboardByIdQuery } from 'src/queries/cloudpulse/dashboards'; -import { useResourcesQuery } from 'src/queries/cloudpulse/resources'; import { useCloudPulseJWEtokenQuery, useGetCloudPulseMetricDefinitionsByServiceType, @@ -15,6 +14,7 @@ import { RenderWidgets } from '../Widget/CloudPulseWidgetRenderer'; import type { CloudPulseMetricsAdditionalFilters } from '../Widget/CloudPulseWidget'; import type { JWETokenPayLoad, TimeDuration } from '@linode/api-v4'; +import { CloudPulseResources } from '../shared/CloudPulseResourcesSelect'; export interface DashboardProperties { /** @@ -45,7 +45,7 @@ export interface DashboardProperties { /** * Selected resources for the dashboard */ - resources: string[]; + resources: CloudPulseResources[]; /** * optional flag to check whether changes should be stored in preferences or not (in case this component is reused) @@ -67,7 +67,7 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { const getJweTokenPayload = (): JWETokenPayLoad => { return { - resource_ids: resourceList?.map((resource) => Number(resource.id)) ?? [], + resource_ids: resources?.map((resource) => Number(resource.id)) ?? [], }; }; @@ -77,17 +77,6 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { isLoading: isDashboardLoading, } = useCloudPulseDashboardByIdQuery(dashboardId); - const { - data: resourceList, - isError: isResourcesApiError, - isLoading: isResourcesLoading, - } = useResourcesQuery( - Boolean(dashboard?.service_type), - dashboard?.service_type, - {}, - dashboard?.service_type === 'dbaas' ? { platform: 'rdbms-default' } : {} - ); - const { data: metricDefinitions, isError: isMetricDefinitionError, @@ -104,17 +93,13 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { } = useCloudPulseJWEtokenQuery( dashboard?.service_type, getJweTokenPayload(), - Boolean(resourceList) + Boolean(resources) && !isDashboardLoading && !isDashboardApiError ); if (isDashboardApiError) { return renderErrorState('Failed to fetch the dashboard details.'); } - if (isResourcesApiError) { - return renderErrorState('Failed to fetch Resources.'); - } - if (isJweTokenError) { return renderErrorState('Failed to get the authentication token.'); } @@ -126,7 +111,6 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { if ( isMetricDefinitionLoading || isDashboardLoading || - isResourcesLoading || isJweTokenLoading ) { return ; @@ -141,7 +125,6 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { manualRefreshTimeStamp={manualRefreshTimeStamp} metricDefinitions={metricDefinitions} preferences={preferences} - resourceList={resourceList} resources={resources} savePref={savePref} /> diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx index 828a05301c7..e886ad9101e 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx @@ -4,9 +4,16 @@ import * as React from 'react'; import { GlobalFilters } from '../Overview/GlobalFilters'; import { CloudPulseDashboardRenderer } from './CloudPulseDashboardRenderer'; +import type { CloudPulseResources } from '../shared/CloudPulseResourcesSelect'; import type { Dashboard, TimeDuration } from '@linode/api-v4'; -export type FilterValueType = number | number[] | string | string[] | undefined; +export type FilterValueType = + | CloudPulseResources[] + | number + | number[] + | string + | string[] + | undefined; export interface DashboardProp { dashboard?: Dashboard; diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx index a1cb03e235b..1a18cbe6081 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx @@ -9,6 +9,7 @@ import { import { FILTER_CONFIG } from '../Utils/FilterConfig'; import { CloudPulseDashboard } from './CloudPulseDashboard'; +import type { CloudPulseResources } from '../shared/CloudPulseResourcesSelect'; import type { DashboardProp } from './CloudPulseDashboardLanding'; export const CloudPulseDashboardRenderer = React.memo( @@ -66,7 +67,7 @@ export const CloudPulseDashboardRenderer = React.memo( } resources={ filterValue[RESOURCE_ID] && Array.isArray(filterValue[RESOURCE_ID]) - ? (filterValue[RESOURCE_ID] as string[]) + ? (filterValue[RESOURCE_ID] as CloudPulseResources[]) : [] } additionalFilters={getMetricsCall} diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx index 56d27e950a2..65a787fb7f3 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx @@ -34,8 +34,8 @@ interface WidgetProps { manualRefreshTimeStamp?: number; metricDefinitions: MetricDefinitions | undefined; preferences?: AclpConfig; - resourceList: CloudPulseResources[] | undefined; - resources: string[]; + //resourceList: CloudPulseResources[] | undefined; + resources: CloudPulseResources[]; savePref?: boolean; } @@ -59,7 +59,6 @@ export const RenderWidgets = React.memo( manualRefreshTimeStamp, metricDefinitions, preferences, - resourceList, resources, savePref, } = props; @@ -74,7 +73,7 @@ export const RenderWidgets = React.memo( availableMetrics: undefined, duration, errorLabel: 'Error occurred while loading data.', - resourceIds: resources, + resourceIds: resources.map((resource) => String(resource.id)), resources: [], serviceType: dashboard?.service_type ?? '', timeStamp: manualRefreshTimeStamp, @@ -124,7 +123,7 @@ export const RenderWidgets = React.memo( !dashboard.service_type || !Boolean(resources.length > 0) || !jweToken?.token || - !Boolean(resourceList?.length) + !Boolean(resources?.length) ) { return renderPlaceHolder( 'Select a dashboard and filters to visualize metrics.' @@ -162,7 +161,7 @@ export const RenderWidgets = React.memo( {...cloudPulseWidgetProperties} authToken={jweToken?.token} availableMetrics={availMetrics} - resources={resourceList!} + resources={resources} savePref={savePref} /> ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index 4444f942a57..d413e6a8f57 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -26,7 +26,23 @@ import { FILTER_CONFIG } from '../Utils/FilterConfig'; import type { FilterValueType } from '../Dashboard/CloudPulseDashboardLanding'; import type { CloudPulseServiceTypeFilters } from '../Utils/models'; import type { CloudPulseResources } from './CloudPulseResourcesSelect'; -import type { AclpConfig, Dashboard } from '@linode/api-v4'; +import type { AclpConfig, AclpWidget, Dashboard } from '@linode/api-v4'; + +type WidgetFilterValue = { [key: string]: AclpWidget }; + +type FilterValue = + | CloudPulseResources[] + | WidgetFilterValue + | number + | number[] + | string + | string[] + | undefined; + +interface AclpConfigExtended { + [key: string]: FilterValue; + widgets?: WidgetFilterValue; +} export interface CloudPulseDashboardFilterBuilderProps { /** @@ -106,7 +122,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( filterKey: string, filterValue: FilterValueType, savePref: boolean = false, - updatedPreferenceData: AclpConfig = {} + updatedPreferenceData: AclpConfigExtended = {} ) => { emitFilterChange( filterKey, @@ -120,17 +136,10 @@ export const CloudPulseDashboardFilterBuilder = React.memo( ); const handleResourceChange = React.useCallback( - (resourceId: CloudPulseResources[], savePref: boolean = false) => { - emitFilterChangeByFilterKey( - RESOURCE_ID, - resourceId.map((resource) => resource.id), - savePref, - { - [RESOURCES]: resourceId.map((resource: { id: string }) => - String(resource.id) - ), - } - ); + (resources: CloudPulseResources[], savePref: boolean = false) => { + emitFilterChangeByFilterKey(RESOURCES, resources, savePref, { + [RESOURCES]: resources, + }); }, [emitFilterChangeByFilterKey] ); diff --git a/packages/manager/src/queries/cloudpulse/queries.ts b/packages/manager/src/queries/cloudpulse/queries.ts index 74bb3ec7e2b..bdc1715e0d7 100644 --- a/packages/manager/src/queries/cloudpulse/queries.ts +++ b/packages/manager/src/queries/cloudpulse/queries.ts @@ -80,6 +80,6 @@ export const queryFactory = createQueryKeys(key, { token: (serviceType: string | undefined, request: JWETokenPayLoad) => ({ queryFn: () => getJWEToken(request, serviceType!), - queryKey: [serviceType], + queryKey: [serviceType, { resource_ids: request.resource_ids }], }), }); From 4af2a8d34234f665d6e43da7343c4db3e7608cc0 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Wed, 13 Nov 2024 11:07:25 +0530 Subject: [PATCH 326/474] upcoming: [DI-21119] - small fix --- .../shared/CloudPulseDashboardFilterBuilder.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index d413e6a8f57..b2183d6a562 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -137,9 +137,14 @@ export const CloudPulseDashboardFilterBuilder = React.memo( const handleResourceChange = React.useCallback( (resources: CloudPulseResources[], savePref: boolean = false) => { - emitFilterChangeByFilterKey(RESOURCES, resources, savePref, { - [RESOURCES]: resources, - }); + emitFilterChangeByFilterKey( + RESOURCE_ID, + resources, + savePref, + { + [RESOURCES]: resources, + } + ); }, [emitFilterChangeByFilterKey] ); From a18b6fc9f1d8c3e081a9486c23cd57016624550c Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Mon, 18 Nov 2024 09:54:35 +0530 Subject: [PATCH 327/474] upcoming: [DI-21119] - Wait issue & preferences fix, UTs updated --- .../Dashboard/CloudPulseDashboard.tsx | 11 +++---- .../Dashboard/CloudPulseDashboardLanding.tsx | 5 ++- .../ReusableDashboardFilterUtils.test.ts | 9 +++-- .../Utils/ReusableDashboardFilterUtils.ts | 4 ++- .../CloudPulse/Widget/CloudPulseWidget.tsx | 4 +-- .../Widget/CloudPulseWidgetRenderer.tsx | 5 +-- .../CloudPulseDashboardFilterBuilder.tsx | 33 +++++++------------ .../manager/src/queries/cloudpulse/metrics.ts | 4 +-- .../src/queries/cloudpulse/services.ts | 3 +- 9 files changed, 37 insertions(+), 41 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index a898bea8a36..afc65e94a84 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -12,9 +12,9 @@ import { import { useAclpPreference } from '../Utils/UserPreference'; import { RenderWidgets } from '../Widget/CloudPulseWidgetRenderer'; +import type { CloudPulseResources } from '../shared/CloudPulseResourcesSelect'; import type { CloudPulseMetricsAdditionalFilters } from '../Widget/CloudPulseWidget'; import type { JWETokenPayLoad, TimeDuration } from '@linode/api-v4'; -import { CloudPulseResources } from '../shared/CloudPulseResourcesSelect'; export interface DashboardProperties { /** @@ -108,11 +108,7 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { return renderErrorState('Error loading the definitions of metrics.'); } - if ( - isMetricDefinitionLoading || - isDashboardLoading || - isJweTokenLoading - ) { + if (isMetricDefinitionLoading || isDashboardLoading) { return ; } @@ -121,7 +117,8 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { additionalFilters={additionalFilters} dashboard={dashboard} duration={duration} - jweToken={jweToken} + isJweTokenLoading={isJweTokenLoading} + jweToken={isJweTokenLoading ? undefined : jweToken} manualRefreshTimeStamp={manualRefreshTimeStamp} metricDefinitions={metricDefinitions} preferences={preferences} diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx index e886ad9101e..c1b01e05b64 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx @@ -5,10 +5,13 @@ import { GlobalFilters } from '../Overview/GlobalFilters'; import { CloudPulseDashboardRenderer } from './CloudPulseDashboardRenderer'; import type { CloudPulseResources } from '../shared/CloudPulseResourcesSelect'; -import type { Dashboard, TimeDuration } from '@linode/api-v4'; +import type { AclpWidget, Dashboard, TimeDuration } from '@linode/api-v4'; + +export type WidgetFilterValue = { [key: string]: AclpWidget }; export type FilterValueType = | CloudPulseResources[] + | WidgetFilterValue | number | number[] | string diff --git a/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.test.ts b/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.test.ts index 56b4e1e060f..3ac95e147d5 100644 --- a/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.test.ts +++ b/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.test.ts @@ -13,13 +13,18 @@ const mockDashboard = dashboardFactory.build(); it('test getDashboardProperties method', () => { const result = getDashboardProperties({ dashboardObj: mockDashboard, - filterValue: { region: 'us-east' }, + filterValue: { + region: 'us-east', + resource_id: [{ id: '1', label: 'linode-1', region: 'us-east' }], + }, resource: 1, }); expect(result).toBeDefined(); expect(result.dashboardId).toEqual(mockDashboard.id); - expect(result.resources).toEqual(['1']); + expect(result.resources).toEqual([ + { id: '1', label: 'linode-1', region: 'us-east' }, + ]); }); it('test checkMandatoryFiltersSelected method for time duration and resource', () => { diff --git a/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.ts b/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.ts index 969b5f1f543..06911d0c02b 100644 --- a/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.ts @@ -1,7 +1,9 @@ +import { RESOURCE_ID } from './constants'; import { FILTER_CONFIG } from './FilterConfig'; import type { DashboardProperties } from '../Dashboard/CloudPulseDashboard'; import type { FilterValueType } from '../Dashboard/CloudPulseDashboardLanding'; +import type { CloudPulseResources } from '../shared/CloudPulseResourcesSelect'; import type { CloudPulseMetricsAdditionalFilters } from '../Widget/CloudPulseWidget'; import type { Dashboard, TimeDuration } from '@linode/api-v4'; @@ -43,7 +45,7 @@ export const getDashboardProperties = ( }), dashboardId: dashboardObj.id, duration: timeDuration ?? { unit: 'min', value: 30 }, - resources: [String(resource)], + resources: filterValue[RESOURCE_ID] as CloudPulseResources[], savePref: false, }; }; diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 097404aedcf..3a957bad028 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -51,7 +51,7 @@ export interface CloudPulseWidgetProperties { /** * token to fetch metrics data */ - authToken: string; + authToken?: string; /** * metrics defined of this widget @@ -232,7 +232,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { }, { authToken, - isFlags: Boolean(flags), + isFlags: Boolean(flags && authToken), label: widget.label, timeStamp, url: flags.aclpReadEndpoint!, diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx index 65a787fb7f3..a482d95dd4f 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx @@ -30,11 +30,11 @@ interface WidgetProps { additionalFilters?: CloudPulseMetricsAdditionalFilters[]; dashboard?: Dashboard | undefined; duration: TimeDuration; + isJweTokenLoading: boolean; jweToken?: JWEToken | undefined; manualRefreshTimeStamp?: number; metricDefinitions: MetricDefinitions | undefined; preferences?: AclpConfig; - //resourceList: CloudPulseResources[] | undefined; resources: CloudPulseResources[]; savePref?: boolean; } @@ -55,6 +55,7 @@ export const RenderWidgets = React.memo( additionalFilters, dashboard, duration, + isJweTokenLoading, jweToken, manualRefreshTimeStamp, metricDefinitions, @@ -122,7 +123,7 @@ export const RenderWidgets = React.memo( if ( !dashboard.service_type || !Boolean(resources.length > 0) || - !jweToken?.token || + (!isJweTokenLoading && !jweToken?.token) || !Boolean(resources?.length) ) { return renderPlaceHolder( diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index b2183d6a562..378c3aaf906 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -23,24 +23,16 @@ import { } from '../Utils/FilterBuilder'; import { FILTER_CONFIG } from '../Utils/FilterConfig'; -import type { FilterValueType } from '../Dashboard/CloudPulseDashboardLanding'; +import type { + FilterValueType, + WidgetFilterValue, +} from '../Dashboard/CloudPulseDashboardLanding'; import type { CloudPulseServiceTypeFilters } from '../Utils/models'; import type { CloudPulseResources } from './CloudPulseResourcesSelect'; -import type { AclpConfig, AclpWidget, Dashboard } from '@linode/api-v4'; - -type WidgetFilterValue = { [key: string]: AclpWidget }; - -type FilterValue = - | CloudPulseResources[] - | WidgetFilterValue - | number - | number[] - | string - | string[] - | undefined; +import type { AclpConfig, Dashboard } from '@linode/api-v4'; interface AclpConfigExtended { - [key: string]: FilterValue; + [key: string]: FilterValueType; widgets?: WidgetFilterValue; } @@ -137,14 +129,11 @@ export const CloudPulseDashboardFilterBuilder = React.memo( const handleResourceChange = React.useCallback( (resources: CloudPulseResources[], savePref: boolean = false) => { - emitFilterChangeByFilterKey( - RESOURCE_ID, - resources, - savePref, - { - [RESOURCES]: resources, - } - ); + emitFilterChangeByFilterKey(RESOURCE_ID, resources, savePref, { + [RESOURCES]: resources.map((resource: { id: string }) => + String(resource.id) + ), + }); }, [emitFilterChangeByFilterKey] ); diff --git a/packages/manager/src/queries/cloudpulse/metrics.ts b/packages/manager/src/queries/cloudpulse/metrics.ts index 4f6f23622ab..f83b7fd98f9 100644 --- a/packages/manager/src/queries/cloudpulse/metrics.ts +++ b/packages/manager/src/queries/cloudpulse/metrics.ts @@ -18,7 +18,7 @@ export const useCloudPulseMetricsQuery = ( serviceType: string, request: CloudPulseMetricsRequest, obj: { - authToken: string; + authToken?: string; isFlags: boolean; label: string; timeStamp: number | undefined; @@ -29,7 +29,7 @@ export const useCloudPulseMetricsQuery = ( const query = useQuery({ ...queryFactory.metrics( - obj.authToken, + obj.authToken ?? '', obj.url, serviceType, request, diff --git a/packages/manager/src/queries/cloudpulse/services.ts b/packages/manager/src/queries/cloudpulse/services.ts index 743aad0ac5e..f71e04deeb3 100644 --- a/packages/manager/src/queries/cloudpulse/services.ts +++ b/packages/manager/src/queries/cloudpulse/services.ts @@ -1,4 +1,4 @@ -import { keepPreviousData, useQuery } from '@tanstack/react-query'; +import { useQuery } from '@tanstack/react-query'; import { queryFactory } from './queries'; @@ -28,7 +28,6 @@ export const useCloudPulseJWEtokenQuery = ( return useQuery({ ...queryFactory.token(serviceType, request), enabled: runQuery, - placeholderData: keepPreviousData, refetchOnWindowFocus: false, }); }; From 5f2c31905d10cd4695a74cf5eb933f76005afaa4 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Mon, 18 Nov 2024 10:59:27 +0530 Subject: [PATCH 328/474] upcoming: [DI-21119] - Comments updated --- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 14 +++++++------- .../CloudPulse/Widget/CloudPulseWidget.tsx | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index 8b386768eb4..8cddbb07f94 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -44,7 +44,7 @@ interface LabelNameOptionsProps { metric: { [label: string]: string }; /** - * list of CloudPulseResources available + * list of selected CloudPulseResources */ resources: CloudPulseResources[]; @@ -76,7 +76,7 @@ interface GraphDataOptionsProps { metricsList: CloudPulseMetricsResponse | undefined; /** - * list of CloudPulse resources + * list of selected CloudPulse resources */ resources: CloudPulseResources[]; @@ -108,7 +108,7 @@ interface MetricRequestProps { resourceIds: string[]; /** - * list of CloudPulse resources available + * list of selected CloudPulse resources */ resources: CloudPulseResources[]; @@ -130,7 +130,7 @@ interface DimensionNameProperties { metric: { [label: string]: string }; /** - * resources list of CloudPulseResources available + * list of selected CloudPulseResources */ resources: CloudPulseResources[]; } @@ -323,7 +323,7 @@ const getLabelName = (props: LabelNameOptionsProps): string => { /** * - * @returns generated dimension name based on resources + * @returns generated dimension name based on selected resources */ export const getDimensionName = (props: DimensionNameProperties): string => { const { flag, metric, resources } = props; @@ -341,8 +341,8 @@ export const getDimensionName = (props: DimensionNameProperties): string => { /** * - * @param id resource id that should be searched in resources list - * @param resources list of CloudPulseResources available + * @param id resource id that should be searched in selected resources list + * @param resources list of selected CloudPulseResources * @returns resource label if id is found, the id if label is not found, and fall back on an empty string with an undefined id */ export const mapResourceIdToName = ( diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 3a957bad028..0391e83db58 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -74,7 +74,7 @@ export interface CloudPulseWidgetProperties { resourceIds: string[]; /** - * List of resources available of selected service type + * List of selected resources available of selected service type */ resources: CloudPulseResources[]; From 9895122fceef58cf6a5b6a700d2112bbe1c14024 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Mon, 18 Nov 2024 12:36:05 +0530 Subject: [PATCH 329/474] upcoming: [DI-21119] - Small fix --- .../features/CloudPulse/Dashboard/CloudPulseDashboard.tsx | 6 +++--- .../features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index afc65e94a84..522987a6cdd 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -89,7 +89,7 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { const { data: jweToken, isError: isJweTokenError, - isLoading: isJweTokenLoading, + isFetching: isJweTokenFetching, } = useCloudPulseJWEtokenQuery( dashboard?.service_type, getJweTokenPayload(), @@ -117,8 +117,8 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { additionalFilters={additionalFilters} dashboard={dashboard} duration={duration} - isJweTokenLoading={isJweTokenLoading} - jweToken={isJweTokenLoading ? undefined : jweToken} + isJweTokenFetching={isJweTokenFetching} + jweToken={isJweTokenFetching ? undefined : jweToken} manualRefreshTimeStamp={manualRefreshTimeStamp} metricDefinitions={metricDefinitions} preferences={preferences} diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx index a482d95dd4f..9d2435d3d63 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx @@ -30,7 +30,7 @@ interface WidgetProps { additionalFilters?: CloudPulseMetricsAdditionalFilters[]; dashboard?: Dashboard | undefined; duration: TimeDuration; - isJweTokenLoading: boolean; + isJweTokenFetching: boolean; jweToken?: JWEToken | undefined; manualRefreshTimeStamp?: number; metricDefinitions: MetricDefinitions | undefined; @@ -55,7 +55,7 @@ export const RenderWidgets = React.memo( additionalFilters, dashboard, duration, - isJweTokenLoading, + isJweTokenFetching, jweToken, manualRefreshTimeStamp, metricDefinitions, @@ -123,7 +123,7 @@ export const RenderWidgets = React.memo( if ( !dashboard.service_type || !Boolean(resources.length > 0) || - (!isJweTokenLoading && !jweToken?.token) || + (!isJweTokenFetching && !jweToken?.token) || !Boolean(resources?.length) ) { return renderPlaceHolder( From 8db62b49e09894243ab2d966bf5d3a8fb802ae90 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Mon, 18 Nov 2024 13:55:09 +0530 Subject: [PATCH 330/474] upcoming: [DI-21119] - Small fix --- .../src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx index 9d2435d3d63..020726ef78c 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx @@ -122,7 +122,6 @@ export const RenderWidgets = React.memo( if ( !dashboard.service_type || - !Boolean(resources.length > 0) || (!isJweTokenFetching && !jweToken?.token) || !Boolean(resources?.length) ) { From e61eadc6b5ecb9aeed502909e071358f1a2b22ef Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Mon, 18 Nov 2024 16:22:35 +0530 Subject: [PATCH 331/474] upcoming: [DI-21119] - PR comments --- .../CloudPulse/Dashboard/CloudPulseDashboard.tsx | 2 +- .../features/CloudPulse/Widget/CloudPulseWidget.tsx | 10 ++++++++-- .../CloudPulse/Widget/CloudPulseWidgetRenderer.tsx | 2 ++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index 522987a6cdd..5b60794e59e 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -118,7 +118,7 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { dashboard={dashboard} duration={duration} isJweTokenFetching={isJweTokenFetching} - jweToken={isJweTokenFetching ? undefined : jweToken} + jweToken={jweToken} manualRefreshTimeStamp={manualRefreshTimeStamp} metricDefinitions={metricDefinitions} preferences={preferences} diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 0391e83db58..7d8bbf5f605 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -68,6 +68,11 @@ export interface CloudPulseWidgetProperties { */ errorLabel?: string; + /** + * Jwe token fetching status check + */ + isJweTokenFetching: boolean; + /** * resources ids selected by user to show metrics for */ @@ -136,6 +141,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { authToken, availableMetrics, duration, + isJweTokenFetching, resourceIds, resources, savePref, @@ -232,7 +238,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { }, { authToken, - isFlags: Boolean(flags && authToken), + isFlags: Boolean(flags && !isJweTokenFetching), label: widget.label, timeStamp, url: flags.aclpReadEndpoint!, @@ -332,7 +338,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { dotRadius={1.5} height={424} legendRows={legendRows} - loading={isLoading || metricsApiCallError === jweTokenExpiryError} // keep loading until we fetch the refresh token + loading={isLoading || isJweTokenFetching} // keep loading until we are trying to fetch the refresh token showDot showLegend={data.length !== 0} timezone={timezone} diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx index 020726ef78c..e0fe50c5a77 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx @@ -74,6 +74,7 @@ export const RenderWidgets = React.memo( availableMetrics: undefined, duration, errorLabel: 'Error occurred while loading data.', + isJweTokenFetching: false, resourceIds: resources.map((resource) => String(resource.id)), resources: [], serviceType: dashboard?.service_type ?? '', @@ -161,6 +162,7 @@ export const RenderWidgets = React.memo( {...cloudPulseWidgetProperties} authToken={jweToken?.token} availableMetrics={availMetrics} + isJweTokenFetching={isJweTokenFetching} resources={resources} savePref={savePref} /> From 22c7a51cd4fb93eb50d82f3714a080ef4086f69b Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Tue, 19 Nov 2024 15:58:30 +0530 Subject: [PATCH 332/474] upcoming: [DI-21200] - Code optimization --- packages/api-v4/src/cloudpulse/types.ts | 2 +- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 37 ------------------- .../CloudPulse/Widget/CloudPulseWidget.tsx | 2 +- .../Widget/components/CloudPulseLineGraph.tsx | 9 +++-- 4 files changed, 8 insertions(+), 42 deletions(-) diff --git a/packages/api-v4/src/cloudpulse/types.ts b/packages/api-v4/src/cloudpulse/types.ts index 19a5149c76a..44723907337 100644 --- a/packages/api-v4/src/cloudpulse/types.ts +++ b/packages/api-v4/src/cloudpulse/types.ts @@ -28,7 +28,7 @@ export interface Widgets { namespace_id: number; color: string; size: number; - chart_type: string; + chart_type: 'line' | 'area'; y_label: string; filters: Filters[]; serviceType: string; diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index 5fae267941d..6635ae3f073 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -370,40 +370,3 @@ export const getAutocompleteWidgetStyles = (theme: Theme) => ({ width: '90px', }, }); - -/** - * This method handles the existing issue in chart JS, and it will deleted when the recharts migration is completed - * @param arraysToBeFilled The list of dimension data to be filled - * @returns The list of dimension data filled with null values for missing timestamps - */ -// TODO: CloudPulse - delete when recharts migration completed -export const fillMissingTimeStampsAcrossDimensions = ( - ...arraysToBeFilled: [number, null | number][][] -): [number, null | number][][] => { - if (arraysToBeFilled.length === 0) { - return []; - } - - // Step 1: Collect all unique keys from all arrays - const allTimestamps = new Set(); - - // Collect timestamps from each array, array[0], contains the number timestamp - arraysToBeFilled.forEach((array) => { - array.forEach(([timeStamp]) => allTimestamps.add(timeStamp)); - }); - - // Step 2: Sort the timestamps to maintain chronological order - const sortedTimestamps = Array.from(allTimestamps).sort((a, b) => a - b); - - // Step 3: Synchronize the arrays to have null values for all missing timestamps - return arraysToBeFilled.map((array) => { - // Step 3.1: Convert the array into a map for fast lookup - const map = new Map(array.map(([key, value]) => [key, value])); - - // Step 3.2: Build the synchronized array by checking if a key exists - return sortedTimestamps.map((key) => { - // If the current array has the key, use its value; otherwise, set it to null, so that the gap is properly visible - return [key, map.get(key) ?? null] as [number, null | number]; - }); - }); -}; diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 6355917a0c1..19c208e61f4 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -243,7 +243,7 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { let legendRows: MetricsDisplayRow[] = []; let currentUnit = unit; let areas: AreaProps[] = []; - const variant: ChartVariant = widget.chart_type === 'line' ? 'line' : 'area'; + const variant: ChartVariant = widget.chart_type; if (!isLoading && metricsList) { const generatedData = generateGraphData({ flags, diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index cb44af105bf..e07cd72627c 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -1,5 +1,5 @@ import { CircleProgress } from '@linode/ui'; -import { Box, Typography, useTheme } from '@mui/material'; +import { Box, Typography, useMediaQuery, useTheme } from '@mui/material'; import * as React from 'react'; import { AreaChart } from 'src/components/AreaChart/AreaChart'; @@ -21,6 +21,10 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { const { error, loading, ...rest } = props; const theme = useTheme(); + + // to reduce the x-axis tick count for small screen + const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm')); + if (loading) { return ; } @@ -30,7 +34,6 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { } const noDataMessage = 'No data to display'; - return ( {error ? ( @@ -42,7 +45,7 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { {...rest} fillOpacity={0.5} legendHeight={theme.spacing(16)} - xAxisTickCount={7} + xAxisTickCount={isSmallScreen ? 5 : 7} /> )} {rest.data.length === 0 && ( From 9676ce4489aee1897306c68b5cf62b8967ece449 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Tue, 19 Nov 2024 16:03:39 +0530 Subject: [PATCH 333/474] upcoming: [DI-21200] - Updated type safety --- .../src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index 6635ae3f073..ea134158445 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -86,9 +86,9 @@ interface GraphDataOptionsProps { serviceType: string; /** - * status returned from react query ( loading | error | success) + * status returned from react query ( pending | error | success) */ - status: string | undefined; + status: 'error' | 'pending' | 'success'; /** * unit of the data From 7a133a72f1a4d88aa23932147104440df840c821 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Tue, 19 Nov 2024 16:25:35 +0530 Subject: [PATCH 334/474] upcoming: [DI-21200] - Updated x-axis tick count for different screen size --- .../CloudPulse/Widget/components/CloudPulseLineGraph.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index e07cd72627c..2c2da86d460 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -45,7 +45,7 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { {...rest} fillOpacity={0.5} legendHeight={theme.spacing(16)} - xAxisTickCount={isSmallScreen ? 5 : 7} + xAxisTickCount={isSmallScreen ? undefined : 7} /> )} {rest.data.length === 0 && ( From 7d18662fab874d9c2494f8c33834214ce47f5a28 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Tue, 19 Nov 2024 16:28:42 +0530 Subject: [PATCH 335/474] upcoming: [DI-21999] - Bug fix for resource limit selection --- .../shared/CloudPulseResourcesSelect.tsx | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index 8137590ea25..6c0cd10faeb 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -1,8 +1,11 @@ -import { Box, ListItem } from '@mui/material'; +import { Box } from '@mui/material'; import React from 'react'; import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; -import { SelectedIcon } from 'src/components/Autocomplete/Autocomplete.styles'; +import { + SelectedIcon, + StyledListItem, +} from 'src/components/Autocomplete/Autocomplete.styles'; import { useFlags } from 'src/hooks/useFlags'; import { useResourcesQuery } from 'src/queries/cloudpulse/resources'; import { themes } from 'src/utilities/theme'; @@ -142,10 +145,20 @@ export const CloudPulseResourcesSelect = React.memo( const isResourceSelected = selectedResources?.some( (item) => item.label === option.label ); + + const isSelectAllORDeslectAllOption = + option.label === 'Select All ' || option.label === 'Deselect All '; + const isMaxSelectionsReached = selectedResources && selectedResources.length >= maxResourceSelectionLimit && - !isResourceSelected; + !isResourceSelected && + !isSelectAllORDeslectAllOption; + + const ListItem = isSelectAllORDeslectAllOption + ? StyledListItem + : 'li'; + return ( Date: Tue, 19 Nov 2024 17:30:44 +0530 Subject: [PATCH 336/474] upcoming: [DI-21200] - updated test cases --- .../core/cloudpulse/dbaas-widgets-verification.spec.ts | 8 ++++---- .../core/cloudpulse/linode-widget-verification.spec.ts | 8 +++----- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts index 0634d51fdbc..e57b259d25e 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts @@ -49,6 +49,8 @@ import { formatToolTip } from 'src/features/CloudPulse/Utils/unitConversion'; const expectedGranularityArray = ['Auto', '1 day', '1 hr', '5 min']; const timeDurationToSelect = 'Last 24 Hours'; +const flags : Partial= {aclp: { enabled: true, beta: true}} + const { metrics, id, @@ -122,7 +124,7 @@ const getWidgetLegendRowValuesFromResponse = ( ) => { // Generate graph data using the provided parameters const graphData = generateGraphData({ - flags: { enabled: true } as Partial, + flags, label: label, metricsList: responsePayload, resources: [ @@ -164,9 +166,7 @@ const databaseMock: Database = databaseFactory.build({ describe('Integration Tests for DBaaS Dashboard ', () => { beforeEach(() => { - mockAppendFeatureFlags({ - aclp: { beta: true, enabled: true }, - }); + mockAppendFeatureFlags(flags); mockGetAccount(mockAccount); // Enables the account to have capability for Akamai Cloud Pulse mockGetLinodes([mockLinode]); mockGetCloudPulseMetricDefinitions(serviceType, metricDefinitions); diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 3fca58d1d5b..731e53bf993 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -46,7 +46,7 @@ import { formatToolTip } from 'src/features/CloudPulse/Utils/unitConversion'; */ const expectedGranularityArray = ['Auto', '1 day', '1 hr', '5 min']; const timeDurationToSelect = 'Last 24 Hours'; - +const flags : Partial = {aclp: {enabled: true, beta: true}} const { metrics, id, @@ -118,7 +118,7 @@ const getWidgetLegendRowValuesFromResponse = ( ) => { // Generate graph data using the provided parameters const graphData = generateGraphData({ - flags: { enabled: true } as Partial, + flags, label: label, metricsList: responsePayload, resources: [ @@ -146,9 +146,7 @@ const getWidgetLegendRowValuesFromResponse = ( describe('Integration Tests for Linode Dashboard ', () => { beforeEach(() => { - mockAppendFeatureFlags({ - aclp: { beta: true, enabled: true }, - }); + mockAppendFeatureFlags(flags); mockGetAccount(mockAccount); // Enables the account to have capability for Akamai Cloud Pulse mockGetLinodes([mockLinode]); mockGetCloudPulseMetricDefinitions(serviceType, metricDefinitions); From 258d73ecbbc0a265ccc88d4eeb09bfeb266eb908 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Tue, 19 Nov 2024 17:41:36 +0530 Subject: [PATCH 337/474] upcoming: [DI-21200] - Fixed eslint error --- packages/manager/src/factories/dashboards.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/manager/src/factories/dashboards.ts b/packages/manager/src/factories/dashboards.ts index 9506c349794..371252ec79d 100644 --- a/packages/manager/src/factories/dashboards.ts +++ b/packages/manager/src/factories/dashboards.ts @@ -7,9 +7,10 @@ import type { Dashboard, Widgets, } from '@linode/api-v4'; +import type { ChartVariant } from 'src/components/AreaChart/AreaChart'; const color = ['blue', 'red', 'green', 'yellow']; -const chart_type = ['area', 'area', 'area', 'line']; +const chart_type: ChartVariant[] = ['area', 'area', 'area', 'line']; const scrape_interval = ['2m', '30s', '30s', '30s']; export const dashboardFactory = Factory.Sync.makeFactory({ From f0cce9d8ffcb7eeb7c9142e6f20a6412cbd67d04 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Tue, 19 Nov 2024 18:13:49 +0530 Subject: [PATCH 338/474] upcoming: [DI-21200] - Added test cases --- .../src/components/AreaChart/utils.test.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/packages/manager/src/components/AreaChart/utils.test.ts b/packages/manager/src/components/AreaChart/utils.test.ts index 1b98dd93e9d..23af99b6ffa 100644 --- a/packages/manager/src/components/AreaChart/utils.test.ts +++ b/packages/manager/src/components/AreaChart/utils.test.ts @@ -1,6 +1,7 @@ import { determinePower } from 'src/utilities/unitConversions'; import { + generate12HourTicks, getAccessibleTimestamp, humanizeLargeData, tooltipLabelFormatter, @@ -72,3 +73,24 @@ describe('determinePower', () => { ).toBe(1); }); }); + +describe('generate x-axis ticks', () => { + const data = [ + { label: '0.3744841110560275', timestamp: 1721854379 }, + { label: '0.4980357104166823', timestamp: 1721857979 }, + { label: '0.3290476561287732', timestamp: 1721861579 }, + { label: '0.42148793964961897', timestamp: 1721865179 }, + { label: '0.2269247326830727', timestamp: 1721868779 }, + { label: '0.3393055885526987', timestamp: 1721872379 }, + { label: '0.5237102833940027', timestamp: 1721875979 }, + ]; + it('should return empty x-axis tick list', () => { + const ticks = generate12HourTicks(data, 'GMT', 0); + expect(ticks.length).toBe(0); + }); + + it('should return 7 x-axis tick', () => { + const ticks = generate12HourTicks(data, 'GMT', 7); + expect(ticks.length).toBe(7); + }); +}); From 7db15f4245faca9b01740b039b92116e30e13b4e Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Tue, 19 Nov 2024 18:14:07 +0530 Subject: [PATCH 339/474] upcoming: [DI-21200] - Updated changeset --- .../.changeset/pr-11204-upcoming-features-1732020050249.md | 5 +++++ .../.changeset/pr-11204-upcoming-features-1730713318901.md | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 packages/api-v4/.changeset/pr-11204-upcoming-features-1732020050249.md diff --git a/packages/api-v4/.changeset/pr-11204-upcoming-features-1732020050249.md b/packages/api-v4/.changeset/pr-11204-upcoming-features-1732020050249.md new file mode 100644 index 00000000000..4444ce3f7ef --- /dev/null +++ b/packages/api-v4/.changeset/pr-11204-upcoming-features-1732020050249.md @@ -0,0 +1,5 @@ +--- +"@linode/api-v4": Upcoming Features +--- + +Modify `chart_type` property type in `types.ts` ([#11204](https://github.com/linode/manager/pull/11204)) diff --git a/packages/manager/.changeset/pr-11204-upcoming-features-1730713318901.md b/packages/manager/.changeset/pr-11204-upcoming-features-1730713318901.md index d35b05d620c..2b1252d3b29 100644 --- a/packages/manager/.changeset/pr-11204-upcoming-features-1730713318901.md +++ b/packages/manager/.changeset/pr-11204-upcoming-features-1730713318901.md @@ -2,4 +2,4 @@ "@linode/manager": Upcoming Features --- -Replace `LineGraph` with `AreaChart` and add `DataSet` type in `CloudPulseLineGraph` component, add `connectNulls` property in `AreaChart.ts` ([#11204](https://github.com/linode/manager/pull/11204)) +Replace `LineGraph` with `AreaChart` and add `DataSet` type in `CloudPulseLineGraph` component, add `connectNulls`, `dotRadius`, `showDot`, `xAxisTickCount` property and `ChartVariant` interface in `AreaChart.ts` ([#11204](https://github.com/linode/manager/pull/11204)) From 3406546baa1d889fef97109e658627e99d53d7d1 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Tue, 19 Nov 2024 18:25:09 +0530 Subject: [PATCH 340/474] upcoming: [DI-21999] - Improved test coverage --- .../shared/CloudPulseResourcesSelect.test.tsx | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx index 7c20da6c349..5278c147259 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx @@ -103,7 +103,7 @@ describe('CloudPulseResourcesSelect component tests', () => { it('should be able to deselect the selected resources', () => { queryMocks.useResourcesQuery.mockReturnValue({ - data: linodeFactory.buildList(2), + data: linodeFactory.buildList(10), isError: false, isLoading: false, status: 'success', @@ -148,23 +148,23 @@ describe('CloudPulseResourcesSelect component tests', () => { /> ); fireEvent.click(screen.getByRole('button', { name: 'Open' })); - fireEvent.click(screen.getByRole('option', { name: 'linode-9' })); - fireEvent.click(screen.getByRole('option', { name: 'linode-10' })); + fireEvent.click(screen.getByRole('option', { name: 'linode-17' })); + fireEvent.click(screen.getByRole('option', { name: 'linode-18' })); expect(screen.getByLabelText('Resources')).toBeInTheDocument(); expect( screen.getByRole('option', { - name: 'linode-9', + name: 'linode-17', }) ).toHaveAttribute(ARIA_SELECTED, 'true'); expect( screen.getByRole('option', { - name: 'linode-10', + name: 'linode-18', }) ).toHaveAttribute(ARIA_SELECTED, 'true'); expect( screen.getByRole('option', { - name: 'linode-11', + name: 'linode-19', }) ).toHaveAttribute(ARIA_SELECTED, 'false'); expect( @@ -183,7 +183,7 @@ describe('CloudPulseResourcesSelect component tests', () => { renderWithTheme( { expect( screen.getByRole('button', { - name: 'linode-12', + name: 'linode-20', }) ).toBeInTheDocument(); @@ -202,7 +202,7 @@ describe('CloudPulseResourcesSelect component tests', () => { expect( screen.getByRole('option', { - name: 'linode-13', + name: 'linode-21', }) ).toHaveAttribute(ARIA_SELECTED, 'false'); }); @@ -253,7 +253,7 @@ describe('CloudPulseResourcesSelect component tests', () => { expect(screen.getByText('Failed to fetch Resources.')).toBeInTheDocument(); }); - it('should be able to select limited resources', () => { + it('should be able to select limited resources and select/deselect all will not be available if resource are more than max resource selection limit', () => { queryMocks.useResourcesQuery.mockReturnValue({ data: linodeFactory.buildList(12), isError: false, @@ -274,7 +274,7 @@ describe('CloudPulseResourcesSelect component tests', () => { expect(screen.getByLabelText('Resources')).toBeInTheDocument(); expect(screen.getByText('Select up to 10 Resources')).toBeInTheDocument(); - for (let i = 14; i <= 23; i++) { + for (let i = 22; i <= 31; i++) { fireEvent.click(screen.getByRole('option', { name: `linode-${i}` })); } const selectedOptions = screen @@ -282,7 +282,7 @@ describe('CloudPulseResourcesSelect component tests', () => { .filter((option) => option.getAttribute(ARIA_SELECTED) === 'true'); expect(selectedOptions.length).toBe(10); - expect(screen.getByRole('option', { name: `linode-24` })).toHaveAttribute( + expect(screen.getByRole('option', { name: `linode-32` })).toHaveAttribute( ARIA_DISABLED, 'true' ); From 69585985c99b1e103d6d7c47c72478382485990b Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Wed, 20 Nov 2024 08:15:37 +0530 Subject: [PATCH 341/474] upcoming: [DI-21999] - Updated UT --- .../shared/CloudPulseResourcesSelect.test.tsx | 49 ++++++++++++++----- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx index 5278c147259..800f9ca4cd2 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx @@ -103,7 +103,7 @@ describe('CloudPulseResourcesSelect component tests', () => { it('should be able to deselect the selected resources', () => { queryMocks.useResourcesQuery.mockReturnValue({ - data: linodeFactory.buildList(10), + data: linodeFactory.buildList(2), isError: false, isLoading: false, status: 'success', @@ -148,23 +148,23 @@ describe('CloudPulseResourcesSelect component tests', () => { /> ); fireEvent.click(screen.getByRole('button', { name: 'Open' })); - fireEvent.click(screen.getByRole('option', { name: 'linode-17' })); - fireEvent.click(screen.getByRole('option', { name: 'linode-18' })); + fireEvent.click(screen.getByRole('option', { name: 'linode-9' })); + fireEvent.click(screen.getByRole('option', { name: 'linode-10' })); expect(screen.getByLabelText('Resources')).toBeInTheDocument(); expect( screen.getByRole('option', { - name: 'linode-17', + name: 'linode-9', }) ).toHaveAttribute(ARIA_SELECTED, 'true'); expect( screen.getByRole('option', { - name: 'linode-18', + name: 'linode-10', }) ).toHaveAttribute(ARIA_SELECTED, 'true'); expect( screen.getByRole('option', { - name: 'linode-19', + name: 'linode-11', }) ).toHaveAttribute(ARIA_SELECTED, 'false'); expect( @@ -183,7 +183,7 @@ describe('CloudPulseResourcesSelect component tests', () => { renderWithTheme( { expect( screen.getByRole('button', { - name: 'linode-20', + name: 'linode-12', }) ).toBeInTheDocument(); @@ -202,7 +202,7 @@ describe('CloudPulseResourcesSelect component tests', () => { expect( screen.getByRole('option', { - name: 'linode-21', + name: 'linode-13', }) ).toHaveAttribute(ARIA_SELECTED, 'false'); }); @@ -274,7 +274,7 @@ describe('CloudPulseResourcesSelect component tests', () => { expect(screen.getByLabelText('Resources')).toBeInTheDocument(); expect(screen.getByText('Select up to 10 Resources')).toBeInTheDocument(); - for (let i = 22; i <= 31; i++) { + for (let i = 14; i <= 23; i++) { fireEvent.click(screen.getByRole('option', { name: `linode-${i}` })); } const selectedOptions = screen @@ -282,11 +282,38 @@ describe('CloudPulseResourcesSelect component tests', () => { .filter((option) => option.getAttribute(ARIA_SELECTED) === 'true'); expect(selectedOptions.length).toBe(10); - expect(screen.getByRole('option', { name: `linode-32` })).toHaveAttribute( + expect(screen.getByRole('option', { name: `linode-24` })).toHaveAttribute( ARIA_DISABLED, 'true' ); expect(queryByRole('option', { name: SELECT_ALL })).not.toBeInTheDocument(); }); + + it('should be able to select all and deselect all the resources when number of resources are equal to resource limit', () => { + queryMocks.useResourcesQuery.mockReturnValue({ + data: linodeFactory.buildList(10), + isError: false, + isLoading: false, + status: 'success', + }); + renderWithTheme( + + ); + fireEvent.click(screen.getByRole('button', { name: 'Open' })); + fireEvent.click(screen.getByRole('option', { name: SELECT_ALL })); + fireEvent.click(screen.getByRole('option', { name: 'Deselect All' })); + expect(screen.getByLabelText('Resources')).toBeInTheDocument(); + + for (let i = 26; i <= 35; i++) { + expect( + screen.getByRole('option', { name: `linode-${i}` }) + ).toHaveAttribute(ARIA_SELECTED, 'false'); + } + }); }); From 496d4387537f629324b8040adaa84fa6d4620682 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 20 Nov 2024 12:24:09 +0530 Subject: [PATCH 342/474] upcoming: [DI-21200] - Renamed metrics display styles file --- .../{MetricDisplay.styles.ts => MetricsDisplay.styles.ts} | 0 packages/manager/src/components/LineGraph/MetricsDisplay.tsx | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename packages/manager/src/components/LineGraph/{MetricDisplay.styles.ts => MetricsDisplay.styles.ts} (100%) diff --git a/packages/manager/src/components/LineGraph/MetricDisplay.styles.ts b/packages/manager/src/components/LineGraph/MetricsDisplay.styles.ts similarity index 100% rename from packages/manager/src/components/LineGraph/MetricDisplay.styles.ts rename to packages/manager/src/components/LineGraph/MetricsDisplay.styles.ts diff --git a/packages/manager/src/components/LineGraph/MetricsDisplay.tsx b/packages/manager/src/components/LineGraph/MetricsDisplay.tsx index 5484c287dd9..1f767e972fa 100644 --- a/packages/manager/src/components/LineGraph/MetricsDisplay.tsx +++ b/packages/manager/src/components/LineGraph/MetricsDisplay.tsx @@ -10,7 +10,7 @@ import { StyledButton, StyledTable, StyledTableCell, -} from './MetricDisplay.styles'; +} from './MetricsDisplay.styles'; import type { Metrics } from 'src/utilities/statMetrics'; From e2f7b7e293d040945a6ba4f4861e9a41b1d4d2da Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 20 Nov 2024 15:06:09 +0530 Subject: [PATCH 343/474] upcoming: [DI-21200] - Updated dataset type in place of any --- .../manager/src/components/AreaChart/AreaChart.tsx | 7 +++++++ packages/manager/src/components/AreaChart/utils.ts | 12 ++++++++++-- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 2 +- .../features/CloudPulse/Widget/CloudPulseWidget.tsx | 2 +- .../Widget/components/CloudPulseLineGraph.tsx | 5 ----- 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/packages/manager/src/components/AreaChart/AreaChart.tsx b/packages/manager/src/components/AreaChart/AreaChart.tsx index a9a3dc3651b..db9768a9413 100644 --- a/packages/manager/src/components/AreaChart/AreaChart.tsx +++ b/packages/manager/src/components/AreaChart/AreaChart.tsx @@ -28,6 +28,11 @@ import { import type { TooltipProps } from 'recharts'; import type { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay'; +export interface DataSet { + [label: string]: number; + timestamp: number; +} + export type ChartVariant = 'area' | 'line'; export interface AreaProps { @@ -145,6 +150,8 @@ export interface AreaChartProps { /** * number of x-axis ticks should be shown + * 0 or undefined : ticks will be generated by recharts + * non-zero value : this many ticks will be generated based on the starting & ending timestamp in the data */ xAxisTickCount?: number; } diff --git a/packages/manager/src/components/AreaChart/utils.ts b/packages/manager/src/components/AreaChart/utils.ts index 34f8ba94e4e..2586b048801 100644 --- a/packages/manager/src/components/AreaChart/utils.ts +++ b/packages/manager/src/components/AreaChart/utils.ts @@ -2,7 +2,8 @@ import { DateTime } from 'luxon'; import { roundTo } from 'src/utilities/roundTo'; -import { LinodeNetworkTimeData } from './types'; +import type { DataSet } from './AreaChart'; +import type { LinodeNetworkTimeData } from './types'; export const getAccessibleTimestamp = (timestamp: number, timezone: string) => DateTime.fromMillis(timestamp, { zone: timezone }).toLocaleString( @@ -36,8 +37,15 @@ export const humanizeLargeData = (value: number) => { return `${value}`; }; +/** + * + * @param data dataset for which ticks should be generated + * @param timezone timezone applicable to timestamp in the dataset + * @param tickCount number of ticks to be generated + * @returns list of tickCount number of x-axis ticks + */ export const generate12HourTicks = ( - data: any[], + data: DataSet[], timezone: string, tickCount: number ) => { diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index ea134158445..f4066808b3d 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -14,7 +14,6 @@ import { } from './utils'; import type { CloudPulseResources } from '../shared/CloudPulseResourcesSelect'; -import type { DataSet } from '../Widget/components/CloudPulseLineGraph'; import type { CloudPulseMetricsList, CloudPulseMetricsRequest, @@ -23,6 +22,7 @@ import type { Widgets, } from '@linode/api-v4'; import type { Theme } from '@mui/material'; +import type { DataSet } from 'src/components/AreaChart/AreaChart'; import type { AreaProps } from 'src/components/AreaChart/AreaChart'; import type { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay'; import type { CloudPulseResourceTypeMapFlag, FlagSet } from 'src/featureFlags'; diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 19c208e61f4..8ee8a56eb32 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -23,13 +23,13 @@ import { ZoomIcon } from './components/Zoomer'; import type { FilterValueType } from '../Dashboard/CloudPulseDashboardLanding'; import type { CloudPulseResources } from '../shared/CloudPulseResourcesSelect'; -import type { DataSet } from './components/CloudPulseLineGraph'; import type { Widgets } from '@linode/api-v4'; import type { AvailableMetrics, TimeDuration, TimeGranularity, } from '@linode/api-v4'; +import type { DataSet } from 'src/components/AreaChart/AreaChart'; import type { AreaProps, ChartVariant, diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index 2c2da86d460..a54e2c19747 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -7,11 +7,6 @@ import { ErrorState } from 'src/components/ErrorState/ErrorState'; import type { AreaChartProps } from 'src/components/AreaChart/AreaChart'; -export interface DataSet { - [label: string]: number; - timestamp: number; -} - export interface CloudPulseLineGraph extends AreaChartProps { error?: string; loading?: boolean; From 6e7d2b16149ee13b5a249c1914f92ecd52590cbc Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 20 Nov 2024 15:15:57 +0530 Subject: [PATCH 344/474] upcoming: [DI-21200] - updated test cases --- .../src/components/AreaChart/utils.test.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/manager/src/components/AreaChart/utils.test.ts b/packages/manager/src/components/AreaChart/utils.test.ts index 23af99b6ffa..c2b1bc3d99b 100644 --- a/packages/manager/src/components/AreaChart/utils.test.ts +++ b/packages/manager/src/components/AreaChart/utils.test.ts @@ -8,6 +8,7 @@ import { tooltipValueFormatter, } from './utils'; +import type { DataSet } from './AreaChart'; import type { StorageSymbol } from 'src/utilities/unitConversions'; const timestamp = 1704204000000; @@ -75,14 +76,14 @@ describe('determinePower', () => { }); describe('generate x-axis ticks', () => { - const data = [ - { label: '0.3744841110560275', timestamp: 1721854379 }, - { label: '0.4980357104166823', timestamp: 1721857979 }, - { label: '0.3290476561287732', timestamp: 1721861579 }, - { label: '0.42148793964961897', timestamp: 1721865179 }, - { label: '0.2269247326830727', timestamp: 1721868779 }, - { label: '0.3393055885526987', timestamp: 1721872379 }, - { label: '0.5237102833940027', timestamp: 1721875979 }, + const data: DataSet[] = [ + { label: 0.3744841110560275, timestamp: 1721854379 }, + { label: 0.4980357104166823, timestamp: 1721857979 }, + { label: 0.3290476561287732, timestamp: 1721861579 }, + { label: 0.4214879396496189, timestamp: 1721865179 }, + { label: 0.2269247326830727, timestamp: 1721868779 }, + { label: 0.3393055885526987, timestamp: 1721872379 }, + { label: 0.5237102833940027, timestamp: 1721875979 }, ]; it('should return empty x-axis tick list', () => { const ticks = generate12HourTicks(data, 'GMT', 0); From c570ff1ef5ae3d4aa793db3b752493b5687f21ae Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 20 Nov 2024 17:12:38 +0530 Subject: [PATCH 345/474] Removed unused function --- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 35 ------------------- .../CloudPulse/Widget/CloudPulseWidget.tsx | 12 +------ 2 files changed, 1 insertion(+), 46 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index 93fb0075208..8b386768eb4 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -369,38 +369,3 @@ export const getAutocompleteWidgetStyles = (theme: Theme) => ({ width: '90px', }, }); - -/** - * This method handles the existing issue in chart JS, and it will deleted when the recharts migration is completed - * @param arraysToBeFilled The list of dimension data to be filled - * @returns The list of dimension data filled with null values for missing timestamps - */ -// TODO: CloudPulse - delete when recharts migration completed -export const fillMissingTimeStampsAcrossDimensions = ( - ...arraysToBeFilled: [number, number | null][][] -): [number, number | null][][] => { - if (arraysToBeFilled.length === 0) return []; - - // Step 1: Collect all unique keys from all arrays - const allTimestamps = new Set(); - - // Collect timestamps from each array, array[0], contains the number timestamp - arraysToBeFilled.forEach((array) => { - array.forEach(([timeStamp]) => allTimestamps.add(timeStamp)); - }); - - // Step 2: Sort the timestamps to maintain chronological order - const sortedTimestamps = Array.from(allTimestamps).sort((a, b) => a - b); - - // Step 3: Synchronize the arrays to have null values for all missing timestamps - return arraysToBeFilled.map((array) => { - // Step 3.1: Convert the array into a map for fast lookup - const map = new Map(array.map(([key, value]) => [key, value])); - - // Step 3.2: Build the synchronized array by checking if a key exists - return sortedTimestamps.map((key) => { - // If the current array has the key, use its value; otherwise, set it to null, so that the gap is properly visible - return [key, map.get(key) ?? null] as [number, number | null]; - }); - }); -}; diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index b21f5de50ae..36052d86863 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -8,9 +8,9 @@ import { useCloudPulseMetricsQuery } from 'src/queries/cloudpulse/metrics'; import { useProfile } from 'src/queries/profile/profile'; import { + fillMissingTimeStampsAcrossDimensions, generateGraphData, getCloudPulseMetricRequest, - fillMissingTimeStampsAcrossDimensions, } from '../Utils/CloudPulseWidgetUtils'; import { AGGREGATE_FUNCTION, SIZE, TIME_GRANULARITY } from '../Utils/constants'; import { constructAdditionalRequestFilters } from '../Utils/FilterBuilder'; @@ -258,16 +258,6 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { data = generatedData.dimensions; - // add missing timestamps across all the dimensions - const filledArrays = fillMissingTimeStampsAcrossDimensions( - ...data.map((data) => data.data) - ); - - //update the chart data with updated arrays - filledArrays.forEach((arr, index) => { - data[index].data = arr; - }); - legendRows = generatedData.legendRowsData; scaledWidgetUnit.current = generatedData.unit; // here state doesn't matter, as this is always the latest re-render currentUnit = generatedData.unit; From b06fbd66f87fd5172661e0cbecd917dce2cf9bef Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 20 Nov 2024 17:48:04 +0530 Subject: [PATCH 346/474] eslint error resolved --- .../src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts | 1 - .../manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index 77909a3d532..f4066808b3d 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -18,7 +18,6 @@ import type { CloudPulseMetricsList, CloudPulseMetricsRequest, CloudPulseMetricsResponse, - DataSet, TimeDuration, Widgets, } from '@linode/api-v4'; diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index f136eacfac4..8ee8a56eb32 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -8,7 +8,6 @@ import { useCloudPulseMetricsQuery } from 'src/queries/cloudpulse/metrics'; import { useProfile } from 'src/queries/profile/profile'; import { - fillMissingTimeStampsAcrossDimensions, generateGraphData, getCloudPulseMetricRequest, } from '../Utils/CloudPulseWidgetUtils'; From 68df67b6252e87d2d8c507b23e1c0ee0a76c8893 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Wed, 20 Nov 2024 18:57:43 +0530 Subject: [PATCH 347/474] upcoming: [DI-21119] - Resources call restored and minor updates --- .../Dashboard/CloudPulseDashboard.tsx | 24 ++++++++++++--- .../Dashboard/CloudPulseDashboardLanding.tsx | 14 ++------- .../Dashboard/CloudPulseDashboardRenderer.tsx | 3 +- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 12 ++++---- .../ReusableDashboardFilterUtils.test.ts | 5 +--- .../Utils/ReusableDashboardFilterUtils.ts | 4 +-- .../CloudPulse/Widget/CloudPulseWidget.tsx | 10 +++++-- .../Widget/CloudPulseWidgetRenderer.tsx | 12 ++++---- .../CloudPulseDashboardFilterBuilder.tsx | 29 +++++++++---------- .../manager/src/queries/cloudpulse/metrics.ts | 4 +-- .../src/queries/cloudpulse/services.ts | 3 +- 11 files changed, 62 insertions(+), 58 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index 5b60794e59e..5c2ce357d3c 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -4,6 +4,7 @@ import React from 'react'; import { CircleProgress } from 'src/components/CircleProgress'; import { ErrorState } from 'src/components/ErrorState/ErrorState'; import { useCloudPulseDashboardByIdQuery } from 'src/queries/cloudpulse/dashboards'; +import { useResourcesQuery } from 'src/queries/cloudpulse/resources'; import { useCloudPulseJWEtokenQuery, useGetCloudPulseMetricDefinitionsByServiceType, @@ -12,7 +13,6 @@ import { import { useAclpPreference } from '../Utils/UserPreference'; import { RenderWidgets } from '../Widget/CloudPulseWidgetRenderer'; -import type { CloudPulseResources } from '../shared/CloudPulseResourcesSelect'; import type { CloudPulseMetricsAdditionalFilters } from '../Widget/CloudPulseWidget'; import type { JWETokenPayLoad, TimeDuration } from '@linode/api-v4'; @@ -45,7 +45,7 @@ export interface DashboardProperties { /** * Selected resources for the dashboard */ - resources: CloudPulseResources[]; + resources: string[]; /** * optional flag to check whether changes should be stored in preferences or not (in case this component is reused) @@ -67,7 +67,7 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { const getJweTokenPayload = (): JWETokenPayLoad => { return { - resource_ids: resources?.map((resource) => Number(resource.id)) ?? [], + resource_ids: resources?.map((resource) => Number(resource)) ?? [], }; }; @@ -77,6 +77,17 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { isLoading: isDashboardLoading, } = useCloudPulseDashboardByIdQuery(dashboardId); + const { + data: resourceList, + isError: isResourcesApiError, + isLoading: isResourcesLoading, + } = useResourcesQuery( + Boolean(dashboard?.service_type), + dashboard?.service_type, + {}, + dashboard?.service_type === 'dbaas' ? { platform: 'rdbms-default' } : {} + ); + const { data: metricDefinitions, isError: isMetricDefinitionError, @@ -100,6 +111,10 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { return renderErrorState('Failed to fetch the dashboard details.'); } + if (isResourcesApiError) { + return renderErrorState('Failed to fetch Resources.'); + } + if (isJweTokenError) { return renderErrorState('Failed to get the authentication token.'); } @@ -108,7 +123,7 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { return renderErrorState('Error loading the definitions of metrics.'); } - if (isMetricDefinitionLoading || isDashboardLoading) { + if (isMetricDefinitionLoading || isDashboardLoading || isResourcesLoading) { return ; } @@ -123,6 +138,7 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { metricDefinitions={metricDefinitions} preferences={preferences} resources={resources} + resourcesList={resourceList} savePref={savePref} /> ); diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx index c1b01e05b64..828a05301c7 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx @@ -4,19 +4,9 @@ import * as React from 'react'; import { GlobalFilters } from '../Overview/GlobalFilters'; import { CloudPulseDashboardRenderer } from './CloudPulseDashboardRenderer'; -import type { CloudPulseResources } from '../shared/CloudPulseResourcesSelect'; -import type { AclpWidget, Dashboard, TimeDuration } from '@linode/api-v4'; +import type { Dashboard, TimeDuration } from '@linode/api-v4'; -export type WidgetFilterValue = { [key: string]: AclpWidget }; - -export type FilterValueType = - | CloudPulseResources[] - | WidgetFilterValue - | number - | number[] - | string - | string[] - | undefined; +export type FilterValueType = number | number[] | string | string[] | undefined; export interface DashboardProp { dashboard?: Dashboard; diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx index 1a18cbe6081..a1cb03e235b 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx @@ -9,7 +9,6 @@ import { import { FILTER_CONFIG } from '../Utils/FilterConfig'; import { CloudPulseDashboard } from './CloudPulseDashboard'; -import type { CloudPulseResources } from '../shared/CloudPulseResourcesSelect'; import type { DashboardProp } from './CloudPulseDashboardLanding'; export const CloudPulseDashboardRenderer = React.memo( @@ -67,7 +66,7 @@ export const CloudPulseDashboardRenderer = React.memo( } resources={ filterValue[RESOURCE_ID] && Array.isArray(filterValue[RESOURCE_ID]) - ? (filterValue[RESOURCE_ID] as CloudPulseResources[]) + ? (filterValue[RESOURCE_ID] as string[]) : [] } additionalFilters={getMetricsCall} diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index 8cddbb07f94..992f7a0ee06 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -44,7 +44,7 @@ interface LabelNameOptionsProps { metric: { [label: string]: string }; /** - * list of selected CloudPulseResources + * list of CloudPulseResources available */ resources: CloudPulseResources[]; @@ -76,7 +76,7 @@ interface GraphDataOptionsProps { metricsList: CloudPulseMetricsResponse | undefined; /** - * list of selected CloudPulse resources + * list of CloudPulse resources */ resources: CloudPulseResources[]; @@ -108,7 +108,7 @@ interface MetricRequestProps { resourceIds: string[]; /** - * list of selected CloudPulse resources + * list of CloudPulse resources available */ resources: CloudPulseResources[]; @@ -323,7 +323,7 @@ const getLabelName = (props: LabelNameOptionsProps): string => { /** * - * @returns generated dimension name based on selected resources + * @returns generated dimension name based on resources */ export const getDimensionName = (props: DimensionNameProperties): string => { const { flag, metric, resources } = props; @@ -341,8 +341,8 @@ export const getDimensionName = (props: DimensionNameProperties): string => { /** * - * @param id resource id that should be searched in selected resources list - * @param resources list of selected CloudPulseResources + * @param id resource id that should be searched in resources list + * @param resources resources list of CloudPulseResources available * @returns resource label if id is found, the id if label is not found, and fall back on an empty string with an undefined id */ export const mapResourceIdToName = ( diff --git a/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.test.ts b/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.test.ts index 3ac95e147d5..efebbe9ef88 100644 --- a/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.test.ts +++ b/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.test.ts @@ -15,16 +15,13 @@ it('test getDashboardProperties method', () => { dashboardObj: mockDashboard, filterValue: { region: 'us-east', - resource_id: [{ id: '1', label: 'linode-1', region: 'us-east' }], }, resource: 1, }); expect(result).toBeDefined(); expect(result.dashboardId).toEqual(mockDashboard.id); - expect(result.resources).toEqual([ - { id: '1', label: 'linode-1', region: 'us-east' }, - ]); + expect(result.resources).toEqual(['1']); }); it('test checkMandatoryFiltersSelected method for time duration and resource', () => { diff --git a/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.ts b/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.ts index 06911d0c02b..969b5f1f543 100644 --- a/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.ts @@ -1,9 +1,7 @@ -import { RESOURCE_ID } from './constants'; import { FILTER_CONFIG } from './FilterConfig'; import type { DashboardProperties } from '../Dashboard/CloudPulseDashboard'; import type { FilterValueType } from '../Dashboard/CloudPulseDashboardLanding'; -import type { CloudPulseResources } from '../shared/CloudPulseResourcesSelect'; import type { CloudPulseMetricsAdditionalFilters } from '../Widget/CloudPulseWidget'; import type { Dashboard, TimeDuration } from '@linode/api-v4'; @@ -45,7 +43,7 @@ export const getDashboardProperties = ( }), dashboardId: dashboardObj.id, duration: timeDuration ?? { unit: 'min', value: 30 }, - resources: filterValue[RESOURCE_ID] as CloudPulseResources[], + resources: [String(resource)], savePref: false, }; }; diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index 7d8bbf5f605..df78ec91c4b 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -51,7 +51,7 @@ export interface CloudPulseWidgetProperties { /** * token to fetch metrics data */ - authToken?: string; + authToken: string; /** * metrics defined of this widget @@ -79,7 +79,7 @@ export interface CloudPulseWidgetProperties { resourceIds: string[]; /** - * List of selected resources available of selected service type + * List of resources available of selected service type */ resources: CloudPulseResources[]; @@ -332,13 +332,17 @@ export const CloudPulseWidget = (props: CloudPulseWidgetProperties) => { ? metricsApiCallError ?? 'Error while rendering graph' : undefined } + loading={ + isLoading || + metricsApiCallError === jweTokenExpiryError || + isJweTokenFetching + } // keep loading until we are trying to fetch the refresh token areas={areas} ariaLabel={ariaLabel ? ariaLabel : ''} data={data} dotRadius={1.5} height={424} legendRows={legendRows} - loading={isLoading || isJweTokenFetching} // keep loading until we are trying to fetch the refresh token showDot showLegend={data.length !== 0} timezone={timezone} diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx index e0fe50c5a77..6c128137dd2 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx @@ -35,7 +35,8 @@ interface WidgetProps { manualRefreshTimeStamp?: number; metricDefinitions: MetricDefinitions | undefined; preferences?: AclpConfig; - resources: CloudPulseResources[]; + resources: string[]; + resourcesList: CloudPulseResources[] | undefined; savePref?: boolean; } @@ -61,6 +62,7 @@ export const RenderWidgets = React.memo( metricDefinitions, preferences, resources, + resourcesList, savePref, } = props; @@ -75,7 +77,7 @@ export const RenderWidgets = React.memo( duration, errorLabel: 'Error occurred while loading data.', isJweTokenFetching: false, - resourceIds: resources.map((resource) => String(resource.id)), + resourceIds: resources, resources: [], serviceType: dashboard?.service_type ?? '', timeStamp: manualRefreshTimeStamp, @@ -123,8 +125,8 @@ export const RenderWidgets = React.memo( if ( !dashboard.service_type || - (!isJweTokenFetching && !jweToken?.token) || - !Boolean(resources?.length) + !Boolean(resources.length > 0) || + (!isJweTokenFetching && !jweToken?.token) ) { return renderPlaceHolder( 'Select a dashboard and filters to visualize metrics.' @@ -163,7 +165,7 @@ export const RenderWidgets = React.memo( authToken={jweToken?.token} availableMetrics={availMetrics} isJweTokenFetching={isJweTokenFetching} - resources={resources} + resources={resourcesList!} savePref={savePref} /> ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index 378c3aaf906..4444f942a57 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -23,19 +23,11 @@ import { } from '../Utils/FilterBuilder'; import { FILTER_CONFIG } from '../Utils/FilterConfig'; -import type { - FilterValueType, - WidgetFilterValue, -} from '../Dashboard/CloudPulseDashboardLanding'; +import type { FilterValueType } from '../Dashboard/CloudPulseDashboardLanding'; import type { CloudPulseServiceTypeFilters } from '../Utils/models'; import type { CloudPulseResources } from './CloudPulseResourcesSelect'; import type { AclpConfig, Dashboard } from '@linode/api-v4'; -interface AclpConfigExtended { - [key: string]: FilterValueType; - widgets?: WidgetFilterValue; -} - export interface CloudPulseDashboardFilterBuilderProps { /** * We need the dashboard here, as we can infer serviceType and other required properties from it. @@ -114,7 +106,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( filterKey: string, filterValue: FilterValueType, savePref: boolean = false, - updatedPreferenceData: AclpConfigExtended = {} + updatedPreferenceData: AclpConfig = {} ) => { emitFilterChange( filterKey, @@ -128,12 +120,17 @@ export const CloudPulseDashboardFilterBuilder = React.memo( ); const handleResourceChange = React.useCallback( - (resources: CloudPulseResources[], savePref: boolean = false) => { - emitFilterChangeByFilterKey(RESOURCE_ID, resources, savePref, { - [RESOURCES]: resources.map((resource: { id: string }) => - String(resource.id) - ), - }); + (resourceId: CloudPulseResources[], savePref: boolean = false) => { + emitFilterChangeByFilterKey( + RESOURCE_ID, + resourceId.map((resource) => resource.id), + savePref, + { + [RESOURCES]: resourceId.map((resource: { id: string }) => + String(resource.id) + ), + } + ); }, [emitFilterChangeByFilterKey] ); diff --git a/packages/manager/src/queries/cloudpulse/metrics.ts b/packages/manager/src/queries/cloudpulse/metrics.ts index f83b7fd98f9..4f6f23622ab 100644 --- a/packages/manager/src/queries/cloudpulse/metrics.ts +++ b/packages/manager/src/queries/cloudpulse/metrics.ts @@ -18,7 +18,7 @@ export const useCloudPulseMetricsQuery = ( serviceType: string, request: CloudPulseMetricsRequest, obj: { - authToken?: string; + authToken: string; isFlags: boolean; label: string; timeStamp: number | undefined; @@ -29,7 +29,7 @@ export const useCloudPulseMetricsQuery = ( const query = useQuery({ ...queryFactory.metrics( - obj.authToken ?? '', + obj.authToken, obj.url, serviceType, request, diff --git a/packages/manager/src/queries/cloudpulse/services.ts b/packages/manager/src/queries/cloudpulse/services.ts index f71e04deeb3..743aad0ac5e 100644 --- a/packages/manager/src/queries/cloudpulse/services.ts +++ b/packages/manager/src/queries/cloudpulse/services.ts @@ -1,4 +1,4 @@ -import { useQuery } from '@tanstack/react-query'; +import { keepPreviousData, useQuery } from '@tanstack/react-query'; import { queryFactory } from './queries'; @@ -28,6 +28,7 @@ export const useCloudPulseJWEtokenQuery = ( return useQuery({ ...queryFactory.token(serviceType, request), enabled: runQuery, + placeholderData: keepPreviousData, refetchOnWindowFocus: false, }); }; From 00d242524d5715f2dc9196020ed32bf9381cca8e Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Wed, 20 Nov 2024 19:24:39 +0530 Subject: [PATCH 348/474] upcoming: [DI-21119] - Sanity fixes --- .../features/CloudPulse/Dashboard/CloudPulseDashboard.tsx | 2 +- .../src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts | 4 ++-- .../features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index 5c2ce357d3c..77ab83eb946 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -137,8 +137,8 @@ export const CloudPulseDashboard = (props: DashboardProperties) => { manualRefreshTimeStamp={manualRefreshTimeStamp} metricDefinitions={metricDefinitions} preferences={preferences} + resourceList={resourceList} resources={resources} - resourcesList={resourceList} savePref={savePref} /> ); diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index 992f7a0ee06..8b386768eb4 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -130,7 +130,7 @@ interface DimensionNameProperties { metric: { [label: string]: string }; /** - * list of selected CloudPulseResources + * resources list of CloudPulseResources available */ resources: CloudPulseResources[]; } @@ -342,7 +342,7 @@ export const getDimensionName = (props: DimensionNameProperties): string => { /** * * @param id resource id that should be searched in resources list - * @param resources resources list of CloudPulseResources available + * @param resources list of CloudPulseResources available * @returns resource label if id is found, the id if label is not found, and fall back on an empty string with an undefined id */ export const mapResourceIdToName = ( diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx index 6c128137dd2..9b67814269f 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx @@ -35,8 +35,8 @@ interface WidgetProps { manualRefreshTimeStamp?: number; metricDefinitions: MetricDefinitions | undefined; preferences?: AclpConfig; + resourceList: CloudPulseResources[] | undefined; resources: string[]; - resourcesList: CloudPulseResources[] | undefined; savePref?: boolean; } @@ -61,8 +61,8 @@ export const RenderWidgets = React.memo( manualRefreshTimeStamp, metricDefinitions, preferences, + resourceList, resources, - resourcesList, savePref, } = props; @@ -165,7 +165,7 @@ export const RenderWidgets = React.memo( authToken={jweToken?.token} availableMetrics={availMetrics} isJweTokenFetching={isJweTokenFetching} - resources={resourcesList!} + resources={resourceList!} savePref={savePref} /> ); From caba7390549daaeb1aca39d9cb6f0b3f1bf5b3ec Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Wed, 20 Nov 2024 21:00:35 +0530 Subject: [PATCH 349/474] upcoming: [DI-21119] - Fallback fix for undefined token --- .../src/features/CloudPulse/Widget/CloudPulseWidget.tsx | 2 +- .../features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx | 3 ++- packages/manager/src/queries/cloudpulse/metrics.ts | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx index df78ec91c4b..494c2d359dc 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidget.tsx @@ -51,7 +51,7 @@ export interface CloudPulseWidgetProperties { /** * token to fetch metrics data */ - authToken: string; + authToken?: string; /** * metrics defined of this widget diff --git a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx index 9b67814269f..b444754fb46 100644 --- a/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/CloudPulseWidgetRenderer.tsx @@ -126,7 +126,8 @@ export const RenderWidgets = React.memo( if ( !dashboard.service_type || !Boolean(resources.length > 0) || - (!isJweTokenFetching && !jweToken?.token) + (!isJweTokenFetching && !jweToken?.token) || + !Boolean(resourceList?.length) ) { return renderPlaceHolder( 'Select a dashboard and filters to visualize metrics.' diff --git a/packages/manager/src/queries/cloudpulse/metrics.ts b/packages/manager/src/queries/cloudpulse/metrics.ts index 4f6f23622ab..f83b7fd98f9 100644 --- a/packages/manager/src/queries/cloudpulse/metrics.ts +++ b/packages/manager/src/queries/cloudpulse/metrics.ts @@ -18,7 +18,7 @@ export const useCloudPulseMetricsQuery = ( serviceType: string, request: CloudPulseMetricsRequest, obj: { - authToken: string; + authToken?: string; isFlags: boolean; label: string; timeStamp: number | undefined; @@ -29,7 +29,7 @@ export const useCloudPulseMetricsQuery = ( const query = useQuery({ ...queryFactory.metrics( - obj.authToken, + obj.authToken ?? '', obj.url, serviceType, request, From 48563852002930a2dba89dc6aed1baba200cfba3 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Thu, 21 Nov 2024 18:27:24 +0530 Subject: [PATCH 350/474] upcoming: [DI-21119] - sorting for payload --- .../CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx | 2 +- packages/manager/src/queries/cloudpulse/queries.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index 4444f942a57..1860f753814 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -311,7 +311,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( container display={showFilter ? 'flex' : 'none'} item - maxHeight={theme.spacing(22)} + maxHeight={theme.spacing(23)} overflow={'auto'} rowGap={theme.spacing(2)} xs={12} diff --git a/packages/manager/src/queries/cloudpulse/queries.ts b/packages/manager/src/queries/cloudpulse/queries.ts index bdc1715e0d7..0269c611ac8 100644 --- a/packages/manager/src/queries/cloudpulse/queries.ts +++ b/packages/manager/src/queries/cloudpulse/queries.ts @@ -80,6 +80,6 @@ export const queryFactory = createQueryKeys(key, { token: (serviceType: string | undefined, request: JWETokenPayLoad) => ({ queryFn: () => getJWEToken(request, serviceType!), - queryKey: [serviceType, { resource_ids: request.resource_ids }], + queryKey: [serviceType, { resource_ids: request.resource_ids.sort() }], }), }); From de1931fc99e3832c16e26617bbdfd390da0eb3bd Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Thu, 21 Nov 2024 19:42:51 +0530 Subject: [PATCH 351/474] upcoming: [DI-21927] - Updated default redirecting url to dashboards for invalid monitor urls --- packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx b/packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx index 7c665f5f33a..40e1f6cb211 100644 --- a/packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx +++ b/packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx @@ -79,7 +79,7 @@ export const CloudPulseTabs = () => { path={`${url}/dashboards`} /> - + From 73f370dda9fc843857d14507abb630931e5fc980 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Thu, 21 Nov 2024 19:52:56 +0530 Subject: [PATCH 352/474] upcoming: [DI-21927] - Updated default redirecting urls --- .../features/CloudPulse/Alerts/AlertsLanding/AlertsLanding.tsx | 3 ++- packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsLanding.tsx b/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsLanding.tsx index 2074b71b548..177b50202cd 100644 --- a/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsLanding.tsx +++ b/packages/manager/src/features/CloudPulse/Alerts/AlertsLanding/AlertsLanding.tsx @@ -85,9 +85,10 @@ export const AlertsLanding = React.memo(() => { - + diff --git a/packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx b/packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx index 40e1f6cb211..6d0a40ad654 100644 --- a/packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx +++ b/packages/manager/src/features/CloudPulse/CloudPulseTabs.tsx @@ -76,10 +76,11 @@ export const CloudPulseTabs = () => { - + From 0da63896746ae641ca912db6cac33e39fd7a3469 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Fri, 22 Nov 2024 13:22:52 +0530 Subject: [PATCH 353/474] upcoming: [DI-21119] - test case update --- .../shared/CloudPulseResourcesSelect.test.tsx | 59 ++++++++++--------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx index 31a5754b398..54982c42b1a 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx @@ -291,33 +291,6 @@ describe('CloudPulseResourcesSelect component tests', () => { expect(queryByRole('option', { name: SELECT_ALL })).not.toBeInTheDocument(); }); - it('should be able to select all and deselect all the resources when number of resources are equal to resource limit', () => { - queryMocks.useResourcesQuery.mockReturnValue({ - data: linodeFactory.buildList(10), - isError: false, - isLoading: false, - status: 'success', - }); - renderWithTheme( - - ); - fireEvent.click(screen.getByRole('button', { name: 'Open' })); - fireEvent.click(screen.getByRole('option', { name: SELECT_ALL })); - fireEvent.click(screen.getByRole('option', { name: 'Deselect All' })); - expect(screen.getByLabelText('Resources')).toBeInTheDocument(); - - for (let i = 26; i <= 35; i++) { - expect( - screen.getByRole('option', { name: `linode-${i}` }) - ).toHaveAttribute(ARIA_SELECTED, 'false'); - } - }); - it('should be able to select limited resources', async () => { const user = userEvent.setup(); @@ -362,4 +335,36 @@ describe('CloudPulseResourcesSelect component tests', () => { expect(queryByRole('option', { name: SELECT_ALL })).not.toBeInTheDocument(); }); + + it('should be able to select all and deselect all the resources when number of resources are equal to resource limit', async () => { + const user = userEvent.setup(); + + queryMocks.useResourcesQuery.mockReturnValue({ + data: linodeFactory.buildList(10), + isError: false, + isLoading: false, + status: 'success', + }); + + renderWithTheme( + + ); + + await user.click(screen.getByRole('button', { name: 'Open' })); + await user.click(screen.getByRole('option', { name: SELECT_ALL })); + await user.click(screen.getByRole('option', { name: 'Deselect All' })); + + expect(screen.getByLabelText('Resources')).toBeInTheDocument(); + + for (let i = 26; i <= 35; i++) { + expect( + screen.getByRole('option', { name: `linode-${i}` }) + ).toHaveAttribute(ARIA_SELECTED, 'false'); + } + }); }); From 7dfb353b5ed561af6078dc6868894ed12b5460f4 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Fri, 22 Nov 2024 14:18:34 +0530 Subject: [PATCH 354/474] upcoming: [DI-21119] - test case update --- .../shared/CloudPulseResourcesSelect.test.tsx | 45 ------------------- 1 file changed, 45 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx index 54982c42b1a..7f62d9be84a 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx @@ -291,51 +291,6 @@ describe('CloudPulseResourcesSelect component tests', () => { expect(queryByRole('option', { name: SELECT_ALL })).not.toBeInTheDocument(); }); - it('should be able to select limited resources', async () => { - const user = userEvent.setup(); - - queryMocks.useResourcesQuery.mockReturnValue({ - data: linodeFactory.buildList(12), - isError: false, - isLoading: false, - status: 'success', - }); - - const { queryByRole } = renderWithTheme( - - ); - - await user.click(screen.getByRole('button', { name: 'Open' })); - - expect(screen.getByLabelText('Resources')).toBeInTheDocument(); - expect(screen.getByText('Select up to 10 Resources')).toBeInTheDocument(); - - for (let i = 14; i <= 23; i++) { - // eslint-disable-next-line no-await-in-loop - const option = await screen.findByRole('option', { name: `linode-${i}` }); - // eslint-disable-next-line no-await-in-loop - await user.click(option); - } - - const selectedOptions = screen - .getAllByRole('option') - .filter((option) => option.getAttribute(ARIA_SELECTED) === 'true'); - - expect(selectedOptions.length).toBe(10); - - const isResourceWithExceededLimit = await screen.findByRole('option', { - name: 'linode-24', - }); - expect(isResourceWithExceededLimit).toHaveAttribute(ARIA_DISABLED, 'true'); - - expect(queryByRole('option', { name: SELECT_ALL })).not.toBeInTheDocument(); - }); - it('should be able to select all and deselect all the resources when number of resources are equal to resource limit', async () => { const user = userEvent.setup(); From 3e68332442a78c0855226c418057c3e50b415b42 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Fri, 22 Nov 2024 18:18:59 +0530 Subject: [PATCH 355/474] upcoming: [DI-21842] - Updated logic to handle 1 xAxisTickCount --- packages/manager/src/components/AreaChart/utils.ts | 4 ++++ .../CloudPulse/Widget/components/CloudPulseLineGraph.tsx | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/manager/src/components/AreaChart/utils.ts b/packages/manager/src/components/AreaChart/utils.ts index 2586b048801..d540e1a56c2 100644 --- a/packages/manager/src/components/AreaChart/utils.ts +++ b/packages/manager/src/components/AreaChart/utils.ts @@ -57,6 +57,10 @@ export const generate12HourTicks = ( const startTime = data[0].timestamp; const endTime = data[data.length - 1].timestamp; + if (tickCount === 1) { + return [(startTime + endTime) / 2]; + } + // Calculate duration in hours const duration = DateTime.fromMillis(endTime, { zone: timezone }).diff( DateTime.fromMillis(startTime, { zone: timezone }), diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index a54e2c19747..9167b2cfaf2 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -38,9 +38,11 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { ) : ( )} {rest.data.length === 0 && ( From db1cee2597a152e5eb9d7277d1ece973be13ef5e Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Fri, 22 Nov 2024 18:37:45 +0530 Subject: [PATCH 356/474] upcoming: [DI-21842] - Updated legends height --- .../CloudPulse/Widget/components/CloudPulseLineGraph.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx index 9167b2cfaf2..2f6e93cb3e7 100644 --- a/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx +++ b/packages/manager/src/features/CloudPulse/Widget/components/CloudPulseLineGraph.tsx @@ -42,7 +42,7 @@ export const CloudPulseLineGraph = React.memo((props: CloudPulseLineGraph) => { isSmallScreen ? undefined : Math.min(rest.data.length, 7) } fillOpacity={0.5} - legendHeight={theme.spacing(16)} + legendHeight={theme.spacing(18)} /> )} {rest.data.length === 0 && ( From ca06780e0a3c820ebd625bbd6b3bc3495ef63ea7 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Thu, 28 Nov 2024 15:51:28 +0530 Subject: [PATCH 357/474] upcoming: [DI-20929] - Added labels parameter to global filter change handlers --- .../Dashboard/CloudPulseDashboardLanding.tsx | 37 ++++++++++++++----- .../CloudPulseDashboardWithFilters.tsx | 31 ++++++++++++---- .../CloudPulse/Overview/GlobalFilters.tsx | 11 ++++-- .../CloudPulse/Utils/FilterBuilder.ts | 7 +++- .../shared/CloudPulseCustomSelect.tsx | 2 + .../shared/CloudPulseCustomSelectUtils.ts | 18 ++++++++- .../CloudPulseDashboardFilterBuilder.tsx | 15 +++++++- .../shared/CloudPulseRegionSelect.tsx | 18 ++++++--- 8 files changed, 108 insertions(+), 31 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx index 828a05301c7..2613a777833 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx @@ -8,6 +8,10 @@ import type { Dashboard, TimeDuration } from '@linode/api-v4'; export type FilterValueType = number | number[] | string | string[] | undefined; +export interface FilterValue { + id: { [key: string]: FilterValueType }; + label: string[]; +} export interface DashboardProp { dashboard?: Dashboard; filterValue: { @@ -17,26 +21,39 @@ export interface DashboardProp { } export const CloudPulseDashboardLanding = () => { - const [filterValue, setFilterValue] = React.useState<{ - [key: string]: FilterValueType; - }>({}); + const [filterValue, setFilterValue] = React.useState({ + id: {}, + label: [], + }); + const [timeDuration, setTimeDuration] = React.useState(); const [dashboard, setDashboard] = React.useState(); const onFilterChange = React.useCallback( - (filterKey: string, filterValue: FilterValueType) => { - setFilterValue((prev: { [key: string]: FilterValueType }) => ({ - ...prev, - [filterKey]: filterValue, - })); + (filterKey: string, filterValue: FilterValueType, labels: string[]) => { + setFilterValue((prev: FilterValue) => { + return { + id: { + ...prev.id, + [filterKey]: filterValue, + }, + label: { + ...prev.label, + [filterKey]: labels, + }, + }; + }); }, [] ); const onDashboardChange = React.useCallback((dashboardObj: Dashboard) => { setDashboard(dashboardObj); - setFilterValue({}); // clear the filter values on dashboard change + setFilterValue({ + id: {}, + label: [], + }); // clear the filter values on dashboard change }, []); const onTimeDurationChange = React.useCallback( (timeDurationObj: TimeDuration) => { @@ -57,7 +74,7 @@ export const CloudPulseDashboardLanding = () => { diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx index 00f73834381..248ec5d9f03 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx @@ -16,7 +16,10 @@ import { } from '../Utils/ReusableDashboardFilterUtils'; import { CloudPulseDashboard } from './CloudPulseDashboard'; -import type { FilterValueType } from './CloudPulseDashboardLanding'; +import type { + FilterValue, + FilterValueType, +} from './CloudPulseDashboardLanding'; import type { TimeDuration } from '@linode/api-v4'; export interface CloudPulseDashboardWithFiltersProp { @@ -37,9 +40,10 @@ export const CloudPulseDashboardWithFilters = React.memo( dashboardId ); - const [filterValue, setFilterValue] = React.useState<{ - [key: string]: FilterValueType; - }>({}); + const [filterValue, setFilterValue] = React.useState({ + id: {}, + label: [], + }); const [timeDuration, setTimeDuration] = React.useState({ unit: 'min', @@ -47,8 +51,19 @@ export const CloudPulseDashboardWithFilters = React.memo( }); const onFilterChange = React.useCallback( - (filterKey: string, value: FilterValueType) => { - setFilterValue((prev) => ({ ...prev, [filterKey]: value })); + (filterKey: string, value: FilterValueType, labels: string[]) => { + setFilterValue((prev) => { + return { + id: { + ...prev.id, + [filterKey]: value, + }, + label: { + ...prev.label, + [filterKey]: labels, + }, + }; + }); }, [] ); @@ -91,7 +106,7 @@ export const CloudPulseDashboardWithFilters = React.memo( const isFilterBuilderNeeded = checkIfFilterBuilderNeeded(dashboard); const isMandatoryFiltersSelected = checkMandatoryFiltersSelected({ dashboardObj: dashboard, - filterValue, + filterValue: filterValue.id, resource, timeDuration, }); @@ -140,7 +155,7 @@ export const CloudPulseDashboardWithFilters = React.memo( { ( filterKey: string, value: FilterValueType, + labels: string[], savePref: boolean = false, updatedPreferenceData: AclpConfig = {} ) => { if (savePref) { updatePreferences(updatedPreferenceData); } - handleAnyFilterChange(filterKey, value); + handleAnyFilterChange(filterKey, value, labels); }, [] ); const handleGlobalRefresh = React.useCallback(() => { - handleAnyFilterChange(REFRESH, Date.now()); + handleAnyFilterChange(REFRESH, Date.now(), []); }, []); const theme = useTheme(); diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts index e058b2e3d03..93a72d435f8 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts @@ -54,7 +54,11 @@ interface CloudPulseMandatoryFilterCheckProps { */ export const getRegionProperties = ( props: CloudPulseFilterProperties, - handleRegionChange: (region: string | undefined, savePref?: boolean) => void + handleRegionChange: ( + region: string | undefined, + labels: [], + savePref?: boolean + ) => void ): CloudPulseRegionSelectProps => { const { name: label, placeholder } = props.config.configuration; const { dashboard, isServiceAnalyticsIntegration, preferences } = props; @@ -119,6 +123,7 @@ export const getCustomSelectProperties = ( handleCustomSelectChange: ( filterKey: string, value: FilterValueType, + labels: string[], savePref?: boolean, updatedPreferenceData?: {} ) => void diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index 95c413c4adc..159d1f93cfc 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -68,10 +68,12 @@ export interface CloudPulseCustomSelectProps { * The callback function , that will be called on a filter change * @param filterKey - The filterKey of the component * @param value - The selected filter value + * @param labels - Lables of the selected filter value */ handleSelectionChange: ( filterKey: string, value: FilterValueType, + labels: string[], savePref?: boolean, updatedPreferenceData?: AclpConfig ) => void; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts index ce6dabc4a02..164e22d5471 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts @@ -14,6 +14,7 @@ interface CloudPulseCustomSelectProps { handleSelectionChange: ( filterKey: string, value: FilterValueType, + labels: string[], savePref?: boolean, updatedPreferenceData?: AclpConfig ) => void; @@ -139,7 +140,8 @@ export const getInitialDefaultSelections = ( const initialSelection = isMultiSelect ? [options[0]] : options[0]; handleSelectionChange( filterKey, - isMultiSelect ? [options[0].id] : options[0].id + isMultiSelect ? [options[0].id] : options[0].id, + [options[0].label] ); return initialSelection; } @@ -155,7 +157,12 @@ export const getInitialDefaultSelections = ( ? isMultiSelect ? selectedValues.map(({ id }) => id) : selectedValues[0].id - : undefined // if this is multiselect, return list of ids, otherwise return single id + : undefined, // if this is multiselect, return list of ids, otherwise return single id + selectedValues && selectedValues.length > 0 + ? isMultiSelect + ? selectedValues.map(({ label }) => label) + : [selectedValues[0].label] + : [] ); return selectedValues?.length ? isMultiSelect @@ -195,6 +202,12 @@ export const handleCustomSelectionChange = ( : String(value.id) : undefined; + const labels = value + ? Array.isArray(value) + ? value.map(({ label }) => label) + : [value.label] + : []; + let updatedPreferenceData: AclpConfig = {}; // update the preferences @@ -216,6 +229,7 @@ export const handleCustomSelectionChange = ( handleSelectionChange( filterKey, result, + labels, savePreferences, updatedPreferenceData ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index d836b73ec63..bfe51315b01 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -41,6 +41,7 @@ export interface CloudPulseDashboardFilterBuilderProps { emitFilterChange: ( filterKey: string, value: FilterValueType, + labels: string[], savePref?: boolean, updatePreferenceData?: {} ) => void; @@ -105,12 +106,14 @@ export const CloudPulseDashboardFilterBuilder = React.memo( ( filterKey: string, filterValue: FilterValueType, + labels: string[], savePref: boolean = false, updatedPreferenceData: AclpConfig = {} ) => { emitFilterChange( filterKey, filterValue, + labels, savePref, updatedPreferenceData ); @@ -124,6 +127,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( emitFilterChangeByFilterKey( RESOURCE_ID, resourceId.map((resource) => resource.id), + resourceId.map((resource) => resource.label), savePref, { [RESOURCES]: resourceId.map((resource: { id: string }) => @@ -136,7 +140,11 @@ export const CloudPulseDashboardFilterBuilder = React.memo( ); const handleRegionChange = React.useCallback( - (region: string | undefined, savePref: boolean = false) => { + ( + region: string | undefined, + labels: string[], + savePref: boolean = false + ) => { const updatedPreferenceData = { [REGION]: region, [RESOURCES]: undefined, @@ -144,6 +152,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( emitFilterChangeByFilterKey( REGION, region, + labels, savePref, updatedPreferenceData ); @@ -155,12 +164,14 @@ export const CloudPulseDashboardFilterBuilder = React.memo( ( filterKey: string, value: FilterValueType, + labels: string[], savePref: boolean = false, updatedPreferenceData: {} = {} ) => { emitFilterChangeByFilterKey( filterKey, value, + labels, savePref, updatedPreferenceData ); @@ -228,7 +239,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( CustomIcon={InfoIcon} CustomIconStyles={{ height: '40px', width: '40px' }} errorText={'Please configure filters to continue'} - > + /> ); } diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index bb8a1c25f03..3d38f51c287 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -7,7 +7,11 @@ import type { Dashboard, FilterValue } from '@linode/api-v4'; export interface CloudPulseRegionSelectProps { defaultValue?: FilterValue; - handleRegionChange: (region: string | undefined, savePref?: boolean) => void; + handleRegionChange: ( + region: string | undefined, + labels: string[], + savePref?: boolean + ) => void; label: string; placeholder?: string; savePreferences?: boolean; @@ -32,10 +36,10 @@ export const CloudPulseRegionSelect = React.memo( React.useEffect(() => { if (regions && savePreferences) { const region = defaultValue - ? regions.find((regionObj) => regionObj.id === defaultValue)?.id + ? regions.find((regionObj) => regionObj.id === defaultValue) : undefined; - handleRegionChange(region); - setSelectedRegion(region); + handleRegionChange(region?.id, region ? [region.label] : []); + setSelectedRegion(region?.id); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [regions]); @@ -44,7 +48,11 @@ export const CloudPulseRegionSelect = React.memo( { setSelectedRegion(region?.id); - handleRegionChange(region?.id, savePreferences); + handleRegionChange( + region?.id, + region ? [region.label] : [], + savePreferences + ); }} currentCapability={undefined} data-testid="region-select" From d8c364cedeaa8791256d23c7133eab999e6d1be7 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Mon, 2 Dec 2024 15:08:14 +0530 Subject: [PATCH 358/474] upcoming: [DI-20929] - Added cloudpulse applied filter --- .../Dashboard/CloudPulseDashboardLanding.tsx | 36 +++++++++--- .../CloudPulseDashboardWithFilters.tsx | 20 ++++++- .../CloudPulse/Overview/GlobalFilters.tsx | 3 + .../shared/CloudPulseAppliedFilter.tsx | 57 +++++++++++++++++++ .../CloudPulseAppliedFilterRenderer.tsx | 39 +++++++++++++ .../CloudPulseDashboardFilterBuilder.tsx | 4 ++ 6 files changed, 149 insertions(+), 10 deletions(-) create mode 100644 packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx create mode 100644 packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilterRenderer.tsx diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx index 2613a777833..3cd47ce2aaa 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx @@ -1,7 +1,8 @@ -import { Grid, Paper } from '@mui/material'; +import { Box, Grid, Paper } from '@mui/material'; import * as React from 'react'; import { GlobalFilters } from '../Overview/GlobalFilters'; +import { CloudPulseAppliedFilterRenderer } from '../shared/CloudPulseAppliedFilterRenderer'; import { CloudPulseDashboardRenderer } from './CloudPulseDashboardRenderer'; import type { Dashboard, TimeDuration } from '@linode/api-v4'; @@ -10,7 +11,7 @@ export type FilterValueType = number | number[] | string | string[] | undefined; export interface FilterValue { id: { [key: string]: FilterValueType }; - label: string[]; + label: { [key: string]: string[] }; } export interface DashboardProp { dashboard?: Dashboard; @@ -23,13 +24,21 @@ export interface DashboardProp { export const CloudPulseDashboardLanding = () => { const [filterValue, setFilterValue] = React.useState({ id: {}, - label: [], + label: {}, }); const [timeDuration, setTimeDuration] = React.useState(); const [dashboard, setDashboard] = React.useState(); + const [showAppliedFilters, setShowAppliedFilters] = React.useState( + false + ); + + const toggleAppliedFilter = (isVisible: boolean) => { + setShowAppliedFilters(isVisible); + }; + const onFilterChange = React.useCallback( (filterKey: string, filterValue: FilterValueType, labels: string[]) => { setFilterValue((prev: FilterValue) => { @@ -52,7 +61,7 @@ export const CloudPulseDashboardLanding = () => { setDashboard(dashboardObj); setFilterValue({ id: {}, - label: [], + label: {}, }); // clear the filter values on dashboard change }, []); const onTimeDurationChange = React.useCallback( @@ -65,11 +74,20 @@ export const CloudPulseDashboardLanding = () => { - + + + {dashboard?.service_type && showAppliedFilters && ( + + )} + ({ id: {}, - label: [], + label: {}, }); const [timeDuration, setTimeDuration] = React.useState({ @@ -50,6 +51,14 @@ export const CloudPulseDashboardWithFilters = React.memo( value: 30, }); + const [showAppliedFilters, setShowAppliedFilters] = React.useState( + false + ); + + const toggleAppliedFilter = (isVisible: boolean) => { + setShowAppliedFilters(isVisible); + }; + const onFilterChange = React.useCallback( (filterKey: string, value: FilterValueType, labels: string[]) => { setFilterValue((prev) => { @@ -147,9 +156,18 @@ export const CloudPulseDashboardWithFilters = React.memo( )} + + {showAppliedFilters && ( + + )} + {isMandatoryFiltersSelected ? ( { @@ -31,6 +32,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { handleAnyFilterChange, handleDashboardChange, handleTimeDurationChange, + handleToggleAppliedFilter, } = props; const { @@ -148,6 +150,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx new file mode 100644 index 00000000000..b6ad763e893 --- /dev/null +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx @@ -0,0 +1,57 @@ +import { Box, Chip, Typography } from '@mui/material'; +import React from 'react'; + +interface CloudPulseAppliedFilterProps { + filters: { + [label: string]: string[]; + }; +} +export const CloudPulseAppliedFilter = ( + props: CloudPulseAppliedFilterProps +) => { + const { filters } = props; + + return ( + + {Object.entries(filters).map((data) => { + const label = data[0]; + const filterValue = data[1]; + return ( + <> + {`${label}:`} + {filterValue.map((value, index) => { + return ( + + ); + })} + + ); + })} + + ); +}; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilterRenderer.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilterRenderer.tsx new file mode 100644 index 00000000000..ea35136782f --- /dev/null +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilterRenderer.tsx @@ -0,0 +1,39 @@ +import React from 'react'; + +import { FILTER_CONFIG } from '../Utils/FilterConfig'; +import { CloudPulseAppliedFilter } from './CloudPulseAppliedFilter'; + +interface AppliedFilterRendererProps { + filters: { + [label: string]: string[]; + }; + serviceType: string; +} + +export const CloudPulseAppliedFilterRenderer = ( + props: AppliedFilterRendererProps +) => { + const { filters, serviceType } = props; + + const filterConfig = FILTER_CONFIG.get(serviceType); + + if (!filterConfig) { + return <>; + } + const configuredFilters = filterConfig.filters; + + const appliedFilter = configuredFilters + .filter((filter) => { + const filterKey = filter.configuration.filterKey; + return Boolean(filters[filterKey]?.length); + }) + .reduce( + (prevValue, filter) => ({ + ...prevValue, + [filter.configuration.name]: filters[filter.configuration.filterKey], + }), + {} + ); + + return ; +}; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index bfe51315b01..a59caa17471 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -46,6 +46,8 @@ export interface CloudPulseDashboardFilterBuilderProps { updatePreferenceData?: {} ) => void; + handleToggleAppliedFilter: (isVisible: boolean) => void; + /** * this will handle the restrictions, if the parent of the component is going to be integrated in service analytics page */ @@ -62,6 +64,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( const { dashboard, emitFilterChange, + handleToggleAppliedFilter, isServiceAnalyticsIntegration, preferences, } = props; @@ -227,6 +230,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( const toggleShowFilter = () => { setShowFilter((showFilterPrev) => !showFilterPrev); + handleToggleAppliedFilter(showFilter); }; const RenderFilters = React.useCallback(() => { From 31ad379206b38f678024c359ac7c09e620573dad Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Mon, 2 Dec 2024 15:29:53 +0530 Subject: [PATCH 359/474] upcoming: [DI-20929] - Added test cases --- .../shared/CloudPulseAppliedFilter.test.tsx | 40 +++++++++++++++++++ .../shared/CloudPulseAppliedFilter.tsx | 1 + 2 files changed, 41 insertions(+) create mode 100644 packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.test.tsx diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.test.tsx new file mode 100644 index 00000000000..531d2209d0f --- /dev/null +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.test.tsx @@ -0,0 +1,40 @@ +import React from 'react'; +import { i } from 'vite/dist/node/types.d-aGj9QkWt'; + +import { renderWithTheme } from 'src/utilities/testHelpers'; + +import { CloudPulseAppliedFilter } from './CloudPulseAppliedFilter'; +import { CloudPulseAppliedFilterRenderer } from './CloudPulseAppliedFilterRenderer'; + +const data = { + region: ['us-east'], + resource: ['res1', 'res2'], +}; + +const testId = 'applied-filter'; + +describe('CloudPulse Applied Filter', () => { + it('should render applied filter component', () => { + const { getByTestId } = renderWithTheme( + + ); + expect(getByTestId(testId)).toBeInTheDocument(); + }); + + it('should render the applied filter key & values', () => { + const { getByTestId } = renderWithTheme( + + ); + expect(getByTestId(testId)).toHaveTextContent('region'); + expect(getByTestId(testId)).toHaveTextContent('res1'); + expect(getByTestId(testId)).not.toHaveTextContent('resources'); + }); + + it('should not render the applied filter component', () => { + const { queryByTestId } = renderWithTheme( + + ); + + expect(queryByTestId(testId)).toBe(null); + }); +}); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx index b6ad763e893..b4cc01899cf 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx @@ -13,6 +13,7 @@ export const CloudPulseAppliedFilter = ( return ( Date: Mon, 2 Dec 2024 16:12:34 +0530 Subject: [PATCH 360/474] upcoming: [DI-20929] - updated failing test cases --- .../src/features/CloudPulse/Overview/GlobalFilters.test.tsx | 2 ++ .../features/CloudPulse/shared/CloudPulseAppliedFilter.test.tsx | 1 - .../CloudPulse/shared/CloudPulseDashboardFilterBuilder.test.tsx | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.test.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.test.tsx index 286c95377e1..d1591390f97 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.test.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.test.tsx @@ -7,6 +7,7 @@ import { GlobalFilters } from './GlobalFilters'; const mockHandleAnyFilterChange = vi.fn(); const mockHandleDashboardChange = vi.fn(); const mockHandleTimeDurationChange = vi.fn(); +const mockHandleToggleAppliedFilter = vi.fn(); const timeRangeSelectId = 'cloudpulse-time-duration'; const setup = () => { return renderWithTheme( @@ -14,6 +15,7 @@ const setup = () => { handleAnyFilterChange={mockHandleAnyFilterChange} handleDashboardChange={mockHandleDashboardChange} handleTimeDurationChange={mockHandleTimeDurationChange} + handleToggleAppliedFilter={mockHandleToggleAppliedFilter} /> ); }; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.test.tsx index 531d2209d0f..6a8dbb2a274 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.test.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import { i } from 'vite/dist/node/types.d-aGj9QkWt'; import { renderWithTheme } from 'src/utilities/testHelpers'; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.test.tsx index ec2c10bacc5..71a684c9a1d 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.test.tsx @@ -13,6 +13,7 @@ describe('CloudPulseDashboardFilterBuilder component tests', () => { service_type: 'linode', })} emitFilterChange={vi.fn()} + handleToggleAppliedFilter={vi.fn()} isServiceAnalyticsIntegration={false} /> ); @@ -28,6 +29,7 @@ describe('CloudPulseDashboardFilterBuilder component tests', () => { service_type: 'dbaas', })} emitFilterChange={vi.fn()} + handleToggleAppliedFilter={vi.fn()} isServiceAnalyticsIntegration={false} /> ); From 50e748ae15d4a58e9e443633efe66af7a9836fbf Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Mon, 2 Dec 2024 19:04:03 +0530 Subject: [PATCH 361/474] upcoming: [DI-20595] - ACLP Supported regions per service type --- packages/manager/src/featureFlags.ts | 5 +- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 8 +-- .../features/CloudPulse/Utils/FilterConfig.ts | 12 +++- .../src/features/CloudPulse/Utils/models.ts | 11 ++- .../shared/CloudPulseRegionSelect.test.tsx | 72 +++++++++++++++++-- .../shared/CloudPulseRegionSelect.tsx | 44 +++++++++++- .../shared/CloudPulseResourcesSelect.tsx | 4 +- 7 files changed, 137 insertions(+), 19 deletions(-) diff --git a/packages/manager/src/featureFlags.ts b/packages/manager/src/featureFlags.ts index 9dccad6f9a2..d2121189744 100644 --- a/packages/manager/src/featureFlags.ts +++ b/packages/manager/src/featureFlags.ts @@ -69,10 +69,11 @@ interface LkeEnterpriseFlag extends BaseFeatureFlag { la: boolean; } -export interface CloudPulseResourceTypeMapFlag { +export interface CloudPulseServiceTypeMapFlag { dimensionKey: string; maxResourceSelections?: number; serviceType: string; + supportedRegionIds?: string; } interface gpuV2 { @@ -101,7 +102,7 @@ export interface Flags { aclp: AclpFlag; aclpAlerting: AclpAlerting; aclpReadEndpoint: string; - aclpResourceTypeMap: CloudPulseResourceTypeMapFlag[]; + aclpServiceTypeMap: CloudPulseServiceTypeMapFlag[]; apiMaintenance: APIMaintenance; apicliButtonCopy: string; apl: boolean; diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index f4066808b3d..b1166834b05 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -25,7 +25,7 @@ import type { Theme } from '@mui/material'; import type { DataSet } from 'src/components/AreaChart/AreaChart'; import type { AreaProps } from 'src/components/AreaChart/AreaChart'; import type { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay'; -import type { CloudPulseResourceTypeMapFlag, FlagSet } from 'src/featureFlags'; +import type { CloudPulseServiceTypeMapFlag, FlagSet } from 'src/featureFlags'; interface LabelNameOptionsProps { /** @@ -122,7 +122,7 @@ interface DimensionNameProperties { /** * flag dimension key mapping for service type */ - flag: CloudPulseResourceTypeMapFlag | undefined; + flag: CloudPulseServiceTypeMapFlag | undefined; /** * metric key-value to generate dimension name @@ -315,8 +315,8 @@ const getLabelName = (props: LabelNameOptionsProps): string => { return `${label} (${unit})`; } - const flag = flags?.aclpResourceTypeMap?.find( - (obj: CloudPulseResourceTypeMapFlag) => obj.serviceType === serviceType + const flag = flags?.aclpServiceTypeMap?.find( + (obj: CloudPulseServiceTypeMapFlag) => obj.serviceType === serviceType ); return getDimensionName({ flag, metric, resources }); diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts b/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts index 55c96678749..3cdacc9d1de 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts @@ -3,11 +3,14 @@ import { CloudPulseSelectTypes } from './models'; import type { CloudPulseServiceTypeFilterMap } from './models'; const TIME_DURATION = 'Time Range'; +const DBAAS_CAPABILITY = 'Managed Databases'; +const LINODE_CAPABILITY = 'Linodes'; export const LINODE_CONFIG: Readonly = { filters: [ { configuration: { + capability: LINODE_CAPABILITY, filterKey: 'region', filterType: 'string', isFilterable: false, @@ -20,6 +23,7 @@ export const LINODE_CONFIG: Readonly = { }, { configuration: { + capability: LINODE_CAPABILITY, dependency: ['region'], filterKey: 'resource_id', filterType: 'string', @@ -35,6 +39,7 @@ export const LINODE_CONFIG: Readonly = { }, { configuration: { + capability: LINODE_CAPABILITY, filterKey: 'relative_time_duration', filterType: 'string', isFilterable: true, @@ -55,6 +60,7 @@ export const DBAAS_CONFIG: Readonly = { filters: [ { configuration: { + capability: DBAAS_CAPABILITY, filterKey: 'engine', filterType: 'string', isFilterable: false, // isFilterable -- this determines whethere you need to pass it metrics api @@ -80,6 +86,7 @@ export const DBAAS_CONFIG: Readonly = { }, { configuration: { + capability: DBAAS_CAPABILITY, filterKey: 'region', filterType: 'string', isFilterable: false, @@ -92,6 +99,7 @@ export const DBAAS_CONFIG: Readonly = { }, { configuration: { + capability: DBAAS_CAPABILITY, dependency: ['region', 'engine'], filterKey: 'resource_id', filterType: 'string', @@ -107,6 +115,7 @@ export const DBAAS_CONFIG: Readonly = { }, { configuration: { + capability: DBAAS_CAPABILITY, filterKey: 'relative_time_duration', filterType: 'string', isFilterable: true, @@ -121,6 +130,7 @@ export const DBAAS_CONFIG: Readonly = { }, { configuration: { + capability: DBAAS_CAPABILITY, filterKey: 'node_type', filterType: 'string', isFilterable: true, // isFilterable -- this determines whether you need to pass it metrics api @@ -149,7 +159,7 @@ export const DBAAS_CONFIG: Readonly = { }; export const FILTER_CONFIG: Readonly< - Map + Map > = new Map([ ['dbaas', DBAAS_CONFIG], ['linode', LINODE_CONFIG], diff --git a/packages/manager/src/features/CloudPulse/Utils/models.ts b/packages/manager/src/features/CloudPulse/Utils/models.ts index f51e945074e..02d58fbc570 100644 --- a/packages/manager/src/features/CloudPulse/Utils/models.ts +++ b/packages/manager/src/features/CloudPulse/Utils/models.ts @@ -1,4 +1,8 @@ -import type { DatabaseEngine, DatabaseType } from '@linode/api-v4'; +import type { + Capabilities, + DatabaseEngine, + DatabaseType, +} from '@linode/api-v4'; import type { QueryFunction, QueryKey } from '@tanstack/react-query'; /** @@ -83,6 +87,11 @@ export interface CloudPulseServiceTypeFiltersConfiguration { */ apiV4QueryKey?: QueryFunctionAndKey; + /** + * This is the current capability corresponding to the service type + */ + capability: Capabilities; + /** * This is an optional field, it is used to disable a certain filter, untill of the dependent filters are selected */ diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx index 9372ec32ead..9aaf2799528 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx @@ -1,12 +1,15 @@ +import userEvent from '@testing-library/user-event'; import * as React from 'react'; -import * as regions from 'src/queries/regions/regions'; +import { dashboardFactory, regionFactory } from 'src/factories'; import { renderWithTheme } from 'src/utilities/testHelpers'; import { CloudPulseRegionSelect } from './CloudPulseRegionSelect'; import type { CloudPulseRegionSelectProps } from './CloudPulseRegionSelect'; import type { Region } from '@linode/api-v4'; +import type { CloudPulseServiceTypeMapFlag, Flags } from 'src/featureFlags'; +import type * as regions from 'src/queries/regions/regions'; const props: CloudPulseRegionSelectProps = { handleRegionChange: vi.fn(), @@ -14,11 +17,32 @@ const props: CloudPulseRegionSelectProps = { selectedDashboard: undefined, }; -describe('CloudPulseRegionSelect', () => { - vi.spyOn(regions, 'useRegionsQuery').mockReturnValue({ - data: Array(), - } as ReturnType); +const queryMocks = vi.hoisted(() => ({ + useRegionsQuery: vi.fn().mockReturnValue({}), +})); + +const flags: Partial = { + aclpServiceTypeMap: [ + { + serviceType: 'dbaas', + supportedRegionIds: 'us-west', + }, + { + serviceType: 'linode', + supportedRegionIds: 'us-east', + }, + ] as CloudPulseServiceTypeMapFlag[], +}; +vi.mock('src/queries/regions/regions', async () => { + const actual = await vi.importActual('src/queries/regions/regions'); + return { + ...actual, + useRegionsQuery: queryMocks.useRegionsQuery, + }; +}); + +describe('CloudPulseRegionSelect', () => { it('should render a Region Select component', () => { const { getByLabelText, getByTestId } = renderWithTheme( @@ -29,7 +53,7 @@ describe('CloudPulseRegionSelect', () => { }); it('should render a Region Select component with proper error message on api call failure', () => { - vi.spyOn(regions, 'useRegionsQuery').mockReturnValue({ + queryMocks.useRegionsQuery.mockReturnValue({ data: undefined, isError: true, isLoading: false, @@ -40,4 +64,40 @@ describe('CloudPulseRegionSelect', () => { expect(getByText('Failed to fetch Region.')); }); + + it('should render a Region Select component with capability specific and launchDarkly based supported regions', async () => { + const user = userEvent.setup(); + + const allRegions: Region[] = [ + regionFactory.build({ capabilities: ['Linodes'], id: 'us-east' }), + regionFactory.build({ + capabilities: ['Managed Databases'], + id: 'us-west', + label: 'US, Fremont, CA', + }), + ]; + + queryMocks.useRegionsQuery.mockReturnValue({ + data: allRegions, + isError: false, + isLoading: false, + }); + + const { getByRole } = renderWithTheme( + , + { flags } + ); + + await user.click(getByRole('button', { name: 'Open' })); + // example: region id => 'us-west' belongs to service type - 'dbass', capability -'Managed Databases', and is supported via launchDarkly + expect( + getByRole('option', { + name: 'US, Fremont, CA (us-west)', + }) + ).toBeInTheDocument(); }); +}); \ No newline at end of file diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index bb8a1c25f03..6e0cacd6a9a 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -1,9 +1,13 @@ import * as React from 'react'; import { RegionSelect } from 'src/components/RegionSelect/RegionSelect'; +import { useFlags } from 'src/hooks/useFlags'; import { useRegionsQuery } from 'src/queries/regions/regions'; -import type { Dashboard, FilterValue } from '@linode/api-v4'; +import { FILTER_CONFIG } from '../Utils/FilterConfig'; + +import type { CloudPulseServiceTypeFilters } from '../Utils/models'; +import type { Dashboard, FilterValue, Region } from '@linode/api-v4'; export interface CloudPulseRegionSelectProps { defaultValue?: FilterValue; @@ -18,6 +22,8 @@ export const CloudPulseRegionSelect = React.memo( (props: CloudPulseRegionSelectProps) => { const { data: regions, isError, isLoading } = useRegionsQuery(); + const flags = useFlags(); + const { defaultValue, handleRegionChange, @@ -27,6 +33,16 @@ export const CloudPulseRegionSelect = React.memo( selectedDashboard, } = props; + const currentFilterConfig: + | CloudPulseServiceTypeFilters + | undefined = FILTER_CONFIG.get( + selectedDashboard?.service_type + )?.filters.filter( + (config) => config.configuration.filterKey === 'region' + )[0]; + // Capture the current capability from corresponding filter config + const capability = currentFilterConfig?.configuration.capability; + const [selectedRegion, setSelectedRegion] = React.useState(); // Once the data is loaded, set the state variable with value stored in preferences React.useEffect(() => { @@ -40,13 +56,35 @@ export const CloudPulseRegionSelect = React.memo( // eslint-disable-next-line react-hooks/exhaustive-deps }, [regions]); + // validate launchDrakly region_ids with the ids from the fetched 'all-regions' + const supportedRegions = React.useMemo(() => { + const serviceTypeFlag = flags.aclpServiceTypeMap?.find( + (item) => item.serviceType === selectedDashboard?.service_type + ); + + const supportedRegionsIdList = serviceTypeFlag?.supportedRegionIds + ?.split(',') + .map((regionId) => regionId.trim()); + + if (!supportedRegionsIdList?.length) { + return regions; + } + + const validatedRegions = regions?.filter((region) => + supportedRegionsIdList?.includes(region.id) + ); + + return validatedRegions ? validatedRegions : regions; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [flags.aclpServiceTypeMap, regions, selectedDashboard?.service_type]); + return ( { setSelectedRegion(region?.id); handleRegionChange(region?.id, savePreferences); }} - currentCapability={undefined} + currentCapability={capability} data-testid="region-select" disableClearable={false} disabled={!selectedDashboard || !regions} @@ -56,7 +94,7 @@ export const CloudPulseRegionSelect = React.memo( loading={isLoading} noMarginTop placeholder={placeholder ?? 'Select a Region'} - regions={regions ? regions : []} + regions={supportedRegions ? supportedRegions : []} value={selectedRegion} /> ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index ada3584f781..92ff1bb912f 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -87,11 +87,11 @@ export const CloudPulseResourcesSelect = React.memo( // Maximum resource selection limit is fetched from launchdarkly const maxResourceSelectionLimit = React.useMemo(() => { - const obj = flags.aclpResourceTypeMap?.find( + const obj = flags.aclpServiceTypeMap?.find( (item) => item.serviceType === resourceType ); return obj?.maxResourceSelections || 10; - }, [resourceType, flags.aclpResourceTypeMap]); + }, [resourceType, flags.aclpServiceTypeMap]); const resourcesLimitReached = React.useMemo(() => { return getResourcesList.length > maxResourceSelectionLimit; From 54eb7648843cd33f3172baf35a60382eca88df8e Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Mon, 2 Dec 2024 19:37:34 +0530 Subject: [PATCH 362/474] upcoming: [DI-20595] - small fix --- .../features/CloudPulse/shared/CloudPulseRegionSelect.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index 6e0cacd6a9a..274d67ba7ec 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -70,11 +70,9 @@ export const CloudPulseRegionSelect = React.memo( return regions; } - const validatedRegions = regions?.filter((region) => + return regions?.filter((region) => supportedRegionsIdList?.includes(region.id) ); - - return validatedRegions ? validatedRegions : regions; // eslint-disable-next-line react-hooks/exhaustive-deps }, [flags.aclpServiceTypeMap, regions, selectedDashboard?.service_type]); @@ -94,7 +92,7 @@ export const CloudPulseRegionSelect = React.memo( loading={isLoading} noMarginTop placeholder={placeholder ?? 'Select a Region'} - regions={supportedRegions ? supportedRegions : []} + regions={supportedRegions ? supportedRegions : regions ? regions : []} value={selectedRegion} /> ); From fe2d90c68ca8fd6233fd7a1ac80147da66d63c8c Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Tue, 3 Dec 2024 10:40:33 +0530 Subject: [PATCH 363/474] upcoming: [DI-20595] - improved test quality --- .../shared/CloudPulseRegionSelect.test.tsx | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx index 9aaf2799528..a306c6173d4 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx @@ -29,7 +29,7 @@ const flags: Partial = { }, { serviceType: 'linode', - supportedRegionIds: 'us-east', + supportedRegionIds: 'us-lax', }, ] as CloudPulseServiceTypeMapFlag[], }; @@ -69,7 +69,11 @@ describe('CloudPulseRegionSelect', () => { const user = userEvent.setup(); const allRegions: Region[] = [ - regionFactory.build({ capabilities: ['Linodes'], id: 'us-east' }), + regionFactory.build({ + capabilities: ['Linodes'], + id: 'us-lax', + label: 'US, Los Angeles, CA', + }), regionFactory.build({ capabilities: ['Managed Databases'], id: 'us-west', @@ -83,7 +87,7 @@ describe('CloudPulseRegionSelect', () => { isLoading: false, }); - const { getByRole } = renderWithTheme( + const { getByRole, queryByRole } = renderWithTheme( { name: 'US, Fremont, CA (us-west)', }) ).toBeInTheDocument(); + expect( + queryByRole('option', { + name: 'US, Los Angeles, CA (us-lax)', + }) + ).toBeNull(); + }); }); -}); \ No newline at end of file From 8b1cbcf045eb97d2df7a4da898b5e659ede0e86a Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Tue, 3 Dec 2024 16:30:44 +0530 Subject: [PATCH 364/474] upcoming: [DI-20595] - PR Comments --- packages/manager/src/featureFlags.ts | 4 +- .../CloudPulse/Utils/CloudPulseWidgetUtils.ts | 8 ++-- .../features/CloudPulse/Utils/FilterConfig.ts | 12 ++--- .../src/features/CloudPulse/Utils/models.ts | 9 ++-- .../shared/CloudPulseRegionSelect.test.tsx | 30 ++++++++++--- .../shared/CloudPulseRegionSelect.tsx | 45 ++++++++++--------- .../shared/CloudPulseResourcesSelect.tsx | 4 +- 7 files changed, 65 insertions(+), 47 deletions(-) diff --git a/packages/manager/src/featureFlags.ts b/packages/manager/src/featureFlags.ts index d2121189744..2c56aa7714d 100644 --- a/packages/manager/src/featureFlags.ts +++ b/packages/manager/src/featureFlags.ts @@ -69,7 +69,7 @@ interface LkeEnterpriseFlag extends BaseFeatureFlag { la: boolean; } -export interface CloudPulseServiceTypeMapFlag { +export interface CloudPulseResourceTypeMapFlag { dimensionKey: string; maxResourceSelections?: number; serviceType: string; @@ -102,7 +102,7 @@ export interface Flags { aclp: AclpFlag; aclpAlerting: AclpAlerting; aclpReadEndpoint: string; - aclpServiceTypeMap: CloudPulseServiceTypeMapFlag[]; + aclpResourceTypeMap: CloudPulseResourceTypeMapFlag[]; apiMaintenance: APIMaintenance; apicliButtonCopy: string; apl: boolean; diff --git a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts index b1166834b05..f4066808b3d 100644 --- a/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/CloudPulseWidgetUtils.ts @@ -25,7 +25,7 @@ import type { Theme } from '@mui/material'; import type { DataSet } from 'src/components/AreaChart/AreaChart'; import type { AreaProps } from 'src/components/AreaChart/AreaChart'; import type { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay'; -import type { CloudPulseServiceTypeMapFlag, FlagSet } from 'src/featureFlags'; +import type { CloudPulseResourceTypeMapFlag, FlagSet } from 'src/featureFlags'; interface LabelNameOptionsProps { /** @@ -122,7 +122,7 @@ interface DimensionNameProperties { /** * flag dimension key mapping for service type */ - flag: CloudPulseServiceTypeMapFlag | undefined; + flag: CloudPulseResourceTypeMapFlag | undefined; /** * metric key-value to generate dimension name @@ -315,8 +315,8 @@ const getLabelName = (props: LabelNameOptionsProps): string => { return `${label} (${unit})`; } - const flag = flags?.aclpServiceTypeMap?.find( - (obj: CloudPulseServiceTypeMapFlag) => obj.serviceType === serviceType + const flag = flags?.aclpResourceTypeMap?.find( + (obj: CloudPulseResourceTypeMapFlag) => obj.serviceType === serviceType ); return getDimensionName({ flag, metric, resources }); diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts b/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts index 3cdacc9d1de..c6313bbb1f4 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts @@ -7,10 +7,10 @@ const DBAAS_CAPABILITY = 'Managed Databases'; const LINODE_CAPABILITY = 'Linodes'; export const LINODE_CONFIG: Readonly = { + capability: LINODE_CAPABILITY, filters: [ { configuration: { - capability: LINODE_CAPABILITY, filterKey: 'region', filterType: 'string', isFilterable: false, @@ -23,7 +23,6 @@ export const LINODE_CONFIG: Readonly = { }, { configuration: { - capability: LINODE_CAPABILITY, dependency: ['region'], filterKey: 'resource_id', filterType: 'string', @@ -39,7 +38,6 @@ export const LINODE_CONFIG: Readonly = { }, { configuration: { - capability: LINODE_CAPABILITY, filterKey: 'relative_time_duration', filterType: 'string', isFilterable: true, @@ -57,10 +55,10 @@ export const LINODE_CONFIG: Readonly = { }; export const DBAAS_CONFIG: Readonly = { + capability: DBAAS_CAPABILITY, filters: [ { configuration: { - capability: DBAAS_CAPABILITY, filterKey: 'engine', filterType: 'string', isFilterable: false, // isFilterable -- this determines whethere you need to pass it metrics api @@ -86,7 +84,6 @@ export const DBAAS_CONFIG: Readonly = { }, { configuration: { - capability: DBAAS_CAPABILITY, filterKey: 'region', filterType: 'string', isFilterable: false, @@ -99,7 +96,6 @@ export const DBAAS_CONFIG: Readonly = { }, { configuration: { - capability: DBAAS_CAPABILITY, dependency: ['region', 'engine'], filterKey: 'resource_id', filterType: 'string', @@ -115,7 +111,6 @@ export const DBAAS_CONFIG: Readonly = { }, { configuration: { - capability: DBAAS_CAPABILITY, filterKey: 'relative_time_duration', filterType: 'string', isFilterable: true, @@ -130,7 +125,6 @@ export const DBAAS_CONFIG: Readonly = { }, { configuration: { - capability: DBAAS_CAPABILITY, filterKey: 'node_type', filterType: 'string', isFilterable: true, // isFilterable -- this determines whether you need to pass it metrics api @@ -159,7 +153,7 @@ export const DBAAS_CONFIG: Readonly = { }; export const FILTER_CONFIG: Readonly< - Map + Map > = new Map([ ['dbaas', DBAAS_CONFIG], ['linode', LINODE_CONFIG], diff --git a/packages/manager/src/features/CloudPulse/Utils/models.ts b/packages/manager/src/features/CloudPulse/Utils/models.ts index 02d58fbc570..05d4c7fc926 100644 --- a/packages/manager/src/features/CloudPulse/Utils/models.ts +++ b/packages/manager/src/features/CloudPulse/Utils/models.ts @@ -9,6 +9,10 @@ import type { QueryFunction, QueryKey } from '@tanstack/react-query'; * The CloudPulseServiceTypeMap has list of filters to be built for different service types like dbaas, linode etc.,The properties here are readonly as it is only for reading and can't be modified in code */ export interface CloudPulseServiceTypeFilterMap { + /** + * Current capability corresponding to a service type + */ + readonly capability: Capabilities; /** * The list of filters for a service type */ @@ -87,11 +91,6 @@ export interface CloudPulseServiceTypeFiltersConfiguration { */ apiV4QueryKey?: QueryFunctionAndKey; - /** - * This is the current capability corresponding to the service type - */ - capability: Capabilities; - /** * This is an optional field, it is used to disable a certain filter, untill of the dependent filters are selected */ diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx index a306c6173d4..198ca48098d 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx @@ -8,7 +8,7 @@ import { CloudPulseRegionSelect } from './CloudPulseRegionSelect'; import type { CloudPulseRegionSelectProps } from './CloudPulseRegionSelect'; import type { Region } from '@linode/api-v4'; -import type { CloudPulseServiceTypeMapFlag, Flags } from 'src/featureFlags'; +import type { CloudPulseResourceTypeMapFlag, Flags } from 'src/featureFlags'; import type * as regions from 'src/queries/regions/regions'; const props: CloudPulseRegionSelectProps = { @@ -22,16 +22,16 @@ const queryMocks = vi.hoisted(() => ({ })); const flags: Partial = { - aclpServiceTypeMap: [ + aclpResourceTypeMap: [ { serviceType: 'dbaas', - supportedRegionIds: 'us-west', + supportedRegionIds: 'us-west, us-east', }, { serviceType: 'linode', - supportedRegionIds: 'us-lax', + supportedRegionIds: 'us-lax, us-mia', }, - ] as CloudPulseServiceTypeMapFlag[], + ] as CloudPulseResourceTypeMapFlag[], }; vi.mock('src/queries/regions/regions', async () => { @@ -74,11 +74,21 @@ describe('CloudPulseRegionSelect', () => { id: 'us-lax', label: 'US, Los Angeles, CA', }), + regionFactory.build({ + capabilities: ['Linodes'], + id: 'us-mia', + label: 'US, Miami, FL', + }), regionFactory.build({ capabilities: ['Managed Databases'], id: 'us-west', label: 'US, Fremont, CA', }), + regionFactory.build({ + capabilities: ['Managed Databases'], + id: 'us-east', + label: 'US, Newark, NJ', + }), ]; queryMocks.useRegionsQuery.mockReturnValue({ @@ -103,10 +113,20 @@ describe('CloudPulseRegionSelect', () => { name: 'US, Fremont, CA (us-west)', }) ).toBeInTheDocument(); + expect( + getByRole('option', { + name: 'US, Newark, NJ (us-east)', + }) + ).toBeInTheDocument(); expect( queryByRole('option', { name: 'US, Los Angeles, CA (us-lax)', }) ).toBeNull(); + expect( + queryByRole('option', { + name: 'US, Miami, FL (us-mia)', + }) + ).toBeNull(); }); }); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index 274d67ba7ec..8089c07348d 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -6,8 +6,13 @@ import { useRegionsQuery } from 'src/queries/regions/regions'; import { FILTER_CONFIG } from '../Utils/FilterConfig'; -import type { CloudPulseServiceTypeFilters } from '../Utils/models'; -import type { Dashboard, FilterValue, Region } from '@linode/api-v4'; +import type { + Capabilities, + Dashboard, + FilterValue, + Region, +} from '@linode/api-v4'; +import type { CloudPulseResourceTypeMapFlag } from 'src/featureFlags'; export interface CloudPulseRegionSelectProps { defaultValue?: FilterValue; @@ -33,15 +38,12 @@ export const CloudPulseRegionSelect = React.memo( selectedDashboard, } = props; - const currentFilterConfig: - | CloudPulseServiceTypeFilters - | undefined = FILTER_CONFIG.get( - selectedDashboard?.service_type - )?.filters.filter( - (config) => config.configuration.filterKey === 'region' - )[0]; - // Capture the current capability from corresponding filter config - const capability = currentFilterConfig?.configuration.capability; + const serviceType: string | undefined = selectedDashboard?.service_type; + const capability = React.useMemo(() => { + return serviceType + ? FILTER_CONFIG.get(serviceType)?.capability + : undefined; + }, [serviceType]); const [selectedRegion, setSelectedRegion] = React.useState(); // Once the data is loaded, set the state variable with value stored in preferences @@ -58,23 +60,26 @@ export const CloudPulseRegionSelect = React.memo( // validate launchDrakly region_ids with the ids from the fetched 'all-regions' const supportedRegions = React.useMemo(() => { - const serviceTypeFlag = flags.aclpServiceTypeMap?.find( - (item) => item.serviceType === selectedDashboard?.service_type + const serviceTypeFlag: + | CloudPulseResourceTypeMapFlag + | undefined = flags.aclpResourceTypeMap?.find( + (item: CloudPulseResourceTypeMapFlag) => + item.serviceType === serviceType ); - const supportedRegionsIdList = serviceTypeFlag?.supportedRegionIds - ?.split(',') - .map((regionId) => regionId.trim()); + const supportedRegionsIdList: string[] = + serviceTypeFlag?.supportedRegionIds + ?.split(',') + .map((regionId: string) => regionId.trim()) || []; - if (!supportedRegionsIdList?.length) { + if (!supportedRegionsIdList.length) { return regions; } return regions?.filter((region) => supportedRegionsIdList?.includes(region.id) ); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [flags.aclpServiceTypeMap, regions, selectedDashboard?.service_type]); + }, [flags.aclpResourceTypeMap, regions, serviceType]); return ( ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index 92ff1bb912f..ada3584f781 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -87,11 +87,11 @@ export const CloudPulseResourcesSelect = React.memo( // Maximum resource selection limit is fetched from launchdarkly const maxResourceSelectionLimit = React.useMemo(() => { - const obj = flags.aclpServiceTypeMap?.find( + const obj = flags.aclpResourceTypeMap?.find( (item) => item.serviceType === resourceType ); return obj?.maxResourceSelections || 10; - }, [resourceType, flags.aclpServiceTypeMap]); + }, [resourceType, flags.aclpResourceTypeMap]); const resourcesLimitReached = React.useMemo(() => { return getResourcesList.length > maxResourceSelectionLimit; From 91c20e48db220f00a1610b79b941b35db3280c6b Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Tue, 3 Dec 2024 16:34:49 +0530 Subject: [PATCH 365/474] upcoming: [DI-20595] - small fix --- .../src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index 8089c07348d..f981d0c29af 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -60,7 +60,7 @@ export const CloudPulseRegionSelect = React.memo( // validate launchDrakly region_ids with the ids from the fetched 'all-regions' const supportedRegions = React.useMemo(() => { - const serviceTypeFlag: + const resourceTypeFlag: | CloudPulseResourceTypeMapFlag | undefined = flags.aclpResourceTypeMap?.find( (item: CloudPulseResourceTypeMapFlag) => @@ -68,7 +68,7 @@ export const CloudPulseRegionSelect = React.memo( ); const supportedRegionsIdList: string[] = - serviceTypeFlag?.supportedRegionIds + resourceTypeFlag?.supportedRegionIds ?.split(',') .map((regionId: string) => regionId.trim()) || []; From 327e4946d9d05d8a2353c9c3891e34ef29044699 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Tue, 3 Dec 2024 16:44:06 +0530 Subject: [PATCH 366/474] upcoming: [DI-20595] - updated UT --- .../src/features/CloudPulse/Utils/FilterConfig.ts | 4 ++-- .../shared/CloudPulseRegionSelect.test.tsx | 14 ++++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts b/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts index c6313bbb1f4..e5bc12d7e3b 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts @@ -3,8 +3,8 @@ import { CloudPulseSelectTypes } from './models'; import type { CloudPulseServiceTypeFilterMap } from './models'; const TIME_DURATION = 'Time Range'; -const DBAAS_CAPABILITY = 'Managed Databases'; -const LINODE_CAPABILITY = 'Linodes'; +export const DBAAS_CAPABILITY = 'Managed Databases'; +export const LINODE_CAPABILITY = 'Linodes'; export const LINODE_CONFIG: Readonly = { capability: LINODE_CAPABILITY, diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx index 198ca48098d..f775dbcb406 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx @@ -4,6 +4,7 @@ import * as React from 'react'; import { dashboardFactory, regionFactory } from 'src/factories'; import { renderWithTheme } from 'src/utilities/testHelpers'; +import { DBAAS_CAPABILITY, LINODE_CAPABILITY } from '../Utils/FilterConfig'; import { CloudPulseRegionSelect } from './CloudPulseRegionSelect'; import type { CloudPulseRegionSelectProps } from './CloudPulseRegionSelect'; @@ -70,25 +71,30 @@ describe('CloudPulseRegionSelect', () => { const allRegions: Region[] = [ regionFactory.build({ - capabilities: ['Linodes'], + capabilities: [LINODE_CAPABILITY], id: 'us-lax', label: 'US, Los Angeles, CA', }), regionFactory.build({ - capabilities: ['Linodes'], + capabilities: [LINODE_CAPABILITY], id: 'us-mia', label: 'US, Miami, FL', }), regionFactory.build({ - capabilities: ['Managed Databases'], + capabilities: [DBAAS_CAPABILITY], id: 'us-west', label: 'US, Fremont, CA', }), regionFactory.build({ - capabilities: ['Managed Databases'], + capabilities: [DBAAS_CAPABILITY], id: 'us-east', label: 'US, Newark, NJ', }), + regionFactory.build({ + capabilities: [DBAAS_CAPABILITY], + id: 'us-central', + label: 'US, Dallas, TX', + }), ]; queryMocks.useRegionsQuery.mockReturnValue({ From 224621acaae11f43eefd52d44fd40d1af7864d2a Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Tue, 3 Dec 2024 16:53:17 +0530 Subject: [PATCH 367/474] upcoming: [DI-22221] - Fixed console error --- .../features/CloudPulse/shared/CloudPulseAppliedFilter.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx index b4cc01899cf..9710e6afe39 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx @@ -24,11 +24,11 @@ export const CloudPulseAppliedFilter = ( pb={2} rowGap={1.5} > - {Object.entries(filters).map((data) => { + {Object.entries(filters).map((data, index) => { const label = data[0]; const filterValue = data[1]; return ( - <> + ); })} - + ); })} From 0f9ea24dd8cffeda12d0f77a15791d442385467b Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Tue, 3 Dec 2024 16:55:51 +0530 Subject: [PATCH 368/474] upcoming: [DI-20595] - updated UT --- .../CloudPulse/shared/CloudPulseRegionSelect.test.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx index f775dbcb406..6a1ed09de3e 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx @@ -124,6 +124,11 @@ describe('CloudPulseRegionSelect', () => { name: 'US, Newark, NJ (us-east)', }) ).toBeInTheDocument(); + expect( + queryByRole('option', { + name: 'US, Dallas, TX (us-central)', + }) + ).toBeNull(); expect( queryByRole('option', { name: 'US, Los Angeles, CA (us-lax)', From 2aee4372e8fcf4d2016f81eac353d8c6e3183453 Mon Sep 17 00:00:00 2001 From: agorthi Date: Tue, 3 Dec 2024 17:07:59 +0530 Subject: [PATCH 369/474] DI-20929: adding changes for Applied global level filters and remove enter option --- .../dbaas-widgets-verification.spec.ts | 78 ++++++++++++------- .../linode-widget-verification.spec.ts | 52 ++++++++----- .../shared/CloudPulseAppliedFilter.tsx | 1 + 3 files changed, 83 insertions(+), 48 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts index 1c63c435993..43f276c6a59 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts @@ -27,7 +27,6 @@ import { mockGetAccount } from 'support/intercepts/account'; import { mockGetLinodes } from 'support/intercepts/linodes'; import { mockGetUserPreferences } from 'support/intercepts/profile'; import { mockGetRegions } from 'support/intercepts/regions'; -import { extendRegion } from 'support/util/regions'; import { CloudPulseMetricsResponse, Database } from '@linode/api-v4'; import { Interception } from 'cypress/types/net-stubbing'; import { generateRandomMetricsData } from 'support/util/cloudpulse'; @@ -56,7 +55,6 @@ const { id, serviceType, dashboardName, - region, engine, clusterName, nodeType, @@ -91,14 +89,13 @@ const mockLinode = linodeFactory.build({ }); const mockAccount = accountFactory.build(); -const mockRegion = extendRegion( - regionFactory.build({ - capabilities: ['Linodes'], - id: 'us-ord', - label: 'Chicago, IL', - country: 'us', - }) -); + +const mockRegion = regionFactory.build({ + capabilities: ['Linodes'], + id: 'us-ord', + label: 'Chicago, IL', + country: 'us', +}); const metricsAPIResponsePayload = cloudPulseMetricsResponseFactory.build({ data: generateRandomMetricsData(timeDurationToSelect, '5 min'), }); @@ -151,9 +148,9 @@ const getWidgetLegendRowValuesFromResponse = ( }; const databaseMock: Database = databaseFactory.build({ - label: widgetDetails.dbaas.clusterName, - type: widgetDetails.dbaas.engine, - region: widgetDetails.dbaas.region, + label: clusterName, + type: engine, + region: mockRegion.label, version: '1', status: 'provisioning', cluster_size: 1, @@ -191,40 +188,67 @@ describe('Integration Tests for DBaaS Dashboard ', () => { ui.autocomplete .findByLabel('Dashboard') .should('be.visible') - .type(`${dashboardName}{enter}`) - .should('be.visible'); + .type(dashboardName); + + ui.autocompletePopper + .findByTitle(dashboardName) + .should('be.visible') + .click(); // Select a time duration from the autocomplete input. ui.autocomplete .findByLabel('Time Range') .should('be.visible') - .type(`${timeDurationToSelect}{enter}`) - .should('be.visible'); + .type(timeDurationToSelect); + + ui.autocompletePopper + .findByTitle(timeDurationToSelect) + .should('be.visible') + .click(); - //Select a Engine from the autocomplete input. + //Select a Database Engine from the autocomplete input. ui.autocomplete .findByLabel('Database Engine') .should('be.visible') - .type(`${engine}{enter}`) - .should('be.visible'); + .type(engine); - // Select a region from the dropdown. - ui.regionSelect.find().click().type(`${region}{enter}`); + ui.autocompletePopper + .findByTitle(engine) + .should('be.visible') + .click(); - // Select a resource from the autocomplete input. + // Select a region from the dropdown. + ui.regionSelect.find().click(); + ui.regionSelect + .findItemByRegionId(mockRegion.id, [mockRegion]) + .should('be.visible') + .click(); + + // Select a resource (Database Clusters) from the autocomplete input. ui.autocomplete .findByLabel('Database Clusters') .should('be.visible') - .type(`${clusterName}{enter}`) - .click(); - cy.findByText(clusterName).should('be.visible'); + .type(clusterName); - //Select a Node from the autocomplete input. + ui.autocompletePopper.findByTitle(clusterName).should('be.visible').click(); + + // Select a Node from the autocomplete input. ui.autocomplete .findByLabel('Node Type') .should('be.visible') .type(`${nodeType}{enter}`); + // Expand the applied filters section + ui.button.findByTitle('Filters').should('be.visible').click(); + + // Verify that the applied filters + cy.get('[data-testid="applied-filter"]').within(() => { + cy.get(`[data-qa-value="Database Engine ${engine}"]`); + cy.get(`[data-qa-value="Region US, Chicago, IL"]`); + cy.get(`[data-qa-value="Node Type ${nodeType}"]`); + cy.get(`[data-qa-value="Database Clusters ${databaseMock.label}"]`); + }); + // Wait for all metrics query requests to resolve. cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']); }); diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 303748e957a..c6a5d197c01 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -26,7 +26,6 @@ import { mockGetAccount } from 'support/intercepts/account'; import { mockGetLinodes } from 'support/intercepts/linodes'; import { mockGetUserPreferences } from 'support/intercepts/profile'; import { mockGetRegions } from 'support/intercepts/regions'; -import { extendRegion } from 'support/util/regions'; import { CloudPulseMetricsResponse } from '@linode/api-v4'; import { generateRandomMetricsData } from 'support/util/cloudpulse'; import { Interception } from 'cypress/types/net-stubbing'; @@ -47,14 +46,8 @@ import { formatToolTip } from 'src/features/CloudPulse/Utils/unitConversion'; const expectedGranularityArray = ['Auto', '1 day', '1 hr', '5 min']; const timeDurationToSelect = 'Last 24 Hours'; const flags: Partial = { aclp: { enabled: true, beta: true } }; -const { - metrics, - id, - serviceType, - dashboardName, - region, - resource, -} = widgetDetails.linode; +const { metrics, id, serviceType, dashboardName, region, resource } = + widgetDetails.linode; const dashboard = dashboardFactory.build({ label: dashboardName, @@ -85,14 +78,13 @@ const mockLinode = linodeFactory.build({ }); const mockAccount = accountFactory.build(); -const mockRegion = extendRegion( - regionFactory.build({ - capabilities: ['Linodes'], - id: 'us-ord', - label: 'Chicago, IL', - country: 'us', - }) -); + +const mockRegion = regionFactory.build({ + capabilities: ['Linodes'], + id: 'us-ord', + label: 'Chicago, IL', + country: 'us', +}); const metricsAPIResponsePayload = cloudPulseMetricsResponseFactory.build({ data: generateRandomMetricsData(timeDurationToSelect, '5 min'), }); @@ -170,15 +162,23 @@ describe('Integration Tests for Linode Dashboard ', () => { ui.autocomplete .findByLabel('Dashboard') .should('be.visible') - .type(`${dashboardName}{enter}`) - .should('be.visible'); + .type(dashboardName); + + ui.autocompletePopper + .findByTitle(dashboardName) + .should('be.visible') + .click(); // Select a time duration from the autocomplete input. ui.autocomplete .findByLabel('Time Range') .should('be.visible') - .type(`${timeDurationToSelect}{enter}`) - .should('be.visible'); + .type(timeDurationToSelect); + + ui.autocompletePopper + .findByTitle(timeDurationToSelect) + .should('be.visible') + .click(); // Select a region from the dropdown. ui.regionSelect.find().click().type(`${region}{enter}`); @@ -191,6 +191,16 @@ describe('Integration Tests for Linode Dashboard ', () => { .click(); cy.findByText(resource).should('be.visible'); + + // Expand the applied filters section + ui.button.findByTitle('Filters').should('be.visible').click(); + + // Verify that the applied filters + cy.get('[data-testid="applied-filter"]').within(() => { + cy.get(`[data-qa-value="Region US, Chicago, IL"]`); + cy.get(`[data-qa-value="Resources ${mockLinode.label}"]`); + }); + // Wait for all metrics query requests to resolve. cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']); }); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx index b4cc01899cf..17bf6de5624 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx @@ -45,6 +45,7 @@ export const CloudPulseAppliedFilter = ( px: 1, py: 0.5, }} + data-qa-value={`${label} ${value}`} key={`${label} ${value}`} label={value} /> From 1b7e33211abc7d0607db971288b975614693e197 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Tue, 3 Dec 2024 17:21:30 +0530 Subject: [PATCH 370/474] upcoming: [DI-20595] - updated types --- .../CloudPulse/shared/CloudPulseRegionSelect.tsx | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index f981d0c29af..09d58673744 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -39,11 +39,9 @@ export const CloudPulseRegionSelect = React.memo( } = props; const serviceType: string | undefined = selectedDashboard?.service_type; - const capability = React.useMemo(() => { - return serviceType - ? FILTER_CONFIG.get(serviceType)?.capability - : undefined; - }, [serviceType]); + const capability = serviceType + ? FILTER_CONFIG.get(serviceType)?.capability + : undefined; const [selectedRegion, setSelectedRegion] = React.useState(); // Once the data is loaded, set the state variable with value stored in preferences @@ -60,14 +58,12 @@ export const CloudPulseRegionSelect = React.memo( // validate launchDrakly region_ids with the ids from the fetched 'all-regions' const supportedRegions = React.useMemo(() => { - const resourceTypeFlag: - | CloudPulseResourceTypeMapFlag - | undefined = flags.aclpResourceTypeMap?.find( + const resourceTypeFlag = flags.aclpResourceTypeMap?.find( (item: CloudPulseResourceTypeMapFlag) => item.serviceType === serviceType ); - const supportedRegionsIdList: string[] = + const supportedRegionsIdList = resourceTypeFlag?.supportedRegionIds ?.split(',') .map((regionId: string) => regionId.trim()) || []; From c763e27d6ef3227a391a96c336fb1fbd3543e24a Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Tue, 3 Dec 2024 18:47:38 +0530 Subject: [PATCH 371/474] upcoming: [DI-20595] - small linting fix --- .../features/CloudPulse/shared/CloudPulseRegionSelect.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index 09d58673744..3ad0acda4ae 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -6,12 +6,7 @@ import { useRegionsQuery } from 'src/queries/regions/regions'; import { FILTER_CONFIG } from '../Utils/FilterConfig'; -import type { - Capabilities, - Dashboard, - FilterValue, - Region, -} from '@linode/api-v4'; +import type { Dashboard, FilterValue, Region } from '@linode/api-v4'; import type { CloudPulseResourceTypeMapFlag } from 'src/featureFlags'; export interface CloudPulseRegionSelectProps { From 12b52363a17bdb29f3358ff7dd4aaf7a9e4fbdcf Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Tue, 3 Dec 2024 18:48:10 +0530 Subject: [PATCH 372/474] upcoming: [DI-20595] - incorrect merge fix --- .../shared/CloudPulseResourcesSelect.test.tsx | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx index 7f62d9be84a..d6dc9f0c9e5 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx @@ -254,7 +254,9 @@ describe('CloudPulseResourcesSelect component tests', () => { expect(screen.getByText('Failed to fetch Resources.')).toBeInTheDocument(); }); - it('should be able to select limited resources and select/deselect all will not be available if resource are more than max resource selection limit', () => { + it('should be able to select limited resources and select/deselect all will not be available if resource are more than max resource selection limit', async () => { + const user = userEvent.setup(); + queryMocks.useResourcesQuery.mockReturnValue({ data: linodeFactory.buildList(12), isError: false, @@ -271,22 +273,28 @@ describe('CloudPulseResourcesSelect component tests', () => { /> ); - fireEvent.click(screen.getByRole('button', { name: 'Open' })); + await user.click(screen.getByRole('button', { name: 'Open' })); + expect(screen.getByLabelText('Resources')).toBeInTheDocument(); expect(screen.getByText('Select up to 10 Resources')).toBeInTheDocument(); for (let i = 14; i <= 23; i++) { - fireEvent.click(screen.getByRole('option', { name: `linode-${i}` })); + // eslint-disable-next-line no-await-in-loop + const option = await screen.findByRole('option', { name: `linode-${i}` }); + // eslint-disable-next-line no-await-in-loop + await user.click(option); } + const selectedOptions = screen .getAllByRole('option') .filter((option) => option.getAttribute(ARIA_SELECTED) === 'true'); expect(selectedOptions.length).toBe(10); - expect(screen.getByRole('option', { name: `linode-24` })).toHaveAttribute( - ARIA_DISABLED, - 'true' - ); + + const isResourceWithExceededLimit = await screen.findByRole('option', { + name: 'linode-24', + }); + expect(isResourceWithExceededLimit).toHaveAttribute(ARIA_DISABLED, 'true'); expect(queryByRole('option', { name: SELECT_ALL })).not.toBeInTheDocument(); }); From 726bddcf52c32c29e751843aa420df521b6b24ca Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Thu, 28 Nov 2024 15:51:28 +0530 Subject: [PATCH 373/474] upcoming: [DI-20929] - Added labels parameter to global filter change handlers --- .../Dashboard/CloudPulseDashboardLanding.tsx | 37 ++++++++++++++----- .../CloudPulseDashboardWithFilters.tsx | 31 ++++++++++++---- .../CloudPulse/Overview/GlobalFilters.tsx | 11 ++++-- .../CloudPulse/Utils/FilterBuilder.ts | 7 +++- .../shared/CloudPulseCustomSelect.tsx | 2 + .../shared/CloudPulseCustomSelectUtils.ts | 18 ++++++++- .../CloudPulseDashboardFilterBuilder.tsx | 15 +++++++- .../shared/CloudPulseRegionSelect.tsx | 18 ++++++--- 8 files changed, 108 insertions(+), 31 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx index 828a05301c7..2613a777833 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx @@ -8,6 +8,10 @@ import type { Dashboard, TimeDuration } from '@linode/api-v4'; export type FilterValueType = number | number[] | string | string[] | undefined; +export interface FilterValue { + id: { [key: string]: FilterValueType }; + label: string[]; +} export interface DashboardProp { dashboard?: Dashboard; filterValue: { @@ -17,26 +21,39 @@ export interface DashboardProp { } export const CloudPulseDashboardLanding = () => { - const [filterValue, setFilterValue] = React.useState<{ - [key: string]: FilterValueType; - }>({}); + const [filterValue, setFilterValue] = React.useState({ + id: {}, + label: [], + }); + const [timeDuration, setTimeDuration] = React.useState(); const [dashboard, setDashboard] = React.useState(); const onFilterChange = React.useCallback( - (filterKey: string, filterValue: FilterValueType) => { - setFilterValue((prev: { [key: string]: FilterValueType }) => ({ - ...prev, - [filterKey]: filterValue, - })); + (filterKey: string, filterValue: FilterValueType, labels: string[]) => { + setFilterValue((prev: FilterValue) => { + return { + id: { + ...prev.id, + [filterKey]: filterValue, + }, + label: { + ...prev.label, + [filterKey]: labels, + }, + }; + }); }, [] ); const onDashboardChange = React.useCallback((dashboardObj: Dashboard) => { setDashboard(dashboardObj); - setFilterValue({}); // clear the filter values on dashboard change + setFilterValue({ + id: {}, + label: [], + }); // clear the filter values on dashboard change }, []); const onTimeDurationChange = React.useCallback( (timeDurationObj: TimeDuration) => { @@ -57,7 +74,7 @@ export const CloudPulseDashboardLanding = () => { diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx index 00f73834381..248ec5d9f03 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx @@ -16,7 +16,10 @@ import { } from '../Utils/ReusableDashboardFilterUtils'; import { CloudPulseDashboard } from './CloudPulseDashboard'; -import type { FilterValueType } from './CloudPulseDashboardLanding'; +import type { + FilterValue, + FilterValueType, +} from './CloudPulseDashboardLanding'; import type { TimeDuration } from '@linode/api-v4'; export interface CloudPulseDashboardWithFiltersProp { @@ -37,9 +40,10 @@ export const CloudPulseDashboardWithFilters = React.memo( dashboardId ); - const [filterValue, setFilterValue] = React.useState<{ - [key: string]: FilterValueType; - }>({}); + const [filterValue, setFilterValue] = React.useState({ + id: {}, + label: [], + }); const [timeDuration, setTimeDuration] = React.useState({ unit: 'min', @@ -47,8 +51,19 @@ export const CloudPulseDashboardWithFilters = React.memo( }); const onFilterChange = React.useCallback( - (filterKey: string, value: FilterValueType) => { - setFilterValue((prev) => ({ ...prev, [filterKey]: value })); + (filterKey: string, value: FilterValueType, labels: string[]) => { + setFilterValue((prev) => { + return { + id: { + ...prev.id, + [filterKey]: value, + }, + label: { + ...prev.label, + [filterKey]: labels, + }, + }; + }); }, [] ); @@ -91,7 +106,7 @@ export const CloudPulseDashboardWithFilters = React.memo( const isFilterBuilderNeeded = checkIfFilterBuilderNeeded(dashboard); const isMandatoryFiltersSelected = checkMandatoryFiltersSelected({ dashboardObj: dashboard, - filterValue, + filterValue: filterValue.id, resource, timeDuration, }); @@ -140,7 +155,7 @@ export const CloudPulseDashboardWithFilters = React.memo( { ( filterKey: string, value: FilterValueType, + labels: string[], savePref: boolean = false, updatedPreferenceData: AclpConfig = {} ) => { if (savePref) { updatePreferences(updatedPreferenceData); } - handleAnyFilterChange(filterKey, value); + handleAnyFilterChange(filterKey, value, labels); }, [] ); const handleGlobalRefresh = React.useCallback(() => { - handleAnyFilterChange(REFRESH, Date.now()); + handleAnyFilterChange(REFRESH, Date.now(), []); }, []); const theme = useTheme(); diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts index e058b2e3d03..93a72d435f8 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts @@ -54,7 +54,11 @@ interface CloudPulseMandatoryFilterCheckProps { */ export const getRegionProperties = ( props: CloudPulseFilterProperties, - handleRegionChange: (region: string | undefined, savePref?: boolean) => void + handleRegionChange: ( + region: string | undefined, + labels: [], + savePref?: boolean + ) => void ): CloudPulseRegionSelectProps => { const { name: label, placeholder } = props.config.configuration; const { dashboard, isServiceAnalyticsIntegration, preferences } = props; @@ -119,6 +123,7 @@ export const getCustomSelectProperties = ( handleCustomSelectChange: ( filterKey: string, value: FilterValueType, + labels: string[], savePref?: boolean, updatedPreferenceData?: {} ) => void diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index 98338efb533..461d224c864 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -68,10 +68,12 @@ export interface CloudPulseCustomSelectProps { * The callback function , that will be called on a filter change * @param filterKey - The filterKey of the component * @param value - The selected filter value + * @param labels - Lables of the selected filter value */ handleSelectionChange: ( filterKey: string, value: FilterValueType, + labels: string[], savePref?: boolean, updatedPreferenceData?: AclpConfig ) => void; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts index ce6dabc4a02..164e22d5471 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelectUtils.ts @@ -14,6 +14,7 @@ interface CloudPulseCustomSelectProps { handleSelectionChange: ( filterKey: string, value: FilterValueType, + labels: string[], savePref?: boolean, updatedPreferenceData?: AclpConfig ) => void; @@ -139,7 +140,8 @@ export const getInitialDefaultSelections = ( const initialSelection = isMultiSelect ? [options[0]] : options[0]; handleSelectionChange( filterKey, - isMultiSelect ? [options[0].id] : options[0].id + isMultiSelect ? [options[0].id] : options[0].id, + [options[0].label] ); return initialSelection; } @@ -155,7 +157,12 @@ export const getInitialDefaultSelections = ( ? isMultiSelect ? selectedValues.map(({ id }) => id) : selectedValues[0].id - : undefined // if this is multiselect, return list of ids, otherwise return single id + : undefined, // if this is multiselect, return list of ids, otherwise return single id + selectedValues && selectedValues.length > 0 + ? isMultiSelect + ? selectedValues.map(({ label }) => label) + : [selectedValues[0].label] + : [] ); return selectedValues?.length ? isMultiSelect @@ -195,6 +202,12 @@ export const handleCustomSelectionChange = ( : String(value.id) : undefined; + const labels = value + ? Array.isArray(value) + ? value.map(({ label }) => label) + : [value.label] + : []; + let updatedPreferenceData: AclpConfig = {}; // update the preferences @@ -216,6 +229,7 @@ export const handleCustomSelectionChange = ( handleSelectionChange( filterKey, result, + labels, savePreferences, updatedPreferenceData ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index d836b73ec63..bfe51315b01 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -41,6 +41,7 @@ export interface CloudPulseDashboardFilterBuilderProps { emitFilterChange: ( filterKey: string, value: FilterValueType, + labels: string[], savePref?: boolean, updatePreferenceData?: {} ) => void; @@ -105,12 +106,14 @@ export const CloudPulseDashboardFilterBuilder = React.memo( ( filterKey: string, filterValue: FilterValueType, + labels: string[], savePref: boolean = false, updatedPreferenceData: AclpConfig = {} ) => { emitFilterChange( filterKey, filterValue, + labels, savePref, updatedPreferenceData ); @@ -124,6 +127,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( emitFilterChangeByFilterKey( RESOURCE_ID, resourceId.map((resource) => resource.id), + resourceId.map((resource) => resource.label), savePref, { [RESOURCES]: resourceId.map((resource: { id: string }) => @@ -136,7 +140,11 @@ export const CloudPulseDashboardFilterBuilder = React.memo( ); const handleRegionChange = React.useCallback( - (region: string | undefined, savePref: boolean = false) => { + ( + region: string | undefined, + labels: string[], + savePref: boolean = false + ) => { const updatedPreferenceData = { [REGION]: region, [RESOURCES]: undefined, @@ -144,6 +152,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( emitFilterChangeByFilterKey( REGION, region, + labels, savePref, updatedPreferenceData ); @@ -155,12 +164,14 @@ export const CloudPulseDashboardFilterBuilder = React.memo( ( filterKey: string, value: FilterValueType, + labels: string[], savePref: boolean = false, updatedPreferenceData: {} = {} ) => { emitFilterChangeByFilterKey( filterKey, value, + labels, savePref, updatedPreferenceData ); @@ -228,7 +239,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( CustomIcon={InfoIcon} CustomIconStyles={{ height: '40px', width: '40px' }} errorText={'Please configure filters to continue'} - > + /> ); } diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index bb8a1c25f03..3d38f51c287 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -7,7 +7,11 @@ import type { Dashboard, FilterValue } from '@linode/api-v4'; export interface CloudPulseRegionSelectProps { defaultValue?: FilterValue; - handleRegionChange: (region: string | undefined, savePref?: boolean) => void; + handleRegionChange: ( + region: string | undefined, + labels: string[], + savePref?: boolean + ) => void; label: string; placeholder?: string; savePreferences?: boolean; @@ -32,10 +36,10 @@ export const CloudPulseRegionSelect = React.memo( React.useEffect(() => { if (regions && savePreferences) { const region = defaultValue - ? regions.find((regionObj) => regionObj.id === defaultValue)?.id + ? regions.find((regionObj) => regionObj.id === defaultValue) : undefined; - handleRegionChange(region); - setSelectedRegion(region); + handleRegionChange(region?.id, region ? [region.label] : []); + setSelectedRegion(region?.id); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [regions]); @@ -44,7 +48,11 @@ export const CloudPulseRegionSelect = React.memo( { setSelectedRegion(region?.id); - handleRegionChange(region?.id, savePreferences); + handleRegionChange( + region?.id, + region ? [region.label] : [], + savePreferences + ); }} currentCapability={undefined} data-testid="region-select" From fab859ac6efd674eec1abf22767eb7457906f2a5 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Mon, 2 Dec 2024 15:08:14 +0530 Subject: [PATCH 374/474] upcoming: [DI-20929] - Added cloudpulse applied filter --- .../Dashboard/CloudPulseDashboardLanding.tsx | 36 +++++++++--- .../CloudPulseDashboardWithFilters.tsx | 20 ++++++- .../CloudPulse/Overview/GlobalFilters.tsx | 3 + .../shared/CloudPulseAppliedFilter.tsx | 57 +++++++++++++++++++ .../CloudPulseAppliedFilterRenderer.tsx | 39 +++++++++++++ .../CloudPulseDashboardFilterBuilder.tsx | 4 ++ 6 files changed, 149 insertions(+), 10 deletions(-) create mode 100644 packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx create mode 100644 packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilterRenderer.tsx diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx index 2613a777833..3cd47ce2aaa 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx @@ -1,7 +1,8 @@ -import { Grid, Paper } from '@mui/material'; +import { Box, Grid, Paper } from '@mui/material'; import * as React from 'react'; import { GlobalFilters } from '../Overview/GlobalFilters'; +import { CloudPulseAppliedFilterRenderer } from '../shared/CloudPulseAppliedFilterRenderer'; import { CloudPulseDashboardRenderer } from './CloudPulseDashboardRenderer'; import type { Dashboard, TimeDuration } from '@linode/api-v4'; @@ -10,7 +11,7 @@ export type FilterValueType = number | number[] | string | string[] | undefined; export interface FilterValue { id: { [key: string]: FilterValueType }; - label: string[]; + label: { [key: string]: string[] }; } export interface DashboardProp { dashboard?: Dashboard; @@ -23,13 +24,21 @@ export interface DashboardProp { export const CloudPulseDashboardLanding = () => { const [filterValue, setFilterValue] = React.useState({ id: {}, - label: [], + label: {}, }); const [timeDuration, setTimeDuration] = React.useState(); const [dashboard, setDashboard] = React.useState(); + const [showAppliedFilters, setShowAppliedFilters] = React.useState( + false + ); + + const toggleAppliedFilter = (isVisible: boolean) => { + setShowAppliedFilters(isVisible); + }; + const onFilterChange = React.useCallback( (filterKey: string, filterValue: FilterValueType, labels: string[]) => { setFilterValue((prev: FilterValue) => { @@ -52,7 +61,7 @@ export const CloudPulseDashboardLanding = () => { setDashboard(dashboardObj); setFilterValue({ id: {}, - label: [], + label: {}, }); // clear the filter values on dashboard change }, []); const onTimeDurationChange = React.useCallback( @@ -65,11 +74,20 @@ export const CloudPulseDashboardLanding = () => { - + + + {dashboard?.service_type && showAppliedFilters && ( + + )} + ({ id: {}, - label: [], + label: {}, }); const [timeDuration, setTimeDuration] = React.useState({ @@ -50,6 +51,14 @@ export const CloudPulseDashboardWithFilters = React.memo( value: 30, }); + const [showAppliedFilters, setShowAppliedFilters] = React.useState( + false + ); + + const toggleAppliedFilter = (isVisible: boolean) => { + setShowAppliedFilters(isVisible); + }; + const onFilterChange = React.useCallback( (filterKey: string, value: FilterValueType, labels: string[]) => { setFilterValue((prev) => { @@ -147,9 +156,18 @@ export const CloudPulseDashboardWithFilters = React.memo( )} + + {showAppliedFilters && ( + + )} + {isMandatoryFiltersSelected ? ( { @@ -31,6 +32,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { handleAnyFilterChange, handleDashboardChange, handleTimeDurationChange, + handleToggleAppliedFilter, } = props; const { @@ -148,6 +150,7 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx new file mode 100644 index 00000000000..b6ad763e893 --- /dev/null +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx @@ -0,0 +1,57 @@ +import { Box, Chip, Typography } from '@mui/material'; +import React from 'react'; + +interface CloudPulseAppliedFilterProps { + filters: { + [label: string]: string[]; + }; +} +export const CloudPulseAppliedFilter = ( + props: CloudPulseAppliedFilterProps +) => { + const { filters } = props; + + return ( + + {Object.entries(filters).map((data) => { + const label = data[0]; + const filterValue = data[1]; + return ( + <> + {`${label}:`} + {filterValue.map((value, index) => { + return ( + + ); + })} + + ); + })} + + ); +}; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilterRenderer.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilterRenderer.tsx new file mode 100644 index 00000000000..ea35136782f --- /dev/null +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilterRenderer.tsx @@ -0,0 +1,39 @@ +import React from 'react'; + +import { FILTER_CONFIG } from '../Utils/FilterConfig'; +import { CloudPulseAppliedFilter } from './CloudPulseAppliedFilter'; + +interface AppliedFilterRendererProps { + filters: { + [label: string]: string[]; + }; + serviceType: string; +} + +export const CloudPulseAppliedFilterRenderer = ( + props: AppliedFilterRendererProps +) => { + const { filters, serviceType } = props; + + const filterConfig = FILTER_CONFIG.get(serviceType); + + if (!filterConfig) { + return <>; + } + const configuredFilters = filterConfig.filters; + + const appliedFilter = configuredFilters + .filter((filter) => { + const filterKey = filter.configuration.filterKey; + return Boolean(filters[filterKey]?.length); + }) + .reduce( + (prevValue, filter) => ({ + ...prevValue, + [filter.configuration.name]: filters[filter.configuration.filterKey], + }), + {} + ); + + return ; +}; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index bfe51315b01..a59caa17471 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -46,6 +46,8 @@ export interface CloudPulseDashboardFilterBuilderProps { updatePreferenceData?: {} ) => void; + handleToggleAppliedFilter: (isVisible: boolean) => void; + /** * this will handle the restrictions, if the parent of the component is going to be integrated in service analytics page */ @@ -62,6 +64,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( const { dashboard, emitFilterChange, + handleToggleAppliedFilter, isServiceAnalyticsIntegration, preferences, } = props; @@ -227,6 +230,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( const toggleShowFilter = () => { setShowFilter((showFilterPrev) => !showFilterPrev); + handleToggleAppliedFilter(showFilter); }; const RenderFilters = React.useCallback(() => { From 24af9e8023fe741df39a32ed8a4e9d4e271f3fc6 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Mon, 2 Dec 2024 15:29:53 +0530 Subject: [PATCH 375/474] upcoming: [DI-20929] - Added test cases --- .../shared/CloudPulseAppliedFilter.test.tsx | 40 +++++++++++++++++++ .../shared/CloudPulseAppliedFilter.tsx | 1 + 2 files changed, 41 insertions(+) create mode 100644 packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.test.tsx diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.test.tsx new file mode 100644 index 00000000000..531d2209d0f --- /dev/null +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.test.tsx @@ -0,0 +1,40 @@ +import React from 'react'; +import { i } from 'vite/dist/node/types.d-aGj9QkWt'; + +import { renderWithTheme } from 'src/utilities/testHelpers'; + +import { CloudPulseAppliedFilter } from './CloudPulseAppliedFilter'; +import { CloudPulseAppliedFilterRenderer } from './CloudPulseAppliedFilterRenderer'; + +const data = { + region: ['us-east'], + resource: ['res1', 'res2'], +}; + +const testId = 'applied-filter'; + +describe('CloudPulse Applied Filter', () => { + it('should render applied filter component', () => { + const { getByTestId } = renderWithTheme( + + ); + expect(getByTestId(testId)).toBeInTheDocument(); + }); + + it('should render the applied filter key & values', () => { + const { getByTestId } = renderWithTheme( + + ); + expect(getByTestId(testId)).toHaveTextContent('region'); + expect(getByTestId(testId)).toHaveTextContent('res1'); + expect(getByTestId(testId)).not.toHaveTextContent('resources'); + }); + + it('should not render the applied filter component', () => { + const { queryByTestId } = renderWithTheme( + + ); + + expect(queryByTestId(testId)).toBe(null); + }); +}); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx index b6ad763e893..b4cc01899cf 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx @@ -13,6 +13,7 @@ export const CloudPulseAppliedFilter = ( return ( Date: Mon, 2 Dec 2024 16:12:34 +0530 Subject: [PATCH 376/474] upcoming: [DI-20929] - updated failing test cases --- .../src/features/CloudPulse/Overview/GlobalFilters.test.tsx | 2 ++ .../features/CloudPulse/shared/CloudPulseAppliedFilter.test.tsx | 1 - .../CloudPulse/shared/CloudPulseDashboardFilterBuilder.test.tsx | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.test.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.test.tsx index 286c95377e1..d1591390f97 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.test.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.test.tsx @@ -7,6 +7,7 @@ import { GlobalFilters } from './GlobalFilters'; const mockHandleAnyFilterChange = vi.fn(); const mockHandleDashboardChange = vi.fn(); const mockHandleTimeDurationChange = vi.fn(); +const mockHandleToggleAppliedFilter = vi.fn(); const timeRangeSelectId = 'cloudpulse-time-duration'; const setup = () => { return renderWithTheme( @@ -14,6 +15,7 @@ const setup = () => { handleAnyFilterChange={mockHandleAnyFilterChange} handleDashboardChange={mockHandleDashboardChange} handleTimeDurationChange={mockHandleTimeDurationChange} + handleToggleAppliedFilter={mockHandleToggleAppliedFilter} /> ); }; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.test.tsx index 531d2209d0f..6a8dbb2a274 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.test.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import { i } from 'vite/dist/node/types.d-aGj9QkWt'; import { renderWithTheme } from 'src/utilities/testHelpers'; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.test.tsx index ec2c10bacc5..71a684c9a1d 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.test.tsx @@ -13,6 +13,7 @@ describe('CloudPulseDashboardFilterBuilder component tests', () => { service_type: 'linode', })} emitFilterChange={vi.fn()} + handleToggleAppliedFilter={vi.fn()} isServiceAnalyticsIntegration={false} /> ); @@ -28,6 +29,7 @@ describe('CloudPulseDashboardFilterBuilder component tests', () => { service_type: 'dbaas', })} emitFilterChange={vi.fn()} + handleToggleAppliedFilter={vi.fn()} isServiceAnalyticsIntegration={false} /> ); From 2ec9bd6ae6b8b25eb090b92f4067f9d05bcd6b74 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Tue, 3 Dec 2024 16:53:17 +0530 Subject: [PATCH 377/474] upcoming: [DI-22221] - Fixed console error --- .../features/CloudPulse/shared/CloudPulseAppliedFilter.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx index b4cc01899cf..9710e6afe39 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx @@ -24,11 +24,11 @@ export const CloudPulseAppliedFilter = ( pb={2} rowGap={1.5} > - {Object.entries(filters).map((data) => { + {Object.entries(filters).map((data, index) => { const label = data[0]; const filterValue = data[1]; return ( - <> + ); })} - + ); })} From 7177bc5cca1c8ee643f245f81a1f5981e02ccc14 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Tue, 3 Dec 2024 20:27:09 +0530 Subject: [PATCH 378/474] upcoming: [DI-20929] - Added changeset --- .../.changeset/pr-11354-upcoming-features-1733237771685.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 packages/manager/.changeset/pr-11354-upcoming-features-1733237771685.md diff --git a/packages/manager/.changeset/pr-11354-upcoming-features-1733237771685.md b/packages/manager/.changeset/pr-11354-upcoming-features-1733237771685.md new file mode 100644 index 00000000000..6792c206660 --- /dev/null +++ b/packages/manager/.changeset/pr-11354-upcoming-features-1733237771685.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Upcoming Features +--- + +Add `CloudPulseAppliedFilter` and CloudPulseAppliedFilterRenderer` components, update filter change handler function to add another parameter `label` ([#11354](https://github.com/linode/manager/pull/11354)) From 265cb6292af7fcab1c84c5f6f45ba4865153988c Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Tue, 3 Dec 2024 20:30:49 +0530 Subject: [PATCH 379/474] upcoming: [DI-20929] - Updated changeset --- .../.changeset/pr-11354-upcoming-features-1733237771685.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/.changeset/pr-11354-upcoming-features-1733237771685.md b/packages/manager/.changeset/pr-11354-upcoming-features-1733237771685.md index 6792c206660..2d5d7973305 100644 --- a/packages/manager/.changeset/pr-11354-upcoming-features-1733237771685.md +++ b/packages/manager/.changeset/pr-11354-upcoming-features-1733237771685.md @@ -2,4 +2,4 @@ "@linode/manager": Upcoming Features --- -Add `CloudPulseAppliedFilter` and CloudPulseAppliedFilterRenderer` components, update filter change handler function to add another parameter `label` ([#11354](https://github.com/linode/manager/pull/11354)) +Add `CloudPulseAppliedFilter` and `CloudPulseAppliedFilterRenderer` components, update filter change handler function to add another parameter `label` ([#11354](https://github.com/linode/manager/pull/11354)) From e98fc599d73ad8f86b4139ee7e9ee578f0726ad3 Mon Sep 17 00:00:00 2001 From: agorthi Date: Wed, 4 Dec 2024 09:30:34 +0530 Subject: [PATCH 380/474] fixing code review comments --- .../e2e/core/cloudpulse/cloudpulse-dashboard-errors.spec.ts | 3 +-- .../e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts | 3 +-- .../e2e/core/cloudpulse/linode-widget-verification.spec.ts | 1 - 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-dashboard-errors.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-dashboard-errors.spec.ts index f2fbcdc66a7..2cf61267beb 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-dashboard-errors.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-dashboard-errors.spec.ts @@ -78,10 +78,9 @@ const metricDefinitions = { }; const mockRegion = regionFactory.build({ - capabilities: ['Linodes'], + capabilities: ['Managed Databases'], id: 'us-ord', label: 'Chicago, IL', - country: 'us', }); const databaseMock: Database = databaseFactory.build({ diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts index 43f276c6a59..ce760934da3 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts @@ -91,10 +91,9 @@ const mockLinode = linodeFactory.build({ const mockAccount = accountFactory.build(); const mockRegion = regionFactory.build({ - capabilities: ['Linodes'], + capabilities: ['Managed Databases'], id: 'us-ord', label: 'Chicago, IL', - country: 'us', }); const metricsAPIResponsePayload = cloudPulseMetricsResponseFactory.build({ data: generateRandomMetricsData(timeDurationToSelect, '5 min'), diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index c6a5d197c01..5ab82d37ea3 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -83,7 +83,6 @@ const mockRegion = regionFactory.build({ capabilities: ['Linodes'], id: 'us-ord', label: 'Chicago, IL', - country: 'us', }); const metricsAPIResponsePayload = cloudPulseMetricsResponseFactory.build({ data: generateRandomMetricsData(timeDurationToSelect, '5 min'), From 4a175f7880771f7c12332b17c8fd61b6a92bbdb2 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Thu, 5 Dec 2024 13:41:01 +0530 Subject: [PATCH 381/474] upcoming: [DI-20595] - handle empty regions --- .../CloudPulse/shared/CloudPulseRegionSelect.test.tsx | 2 +- .../features/CloudPulse/shared/CloudPulseRegionSelect.tsx | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx index 6a1ed09de3e..3a47701db75 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx @@ -26,7 +26,7 @@ const flags: Partial = { aclpResourceTypeMap: [ { serviceType: 'dbaas', - supportedRegionIds: 'us-west, us-east', + supportedRegionIds: 'us-west, us-east, ,', }, { serviceType: 'linode', diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index 3ad0acda4ae..6625b443dc1 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -57,16 +57,15 @@ export const CloudPulseRegionSelect = React.memo( (item: CloudPulseResourceTypeMapFlag) => item.serviceType === serviceType ); - const supportedRegionsIdList = resourceTypeFlag?.supportedRegionIds ?.split(',') - .map((regionId: string) => regionId.trim()) || []; + .map((regionId: string) => regionId.trim()) + .filter((regionId: string) => regionId.length > 0) || []; if (!supportedRegionsIdList.length) { return regions; } - return regions?.filter((region) => supportedRegionsIdList?.includes(region.id) ); From 13242675e1f86219b563ee27923519e983a07216 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Thu, 5 Dec 2024 15:25:16 +0530 Subject: [PATCH 382/474] change: [DI-22125] - Moved time range select outside the paper in contextual view --- .../CloudPulseDashboardWithFilters.tsx | 78 ++++++++---------- .../CloudPulseDashboardFilterBuilder.tsx | 79 +++++++++++-------- .../shared/CloudPulseTimeRangeSelect.tsx | 9 ++- 3 files changed, 84 insertions(+), 82 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx index 5536506ab64..6defbb6533b 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx @@ -1,4 +1,4 @@ -import { CircleProgress, Paper } from '@linode/ui'; +import { Box, CircleProgress, Paper } from '@linode/ui'; import { Grid } from '@mui/material'; import React from 'react'; @@ -121,54 +121,40 @@ export const CloudPulseDashboardWithFilters = React.memo( }); return ( - <> - - + + + + + + - - - - - {isFilterBuilderNeeded && ( - - )} - - {showAppliedFilters && ( - )} - - + + {showAppliedFilters && ( + + )} + + + {isMandatoryFiltersSelected ? ( + ); } ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index a59caa17471..3000d0d652d 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -276,6 +276,15 @@ export const CloudPulseDashboardFilterBuilder = React.memo( return ; // in this we don't want to show the filters at all } + // Count number of filters to be render + const filterCount = FILTER_CONFIG.get( + dashboard.service_type + )?.filters?.filter((config) => + isServiceAnalyticsIntegration + ? config.configuration.neededInServicePage + : config.configuration.filterKey !== RELATIVE_TIME_DURATION + ).length; + return ( - - - + + + )} { - const { defaultValue, handleStatsChange, label, savePreferences } = props; + const { + defaultValue, + handleStatsChange, + label = 'Time Range', + savePreferences, + } = props; const options = generateSelectOptions(); const getDefaultValue = React.useCallback((): Item => { if (!savePreferences) { @@ -84,7 +89,7 @@ export const CloudPulseTimeRangeSelect = React.memo( disableClearable fullWidth isOptionEqualToValue={(option, value) => option.value === value.value} - label={label || 'Time Range'} + label={label} noMarginTop options={options} value={selectedTimeRange} From 5b95f6f336d4445e56d0ad5604e8fd5b5461f7cd Mon Sep 17 00:00:00 2001 From: agorthi Date: Thu, 5 Dec 2024 21:09:11 +0530 Subject: [PATCH 383/474] DI-22212: fixing code review comments --- .../dbaas-widgets-verification.spec.ts | 26 ++++++++++++------- .../linode-widget-verification.spec.ts | 15 ++++++++--- .../shared/CloudPulseAppliedFilter.tsx | 1 + 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts index ce760934da3..6047d5acec7 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts @@ -211,10 +211,7 @@ describe('Integration Tests for DBaaS Dashboard ', () => { .should('be.visible') .type(engine); - ui.autocompletePopper - .findByTitle(engine) - .should('be.visible') - .click(); + ui.autocompletePopper.findByTitle(engine).should('be.visible').click(); // Select a region from the dropdown. ui.regionSelect.find().click(); @@ -241,11 +238,22 @@ describe('Integration Tests for DBaaS Dashboard ', () => { ui.button.findByTitle('Filters').should('be.visible').click(); // Verify that the applied filters - cy.get('[data-testid="applied-filter"]').within(() => { - cy.get(`[data-qa-value="Database Engine ${engine}"]`); - cy.get(`[data-qa-value="Region US, Chicago, IL"]`); - cy.get(`[data-qa-value="Node Type ${nodeType}"]`); - cy.get(`[data-qa-value="Database Clusters ${databaseMock.label}"]`); + cy.get('[data-qa-applied-filter-id="applied-filter"]').within(() => { + cy.get(`[data-qa-value="Database Engine ${engine}"]`) + .should('be.visible') + .should('have.text', engine); + + cy.get(`[data-qa-value="Region US, Chicago, IL"]`) + .should('be.visible') + .should('have.text', 'US, Chicago, IL'); + + cy.get(`[data-qa-value="Node Type ${nodeType}"]`) + .should('be.visible') + .should('have.text', nodeType); + + cy.get(`[data-qa-value="Database Clusters ${clusterName}"]`) + .should('be.visible') + .should('have.text', clusterName); }); // Wait for all metrics query requests to resolve. diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 5ab82d37ea3..12a54f653e2 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -195,10 +195,17 @@ describe('Integration Tests for Linode Dashboard ', () => { ui.button.findByTitle('Filters').should('be.visible').click(); // Verify that the applied filters - cy.get('[data-testid="applied-filter"]').within(() => { - cy.get(`[data-qa-value="Region US, Chicago, IL"]`); - cy.get(`[data-qa-value="Resources ${mockLinode.label}"]`); - }); + cy.get('[data-qa-applied-filter-id="applied-filter"]') + .should('be.visible') + .within(() => { + cy.get(`[data-qa-value="Region US, Chicago, IL"]`) + .should('be.visible') + .should('have.text', 'US, Chicago, IL'); + + cy.get(`[data-qa-value="Resources ${resource}"]`) + .should('be.visible') + .should('have.text', resource); + }); // Wait for all metrics query requests to resolve. cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx index 14bb9b6b53a..d87f4baa166 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx @@ -13,6 +13,7 @@ export const CloudPulseAppliedFilter = ( return ( Date: Fri, 6 Dec 2024 12:17:23 +0530 Subject: [PATCH 384/474] change: [DI-22125] - Moved duplicate code into utils --- .../features/CloudPulse/Utils/FilterBuilder.ts | 17 +++++++++++++++++ .../shared/CloudPulseDashboardFilterBuilder.tsx | 12 ++++-------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts index 93a72d435f8..a303722df3d 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts @@ -449,3 +449,20 @@ const compareArrays = (arr1: T[], arr2: T[]): boolean => { return true; }; + +/** + * + * @param dashboard dashboard for which filters to render + * @param isServiceAnalyticsIntegration boolean value to check if implementation is service analytics integration or not + * @returns list of CloudPulseServiceTypeFilters filtered by passed parameters + */ +export const getFilters = ( + dashboard: Dashboard, + isServiceAnalyticsIntegration: boolean +): CloudPulseServiceTypeFilters[] | undefined => { + return FILTER_CONFIG.get(dashboard.service_type)?.filters.filter((config) => + isServiceAnalyticsIntegration + ? config.configuration.neededInServicePage + : config.configuration.filterKey !== RELATIVE_TIME_DURATION + ); +}; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index 3000d0d652d..6552c5b2063 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -18,6 +18,7 @@ import { } from '../Utils/constants'; import { getCustomSelectProperties, + getFilters, getRegionProperties, getResourcesProperties, } from '../Utils/FilterBuilder'; @@ -234,7 +235,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( }; const RenderFilters = React.useCallback(() => { - const filters = FILTER_CONFIG.get(dashboard.service_type)?.filters || []; + const filters = getFilters(dashboard, isServiceAnalyticsIntegration); if (!filters || filters.length === 0) { // if the filters are not defined , print an error state @@ -277,13 +278,8 @@ export const CloudPulseDashboardFilterBuilder = React.memo( } // Count number of filters to be render - const filterCount = FILTER_CONFIG.get( - dashboard.service_type - )?.filters?.filter((config) => - isServiceAnalyticsIntegration - ? config.configuration.neededInServicePage - : config.configuration.filterKey !== RELATIVE_TIME_DURATION - ).length; + const filterCount = getFilters(dashboard, isServiceAnalyticsIntegration) + ?.length; return ( Date: Fri, 6 Dec 2024 12:21:58 +0530 Subject: [PATCH 385/474] change: [DI-22125] - Added test cases --- .../features/CloudPulse/Utils/FilterBuilder.test.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.test.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.test.ts index 1dbbb4cab1d..66f1ca06ce9 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.test.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.test.ts @@ -2,7 +2,7 @@ import { dashboardFactory } from 'src/factories'; import { databaseQueries } from 'src/queries/databases/databases'; import { RESOURCES } from './constants'; -import { deepEqual } from './FilterBuilder'; +import { deepEqual, getFilters } from './FilterBuilder'; import { buildXFilter, checkIfAllMandatoryFiltersAreSelected, @@ -343,3 +343,12 @@ it('returns false for different arrays', () => { const arr2 = [1, 2, 4]; expect(deepEqual(arr1, arr2)).toBe(false); }); + +it('should return the filters based on dashboard', () => { + const filters = getFilters( + dashboardFactory.build({ service_type: 'dbaas' }), + true + ); + + expect(filters?.length).toBe(1); +}); From 0ccf03e4d0c244549056d62de48202558a6061a6 Mon Sep 17 00:00:00 2001 From: agorthi Date: Fri, 6 Dec 2024 12:38:52 +0530 Subject: [PATCH 386/474] DI-20595:ACLP Supported regions per service type --- .../dbaas-widgets-verification.spec.ts | 18 +++++++++++++++++- .../linode-widget-verification.spec.ts | 18 +++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts index 6047d5acec7..38c1654dd79 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts @@ -48,7 +48,23 @@ import { formatToolTip } from 'src/features/CloudPulse/Utils/unitConversion'; const expectedGranularityArray = ['Auto', '1 day', '1 hr', '5 min']; const timeDurationToSelect = 'Last 24 Hours'; -const flags: Partial = { aclp: { enabled: true, beta: true } }; +const flags: Partial = { + aclp: { enabled: true, beta: true }, + aclpResourceTypeMap: [ + { + dimensionKey: 'LINODE_ID', + maxResourceSelections: 10, + serviceType: 'linode', + supportedRegionIds: '', + }, + { + dimensionKey: 'cluster_id', + maxResourceSelections: 10, + serviceType: 'dbaas', + supportedRegionIds: 'us-east, us-ord', + }, + ], +}; const { metrics, diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 12a54f653e2..8b9e289f91f 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -45,7 +45,23 @@ import { formatToolTip } from 'src/features/CloudPulse/Utils/unitConversion'; */ const expectedGranularityArray = ['Auto', '1 day', '1 hr', '5 min']; const timeDurationToSelect = 'Last 24 Hours'; -const flags: Partial = { aclp: { enabled: true, beta: true } }; +const flags: Partial = { + aclp: { enabled: true, beta: true }, + aclpResourceTypeMap: [ + { + dimensionKey: 'LINODE_ID', + maxResourceSelections: 10, + serviceType: 'linode', + supportedRegionIds: '', + }, + { + dimensionKey: 'cluster_id', + maxResourceSelections: 10, + serviceType: 'dbaas', + supportedRegionIds: '', + }, + ], +}; const { metrics, id, serviceType, dashboardName, region, resource } = widgetDetails.linode; From 1772d782d93cda5b3c6001a0cbc804e4b31eb9c5 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Fri, 6 Dec 2024 14:27:37 +0530 Subject: [PATCH 387/474] upcoming: [DI-20929] - Updated import libraries --- .../CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx | 3 ++- .../src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx index 3cd47ce2aaa..31885ac794b 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx @@ -1,4 +1,5 @@ -import { Box, Grid, Paper } from '@mui/material'; +import { Box, Paper } from '@linode/ui'; +import { Grid } from '@mui/material'; import * as React from 'react'; import { GlobalFilters } from '../Overview/GlobalFilters'; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx index d87f4baa166..cba33e11af8 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx @@ -1,4 +1,4 @@ -import { Box, Chip, Typography } from '@mui/material'; +import { Box, Chip, Typography } from '@linode/ui'; import React from 'react'; interface CloudPulseAppliedFilterProps { From b8d557fccfc282e4bb4c1930f84d599168b30edc Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Fri, 6 Dec 2024 14:48:45 +0530 Subject: [PATCH 388/474] upcomign: [DI-20929] - Updated types --- .../Dashboard/CloudPulseDashboardLanding.tsx | 16 ++++++++-------- .../CloudPulseDashboardWithFilters.tsx | 17 +++++++---------- .../shared/CloudPulseAppliedFilter.tsx | 2 +- .../shared/CloudPulseAppliedFilterRenderer.tsx | 7 +++---- 4 files changed, 19 insertions(+), 23 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx index 31885ac794b..f402ad54f98 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx @@ -10,9 +10,9 @@ import type { Dashboard, TimeDuration } from '@linode/api-v4'; export type FilterValueType = number | number[] | string | string[] | undefined; -export interface FilterValue { - id: { [key: string]: FilterValueType }; - label: { [key: string]: string[] }; +export interface FilterData { + id: { [filterKey: string]: FilterValueType }; + label: { [filterKey: string]: string[] }; } export interface DashboardProp { dashboard?: Dashboard; @@ -23,7 +23,7 @@ export interface DashboardProp { } export const CloudPulseDashboardLanding = () => { - const [filterValue, setFilterValue] = React.useState({ + const [filterData, setFilterData] = React.useState({ id: {}, label: {}, }); @@ -42,7 +42,7 @@ export const CloudPulseDashboardLanding = () => { const onFilterChange = React.useCallback( (filterKey: string, filterValue: FilterValueType, labels: string[]) => { - setFilterValue((prev: FilterValue) => { + setFilterData((prev: FilterData) => { return { id: { ...prev.id, @@ -60,7 +60,7 @@ export const CloudPulseDashboardLanding = () => { const onDashboardChange = React.useCallback((dashboardObj: Dashboard) => { setDashboard(dashboardObj); - setFilterValue({ + setFilterData({ id: {}, label: {}, }); // clear the filter values on dashboard change @@ -84,7 +84,7 @@ export const CloudPulseDashboardLanding = () => { /> {dashboard?.service_type && showAppliedFilters && ( )} @@ -93,7 +93,7 @@ export const CloudPulseDashboardLanding = () => { diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx index 6defbb6533b..234bb49b330 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx @@ -17,10 +17,7 @@ import { } from '../Utils/ReusableDashboardFilterUtils'; import { CloudPulseDashboard } from './CloudPulseDashboard'; -import type { - FilterValue, - FilterValueType, -} from './CloudPulseDashboardLanding'; +import type { FilterData, FilterValueType } from './CloudPulseDashboardLanding'; import type { TimeDuration } from '@linode/api-v4'; export interface CloudPulseDashboardWithFiltersProp { @@ -41,8 +38,8 @@ export const CloudPulseDashboardWithFilters = React.memo( dashboardId ); - const [filterValue, setFilterValue] = React.useState({ - id: {}, + const [filterValue, setFilterValue] = React.useState({ + filterId: {}, label: {}, }); @@ -63,8 +60,8 @@ export const CloudPulseDashboardWithFilters = React.memo( (filterKey: string, value: FilterValueType, labels: string[]) => { setFilterValue((prev) => { return { - id: { - ...prev.id, + filterId: { + ...prev.filterId, [filterKey]: value, }, label: { @@ -115,7 +112,7 @@ export const CloudPulseDashboardWithFilters = React.memo( const isFilterBuilderNeeded = checkIfFilterBuilderNeeded(dashboard); const isMandatoryFiltersSelected = checkMandatoryFiltersSelected({ dashboardObj: dashboard, - filterValue: filterValue.id, + filterValue: filterValue.filterId, resource, timeDuration, }); @@ -159,7 +156,7 @@ export const CloudPulseDashboardWithFilters = React.memo( Date: Fri, 6 Dec 2024 14:51:03 +0530 Subject: [PATCH 389/474] upcomign: [DI-20929] - Updated types --- .../Dashboard/CloudPulseDashboardWithFilters.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx index 234bb49b330..9a54012d43e 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx @@ -39,7 +39,7 @@ export const CloudPulseDashboardWithFilters = React.memo( ); const [filterValue, setFilterValue] = React.useState({ - filterId: {}, + id: {}, label: {}, }); @@ -60,8 +60,8 @@ export const CloudPulseDashboardWithFilters = React.memo( (filterKey: string, value: FilterValueType, labels: string[]) => { setFilterValue((prev) => { return { - filterId: { - ...prev.filterId, + id: { + ...prev.id, [filterKey]: value, }, label: { @@ -112,7 +112,7 @@ export const CloudPulseDashboardWithFilters = React.memo( const isFilterBuilderNeeded = checkIfFilterBuilderNeeded(dashboard); const isMandatoryFiltersSelected = checkMandatoryFiltersSelected({ dashboardObj: dashboard, - filterValue: filterValue.filterId, + filterValue: filterValue.id, resource, timeDuration, }); @@ -156,7 +156,7 @@ export const CloudPulseDashboardWithFilters = React.memo( Date: Fri, 6 Dec 2024 14:57:52 +0530 Subject: [PATCH 390/474] DI-20595:ACLP Supported regions per service typ, fixing code review commentse --- .../dbaas-widgets-verification.spec.ts | 22 ++++++++++++++-- .../linode-widget-verification.spec.ts | 25 +++++++++++++++++-- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts index 38c1654dd79..694359bcaee 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/dbaas-widgets-verification.spec.ts @@ -61,7 +61,7 @@ const flags: Partial = { dimensionKey: 'cluster_id', maxResourceSelections: 10, serviceType: 'dbaas', - supportedRegionIds: 'us-east, us-ord', + supportedRegionIds: 'us-ord', }, ], }; @@ -111,6 +111,12 @@ const mockRegion = regionFactory.build({ id: 'us-ord', label: 'Chicago, IL', }); + +const extendedMockRegion = regionFactory.build({ + capabilities: ['Managed Databases'], + id: 'us-east', + label: 'Newark,NL', +}); const metricsAPIResponsePayload = cloudPulseMetricsResponseFactory.build({ data: generateRandomMetricsData(timeDurationToSelect, '5 min'), }); @@ -189,7 +195,7 @@ describe('Integration Tests for DBaaS Dashboard ', () => { mockCreateCloudPulseMetrics(serviceType, metricsAPIResponsePayload).as( 'getMetrics' ); - mockGetRegions([mockRegion]); + mockGetRegions([mockRegion, extendedMockRegion]); mockGetUserPreferences({}); mockGetDatabases([databaseMock]).as('getDatabases'); @@ -231,6 +237,18 @@ describe('Integration Tests for DBaaS Dashboard ', () => { // Select a region from the dropdown. ui.regionSelect.find().click(); + + ui.regionSelect.find().type(extendedMockRegion.label); + + // Since DBaaS does not support this region, we expect it to not be in the dropdown. + + ui.autocompletePopper.find().within(() => { + cy.findByText( + `${extendedMockRegion.label} (${extendedMockRegion.id})` + ).should('not.exist'); + }); + + ui.regionSelect.find().click().clear(); ui.regionSelect .findItemByRegionId(mockRegion.id, [mockRegion]) .should('be.visible') diff --git a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts index 8b9e289f91f..a2d968555e5 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/linode-widget-verification.spec.ts @@ -52,7 +52,7 @@ const flags: Partial = { dimensionKey: 'LINODE_ID', maxResourceSelections: 10, serviceType: 'linode', - supportedRegionIds: '', + supportedRegionIds: 'us-ord', }, { dimensionKey: 'cluster_id', @@ -100,6 +100,12 @@ const mockRegion = regionFactory.build({ id: 'us-ord', label: 'Chicago, IL', }); + +const extendedMockRegion = regionFactory.build({ + capabilities: ['Managed Databases'], + id: 'us-east', + label: 'Newark,NL', +}); const metricsAPIResponsePayload = cloudPulseMetricsResponseFactory.build({ data: generateRandomMetricsData(timeDurationToSelect, '5 min'), }); @@ -195,8 +201,23 @@ describe('Integration Tests for Linode Dashboard ', () => { .should('be.visible') .click(); + ui.regionSelect.find().click(); + + // Select a region from the dropdown. + ui.regionSelect.find().click(); + + ui.regionSelect.find().type(extendedMockRegion.label); + + // Since Linode does not support this region, we expect it to not be in the dropdown. + + ui.autocompletePopper.find().within(() => { + cy.findByText( + `${extendedMockRegion.label} (${extendedMockRegion.id})` + ).should('not.exist'); + }); + // Select a region from the dropdown. - ui.regionSelect.find().click().type(`${region}{enter}`); + ui.regionSelect.find().click().clear().type(`${region}{enter}`); // Select a resource from the autocomplete input. ui.autocomplete From 2bf49afb7edbab6ca0256a31e171bceae6a9a0ab Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Fri, 6 Dec 2024 14:27:37 +0530 Subject: [PATCH 391/474] upcoming: [DI-20929] - Updated import libraries --- .../CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx | 3 ++- .../src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx index 3cd47ce2aaa..31885ac794b 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx @@ -1,4 +1,5 @@ -import { Box, Grid, Paper } from '@mui/material'; +import { Box, Paper } from '@linode/ui'; +import { Grid } from '@mui/material'; import * as React from 'react'; import { GlobalFilters } from '../Overview/GlobalFilters'; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx index 9710e6afe39..ec0d3cbbb86 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx @@ -1,4 +1,4 @@ -import { Box, Chip, Typography } from '@mui/material'; +import { Box, Chip, Typography } from '@linode/ui'; import React from 'react'; interface CloudPulseAppliedFilterProps { From 755ad00fe738176c1c55e1c82ac7dae16ccc906b Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Fri, 6 Dec 2024 14:48:45 +0530 Subject: [PATCH 392/474] upcomign: [DI-20929] - Updated types --- .../Dashboard/CloudPulseDashboardLanding.tsx | 16 ++++++++-------- .../CloudPulseDashboardWithFilters.tsx | 17 +++++++---------- .../shared/CloudPulseAppliedFilter.tsx | 2 +- .../shared/CloudPulseAppliedFilterRenderer.tsx | 7 +++---- 4 files changed, 19 insertions(+), 23 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx index 31885ac794b..f402ad54f98 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx @@ -10,9 +10,9 @@ import type { Dashboard, TimeDuration } from '@linode/api-v4'; export type FilterValueType = number | number[] | string | string[] | undefined; -export interface FilterValue { - id: { [key: string]: FilterValueType }; - label: { [key: string]: string[] }; +export interface FilterData { + id: { [filterKey: string]: FilterValueType }; + label: { [filterKey: string]: string[] }; } export interface DashboardProp { dashboard?: Dashboard; @@ -23,7 +23,7 @@ export interface DashboardProp { } export const CloudPulseDashboardLanding = () => { - const [filterValue, setFilterValue] = React.useState({ + const [filterData, setFilterData] = React.useState({ id: {}, label: {}, }); @@ -42,7 +42,7 @@ export const CloudPulseDashboardLanding = () => { const onFilterChange = React.useCallback( (filterKey: string, filterValue: FilterValueType, labels: string[]) => { - setFilterValue((prev: FilterValue) => { + setFilterData((prev: FilterData) => { return { id: { ...prev.id, @@ -60,7 +60,7 @@ export const CloudPulseDashboardLanding = () => { const onDashboardChange = React.useCallback((dashboardObj: Dashboard) => { setDashboard(dashboardObj); - setFilterValue({ + setFilterData({ id: {}, label: {}, }); // clear the filter values on dashboard change @@ -84,7 +84,7 @@ export const CloudPulseDashboardLanding = () => { /> {dashboard?.service_type && showAppliedFilters && ( )} @@ -93,7 +93,7 @@ export const CloudPulseDashboardLanding = () => { diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx index 5536506ab64..96944b9f95d 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx @@ -17,10 +17,7 @@ import { } from '../Utils/ReusableDashboardFilterUtils'; import { CloudPulseDashboard } from './CloudPulseDashboard'; -import type { - FilterValue, - FilterValueType, -} from './CloudPulseDashboardLanding'; +import type { FilterData, FilterValueType } from './CloudPulseDashboardLanding'; import type { TimeDuration } from '@linode/api-v4'; export interface CloudPulseDashboardWithFiltersProp { @@ -41,8 +38,8 @@ export const CloudPulseDashboardWithFilters = React.memo( dashboardId ); - const [filterValue, setFilterValue] = React.useState({ - id: {}, + const [filterValue, setFilterValue] = React.useState({ + filterId: {}, label: {}, }); @@ -63,8 +60,8 @@ export const CloudPulseDashboardWithFilters = React.memo( (filterKey: string, value: FilterValueType, labels: string[]) => { setFilterValue((prev) => { return { - id: { - ...prev.id, + filterId: { + ...prev.filterId, [filterKey]: value, }, label: { @@ -115,7 +112,7 @@ export const CloudPulseDashboardWithFilters = React.memo( const isFilterBuilderNeeded = checkIfFilterBuilderNeeded(dashboard); const isMandatoryFiltersSelected = checkMandatoryFiltersSelected({ dashboardObj: dashboard, - filterValue: filterValue.id, + filterValue: filterValue.filterId, resource, timeDuration, }); @@ -173,7 +170,7 @@ export const CloudPulseDashboardWithFilters = React.memo( Date: Fri, 6 Dec 2024 14:51:03 +0530 Subject: [PATCH 393/474] upcomign: [DI-20929] - Updated types --- .../Dashboard/CloudPulseDashboardWithFilters.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx index 96944b9f95d..254f1724914 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx @@ -39,7 +39,7 @@ export const CloudPulseDashboardWithFilters = React.memo( ); const [filterValue, setFilterValue] = React.useState({ - filterId: {}, + id: {}, label: {}, }); @@ -60,8 +60,8 @@ export const CloudPulseDashboardWithFilters = React.memo( (filterKey: string, value: FilterValueType, labels: string[]) => { setFilterValue((prev) => { return { - filterId: { - ...prev.filterId, + id: { + ...prev.id, [filterKey]: value, }, label: { @@ -112,7 +112,7 @@ export const CloudPulseDashboardWithFilters = React.memo( const isFilterBuilderNeeded = checkIfFilterBuilderNeeded(dashboard); const isMandatoryFiltersSelected = checkMandatoryFiltersSelected({ dashboardObj: dashboard, - filterValue: filterValue.filterId, + filterValue: filterValue.id, resource, timeDuration, }); @@ -170,7 +170,7 @@ export const CloudPulseDashboardWithFilters = React.memo( Date: Fri, 6 Dec 2024 19:10:23 +0530 Subject: [PATCH 394/474] upcoming: [DI-20929] - Updated styles for dark theme --- .../features/CloudPulse/shared/CloudPulseAppliedFilter.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx index 4d406c9f732..b368c518180 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx @@ -16,7 +16,7 @@ export const CloudPulseAppliedFilter = ( data-testid="applied-filter" display="flex" flexDirection={{ sm: 'row', xs: 'column' }} - flexWrap={{ sm: 'wrap', xs: 'nowrap' }} + flexWrap={{ sm: 'wrap' }} maxHeight="70px" mb={2} mx={3} @@ -40,10 +40,12 @@ export const CloudPulseAppliedFilter = ( Date: Fri, 6 Dec 2024 19:18:36 +0530 Subject: [PATCH 395/474] adding extra test case for applied-filters and deleteed duplicated validation.spec.ts file --- .../cloudpulse-applied-filters.spec.ts | 277 ++++++++++++++ .../cloudpulse/cloudpulse-validation.spec.ts | 350 ------------------ 2 files changed, 277 insertions(+), 350 deletions(-) create mode 100644 packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-applied-filters.spec.ts delete mode 100644 packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-applied-filters.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-applied-filters.spec.ts new file mode 100644 index 00000000000..67b27b005ad --- /dev/null +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-applied-filters.spec.ts @@ -0,0 +1,277 @@ +/** + * @file Integration Tests for CloudPulse Dbass Dashboard. + */ +import { mockAppendFeatureFlags } from 'support/intercepts/feature-flags'; +import { + mockCreateCloudPulseJWEToken, + mockGetCloudPulseDashboard, + mockCreateCloudPulseMetrics, + mockGetCloudPulseDashboards, + mockGetCloudPulseMetricDefinitions, + mockGetCloudPulseServices, +} from 'support/intercepts/cloudpulse'; +import { ui } from 'support/ui'; +import { widgetDetails } from 'support/constants/widgets'; +import { + accountFactory, + cloudPulseMetricsResponseFactory, + dashboardFactory, + dashboardMetricFactory, + databaseFactory, + regionFactory, + widgetFactory, +} from 'src/factories'; +import { mockGetAccount } from 'support/intercepts/account'; +import { mockGetUserPreferences } from 'support/intercepts/profile'; +import { mockGetRegions } from 'support/intercepts/regions'; +import { Database } from '@linode/api-v4'; +import { generateRandomMetricsData } from 'support/util/cloudpulse'; +import { mockGetDatabases } from 'support/intercepts/databases'; +import type { Flags } from 'src/featureFlags'; + +const timeDurationToSelect = 'Last 24 Hours'; + +const flags: Partial = { aclp: { enabled: true, beta: true } }; + +const { + metrics, + id, + serviceType, + dashboardName, + engine, + clusterName, + nodeType, +} = widgetDetails.dbaas; + +const dashboard = dashboardFactory.build({ + label: dashboardName, + service_type: serviceType, + widgets: metrics.map(({ title, yLabel, name, unit }) => { + return widgetFactory.build({ + label: title, + y_label: yLabel, + metric: name, + unit, + }); + }), +}); + +const metricDefinitions = { + data: metrics.map(({ title, name, unit }) => + dashboardMetricFactory.build({ + label: title, + metric: name, + unit, + }) + ), +}; +const mockAccount = accountFactory.build(); +const mockRegion = regionFactory.build({ + capabilities: ['Managed Databases'], + id: 'us-ord', + label: 'Chicago, IL', +}); +const metricsAPIResponsePayload = cloudPulseMetricsResponseFactory.build({ + data: generateRandomMetricsData(timeDurationToSelect, '5 min'), +}); +const databaseMock: Database = databaseFactory.build({ + label: clusterName, + type: engine, + region: mockRegion.label, + version: '1', + status: 'provisioning', + cluster_size: 1, + engine: 'mysql', + hosts: { + primary: undefined, + secondary: undefined, + }, +}); +const extendDatabaseMock: Database = databaseFactory.build({ + label: 'updated-dbass-mock', + type: engine, + region: mockRegion.label, + version: '1', + status: 'provisioning', + cluster_size: 1, + engine: 'mysql', + hosts: { + primary: undefined, + secondary: undefined, + }, +}); + +describe('Integration Tests for Applied Filters', () => { + beforeEach(() => { + mockAppendFeatureFlags(flags); + mockGetAccount(mockAccount); // Enables the account to have capability for Akamai Cloud Pulse + //mockGetLinodes([mockLinode]); + mockGetCloudPulseMetricDefinitions(serviceType, metricDefinitions); + mockGetCloudPulseDashboards(serviceType, [dashboard]).as('fetchDashboard'); + mockGetCloudPulseServices(serviceType).as('fetchServices'); + mockGetCloudPulseDashboard(id, dashboard); + mockCreateCloudPulseJWEToken(serviceType); + mockCreateCloudPulseMetrics(serviceType, metricsAPIResponsePayload).as( + 'getMetrics' + ); + mockGetRegions([mockRegion]); + mockGetUserPreferences({}); + mockGetDatabases([databaseMock, extendDatabaseMock]); + + // navigate to the cloudpulse page + cy.visitWithLogin('monitor'); + + // Wait for the services and dashboard API calls to complete before proceeding + cy.wait(['@fetchServices', '@fetchDashboard']); + + // Selecting a dashboard from the autocomplete input. + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') + .type(dashboardName); + + ui.autocompletePopper + .findByTitle(dashboardName) + .should('be.visible') + .click(); + }); + + it('should verify that the applied global filters are reflected in the filter section', () => { + //Select a Database Engine from the autocomplete input. + ui.autocomplete + .findByLabel('Database Engine') + .should('be.visible') + .type(engine); + + ui.autocompletePopper.findByTitle(engine).should('be.visible').click(); + + // Select a region from the dropdown. + ui.regionSelect.find().click(); + ui.regionSelect + .findItemByRegionId(mockRegion.id, [mockRegion]) + .should('be.visible') + .click(); + + // Select a resource from the autocomplete input. + ui.autocomplete + .findByLabel('Database Clusters') + .should('be.visible') + .type(`${databaseMock.label}{enter}`) + .click(); + cy.findByText(databaseMock.label).should('be.visible'); + + //Select a Node from the autocomplete input. + ui.autocomplete + .findByLabel('Node Type') + .should('be.visible') + .type(`${nodeType}{enter}`); + + // Wait for all metrics query requests to resolve. + cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']); + //Collapse the Filters section + ui.button.findByTitle('Filters').should('be.visible').click(); + + cy.get('[data-testid="applied-filter"]').within(() => { + cy.get(`[data-qa-value="Database Engine ${engine}"]`) + cy.get(`[data-qa-value="Region US, Chicago, IL"]`) + cy.get(`[data-qa-value="Node Type ${nodeType}"]`) + cy.get(`[data-qa-value="Database Clusters ${databaseMock.label}"]`) + }); + }); + + it('dont create any global filter and check the applied filters', () => { + //Collapse the Filters section + ui.button.findByTitle('Filters').should('be.visible').click(); + cy.get('[data-testid="applied-filter"]').within(() => { + cy.get('h3').should('not.exist'); + }); + }); + + it('apply only database engine and verify applied filters', () => { + //Select a Database Engine from the autocomplete input. + ui.autocomplete + .findByLabel('Database Engine') + .should('be.visible') + .type(engine); + + ui.autocompletePopper.findByTitle(engine).should('be.visible').click(); + //Collapse the Filters section + ui.button.findByTitle('Filters').should('be.visible').click(); + cy.get('[data-testid="applied-filter"]').within(() => { + cy.get(`[data-qa-value="Database Engine ${engine}"]`) + }); + }); + + it('apply only regions and verify applied filters', () => { + // Select a region from the dropdown. + ui.regionSelect.find().click(); + ui.regionSelect + .findItemByRegionId(mockRegion.id, [mockRegion]) + .should('be.visible') + .click(); + + //Collapse the Filters section + ui.button.findByTitle('Filters').should('be.visible').click(); + cy.get('[data-testid="applied-filter"]').within(() => { + cy.get(`[data-qa-value="Region US, Chicago, IL"]`) + }); + }); + + it('apply only node type and verify applied filters', () => { + //Select a Node from the autocomplete input. + ui.autocomplete + .findByLabel('Node Type') + .should('be.visible') + .type(`${nodeType}{enter}`); + + //Collapse the Filters section + ui.button.findByTitle('Filters').should('be.visible').click(); + cy.get('[data-testid="applied-filter"]').within(() => { + cy.get(`[data-qa-value="Node Type ${nodeType}"]`) + }); + }); + it('should update and verify that the applied global filters are reflected in the filter section', () => { + // Select a region from the dropdown. + ui.regionSelect.find().click(); + ui.regionSelect + .findItemByRegionId(mockRegion.id, [mockRegion]) + .should('be.visible') + .click(); + + //Select a Database Engine from the autocomplete input. + ui.autocomplete + .findByLabel('Database Engine') + .should('be.visible') + .type('PostgreSQL'); + + ui.autocompletePopper + .findByTitle('PostgreSQL') + .should('be.visible') + .click(); + + // Select a resource from the autocomplete input. + ui.autocomplete + .findByLabel('Database Clusters') + .should('be.visible') + .type(`${'Select All'}{enter}`) + .click(); + + //Select a Node from the autocomplete input. + ui.autocomplete + .findByLabel('Node Type') + .should('be.visible') + .type(`${'Primary'}{enter}`); + + // Wait for all metrics query requests to resolve. + cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']); + //Collapse the Filters section + ui.button.findByTitle('Filters').should('be.visible').click(); + cy.get('[data-testid="applied-filter"]').within(() => { + cy.get(`[data-qa-value="Database Engine PostgreSQL"]`) + cy.get(`[data-qa-value="Region US, Chicago, IL"]`) + cy.get(`[data-qa-value="Node Type Primary"]`) + cy.get(`[data-qa-value="Database Clusters ${databaseMock.label}"]`) + cy.get(`[data-qa-value="Database Clusters ${extendDatabaseMock.label}"]`) + }); + }); +}); diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts deleted file mode 100644 index 8d92be44b5e..00000000000 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-validation.spec.ts +++ /dev/null @@ -1,350 +0,0 @@ -/** - * @file Error Handling Tests for CloudPulse DBaaS Dashboard. - */ -import { mockAppendFeatureFlags } from 'support/intercepts/feature-flags'; -import { - mockCreateCloudPulseJWEToken, - mockGetCloudPulseDashboard, - mockGetCloudPulseDashboards, - mockGetCloudPulseMetricDefinitions, - mockGetCloudPulseServices, -} from 'support/intercepts/cloudpulse'; -import { ui } from 'support/ui'; -import { widgetDetails } from 'support/constants/widgets'; -import { - dashboardFactory, - dashboardMetricFactory, - databaseFactory, - regionFactory, - widgetFactory, -} from 'src/factories'; -import { mockGetUserPreferences } from 'support/intercepts/profile'; -import { mockGetRegions } from 'support/intercepts/regions'; -import { extendRegion } from 'support/util/regions'; -import { mockGetDatabases } from 'support/intercepts/databases'; -import { apiMatcher } from 'support/util/intercepts'; -import { Database } from '@linode/api-v4'; - -/** - * Verifies the presence and values of specific properties within the aclpPreference object - * of the request payload. This function checks that the expected properties exist - * and have the expected values, allowing for validation of user preferences in the application. - * - * @param requestPayload - The payload received from the request, containing the aclpPreference object. - * @param expectedValues - An object containing the expected values for properties to validate against the requestPayload. - */ -const { - metrics, - id, - serviceType, - dashboardName, - region, - engine, - clusterName, - nodeType, -} = widgetDetails.dbaas; - -const dashboard = dashboardFactory.build({ - label: dashboardName, - service_type: serviceType, - widgets: metrics.map(({ title, yLabel, name, unit }) => { - return widgetFactory.build({ - label: title, - y_label: yLabel, - metric: name, - unit, - }); - }), -}); - -const metricDefinitions = { - data: metrics.map(({ title, name, unit }) => - dashboardMetricFactory.build({ - label: title, - metric: name, - unit, - }) - ), -}; - -const mockRegion = extendRegion( - regionFactory.build({ - capabilities: ['Linodes'], - id: 'us-ord', - label: 'Chicago, IL', - country: 'us', - }) -); -const databaseMock: Database = databaseFactory.build({ - label: widgetDetails.dbaas.clusterName, - type: widgetDetails.dbaas.engine, - region: widgetDetails.dbaas.region, - version: '1', - status: 'provisioning', - cluster_size: 1, - engine: 'mysql', -}); - -describe('Tests for API error handling', () => { - beforeEach(() => { - mockAppendFeatureFlags({ - aclp: { beta: true, enabled: true }, - }); - mockGetCloudPulseMetricDefinitions(serviceType, metricDefinitions); - mockGetCloudPulseDashboards(serviceType, [dashboard]).as('fetchDashboard'); - mockGetCloudPulseServices(serviceType).as('fetchServices'); - mockCreateCloudPulseJWEToken(serviceType); - mockGetCloudPulseDashboard(id, dashboard); - mockGetRegions([mockRegion]); - mockGetUserPreferences({}); - mockGetDatabases([databaseMock]).as('getDatabases'); - }); - - it('should return error response when fetching metric definitions API request', () => { - cy.intercept( - 'GET', - apiMatcher(`/monitor/services/${serviceType}/metric-definitions`), - { statusCode: 500, body: { errors: [{ reason: 'Bad Request' }] }, } - ).as('getMetricDefinitions'); - - cy.visitWithLogin('monitor'); - - // Wait for the services and dashboard API calls to complete before proceeding. - cy.wait(['@fetchServices', '@fetchDashboard']); - - // Selecting a dashboard from the autocomplete input. - ui.autocomplete - .findByLabel('Dashboard') - .should('be.visible') - .type(`${dashboardName}{enter}`) - .should('be.visible'); - - // Select a Database Engine from the autocomplete input. - ui.autocomplete - .findByLabel('Database Engine') - .should('be.visible') - .type(`${engine}{enter}`) - .should('be.visible'); - - // Select a region from the dropdown. - ui.regionSelect.find().click().type(`${region}{enter}`); - - // Select a resource (Database Clusters) from the autocomplete input. - ui.autocomplete - .findByLabel('Database Clusters') - .should('be.visible') - .type(`${clusterName}{enter}`) - .click(); - - // Select a Node from the autocomplete input. - ui.autocomplete - .findByLabel('Node Type') - .should('be.visible') - .type(`${nodeType}{enter}`); - - // Wait for the metric definitions API call to resolve. - cy.wait('@getMetricDefinitions'); - cy.get('[data-qa-error-msg="true"]') - .should('be.visible') - .and('have.text', 'Error loading the definitions of metrics.'); - }); - - it('should return error response when fetching services API request', () => { - cy.intercept('GET', apiMatcher(`/monitor/services`), { - statusCode: 500, - body: { - errors: [{ reason: 'Bad Request' }],}, - }).as('fetchServices'); - cy.visitWithLogin('monitor'); - - cy.get('[data-qa-textfield-error-text="Dashboard"]') - .should('be.visible') - .invoke('text') - .then((text) => { - expect(text).to.equal('Failed to fetch the services.'); - }); - }); - it('should return error response when fetching token API request', () => { - cy.intercept('POST', apiMatcher(`/monitor/services/${serviceType}/token`), { - statusCode: 500, - body: { - errors: [{ reason: 'Bad Request' }], }, - }); - - cy.visitWithLogin('monitor'); - // Wait for both the fetch services and fetch dashboard API calls to complete. - cy.wait(['@fetchServices', '@fetchDashboard']); - - // Selecting a dashboard from the autocomplete input. - ui.autocomplete - .findByLabel('Dashboard') - .should('be.visible') - .type(`${dashboardName}{enter}`) - .should('be.visible'); - - // Select a Database Engine from the autocomplete input. - ui.autocomplete - .findByLabel('Database Engine') - .should('be.visible') - .type(`${engine}{enter}`) - .should('be.visible'); - - // Select a region from the dropdown. - ui.regionSelect.find().click().type(`${region}{enter}`); - - // Select a resource (Database Clusters) from the autocomplete input. - ui.autocomplete - .findByLabel('Database Clusters') - .should('be.visible') - .type(`${clusterName}{enter}`) - .click(); - - // Select a Node from the autocomplete input. - ui.autocomplete - .findByLabel('Node Type') - .should('be.visible') - .type(`${nodeType}{enter}`); - - cy.get('[data-qa-error-msg="true"]') - .should('be.visible') - .and('have.text', 'Failed to get the authentication token.'); - }); - - it('should return error response when fetching Dashboards API Request', () => { - mockGetCloudPulseServices(serviceType).as('fetchServices'); - cy.intercept( - 'GET', - apiMatcher(`/monitor/services/${serviceType}/dashboards`), - { - statusCode: 500, - body: { errors: [{ reason: 'Bad Request' }],}, - } - ).as('fetchDashboard'); - - cy.visitWithLogin('monitor'); - // Wait for both the fetch services and fetch dashboard API calls to complete. - cy.wait(['@fetchServices', '@fetchDashboard']); - - // Assert that the error message for fetching the dashboards is displayed correctly. - cy.get('[data-qa-textfield-error-text="Dashboard"]') - .should('be.visible') - .invoke('text') - .then((text) => { - expect(text).to.equal('Failed to fetch the dashboards.'); - }); - }); - - it('should return error message when the Dashboard details API request fails', () => { - cy.intercept('GET', apiMatcher(`/monitor/dashboards/${id}`), { - statusCode: 500, - body: { errors: [{ reason: 'Bad Request' }] }, - }); - - cy.visitWithLogin('monitor'); - - // Select a dashboard from the autocomplete input. Verify that the input is visible before typing. - ui.autocomplete - .findByLabel('Dashboard') - .should('be.visible') - .type(`${dashboardName}{enter}`) - .should('be.visible'); - - // Select a database engine from the autocomplete input. Verify visibility before interaction. - ui.autocomplete - .findByLabel('Database Engine') - .should('be.visible') - .type(`${engine}{enter}`) - .should('be.visible'); - - // Select a region from the dropdown. Verify visibility before interaction. - ui.regionSelect.find().click().type(`${region}{enter}`); - - // Select a database cluster from the autocomplete input. Verify visibility before interaction. - ui.autocomplete - .findByLabel('Database Clusters') - .should('be.visible') - .type(`${clusterName}{enter}`) - .click(); - - // Select a node type from the autocomplete input. Verify visibility before interaction. - ui.autocomplete - .findByLabel('Node Type') - .should('be.visible') - .type(`${nodeType}{enter}`); - - // Wait for the API calls to fetch services and dashboard to resolve. - cy.wait(['@fetchServices', '@fetchDashboard']); - - cy.get('[data-qa-error-msg="true"]') - .should('be.visible') - .and('have.text', 'Failed to fetch the dashboard details.'); - }); - - it(`should return error message when the Regions API request fails`, () => { - cy.intercept('GET', apiMatcher(`regions*`), { - statusCode: 500, - body: { errors: [{ reason: 'Bad Request' }] }, - }); - - cy.visitWithLogin('monitor'); - - // Wait for the services and dashboard API calls to resolve before proceeding. - cy.wait(['@fetchServices', '@fetchDashboard']); - - // Select a dashboard from the autocomplete input. Verify that the input is visible before typing. - ui.autocomplete - .findByLabel('Dashboard') - .should('be.visible') - .type(`${dashboardName}{enter}`) - .should('be.visible'); - - cy.get('[data-qa-textfield-error-text="Region"]') - .should('be.visible') - .invoke('text') - .then((text) => { - expect(text).to.equal('Failed to fetch Region.'); - }); - }); - - it('should return error response when fetching db cluster API request', () => { - cy.intercept('GET', apiMatcher(`databases/instances*`), { - statusCode: 500, - body: {errors: [{ reason: 'Bad Request' }],}, - }); - - cy.visitWithLogin('monitor'); - - //Wait for the services and dashboard API calls to resolve before proceeding. - cy.wait(['@fetchServices', '@fetchDashboard']); - - // Select a dashboard from the autocomplete input - ui.autocomplete - .findByLabel('Dashboard') - .should('be.visible') - .type(`${dashboardName}{enter}`) - .should('be.visible'); - - // Select a Node Type from the autocomplete input. Verify visibility before typing. - ui.autocomplete - .findByLabel('Node Type') - .should('be.visible') - .type(`${nodeType}{enter}`); - - // Select a region from the dropdown. Click and type the region name. - ui.regionSelect.find().click().type(`${region}{enter}`); - - // Select a Database Engine from the autocomplete input. Verify visibility before typing. - ui.autocomplete - .findByLabel('Database Engine') - .should('be.visible') - .type(`${engine}{enter}`) - .should('be.visible'); - - cy.get('[data-qa-textfield-error-text="Database Clusters"]') - .should('be.visible') - .invoke('text') - .then((text) => { - expect(text).to.equal('Failed to fetch Database Clusters.'); - }); - }); -}); From b33f6a47b495c08c56bd326879ad1f957b0d0f94 Mon Sep 17 00:00:00 2001 From: agorthi Date: Sat, 7 Dec 2024 09:58:38 +0530 Subject: [PATCH 396/474] adding new test cases for region select and contextual view --- .../cloudpulse/cloudpulse-navigation.spec.ts | 9 +- .../cloudpulse-region-support.spec.ts | 368 +++++++++++++++ ...ntextual-dbaas-widget-verification.spec.ts | 428 ++++++++++++++++++ 3 files changed, 803 insertions(+), 2 deletions(-) create mode 100644 packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-region-support.spec.ts create mode 100644 packages/manager/cypress/e2e/core/cloudpulse/contextual-dbaas-widget-verification.spec.ts diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts index 3cf4fa4f700..7d3cf3543ba 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts @@ -1,7 +1,12 @@ /** - * @file Integration tests for CloudPulse navigation. + * @file Error Handling Tests for CloudPulse Region Selection + * + * This file contains tests to verify the proper handling of errors + * when interacting with region selection features in CloudPulse. + * The tests focus on scenarios such as invalid or unsupported regions, + * and ensure the application behaves as expected, providing appropriate + * error messages or fallback behavior when necessary. */ - import { mockAppendFeatureFlags } from 'support/intercepts/feature-flags'; import { mockGetAccount } from 'support/intercepts/account'; import { accountFactory } from 'src/factories'; diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-region-support.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-region-support.spec.ts new file mode 100644 index 00000000000..9972787f5d2 --- /dev/null +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-region-support.spec.ts @@ -0,0 +1,368 @@ +/** + * @file Error Handling Tests for CloudPulse Region Selection + * + * This file contains tests to verify the proper handling of errors + * when interacting with region selection features in CloudPulse. + * The tests focus on scenarios such as invalid or unsupported regions, + * and ensure the application behaves as expected, providing appropriate + * error messages or fallback behavior when necessary. + */ + +import { mockAppendFeatureFlags } from 'support/intercepts/feature-flags'; +import { + mockGetCloudPulseDashboard, + mockGetCloudPulseDashboards, + mockGetCloudPulseServices, +} from 'support/intercepts/cloudpulse'; +import { ui } from 'support/ui'; +import { widgetDetails } from 'support/constants/widgets'; +import { + accountFactory, + dashboardFactory, + regionFactory, + widgetFactory, +} from 'src/factories'; +import { mockGetAccount } from 'support/intercepts/account'; +import { mockGetUserPreferences } from 'support/intercepts/profile'; +import { mockGetRegions } from 'support/intercepts/regions'; +import type { Flags } from 'src/featureFlags'; + +const { metrics, id, serviceType, dashboardName } = widgetDetails.dbaas; + +const dashboard = dashboardFactory.build({ + label: dashboardName, + service_type: serviceType, + widgets: metrics.map(({ title, yLabel, name, unit }) => { + return widgetFactory.build({ + label: title, + y_label: yLabel, + metric: name, + unit, + }); + }), +}); + +const mockAccount = accountFactory.build(); + +const mockRegion = regionFactory.build({ + capabilities: ['Managed Databases'], + id: 'us-ord', + label: 'Chicago, IL', +}); + +const extendedMockRegion = regionFactory.build({ + capabilities: ['Managed Databases'], + id: 'us-east', + label: 'Newark,NL', +}); + +describe('Integration Tests for DBaaS Dashboard ', () => { + beforeEach(() => { + mockGetAccount(mockAccount); // Enables the account to have capability for Akamai Cloud Pulse + mockGetCloudPulseDashboards(serviceType, [dashboard]).as('fetchDashboard'); + mockGetCloudPulseServices(serviceType).as('fetchServices'); + mockGetCloudPulseDashboard(id, dashboard); + mockGetRegions([mockRegion, extendedMockRegion]).as('fetchRegion'); + mockGetUserPreferences({}); + }); + + it('should only display the Chicago region in the dropdown when supportedRegionIds is set to Chicago (us-ord)', () => { + const flags: Partial = { + aclp: { enabled: true, beta: true }, + aclpResourceTypeMap: [ + { + dimensionKey: 'LINODE_ID', + maxResourceSelections: 10, + serviceType: 'linode', + supportedRegionIds: '', + }, + { + dimensionKey: 'cluster_id', + maxResourceSelections: 10, + serviceType: 'dbaas', + supportedRegionIds: 'us-ord', + }, + ], + }; + mockAppendFeatureFlags(flags).as('getFeatureFlags'); + cy.visitWithLogin('monitor'); + cy.wait('@getFeatureFlags'); + + // Selecting a dashboard from the autocomplete input. + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') + .type(dashboardName); + + ui.autocompletePopper + .findByTitle(dashboardName) + .should('be.visible') + .click(); + + // Wait for the services and dashboard ,Region API calls to complete before proceeding + cy.wait(['@fetchServices', '@fetchDashboard', '@fetchRegion']); + + // Select a region from the dropdown. + ui.regionSelect.find().click(); + + ui.regionSelect.find().type(extendedMockRegion.label); + + // Since DBaaS does not support this region, we expect it to not be in the dropdown. + + ui.autocompletePopper.find().within(() => { + cy.findByText( + `${extendedMockRegion.label} (${extendedMockRegion.id})` + ).should('not.exist'); + }); + + ui.regionSelect.find().click().clear(); + ui.regionSelect + .findItemByRegionId(mockRegion.id, [mockRegion]) + .should('be.visible') + .click(); + + // Expand the applied filters section + ui.button.findByTitle('Filters').should('be.visible').click(); + + // Verify that the applied filters + cy.get('[data-qa-applied-filter-id="applied-filter"]').within(() => { + cy.get(`[data-qa-value="Region US, Chicago, IL"]`) + .should('be.visible') + .should('have.text', 'US, Chicago, IL'); + }); + }); + + it('should only display mocking region as Chicago and then supportedRegionIds is set to empty', () => { + const flags: Partial = { + aclp: { enabled: true, beta: true }, + aclpResourceTypeMap: [ + { + dimensionKey: 'LINODE_ID', + maxResourceSelections: 10, + serviceType: 'linode', + supportedRegionIds: '', + }, + { + dimensionKey: 'cluster_id', + maxResourceSelections: 10, + serviceType: 'dbaas', + supportedRegionIds: '', + }, + ], + }; + mockAppendFeatureFlags(flags).as('getFeatureFlags'); + cy.visitWithLogin('monitor'); + cy.wait('@getFeatureFlags'); + + // Selecting a dashboard from the autocomplete input. + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') + .type(dashboardName); + + ui.autocompletePopper + .findByTitle(dashboardName) + .should('be.visible') + .click(); + + // Wait for the services and dashboard ,Region API calls to complete before proceeding + cy.wait(['@fetchServices', '@fetchDashboard', '@fetchRegion']); + + ui.regionSelect.find().click(); + ui.autocompletePopper.find().within(() => { + cy.get('[data-option-index]').should('have.length', 2); + }); + + ui.regionSelect + .findItemByRegionId(mockRegion.id, [mockRegion]) + .should('be.visible') + .click(); + + // Expand the applied filters section + ui.button.findByTitle('Filters').should('be.visible').click(); + + // Verify that the applied filters + cy.get('[data-qa-applied-filter-id="applied-filter"]').within(() => { + cy.get(`[data-qa-value="Region US, Chicago, IL"]`) + .should('be.visible') + .should('have.text', 'US, Chicago, IL'); + }); + }); + + it('should only display mocking region as Chicago and then supportedRegionIds is set to Junk', () => { + const flags: Partial = { + aclp: { enabled: true, beta: true }, + aclpResourceTypeMap: [ + { + dimensionKey: 'LINODE_ID', + maxResourceSelections: 10, + serviceType: 'linode', + supportedRegionIds: '', + }, + { + dimensionKey: 'cluster_id', + maxResourceSelections: 10, + serviceType: 'dbaas', + supportedRegionIds: 'junk', + }, + ], + }; + mockAppendFeatureFlags(flags).as('getFeatureFlags'); + cy.visitWithLogin('monitor'); + cy.wait('@getFeatureFlags'); + + // Selecting a dashboard from the autocomplete input. + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') + .type(dashboardName); + + ui.autocompletePopper + .findByTitle(dashboardName) + .should('be.visible') + .click(); + + // Wait for the services and dashboard ,Region API calls to complete before proceeding + cy.wait(['@fetchServices', '@fetchDashboard', '@fetchRegion']); + + ui.regionSelect.find().click(); + ui.autocompletePopper.find().within(() => { + cy.get('[data-option-index]').should('have.length', 0); + }); + + // Expand the applied filters section + ui.button.findByTitle('Filters').should('be.visible').click(); + + // Verify that the applied filters + cy.get('[data-qa-applied-filter-id="applied-filter"]').within(() => { + cy.get('h3').should('not.exist'); + }); + }); + + it('should only display mocking region as Chicago and then supportedRegionIds is set to us-east', () => { + //Since we are mocking the region as Chicago but setting supportedRegionIds to Newark, + // no region should be displayed in the dropdown, as the region displayed must match the supported region + + const flags: Partial = { + aclp: { enabled: true, beta: true }, + aclpResourceTypeMap: [ + { + dimensionKey: 'LINODE_ID', + maxResourceSelections: 10, + serviceType: 'linode', + supportedRegionIds: '', + }, + { + dimensionKey: 'cluster_id', + maxResourceSelections: 10, + serviceType: 'dbaas', + supportedRegionIds: 'us-east', + }, + ], + }; + mockAppendFeatureFlags(flags).as('getFeatureFlags'); + mockGetRegions([mockRegion]).as('fetchRegion'); + + cy.visitWithLogin('monitor'); + cy.wait('@getFeatureFlags'); + + // Selecting a dashboard from the autocomplete input. + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') + .type(dashboardName); + + ui.autocompletePopper + .findByTitle(dashboardName) + .should('be.visible') + .click(); + + // Wait for the services and dashboard ,Region API calls to complete before proceeding + cy.wait(['@fetchServices', '@fetchDashboard', '@fetchRegion']); + + ui.regionSelect.find().click(); + ui.autocompletePopper.find().within(() => { + cy.get('[data-option-index]').should('have.length', 0); + }); + + // Expand the applied filters section + ui.button.findByTitle('Filters').should('be.visible').click(); + + // Verify that the applied filters + cy.get('[data-qa-applied-filter-id="applied-filter"]').within(() => { + cy.get('h3').should('not.exist'); + }); + }); + + it('should only display the Chicago region in the dropdown when supportedRegionIds is set to Chicago (us-ord) with extra spaces', () => { + // Adding extra space to supportedRegionIds with the value ' us-ord', and the value should be trimmed to remove the extra spaces.', + const flags: Partial = { + aclp: { enabled: true, beta: true }, + aclpResourceTypeMap: [ + { + dimensionKey: 'LINODE_ID', + maxResourceSelections: 10, + serviceType: 'linode', + supportedRegionIds: '', + }, + { + dimensionKey: 'cluster_id', + maxResourceSelections: 10, + serviceType: 'dbaas', + supportedRegionIds: 'in-west, us-ord ', + }, + ], + }; + mockAppendFeatureFlags(flags).as('getFeatureFlags'); + cy.visitWithLogin('monitor'); + cy.wait('@getFeatureFlags'); + + // Selecting a dashboard from the autocomplete input. + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') + .type(dashboardName); + + ui.autocompletePopper + .findByTitle(dashboardName) + .should('be.visible') + .click(); + + // Wait for the services and dashboard ,Region API calls to complete before proceeding + cy.wait(['@fetchServices', '@fetchDashboard', '@fetchRegion']); + + // Select a region from the dropdown. + ui.regionSelect.find().click(); + + ui.regionSelect.find().type(extendedMockRegion.label); + + // Since DBaaS does not support this region, we expect it to not be in the dropdown. + + ui.autocompletePopper.find().within(() => { + cy.findByText( + `${extendedMockRegion.label} (${extendedMockRegion.id})` + ).should('not.exist'); + }); + + ui.regionSelect.find().click().clear(); + ui.regionSelect + .findItemByRegionId(mockRegion.id, [mockRegion]) + .should('be.visible') + .click(); + + ui.regionSelect.find().click(); + ui.autocompletePopper.find().within(() => { + cy.get('[data-option-index]').should('have.length', 1); + }); + + // Expand the applied filters section + ui.button.findByTitle('Filters').should('be.visible').click(); + + // Verify that the applied filters + cy.get('[data-qa-applied-filter-id="applied-filter"]').within(() => { + cy.get(`[data-qa-value="Region US, Chicago, IL"]`) + .should('be.visible') + .should('have.text', 'US, Chicago, IL'); + }); + }); +}); diff --git a/packages/manager/cypress/e2e/core/cloudpulse/contextual-dbaas-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/contextual-dbaas-widget-verification.spec.ts new file mode 100644 index 00000000000..ceed564adf2 --- /dev/null +++ b/packages/manager/cypress/e2e/core/cloudpulse/contextual-dbaas-widget-verification.spec.ts @@ -0,0 +1,428 @@ +/** + * @file Integration Tests for contextualview of Dbass Dashboard. + */ +import { mockAppendFeatureFlags } from 'support/intercepts/feature-flags'; +import { + mockCreateCloudPulseJWEToken, + mockGetCloudPulseDashboard, + mockCreateCloudPulseMetrics, + mockGetCloudPulseMetricDefinitions, +} from 'support/intercepts/cloudpulse'; +import { ui } from 'support/ui'; +import { widgetDetails } from 'support/constants/widgets'; +import { + accountFactory, + cloudPulseMetricsResponseFactory, + dashboardFactory, + dashboardMetricFactory, + databaseFactory, + linodeFactory, + regionFactory, + widgetFactory, +} from 'src/factories'; +import { mockGetAccount } from 'support/intercepts/account'; +import { mockGetRegions } from 'support/intercepts/regions'; +import { CloudPulseMetricsResponse, Database } from '@linode/api-v4'; +import { formatToolTip } from 'src/features/CloudPulse/Utils/unitConversion'; +import { generateRandomMetricsData } from 'support/util/cloudpulse'; +import { + mockGetDatabase, + mockGetDatabaseTypes, + mockGetDatabases, +} from 'support/intercepts/databases'; +import { mockDatabaseNodeTypes } from 'support/constants/databases'; +import { randomIp } from 'support/util/random'; +import { extendRegion } from 'support/util/regions'; +import { Flags } from 'src/featureFlags'; +import { generateGraphData } from 'src/features/CloudPulse/Utils/CloudPulseWidgetUtils'; + +/** + * This test ensures that widget titles are displayed correctly on the dashboard. + * This test suite is dedicated to verifying the functionality and display of widgets on the Cloudpulse dashboard. + * It includes: + * Validating that widgets are correctly loaded and displayed. + * Ensuring that widget titles and data match the expected values. + * Verifying that widget settings, such as granularity and aggregation, are applied correctly. + * Testing widget interactions, including zooming and filtering, to ensure proper behavior. + * Each test ensures that widgets on the dashboard operate correctly and display accurate information. + */ +const expectedGranularityArray = ['1 day', '1 hr', '5 min']; +const timeDurationToSelect = 'Last 24 Hours'; + +const { + metrics, + serviceType, + dashboardName, + region, + engine, + clusterName, + nodeType, +} = widgetDetails.dbaas; + +const dashboard = dashboardFactory.build({ + label: dashboardName, + id: 1, + service_type: serviceType, + widgets: metrics.map(({ title, yLabel, name, unit }) => { + return widgetFactory.build({ + label: title, + y_label: yLabel, + metric: name, + unit, + }); + }), +}); + +const metricDefinitions = { + data: metrics.map(({ title, name, unit }) => + dashboardMetricFactory.build({ + label: title, + metric: name, + unit, + }) + ), +}; + +const mockAccount = accountFactory.build(); + +const metricsAPIResponsePayload = cloudPulseMetricsResponseFactory.build({ + data: generateRandomMetricsData(timeDurationToSelect, '5 min'), +}); + +/** + * Generates graph data from a given CloudPulse metrics response and + * extracts average, last, and maximum metric values from the first + * legend row. The values are rounded to two decimal places for + * better readability. + * + * @param responsePayload - The metrics response object containing + * the necessary data for graph generation. + * @param label - The label for the graph, used for display purposes. + * + * @returns An object containing rounded values for max average, last, + * + */ + +const getWidgetLegendRowValuesFromResponse = ( + responsePayload: CloudPulseMetricsResponse, + label: string, + unit: string +) => { + // Generate graph data using the provided parameters + const graphData = generateGraphData({ + flags: { enabled: true } as Partial, + label: label, + metricsList: responsePayload, + resources: [ + { + id: '1', + label: clusterName, + region: 'us-ord', + }, + ], + serviceType: serviceType, + status: 'success', + unit: unit, + }); + + // Destructure metrics data from the first legend row + const { average, last, max } = graphData.legendRowsData[0].data; + + // Round the metrics values to two decimal places + const roundedAverage = formatToolTip(average, unit); + const roundedLast = formatToolTip(last, unit); + const roundedMax = formatToolTip(max, unit); + // Return the rounded values in an object + return { average: roundedAverage, last: roundedLast, max: roundedMax }; +}; + +const allowedIp = randomIp(); + +const databaseMock: Database = databaseFactory.build({ + label: clusterName, + id: 100, + type: engine, + region: region, + version: '1', + status: 'active', + cluster_size: 1, + engine: 'mysql', + allow_list: [allowedIp], +}); +const mockRegion = extendRegion( + regionFactory.build({ + capabilities: ['Managed Databases'], + id: 'us-ord', + label: 'Chicago, IL', + }) +); + +describe('Integration Tests for DBaaS Dashboard ', () => { + beforeEach(() => { + mockAppendFeatureFlags({ + aclp: { beta: true, enabled: true }, + }); + mockGetAccount(mockAccount); + mockGetCloudPulseMetricDefinitions(serviceType, metricDefinitions); + mockGetCloudPulseDashboard(1, dashboard); + mockCreateCloudPulseJWEToken(serviceType); + mockCreateCloudPulseMetrics(serviceType, metricsAPIResponsePayload).as( + 'getMetrics' + ); + mockGetRegions([mockRegion]); + mockGetDatabase(databaseMock).as('getDatabase'); + mockGetDatabases([databaseMock]).as('getDatabases'); + mockGetDatabaseTypes(mockDatabaseNodeTypes).as('getDatabaseTypes'); + + // navigate to the linodes page + cy.visitWithLogin('/linodes'); + + // navigate to the Databases + cy.get('[data-testid="menu-item-Databases"]') + .should('be.visible') // Check if it is visible + .click(); // Click the link + + // navigate to the Monitor + cy.visitWithLogin( + `/databases/${databaseMock.engine}/${databaseMock.id}/monitor` + ); + + // Select a time duration from the autocomplete input. + ui.autocomplete + .findByLabel('Time Range') + .should('be.visible') + .type(`${timeDurationToSelect}{enter}`) + .should('be.visible'); + + //Select a Node from the autocomplete input. + ui.autocomplete + .findByLabel('Node Type') + .should('be.visible') + .type(`${nodeType}{enter}`); + + // Wait for all metrics query requests to resolve. + cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']); + }); + + it('should allow users to select their desired granularity and see the most recent data from the API reflected in the graph', () => { + // validate the widget level granularity selection and its metrics + metrics.forEach((testData) => { + const widgetSelector = `[data-qa-widget="${testData.title}"]`; + cy.get(widgetSelector) + .should('be.visible') + .find('h2') + .should('have.text', `${testData.title} (${testData.unit.trim()})`); + cy.get(widgetSelector) + .should('be.visible') + .within(() => { + // check for all available granularity in popper + ui.autocomplete + .findByLabel('Select an Interval') + .should('be.visible') + .click(); + + // Verify tooltip message for granularity selection + + ui.tooltip + .findByText('Data aggregation interval') + .should('be.visible'); + + expectedGranularityArray.forEach((option) => { + ui.autocompletePopper.findByTitle(option).should('exist'); + }); + + mockCreateCloudPulseMetrics( + serviceType, + metricsAPIResponsePayload + ).as('getGranularityMetrics'); + + //find the interval component and select the expected granularity + ui.autocomplete + .findByLabel('Select an Interval') + .should('be.visible') + .type(`${testData.expectedGranularity}{enter}`); //type expected granularity + + //check if the API call is made correctly with time granularity value selected + cy.wait('@getGranularityMetrics').then((interception) => { + expect(interception) + .to.have.property('response') + .with.property('statusCode', 200); + expect(testData.expectedGranularity).to.include( + interception.request.body.time_granularity.value + ); + }); + + //validate the widget areachart is present + cy.get('.recharts-responsive-container').within(() => { + const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( + metricsAPIResponsePayload, + testData.title, + testData.unit + ); + const graphRowTitle = `[data-qa-graph-row-title="${testData.title} (${testData.unit})"]`; + + cy.get(graphRowTitle) + .should('be.visible') + .should('have.text', `${testData.title} (${testData.unit})`); + + cy.get(`[data-qa-graph-column-title="Max"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.max}`); + + cy.get(`[data-qa-graph-column-title="Avg"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.average}`); + + cy.get(`[data-qa-graph-column-title="Last"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.last}`); + }); + }); + }); + }); + + it('should allow users to select the desired aggregation and view the latest data from the API displayed in the graph', () => { + metrics.forEach((testData) => { + const widgetSelector = `[data-qa-widget="${testData.title}"]`; + cy.get(widgetSelector) + .should('be.visible') + .within(() => { + mockCreateCloudPulseMetrics( + serviceType, + metricsAPIResponsePayload + ).as('getAggregationMetrics'); + + //find the interval component and select the expected granularity + ui.autocomplete + .findByLabel('Select an Aggregate Function') + .should('be.visible') + .type(`${testData.expectedAggregation}{enter}`); //type expected granularity + + // Verify tooltip message for aggregation selection + + ui.tooltip.findByText('Aggregation function').should('be.visible'); + + //check if the API call is made correctly with time granularity value selected + cy.wait('@getAggregationMetrics').then((interception) => { + expect(interception) + .to.have.property('response') + .with.property('statusCode', 200); + expect(testData.expectedAggregation).to.equal( + interception.request.body.aggregate_function + ); + }); + + //validate the widget areachart is present + cy.get('.recharts-responsive-container').within(() => { + const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( + metricsAPIResponsePayload, + testData.title, + testData.unit + ); + const graphRowTitle = `[data-qa-graph-row-title="${testData.title} (${testData.unit})"]`; + cy.get(graphRowTitle) + .should('be.visible') + .should('have.text', `${testData.title} (${testData.unit})`); + + cy.get(`[data-qa-graph-column-title="Max"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.max}`); + + cy.get(`[data-qa-graph-column-title="Avg"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.average}`); + + cy.get(`[data-qa-graph-column-title="Last"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.last}`); + }); + }); + }); + }); + + it('should zoom in and out of all the widgets', () => { + // do zoom in and zoom out test on all the widgets + metrics.forEach((testData) => { + cy.get(`[data-qa-widget="${testData.title}"]`).as('widget'); + cy.get('@widget') + .should('be.visible') + .within(() => { + ui.button + .findByAttribute('aria-label', 'Zoom In') + .should('be.visible') + .should('be.enabled') + .click(); + + // Verify tooltip message for Zoom-in + + ui.tooltip.findByText('Maximize').should('be.visible'); + + cy.get('@widget').should('be.visible'); + + //validate the widget areachart is present + cy.get('.recharts-responsive-container').within(() => { + const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( + metricsAPIResponsePayload, + testData.title, + testData.unit + ); + + const graphRowTitle = `[data-qa-graph-row-title="${testData.title} (${testData.unit})"]`; + cy.get(graphRowTitle) + .should('be.visible') + .should('have.text', `${testData.title} (${testData.unit})`); + + cy.get(`[data-qa-graph-column-title="Max"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.max}`); + + cy.get(`[data-qa-graph-column-title="Avg"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.average}`); + + cy.get(`[data-qa-graph-column-title="Last"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.last}`); + }); + + // click zoom out and validate the same + ui.button + .findByAttribute('aria-label', 'Zoom Out') + .should('be.visible') + .should('be.enabled') + .scrollIntoView() + .click({ force: true }); + + // Verify tooltip message for Zoom-out + + ui.tooltip.findByText('Minimize').should('be.visible'); + + cy.get('@widget').should('be.visible'); + + cy.get('.recharts-responsive-container').within(() => { + const expectedWidgetValues = getWidgetLegendRowValuesFromResponse( + metricsAPIResponsePayload, + testData.title, + testData.unit + ); + const graphRowTitle = `[data-qa-graph-row-title="${testData.title} (${testData.unit})"]`; + cy.get(graphRowTitle) + .should('be.visible') + .should('have.text', `${testData.title} (${testData.unit})`); + + cy.get(`[data-qa-graph-column-title="Max"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.max}`); + + cy.get(`[data-qa-graph-column-title="Avg"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.average}`); + + cy.get(`[data-qa-graph-column-title="Last"]`) + .should('be.visible') + .should('have.text', `${expectedWidgetValues.last}`); + }); + }); + }); + }); +}); From 4de3ea6003f62421056f0af4fe8988367c8e1d8a Mon Sep 17 00:00:00 2001 From: agorthi Date: Mon, 9 Dec 2024 12:25:00 +0530 Subject: [PATCH 397/474] Please only validate the files dbaas-widgets-verification.spec.ts and linode-widget-verification.spec.ts. other files only for aclp-manager regression simulation --- .../e2e/core/cloudpulse/cloudpulse-navigation.spec.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts index 7d3cf3543ba..3cf4fa4f700 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts @@ -1,12 +1,7 @@ /** - * @file Error Handling Tests for CloudPulse Region Selection - * - * This file contains tests to verify the proper handling of errors - * when interacting with region selection features in CloudPulse. - * The tests focus on scenarios such as invalid or unsupported regions, - * and ensure the application behaves as expected, providing appropriate - * error messages or fallback behavior when necessary. + * @file Integration tests for CloudPulse navigation. */ + import { mockAppendFeatureFlags } from 'support/intercepts/feature-flags'; import { mockGetAccount } from 'support/intercepts/account'; import { accountFactory } from 'src/factories'; From 89528f899760bffa0a77b1ab763c1ae147c5da69 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Mon, 9 Dec 2024 13:23:46 +0530 Subject: [PATCH 398/474] upcoming: [DI-22125] - Added default label to contextual view --- .../Dashboard/CloudPulseDashboardWithFilters.tsx | 1 - .../CloudPulse/shared/CloudPulseTimeRangeSelect.tsx | 9 ++------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx index 6defbb6533b..ad006515cf9 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx @@ -127,7 +127,6 @@ export const CloudPulseDashboardWithFilters = React.memo( diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx index 280d1b9c76f..cd908ba91b8 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx @@ -35,12 +35,7 @@ export type Labels = export const CloudPulseTimeRangeSelect = React.memo( (props: CloudPulseTimeRangeSelectProps) => { - const { - defaultValue, - handleStatsChange, - label = 'Time Range', - savePreferences, - } = props; + const { defaultValue, handleStatsChange, label, savePreferences } = props; const options = generateSelectOptions(); const getDefaultValue = React.useCallback((): Item => { if (!savePreferences) { @@ -89,7 +84,7 @@ export const CloudPulseTimeRangeSelect = React.memo( disableClearable fullWidth isOptionEqualToValue={(option, value) => option.value === value.value} - label={label} + label={label || 'Time Range'} noMarginTop options={options} value={selectedTimeRange} From c5b27103ab58f058b4fda1b29d38dca19b99d33f Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Mon, 9 Dec 2024 14:30:25 +0530 Subject: [PATCH 399/474] upcoming: [DI-20595] - edge case fix --- .../CloudPulse/shared/CloudPulseRegionSelect.tsx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index fdb7a5d9549..78b5d04984c 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -8,6 +8,7 @@ import { FILTER_CONFIG } from '../Utils/FilterConfig'; import type { Dashboard, FilterValue, Region } from '@linode/api-v4'; import type { CloudPulseResourceTypeMapFlag } from 'src/featureFlags'; +import { isNil } from 'ramda'; export interface CloudPulseRegionSelectProps { defaultValue?: FilterValue; @@ -61,17 +62,17 @@ export const CloudPulseRegionSelect = React.memo( (item: CloudPulseResourceTypeMapFlag) => item.serviceType === serviceType ); - const supportedRegionsIdList = - resourceTypeFlag?.supportedRegionIds - ?.split(',') - .map((regionId: string) => regionId.trim()) - .filter((regionId: string) => regionId.length > 0) || []; - if (!supportedRegionsIdList.length) { + if (isNil(resourceTypeFlag?.supportedRegionIds)) { return regions; } + + const supportedRegionsIdList = resourceTypeFlag.supportedRegionIds + .split(',') + .map((regionId: string) => regionId.trim()); + return regions?.filter((region) => - supportedRegionsIdList?.includes(region.id) + supportedRegionsIdList.includes(region.id) ); }, [flags.aclpResourceTypeMap, regions, serviceType]); From af2f2963b22d2594562db90f3cf1f6525603633f Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Mon, 9 Dec 2024 17:51:52 +0530 Subject: [PATCH 400/474] upcoming: [DI-20929] - Updated styling --- .../Dashboard/CloudPulseDashboardLanding.tsx | 4 ++-- .../Dashboard/CloudPulseDashboardWithFilters.tsx | 8 ++++---- .../CloudPulse/shared/CloudPulseAppliedFilter.tsx | 15 +++++++++------ .../CloudPulse/shared/CloudPulseCustomSelect.tsx | 2 +- .../shared/CloudPulseDashboardFilterBuilder.tsx | 7 +++++-- 5 files changed, 21 insertions(+), 15 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx index f402ad54f98..238f81c6189 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardLanding.tsx @@ -74,8 +74,8 @@ export const CloudPulseDashboardLanding = () => { return ( - - + + ({ + const [filterData, setFilterData] = React.useState({ id: {}, label: {}, }); @@ -58,7 +58,7 @@ export const CloudPulseDashboardWithFilters = React.memo( const onFilterChange = React.useCallback( (filterKey: string, value: FilterValueType, labels: string[]) => { - setFilterValue((prev) => { + setFilterData((prev) => { return { id: { ...prev.id, @@ -112,7 +112,7 @@ export const CloudPulseDashboardWithFilters = React.memo( const isFilterBuilderNeeded = checkIfFilterBuilderNeeded(dashboard); const isMandatoryFiltersSelected = checkMandatoryFiltersSelected({ dashboardObj: dashboard, - filterValue: filterValue.id, + filterValue: filterData.id, resource, timeDuration, }); @@ -170,7 +170,7 @@ export const CloudPulseDashboardWithFilters = React.memo( @@ -38,15 +41,15 @@ export const CloudPulseAppliedFilter = ( {filterValue.map((value, index) => { return ( ({ + backgroundColor: theme.tokens.color.Ultramarine[10], + color: theme.tokens.color.Neutrals.Black, fontSize: '14px', mr: index === filterValue.length - 1 ? 4 : 1, px: 1, py: 0.5, - width: { sm: 'fit-content', xs: '100%' }, - }} + width: { sm: 'fit-content', xs: '98%' }, + })} key={`${label} ${value}`} label={value} /> diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index 461d224c864..a68af932c17 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -68,7 +68,7 @@ export interface CloudPulseCustomSelectProps { * The callback function , that will be called on a filter change * @param filterKey - The filterKey of the component * @param value - The selected filter value - * @param labels - Lables of the selected filter value + * @param labels - Labels of the selected filter value */ handleSelectionChange: ( filterKey: string, diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index a59caa17471..4176c81277a 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -229,8 +229,10 @@ export const CloudPulseDashboardFilterBuilder = React.memo( ); const toggleShowFilter = () => { - setShowFilter((showFilterPrev) => !showFilterPrev); - handleToggleAppliedFilter(showFilter); + setShowFilter((showFilterPrev) => { + handleToggleAppliedFilter(showFilterPrev); + return !showFilterPrev; + }); }; const RenderFilters = React.useCallback(() => { @@ -328,6 +330,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( item maxHeight={theme.spacing(23)} overflow={'auto'} + pr={{ sm: 0, xs: 2 }} rowGap={theme.spacing(2)} xs={12} > From 7516f0f093acfe2a648bd7a42227ac87c82ad30e Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Mon, 9 Dec 2024 18:16:26 +0530 Subject: [PATCH 401/474] upcoming: [DI-20929] - Updated qa ids --- .../src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx index ec012793023..3b8ddd67682 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseAppliedFilter.tsx @@ -17,6 +17,7 @@ export const CloudPulseAppliedFilter = ( overflowX: 'hidden', overflowY: 'auto', }} + data-qa-applied-filter-id="applied-filter" data-testid="applied-filter" display="flex" flexDirection={{ sm: 'row', xs: 'column' }} @@ -50,6 +51,7 @@ export const CloudPulseAppliedFilter = ( py: 0.5, width: { sm: 'fit-content', xs: '98%' }, })} + data-qa-value={`${label} ${value}`} key={`${label} ${value}`} label={value} /> From dbdce5606a2540c664d2a05b2a839de5b7eb2256 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Mon, 9 Dec 2024 18:23:53 +0530 Subject: [PATCH 402/474] upcoming: [DI-20929] - updated function order --- .../CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index b4b513884ac..115be16b186 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -230,8 +230,8 @@ export const CloudPulseDashboardFilterBuilder = React.memo( ); const toggleShowFilter = () => { + handleToggleAppliedFilter(showFilter); setShowFilter((showFilterPrev) => { - handleToggleAppliedFilter(showFilterPrev); return !showFilterPrev; }); }; From 719f7c6c4ae956293056f3ab6b675383cc5ae849 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Mon, 9 Dec 2024 18:30:21 +0530 Subject: [PATCH 403/474] upcoming: [DI-20929] - Improved code readability --- .../CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index 115be16b186..ba92c1242b7 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -231,9 +231,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( const toggleShowFilter = () => { handleToggleAppliedFilter(showFilter); - setShowFilter((showFilterPrev) => { - return !showFilterPrev; - }); + setShowFilter((showFilterPrev) => !showFilterPrev); }; const RenderFilters = React.useCallback(() => { From 46b227c3dee79ab10531842b848fc0e3569fbd3c Mon Sep 17 00:00:00 2001 From: agorthi Date: Mon, 9 Dec 2024 18:31:13 +0530 Subject: [PATCH 404/474] add new test case for region select and fixing error.spec failing as region selection is changed --- .../cloudpulse-applied-filters.spec.ts | 18 +++++- .../cloudpulse-dashboard-errors.spec.ts | 23 ++++++- .../cloudpulse-region-support.spec.ts | 60 ++++++++++++++++--- 3 files changed, 88 insertions(+), 13 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-applied-filters.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-applied-filters.spec.ts index 67b27b005ad..ca6dd36d107 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-applied-filters.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-applied-filters.spec.ts @@ -31,7 +31,23 @@ import type { Flags } from 'src/featureFlags'; const timeDurationToSelect = 'Last 24 Hours'; -const flags: Partial = { aclp: { enabled: true, beta: true } }; +const flags: Partial = { + aclp: { enabled: true, beta: true }, + aclpResourceTypeMap: [ + { + dimensionKey: 'LINODE_ID', + maxResourceSelections: 10, + serviceType: 'linode', + supportedRegionIds: '', + }, + { + dimensionKey: 'cluster_id', + maxResourceSelections: 10, + serviceType: 'dbaas', + supportedRegionIds: 'us-ord', + }, + ], +}; const { metrics, diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-dashboard-errors.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-dashboard-errors.spec.ts index 2cf61267beb..7a142a0a6bd 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-dashboard-errors.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-dashboard-errors.spec.ts @@ -35,6 +35,7 @@ import { } from 'support/intercepts/databases'; import { Database } from '@linode/api-v4'; import { mockGetAccount } from 'support/intercepts/account'; +import { Flags } from 'src/featureFlags'; /** * Verifies the presence and values of specific properties within the aclpPreference object @@ -44,6 +45,24 @@ import { mockGetAccount } from 'support/intercepts/account'; * @param requestPayload - The payload received from the request, containing the aclpPreference object. * @param expectedValues - An object containing the expected values for properties to validate against the requestPayload. */ + +const flags: Partial = { + aclp: { enabled: true, beta: true }, + aclpResourceTypeMap: [ + { + dimensionKey: 'LINODE_ID', + maxResourceSelections: 10, + serviceType: 'linode', + supportedRegionIds: 'us-ord', + }, + { + dimensionKey: 'cluster_id', + maxResourceSelections: 10, + serviceType: 'dbaas', + supportedRegionIds: 'us-ord', + }, + ], +}; const { metrics, id, @@ -96,9 +115,7 @@ const mockAccount = accountFactory.build(); describe('Tests for API error handling', () => { beforeEach(() => { - mockAppendFeatureFlags({ - aclp: { beta: true, enabled: true }, - }); + mockAppendFeatureFlags(flags); mockGetAccount(mockAccount); mockGetCloudPulseMetricDefinitions(serviceType, metricDefinitions); mockGetCloudPulseDashboards(serviceType, [dashboard]).as('fetchDashboard'); diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-region-support.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-region-support.spec.ts index 9972787f5d2..ef87bd5ca49 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-region-support.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-region-support.spec.ts @@ -132,21 +132,14 @@ describe('Integration Tests for DBaaS Dashboard ', () => { }); }); - it('should only display mocking region as Chicago and then supportedRegionIds is set to empty', () => { + it.skip('If the supportedRegionIds column is removed, all mocked regions will be considered supported by default', () => { const flags: Partial = { aclp: { enabled: true, beta: true }, aclpResourceTypeMap: [ - { - dimensionKey: 'LINODE_ID', - maxResourceSelections: 10, - serviceType: 'linode', - supportedRegionIds: '', - }, - { + { dimensionKey: 'cluster_id', maxResourceSelections: 10, serviceType: 'dbaas', - supportedRegionIds: '', }, ], }; @@ -188,6 +181,55 @@ describe('Integration Tests for DBaaS Dashboard ', () => { .should('have.text', 'US, Chicago, IL'); }); }); + it('supportedRegionIds is empty, no regions will be displayed', () => { + const flags: Partial = { + aclp: { enabled: true, beta: true }, + aclpResourceTypeMap: [ + { + dimensionKey: 'LINODE_ID', + maxResourceSelections: 10, + serviceType: 'linode', + supportedRegionIds: '', + }, + { + dimensionKey: 'cluster_id', + maxResourceSelections: 10, + serviceType: 'dbaas', + supportedRegionIds: '', + }, + ], + }; + mockAppendFeatureFlags(flags).as('getFeatureFlags'); + cy.visitWithLogin('monitor'); + cy.wait('@getFeatureFlags'); + + // Selecting a dashboard from the autocomplete input. + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') + .type(dashboardName); + + ui.autocompletePopper + .findByTitle(dashboardName) + .should('be.visible') + .click(); + + // Wait for the services and dashboard ,Region API calls to complete before proceeding + cy.wait(['@fetchServices', '@fetchDashboard', '@fetchRegion']); + + ui.regionSelect.find().click(); + ui.autocompletePopper.find().within(() => { + cy.get('[data-option-index]').should('have.length', 0); + }); + + // Expand the applied filters section + ui.button.findByTitle('Filters').should('be.visible').click(); + + // Verify that the applied filters + cy.get('[data-qa-applied-filter-id="applied-filter"]').within(() => { + cy.get('h3').should('not.exist'); + }); + }); it('should only display mocking region as Chicago and then supportedRegionIds is set to Junk', () => { const flags: Partial = { From 6c4fa933e44f70bcee5117fb842401749b474522 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 11 Dec 2024 16:24:50 +0530 Subject: [PATCH 405/474] upcoming: [DI-22125] - Updated logic to hide label in contextual view --- .../Dashboard/CloudPulseDashboardWithFilters.tsx | 1 + .../CloudPulse/shared/CloudPulseTimeRangeSelect.tsx | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx index ad006515cf9..e2c78172962 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx @@ -127,6 +127,7 @@ export const CloudPulseDashboardWithFilters = React.memo( diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx index cd908ba91b8..8dc87ced0b4 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTimeRangeSelect.tsx @@ -18,6 +18,7 @@ export interface CloudPulseTimeRangeSelectProps timeDurationValue?: string, savePref?: boolean ) => void; + hideLabel?: boolean; savePreferences?: boolean; } @@ -35,7 +36,13 @@ export type Labels = export const CloudPulseTimeRangeSelect = React.memo( (props: CloudPulseTimeRangeSelectProps) => { - const { defaultValue, handleStatsChange, label, savePreferences } = props; + const { + defaultValue, + handleStatsChange, + hideLabel, + label, + savePreferences, + } = props; const options = generateSelectOptions(); const getDefaultValue = React.useCallback((): Item => { if (!savePreferences) { @@ -79,6 +86,9 @@ export const CloudPulseTimeRangeSelect = React.memo( onChange={(e, value: Item) => { handleChange(value); }} + textFieldProps={{ + hideLabel, + }} autoHighlight data-testid="cloudpulse-time-duration" disableClearable From f2f92504dee24b40041d24e668b53d5c97ecabdd Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Wed, 11 Dec 2024 16:30:20 +0530 Subject: [PATCH 406/474] upcoming: [DI-22125] - Removed hide label from global filters --- .../manager/src/features/CloudPulse/Overview/GlobalFilters.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx index e371c50351b..6cb3a67f1ad 100644 --- a/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Overview/GlobalFilters.tsx @@ -113,7 +113,6 @@ export const GlobalFilters = React.memo((props: GlobalFilterProperties) => { From 3efdc8a3ebe597ca4fc00479be0ae40b0aad4d97 Mon Sep 17 00:00:00 2001 From: agorthi Date: Thu, 12 Dec 2024 11:00:59 +0530 Subject: [PATCH 407/474] DI-22125:Remove unnecessary mocking regions in contextual specification test cases and enhance their overall quality. --- ...ntextual-dbaas-widget-verification.spec.ts | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/contextual-dbaas-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/contextual-dbaas-widget-verification.spec.ts index ceed564adf2..46852835f96 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/contextual-dbaas-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/contextual-dbaas-widget-verification.spec.ts @@ -16,23 +16,18 @@ import { dashboardFactory, dashboardMetricFactory, databaseFactory, - linodeFactory, - regionFactory, widgetFactory, } from 'src/factories'; import { mockGetAccount } from 'support/intercepts/account'; -import { mockGetRegions } from 'support/intercepts/regions'; import { CloudPulseMetricsResponse, Database } from '@linode/api-v4'; import { formatToolTip } from 'src/features/CloudPulse/Utils/unitConversion'; import { generateRandomMetricsData } from 'support/util/cloudpulse'; import { mockGetDatabase, mockGetDatabaseTypes, - mockGetDatabases, } from 'support/intercepts/databases'; import { mockDatabaseNodeTypes } from 'support/constants/databases'; import { randomIp } from 'support/util/random'; -import { extendRegion } from 'support/util/regions'; import { Flags } from 'src/featureFlags'; import { generateGraphData } from 'src/features/CloudPulse/Utils/CloudPulseWidgetUtils'; @@ -149,13 +144,6 @@ const databaseMock: Database = databaseFactory.build({ engine: 'mysql', allow_list: [allowedIp], }); -const mockRegion = extendRegion( - regionFactory.build({ - capabilities: ['Managed Databases'], - id: 'us-ord', - label: 'Chicago, IL', - }) -); describe('Integration Tests for DBaaS Dashboard ', () => { beforeEach(() => { @@ -164,14 +152,12 @@ describe('Integration Tests for DBaaS Dashboard ', () => { }); mockGetAccount(mockAccount); mockGetCloudPulseMetricDefinitions(serviceType, metricDefinitions); - mockGetCloudPulseDashboard(1, dashboard); - mockCreateCloudPulseJWEToken(serviceType); + mockGetCloudPulseDashboard(1, dashboard).as('getDashboard'); + mockCreateCloudPulseJWEToken(serviceType).as('getServiceType'); mockCreateCloudPulseMetrics(serviceType, metricsAPIResponsePayload).as( 'getMetrics' ); - mockGetRegions([mockRegion]); mockGetDatabase(databaseMock).as('getDatabase'); - mockGetDatabases([databaseMock]).as('getDatabases'); mockGetDatabaseTypes(mockDatabaseNodeTypes).as('getDatabaseTypes'); // navigate to the linodes page @@ -179,14 +165,16 @@ describe('Integration Tests for DBaaS Dashboard ', () => { // navigate to the Databases cy.get('[data-testid="menu-item-Databases"]') - .should('be.visible') // Check if it is visible - .click(); // Click the link + .should('be.visible') + .click(); // navigate to the Monitor cy.visitWithLogin( `/databases/${databaseMock.engine}/${databaseMock.id}/monitor` ); + cy.wait(['@getDashboard', '@getServiceType','@getDatabase']); + // Select a time duration from the autocomplete input. ui.autocomplete .findByLabel('Time Range') From 91b30bdcf1473bc8eb967203e27ad7855a3f3029 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Wed, 11 Dec 2024 12:20:53 +0530 Subject: [PATCH 408/474] upcoming: [DI-20935] - Add support for tags filter - Added tag filter selection component - Made tag filter as an optional dependency - Passed tag as an x-filter to filter resources - Included exhaustive unit test cases - Updated mocks for handling tags --- .../Dashboard/CloudPulseDashboard.tsx | 5 + .../Dashboard/CloudPulseDashboardRenderer.tsx | 7 +- .../CloudPulse/Utils/FilterBuilder.ts | 49 ++++- .../features/CloudPulse/Utils/FilterConfig.ts | 23 ++- .../Utils/ReusableDashboardFilterUtils.ts | 6 +- .../features/CloudPulse/Utils/constants.ts | 2 + .../src/features/CloudPulse/Utils/models.ts | 6 + .../CloudPulseComponentRenderer.test.tsx | 37 ++++ .../shared/CloudPulseComponentRenderer.tsx | 5 + .../CloudPulseDashboardFilterBuilder.test.tsx | 2 +- .../CloudPulseDashboardFilterBuilder.tsx | 31 +++- .../shared/CloudPulseRegionSelect.tsx | 3 + .../shared/CloudPulseResourcesSelect.tsx | 31 +++- .../shared/CloudPulseTagsFilter.test.tsx | 172 ++++++++++++++++++ .../shared/CloudPulseTagsFilter.tsx | 116 ++++++++++++ packages/manager/src/mocks/serverHandlers.ts | 23 ++- .../src/queries/cloudpulse/resources.ts | 9 +- .../manager/src/queries/cloudpulse/tags.ts | 23 +++ 18 files changed, 518 insertions(+), 32 deletions(-) create mode 100644 packages/manager/src/features/CloudPulse/shared/CloudPulseTagsFilter.test.tsx create mode 100644 packages/manager/src/features/CloudPulse/shared/CloudPulseTagsFilter.tsx create mode 100644 packages/manager/src/queries/cloudpulse/tags.ts diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx index 623e12db24a..5cb487cc9b8 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboard.tsx @@ -51,6 +51,11 @@ export interface DashboardProperties { * optional flag to check whether changes should be stored in preferences or not (in case this component is reused) */ savePref?: boolean; + + /** + * Selected tags for the dashboard + */ + tags?: string[]; } export const CloudPulseDashboard = (props: DashboardProperties) => { diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx index a1cb03e235b..0c136e566ff 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardRenderer.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { CloudPulseErrorPlaceholder } from '../shared/CloudPulseErrorPlaceholder'; -import { REFRESH, REGION, RESOURCE_ID } from '../Utils/constants'; +import { REFRESH, REGION, RESOURCE_ID, TAGS } from '../Utils/constants'; import { checkIfAllMandatoryFiltersAreSelected, getMetricsCallCustomFilters, @@ -69,6 +69,11 @@ export const CloudPulseDashboardRenderer = React.memo( ? (filterValue[RESOURCE_ID] as string[]) : [] } + tags={ + filterValue[TAGS] && Array.isArray(filterValue[TAGS]) + ? (filterValue[TAGS] as string[]) + : [] + } additionalFilters={getMetricsCall} dashboardId={dashboard.id} duration={timeDuration} diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts index a303722df3d..960f19f5367 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts @@ -3,6 +3,7 @@ import { RELATIVE_TIME_DURATION, RESOURCE_ID, RESOURCES, + TAGS, } from './constants'; import { FILTER_CONFIG } from './FilterConfig'; import { CloudPulseSelectTypes } from './models'; @@ -14,6 +15,10 @@ import type { CloudPulseResources, CloudPulseResourcesSelectProps, } from '../shared/CloudPulseResourcesSelect'; +import type { + CloudPulseTags, + CloudPulseTagsSelectProps, +} from '../shared/CloudPulseTagsFilter'; import type { CloudPulseTimeRangeSelectProps } from '../shared/CloudPulseTimeRangeSelect'; import type { CloudPulseMetricsAdditionalFilters } from '../Widget/CloudPulseWidget'; import type { CloudPulseServiceTypeFilters } from './models'; @@ -42,6 +47,30 @@ interface CloudPulseMandatoryFilterCheckProps { }; timeDuration: TimeDuration | undefined; } +/** + * This function helps in building the properties needed for tags selection component + * + * @param config - accepts a CloudPulseServiceTypeFilters of tag key + * @param handleTagsChange - the callback when we select new tag + * @param dashboard - the selected dashboard's service type + * @param isServiceAnalyticsIntegration - only if this is false, we need to save preferences , else no need + * @returns CloudPulseTagSelectProps + */ +export const getTagsProperties = ( + props: CloudPulseFilterProperties, + handleTagsChange: (tags: CloudPulseTags[], savePref?: boolean) => void +): CloudPulseTagsSelectProps => { + const { name: label, placeholder } = props.config.configuration; + const { dashboard, isServiceAnalyticsIntegration, preferences } = props; + return { + defaultValue: preferences?.[TAGS], + handleTagsChange, + label, + placeholder, + resourceType: dashboard.service_type, + savePreferences: !isServiceAnalyticsIntegration, + }; +}; /** * This function helps in building the properties needed for region selection component @@ -219,6 +248,7 @@ export const buildXFilter = ( } ): Filter => { const filters: Filter[] = []; + let orCondition: Filter[] = []; const { dependency } = config.configuration; if (dependency) { @@ -226,8 +256,7 @@ export const buildXFilter = ( const value = dependentFilters[key]; if (value !== undefined) { if (Array.isArray(value)) { - const orCondition = value.map((val) => ({ [key]: val })); - filters.push({ '+or': orCondition }); + orCondition = value.map((val) => ({ [key]: val })); } else { filters.push({ [key]: value }); } @@ -235,7 +264,7 @@ export const buildXFilter = ( }); } - return { '+and': filters }; + return { '+and': filters, '+or': orCondition }; }; /** @@ -266,9 +295,14 @@ export const checkIfWeNeedToDisableFilterByFilterKey = ( if (filter) { return filter.configuration.dependency?.some((dependent) => { const dependentFilter = dependentFilters[dependent]; + const optionalFilter = filters.find( + (filter) => filter.configuration.isOptional === true + )?.configuration.filterKey; + return ( - !dependentFilter || - (Array.isArray(dependentFilter) && dependentFilter.length === 0) + dependent !== optionalFilter && + (!dependentFilter || + (Array.isArray(dependentFilter) && dependentFilter.length === 0)) ); }); } @@ -293,7 +327,10 @@ export const checkIfAllMandatoryFiltersAreSelected = ( return false; } - return serviceTypeConfig.filters.every((filter) => { + const mandatoryFilters = serviceTypeConfig.filters.filter( + (filter) => filter.configuration.filterKey !== TAGS + ); + return mandatoryFilters.every((filter) => { const filterKey = filter.configuration.filterKey; if (filterKey === RELATIVE_TIME_DURATION) { diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts b/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts index e5bc12d7e3b..4519e3f48dc 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterConfig.ts @@ -9,6 +9,21 @@ export const LINODE_CAPABILITY = 'Linodes'; export const LINODE_CONFIG: Readonly = { capability: LINODE_CAPABILITY, filters: [ + { + configuration: { + filterKey: 'tags', + filterType: 'string', + isFilterable: false, + isMetricsFilter: false, + isMultiSelect: true, + isOptional: true, + name: 'Tags', + neededInServicePage: false, + placeholder: 'Select Tags', + priority: 1, + }, + name: 'Tags', + }, { configuration: { filterKey: 'region', @@ -17,13 +32,13 @@ export const LINODE_CONFIG: Readonly = { isMetricsFilter: false, name: 'Region', neededInServicePage: false, - priority: 1, + priority: 2, }, name: 'Region', }, { configuration: { - dependency: ['region'], + dependency: ['region', 'tags'], filterKey: 'resource_id', filterType: 'string', isFilterable: true, @@ -32,7 +47,7 @@ export const LINODE_CONFIG: Readonly = { name: 'Resources', neededInServicePage: false, placeholder: 'Select Resources', - priority: 2, + priority: 3, }, name: 'Resources', }, @@ -46,7 +61,7 @@ export const LINODE_CONFIG: Readonly = { name: TIME_DURATION, neededInServicePage: false, placeholder: 'Select a Duration', - priority: 3, + priority: 4, }, name: TIME_DURATION, }, diff --git a/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.ts b/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.ts index 969b5f1f543..3de4d309a12 100644 --- a/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.ts @@ -1,3 +1,4 @@ +import { TAGS } from './constants'; import { FILTER_CONFIG } from './FilterConfig'; import type { DashboardProperties } from '../Dashboard/CloudPulseDashboard'; @@ -66,7 +67,10 @@ export const checkMandatoryFiltersSelected = ( return false; } - return serviceTypeConfig.filters.every(({ configuration }) => { + const mandatoryFilters = serviceTypeConfig.filters.filter( + (filter) => filter.configuration.filterKey !== TAGS + ); + return mandatoryFilters.every(({ configuration }) => { const { filterKey, neededInServicePage } = configuration; // If the filter is not needed, skip it diff --git a/packages/manager/src/features/CloudPulse/Utils/constants.ts b/packages/manager/src/features/CloudPulse/Utils/constants.ts index c3e31b022d9..9cca7b1b2f3 100644 --- a/packages/manager/src/features/CloudPulse/Utils/constants.ts +++ b/packages/manager/src/features/CloudPulse/Utils/constants.ts @@ -18,6 +18,8 @@ export const REFRESH = 'refresh'; export const TIME_GRANULARITY = 'timeGranularity'; +export const TAGS = 'tags'; + export const RELATIVE_TIME_DURATION = 'relative_time_duration'; export const RESOURCE_ID = 'resource_id'; diff --git a/packages/manager/src/features/CloudPulse/Utils/models.ts b/packages/manager/src/features/CloudPulse/Utils/models.ts index 05d4c7fc926..9a7c0300689 100644 --- a/packages/manager/src/features/CloudPulse/Utils/models.ts +++ b/packages/manager/src/features/CloudPulse/Utils/models.ts @@ -119,6 +119,12 @@ export interface CloudPulseServiceTypeFiltersConfiguration { * If this is true, multiselect will be enabled for the filter, only applicable for static and dynamic, not for predefined ones */ isMultiSelect?: boolean; + + /** + * If this is true, we will pass tags as an optional filter + */ + isOptional?: boolean; + /** * If this is true, we will only allow users to select a certain threshold, only applicable for static and dynamic, not for predefined ones */ diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseComponentRenderer.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseComponentRenderer.test.tsx index dd74c70a1ef..a2687c57a6e 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseComponentRenderer.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseComponentRenderer.test.tsx @@ -8,12 +8,49 @@ import RenderComponent from '../shared/CloudPulseComponentRenderer'; import { getRegionProperties, getResourcesProperties, + getTagsProperties, } from '../Utils/FilterBuilder'; import { FILTER_CONFIG } from '../Utils/FilterConfig'; const linodeFilterConfig = FILTER_CONFIG.get('linode'); describe('ComponentRenderer component tests', () => { + it('it should render provided tag filter in props', () => { + const tagProps = linodeFilterConfig?.filters.find( + (filter) => filter.configuration.filterKey === 'tags' + ); + + const mockDashboard = dashboardFactory.build({ + service_type: 'linode', + }); + + if (tagProps === undefined) { + expect(true).toEqual(false); // fail test + return; + } + + const { getByPlaceholderText } = renderWithTheme( + + {RenderComponent({ + componentKey: 'tags', + componentProps: { + ...getTagsProperties( + { + config: tagProps, + dashboard: mockDashboard, + isServiceAnalyticsIntegration: false, + }, + vi.fn() + ), + }, + key: 'tags', + })} + + ); + + expect(getByPlaceholderText('Select Tags')).toBeDefined(); + }); + it('it should render provided region filter in props', () => { const regionProps = linodeFilterConfig?.filters.find( (filter) => filter.configuration.filterKey === 'region' diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseComponentRenderer.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseComponentRenderer.tsx index 224956a45ca..d806a57b695 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseComponentRenderer.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseComponentRenderer.tsx @@ -5,11 +5,13 @@ import NullComponent from 'src/components/NullComponent'; import { CloudPulseCustomSelect } from './CloudPulseCustomSelect'; import { CloudPulseRegionSelect } from './CloudPulseRegionSelect'; import { CloudPulseResourcesSelect } from './CloudPulseResourcesSelect'; +import { CloudPulseTagsSelect } from './CloudPulseTagsFilter'; import { CloudPulseTimeRangeSelect } from './CloudPulseTimeRangeSelect'; import type { CloudPulseCustomSelectProps } from './CloudPulseCustomSelect'; import type { CloudPulseRegionSelectProps } from './CloudPulseRegionSelect'; import type { CloudPulseResourcesSelectProps } from './CloudPulseResourcesSelect'; +import type { CloudPulseTagsSelectProps } from './CloudPulseTagsFilter'; import type { CloudPulseTimeRangeSelectProps } from './CloudPulseTimeRangeSelect'; import type { MemoExoticComponent } from 'react'; @@ -19,6 +21,7 @@ export interface CloudPulseComponentRendererProps { | CloudPulseCustomSelectProps | CloudPulseRegionSelectProps | CloudPulseResourcesSelectProps + | CloudPulseTagsSelectProps | CloudPulseTimeRangeSelectProps; key: string; } @@ -29,6 +32,7 @@ const Components: { | CloudPulseCustomSelectProps | CloudPulseRegionSelectProps | CloudPulseResourcesSelectProps + | CloudPulseTagsSelectProps | CloudPulseTimeRangeSelectProps > >; @@ -37,6 +41,7 @@ const Components: { region: CloudPulseRegionSelect, relative_time_duration: CloudPulseTimeRangeSelect, resource_id: CloudPulseResourcesSelect, + tags: CloudPulseTagsSelect, }; const buildComponent = (props: CloudPulseComponentRendererProps) => { diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.test.tsx index 71a684c9a1d..497c1846d09 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.test.tsx @@ -17,7 +17,7 @@ describe('CloudPulseDashboardFilterBuilder component tests', () => { isServiceAnalyticsIntegration={false} /> ); - + expect(getByTestId('tags-select')).toBeDefined(); expect(getByTestId('resource-select')).toBeDefined(); expect(getByTestId('region-select')).toBeDefined(); }); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index ba92c1242b7..8ed14da9083 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -15,18 +15,21 @@ import { RELATIVE_TIME_DURATION, RESOURCE_ID, RESOURCES, + TAGS, } from '../Utils/constants'; import { getCustomSelectProperties, getFilters, getRegionProperties, getResourcesProperties, + getTagsProperties, } from '../Utils/FilterBuilder'; import { FILTER_CONFIG } from '../Utils/FilterConfig'; import type { FilterValueType } from '../Dashboard/CloudPulseDashboardLanding'; import type { CloudPulseServiceTypeFilters } from '../Utils/models'; import type { CloudPulseResources } from './CloudPulseResourcesSelect'; +import type { CloudPulseTags } from './CloudPulseTagsFilter'; import type { AclpConfig, Dashboard } from '@linode/api-v4'; export interface CloudPulseDashboardFilterBuilderProps { @@ -126,6 +129,21 @@ export const CloudPulseDashboardFilterBuilder = React.memo( [emitFilterChange, checkAndUpdateDependentFilters] ); + const handleTagsChange = React.useCallback( + (tags: CloudPulseTags[], savePref: boolean = false) => { + emitFilterChangeByFilterKey( + TAGS, + tags.map((tag) => tag.label), + tags.map((tag) => tag.label), + savePref, + { + [TAGS]: tags.map((tag: { label: string }) => String(tag.label)), + } + ); + }, + [emitFilterChangeByFilterKey] + ); + const handleResourceChange = React.useCallback( (resourceId: CloudPulseResources[], savePref: boolean = false) => { emitFilterChangeByFilterKey( @@ -185,7 +203,17 @@ export const CloudPulseDashboardFilterBuilder = React.memo( const getProps = React.useCallback( (config: CloudPulseServiceTypeFilters) => { - if (config.configuration.filterKey === REGION) { + if (config.configuration.filterKey === TAGS) { + return getTagsProperties( + { + config, + dashboard, + isServiceAnalyticsIntegration, + preferences, + }, + handleTagsChange + ); + } else if (config.configuration.filterKey === REGION) { return getRegionProperties( { config, @@ -221,6 +249,7 @@ export const CloudPulseDashboardFilterBuilder = React.memo( }, [ dashboard, + handleTagsChange, handleRegionChange, handleResourceChange, handleCustomSelectChange, diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index f69ab97e964..0f586dba2cc 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -88,6 +88,9 @@ export const CloudPulseRegionSelect = React.memo( savePreferences ); }} + textFieldProps={{ + required: true, + }} currentCapability={capability} data-testid="region-select" disableClearable={false} diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index d74778620ae..b9ef89d35ac 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -8,7 +8,16 @@ import { themes } from 'src/utilities/theme'; import { deepEqual } from '../Utils/FilterBuilder'; -import type { Filter, FilterValue } from '@linode/api-v4'; +import type { FilterValueType } from '../Dashboard/CloudPulseDashboardLanding'; +import type { FilterConditionTypes, FilterValue } from '@linode/api-v4'; + +type ExtendedLinodeFilter = + | { + [key in keyof FilterConditionTypes]: FilterConditionTypes[key]; + } + | { [key: string]: FilterValueType }; + +export type ExtendedFilter = ExtendedLinodeFilter | ExtendedLinodeFilter[]; export interface CloudPulseResources { id: string; @@ -28,7 +37,8 @@ export interface CloudPulseResourcesSelectProps { region?: string; resourceType: string | undefined; savePreferences?: boolean; - xFilter?: Filter; + tags?: string[]; + xFilter?: ExtendedFilter; } export const CloudPulseResourcesSelect = React.memo( @@ -42,12 +52,13 @@ export const CloudPulseResourcesSelect = React.memo( region, resourceType, savePreferences, + tags, xFilter, } = props; const flags = useFlags(); - const resourceFilterMap: Record = { + const resourceFilterMap: Record = { dbaas: { '+order': 'asc', '+order_by': 'label', platform: 'rdbms-default' }, }; @@ -57,13 +68,14 @@ export const CloudPulseResourcesSelect = React.memo( {}, xFilter ? { - ...(resourceFilterMap[resourceType ?? ''] ?? {}), - ...xFilter, // the usual xFilters - } + ...(resourceFilterMap[resourceType ?? ''] ?? {}), + ...xFilter, // the usual xFilters + } : { - ...(resourceFilterMap[resourceType ?? ''] ?? {}), - region, - } + ...(resourceFilterMap[resourceType ?? ''] ?? {}), + region, + tags, + } ); const [selectedResources, setSelectedResources] = React.useState< @@ -187,6 +199,7 @@ export const CloudPulseResourcesSelect = React.memo( }, }, }, + required: true, }} autoHighlight clearOnBlur diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTagsFilter.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTagsFilter.test.tsx new file mode 100644 index 00000000000..6d721669cf9 --- /dev/null +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTagsFilter.test.tsx @@ -0,0 +1,172 @@ +import { screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import * as React from 'react'; + +import { tagFactory } from 'src/factories'; +import { renderWithTheme } from 'src/utilities/testHelpers'; + +import { CloudPulseTagsSelect } from './CloudPulseTagsFilter'; + +import type { useTagsQuery } from 'src/queries/cloudpulse/tags'; + +const queryMocks = vi.hoisted(() => ({ + useTagsQuery: vi.fn().mockReturnValue({}), +})); + +vi.mock('src/queries/cloudpulse/tags', async () => { + const actual = await vi.importActual('src/queries/cloudpulse/tags'); + return { + ...actual, + useTagsQuery: queryMocks.useTagsQuery, + }; +}); + +const mockTagsHandler = vi.fn(); +const SELECT_ALL = 'Select All'; +const ARIA_SELECTED = 'aria-selected'; + +describe('CloudPulseTagsSelect component tests', () => { + beforeEach(() => { + tagFactory.resetSequenceNumber(); + }); + + it('should render a tags select component', () => { + queryMocks.useTagsQuery.mockReturnValue({ + data: tagFactory.buildList(2), + isError: false, + isLoading: false, + status: 'success', + }); + const { getByPlaceholderText, getByTestId } = renderWithTheme( + + ); + expect(getByTestId('tags-select')).toBeInTheDocument(); + expect(screen.getByLabelText('Tags')).toBeInTheDocument(); + expect(getByPlaceholderText('Select Tags')).toBeInTheDocument(); + }); + + it('should render a Tags Select component with error message on api call failure', () => { + queryMocks.useTagsQuery.mockReturnValue({ + data: undefined, + isError: true, + isLoading: false, + } as ReturnType); + const { getByText } = renderWithTheme( + + ); + + expect(getByText('Failed to fetch Tags.')); + }); + + it('should select multiple tags', async () => { + const user = userEvent.setup(); + + queryMocks.useTagsQuery.mockReturnValue({ + data: tagFactory.buildList(3), + isError: false, + isLoading: false, + status: 'success', + }); + renderWithTheme( + + ); + await user.click(screen.getByRole('button', { name: 'Open' })); + await user.click(screen.getByRole('option', { name: 'tag-2' })); + await user.click(screen.getByRole('option', { name: 'tag-3' })); + expect(screen.getByLabelText('Tags')).toBeInTheDocument(); + + expect( + screen.getByRole('option', { + name: 'tag-2', + }) + ).toHaveAttribute(ARIA_SELECTED, 'true'); + expect( + screen.getByRole('option', { + name: 'tag-3', + }) + ).toHaveAttribute(ARIA_SELECTED, 'true'); + expect( + screen.getByRole('option', { + name: 'tag-4', + }) + ).toHaveAttribute(ARIA_SELECTED, 'false'); + }); + + it('should be able to deselect the selected tags', async () => { + const user = userEvent.setup(); + + queryMocks.useTagsQuery.mockReturnValue({ + data: tagFactory.buildList(2), + isError: false, + isLoading: false, + status: 'success', + }); + renderWithTheme( + + ); + await user.click(screen.getByRole('button', { name: 'Open' })); + await user.click(screen.getByRole('option', { name: SELECT_ALL })); + await user.click(screen.getByRole('option', { name: 'Deselect All' })); + expect(screen.getByLabelText('Tags')).toBeInTheDocument(); + expect( + screen.getByRole('option', { + name: 'tag-2', + }) + ).toHaveAttribute(ARIA_SELECTED, 'false'); + expect( + screen.getByRole('option', { + name: 'tag-3', + }) + ).toHaveAttribute(ARIA_SELECTED, 'false'); + }); + + it('Should select the default tags returned from preferences', async () => { + const user = userEvent.setup(); + queryMocks.useTagsQuery.mockReturnValue({ + data: tagFactory.buildList(2), + isError: false, + isLoading: false, + status: 'success', + }); + + renderWithTheme( + + ); + + expect( + screen.getByRole('button', { + name: 'tag-2', + }) + ).toBeInTheDocument(); + + await user.click(screen.getByRole('button', { name: 'Open' })); + + expect( + screen.getByRole('option', { + name: 'tag-3', + }) + ).toHaveAttribute(ARIA_SELECTED, 'false'); + }); +}); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseTagsFilter.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseTagsFilter.tsx new file mode 100644 index 00000000000..55fb2495884 --- /dev/null +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseTagsFilter.tsx @@ -0,0 +1,116 @@ +import { Autocomplete } from '@linode/ui'; +import React from 'react'; + +import { useTagsQuery } from 'src/queries/cloudpulse/tags'; +import { themes } from 'src/utilities/theme'; + +import type { FilterValue } from '@linode/api-v4'; + +export interface CloudPulseTags { + label: string; +} + +export interface CloudPulseTagsSelectProps { + defaultValue?: Partial; + disabled?: boolean; + handleTagsChange: (tags: CloudPulseTags[], savePref?: boolean) => void; + label: string; + placeholder?: string; + resourceType: string | undefined; + savePreferences?: boolean; +} + +export const CloudPulseTagsSelect = React.memo( + (props: CloudPulseTagsSelectProps) => { + const { + defaultValue, + disabled, + handleTagsChange, + label, + placeholder, + resourceType, + savePreferences, + } = props; + + const { data: tags, isError, isLoading } = useTagsQuery( + disabled !== undefined ? !disabled : Boolean(resourceType), + resourceType, + {} + ); + + const [selectedTags, setSelectedTags] = React.useState(); + + const isAutocompleteOpen = React.useRef(false); // Ref to track the open state of Autocomplete + + React.useEffect(() => { + if (tags && savePreferences && !selectedTags) { + const defaultTags = + defaultValue && Array.isArray(defaultValue) + ? defaultValue.map((tag) => String(tag)) + : []; + const tag = tags.filter((tag) => + defaultTags.includes(String(tag.label)) + ); + + handleTagsChange(tag); + setSelectedTags(tag); + } else { + if (selectedTags) { + setSelectedTags([]); + } + handleTagsChange([]); + } + + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [tags, resourceType]); + + return ( + { + setSelectedTags(tagSelections); + + if (!isAutocompleteOpen.current) { + handleTagsChange(tagSelections, savePreferences); + } + }} + onClose={() => { + isAutocompleteOpen.current = false; + handleTagsChange(selectedTags ?? [], savePreferences); + }} + onOpen={() => { + isAutocompleteOpen.current = true; + }} + textFieldProps={{ + InputProps: { + sx: { + '::-webkit-scrollbar': { + display: 'none', + }, + maxHeight: '55px', + msOverflowStyle: 'none', + overflow: 'auto', + scrollbarWidth: 'none', + svg: { + color: themes.light.color.grey3, + }, + }, + }, + }} + autoHighlight + clearOnBlur + data-testid="tags-select" + disabled={!resourceType} + errorText={isError ? `Failed to fetch ${label || 'Tags'}.` : ''} + label={label || 'Tags'} + limitTags={1} + loading={isLoading} + multiple + noMarginTop + options={tags ?? []} + placeholder={selectedTags?.length ? '' : placeholder || 'Select Tags'} + value={selectedTags ?? []} + /> + ); + }, + (prevProps, nextProps) => prevProps.resourceType === nextProps.resourceType +); diff --git a/packages/manager/src/mocks/serverHandlers.ts b/packages/manager/src/mocks/serverHandlers.ts index 88c33b8d5d8..8e3ad1da044 100644 --- a/packages/manager/src/mocks/serverHandlers.ts +++ b/packages/manager/src/mocks/serverHandlers.ts @@ -707,21 +707,32 @@ export const handlers = [ if (request.headers.get('x-filter')) { const headers = JSON.parse(request.headers.get('x-filter') || '{}'); const orFilters = headers['+or']; + const andFilters = headers['+and']; + + let filteredLinodes = linodes; // Default to the original linodes in case no filters are applied if (orFilters) { - const filteredLinodes = linodes.filter((linode) => { - const filteredById = orFilters.some( + filteredLinodes = filteredLinodes.filter((linode) => { + return orFilters.some((filter: { tags: string }) => + linode.tags.includes(filter.tags) + ); + }); + } + + if (andFilters) { + filteredLinodes = filteredLinodes.filter((linode) => { + const filteredById = andFilters.every( (filter: { id: number }) => filter.id === linode.id ); - const filteredByRegion = orFilters.some( + const filteredByRegion = andFilters.every( (filter: { region: string }) => filter.region === linode.region ); - return (filteredById || filteredByRegion) ?? linodes; + return filteredById || filteredByRegion; }); - - return HttpResponse.json(makeResourcePage(filteredLinodes)); } + + return HttpResponse.json(makeResourcePage(filteredLinodes)); } return HttpResponse.json(makeResourcePage(linodes)); }), diff --git a/packages/manager/src/queries/cloudpulse/resources.ts b/packages/manager/src/queries/cloudpulse/resources.ts index ee3b80b9aea..946db2d2291 100644 --- a/packages/manager/src/queries/cloudpulse/resources.ts +++ b/packages/manager/src/queries/cloudpulse/resources.ts @@ -2,14 +2,17 @@ import { useQuery } from '@tanstack/react-query'; import { queryFactory } from './queries'; -import type { Filter, Params } from '@linode/api-v4'; -import type { CloudPulseResources } from 'src/features/CloudPulse/shared/CloudPulseResourcesSelect'; +import type { Params } from '@linode/api-v4'; +import type { + CloudPulseResources, + ExtendedFilter, +} from 'src/features/CloudPulse/shared/CloudPulseResourcesSelect'; export const useResourcesQuery = ( enabled = false, resourceType: string | undefined, params?: Params, - filters?: Filter + filters?: ExtendedFilter ) => useQuery({ ...queryFactory.resources(resourceType, params, filters), diff --git a/packages/manager/src/queries/cloudpulse/tags.ts b/packages/manager/src/queries/cloudpulse/tags.ts new file mode 100644 index 00000000000..d08e2757abc --- /dev/null +++ b/packages/manager/src/queries/cloudpulse/tags.ts @@ -0,0 +1,23 @@ +import { useQuery } from '@tanstack/react-query'; + +import { queryFactory } from './queries'; + +import type { APIError, Filter, Params } from '@linode/api-v4'; +import type { CloudPulseTags } from 'src/features/CloudPulse/shared/CloudPulseTagsFilter'; + +export const useTagsQuery = ( + enabled = false, + resourceType: string | undefined, + params?: Params, + filters?: Filter +) => + useQuery({ + ...queryFactory.resources(resourceType, params, filters), + enabled, + select: (resources) => { + const uniqueTags = new Set( + resources.flatMap((resource) => resource.tags) + ); + return Array.from(uniqueTags).map((tag) => ({ label: tag })); + }, + }); From 85374cd29f78bc08d1e1612c9081bb018bfe30a3 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Wed, 11 Dec 2024 15:29:30 +0530 Subject: [PATCH 409/474] upcoming: [DI-20935] - updated mocks --- packages/manager/src/mocks/serverHandlers.ts | 23 ++++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/packages/manager/src/mocks/serverHandlers.ts b/packages/manager/src/mocks/serverHandlers.ts index 8e3ad1da044..3d6b8889e57 100644 --- a/packages/manager/src/mocks/serverHandlers.ts +++ b/packages/manager/src/mocks/serverHandlers.ts @@ -691,6 +691,11 @@ export const handlers = [ tags: ['test1', 'test2', 'test3'], type: 'g5-standard-20-s1', }), + linodeFactory.build({ + // eslint-disable-next-line sonarjs/no-duplicate-string + region: 'us-central', + tags: ['test2'], + }), linodeFactory.build({ label: 'eu-linode', region: 'eu-west', @@ -711,15 +716,7 @@ export const handlers = [ let filteredLinodes = linodes; // Default to the original linodes in case no filters are applied - if (orFilters) { - filteredLinodes = filteredLinodes.filter((linode) => { - return orFilters.some((filter: { tags: string }) => - linode.tags.includes(filter.tags) - ); - }); - } - - if (andFilters) { + if (andFilters?.length) { filteredLinodes = filteredLinodes.filter((linode) => { const filteredById = andFilters.every( (filter: { id: number }) => filter.id === linode.id @@ -732,6 +729,14 @@ export const handlers = [ }); } + if (orFilters?.length) { + filteredLinodes = filteredLinodes.filter((linode) => { + return orFilters.some((filter: { tags: string }) => + linode.tags.includes(filter.tags) + ); + }); + } + return HttpResponse.json(makeResourcePage(filteredLinodes)); } return HttpResponse.json(makeResourcePage(linodes)); From 259a6b4a53660fc1e53540eab43e5a5333f1c8eb Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Wed, 11 Dec 2024 16:02:34 +0530 Subject: [PATCH 410/474] upcoming: [DI-20935] - updated UTs --- .../CloudPulse/Utils/FilterBuilder.test.ts | 13 +++++++++---- .../shared/CloudPulseRegionSelect.test.tsx | 4 ++-- .../shared/CloudPulseResourcesSelect.test.tsx | 14 +++++++------- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.test.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.test.ts index 66f1ca06ce9..3724ffc6e40 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.test.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.test.ts @@ -104,7 +104,9 @@ it('test getResourceSelectionProperties method', () => { expect(handleResourcesSelection).toBeDefined(); expect(savePreferences).toEqual(false); expect(disabled).toEqual(false); - expect(JSON.stringify(xFilter)).toEqual('{"+and":[{"region":"us-east"}]}'); + expect(JSON.stringify(xFilter)).toEqual( + '{"+and":[{"region":"us-east"}],"+or":[]}' + ); expect(label).toEqual(name); } }); @@ -136,7 +138,7 @@ it('test getResourceSelectionProperties method with disabled true', () => { expect(handleResourcesSelection).toBeDefined(); expect(savePreferences).toEqual(false); expect(disabled).toEqual(true); - expect(JSON.stringify(xFilter)).toEqual('{"+and":[]}'); + expect(JSON.stringify(xFilter)).toEqual('{"+and":[],"+or":[]}'); expect(label).toEqual(name); } }); @@ -177,13 +179,16 @@ it('test buildXfilter method', () => { if (resourceSelectionConfig) { let result = buildXFilter(resourceSelectionConfig, { region: 'us-east', + tags: ['test1'], }); - expect(JSON.stringify(result)).toEqual('{"+and":[{"region":"us-east"}]}'); + expect(JSON.stringify(result)).toEqual( + '{"+and":[{"region":"us-east"}],"+or":[{"tags":"test1"}]}' + ); result = buildXFilter(resourceSelectionConfig, {}); - expect(JSON.stringify(result)).toEqual('{"+and":[]}'); + expect(JSON.stringify(result)).toEqual('{"+and":[],"+or":[]}'); } }); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx index 3a47701db75..f5f2e2ab398 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.test.tsx @@ -48,8 +48,8 @@ describe('CloudPulseRegionSelect', () => { const { getByLabelText, getByTestId } = renderWithTheme( ); - const { label } = props; - expect(getByLabelText(label)).toBeInTheDocument(); + + expect(getByLabelText('Region (required)')).toBeInTheDocument(); expect(getByTestId('region-select')).toBeInTheDocument(); }); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx index d6dc9f0c9e5..3f12df66b3e 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx @@ -41,7 +41,7 @@ describe('CloudPulseResourcesSelect component tests', () => { /> ); expect(getByTestId('resource-select')).toBeInTheDocument(); - expect(screen.getByLabelText('Resources')).toBeInTheDocument(); + expect(screen.getByLabelText('Resources (required)')).toBeInTheDocument(); expect(getByPlaceholderText('Select Resources')).toBeInTheDocument(); }), it('should render resources happy path', () => { @@ -60,7 +60,7 @@ describe('CloudPulseResourcesSelect component tests', () => { /> ); fireEvent.click(screen.getByRole('button', { name: 'Open' })); - expect(screen.getByLabelText('Resources')).toBeInTheDocument(); + expect(screen.getByLabelText('Resources (required)')).toBeInTheDocument(); expect( screen.getByRole('option', { name: 'linode-3', @@ -89,7 +89,7 @@ describe('CloudPulseResourcesSelect component tests', () => { ); fireEvent.click(screen.getByRole('button', { name: 'Open' })); fireEvent.click(screen.getByRole('option', { name: SELECT_ALL })); - expect(screen.getByLabelText('Resources')).toBeInTheDocument(); + expect(screen.getByLabelText('Resources (required)')).toBeInTheDocument(); expect( screen.getByRole('option', { name: 'linode-5', @@ -120,7 +120,7 @@ describe('CloudPulseResourcesSelect component tests', () => { fireEvent.click(screen.getByRole('button', { name: 'Open' })); fireEvent.click(screen.getByRole('option', { name: SELECT_ALL })); fireEvent.click(screen.getByRole('option', { name: 'Deselect All' })); - expect(screen.getByLabelText('Resources')).toBeInTheDocument(); + expect(screen.getByLabelText('Resources (required)')).toBeInTheDocument(); expect( screen.getByRole('option', { name: 'linode-7', @@ -151,7 +151,7 @@ describe('CloudPulseResourcesSelect component tests', () => { fireEvent.click(screen.getByRole('button', { name: 'Open' })); fireEvent.click(screen.getByRole('option', { name: 'linode-9' })); fireEvent.click(screen.getByRole('option', { name: 'linode-10' })); - expect(screen.getByLabelText('Resources')).toBeInTheDocument(); + expect(screen.getByLabelText('Resources (required)')).toBeInTheDocument(); expect( screen.getByRole('option', { @@ -275,7 +275,7 @@ describe('CloudPulseResourcesSelect component tests', () => { await user.click(screen.getByRole('button', { name: 'Open' })); - expect(screen.getByLabelText('Resources')).toBeInTheDocument(); + expect(screen.getByLabelText('Resources (required)')).toBeInTheDocument(); expect(screen.getByText('Select up to 10 Resources')).toBeInTheDocument(); for (let i = 14; i <= 23; i++) { @@ -322,7 +322,7 @@ describe('CloudPulseResourcesSelect component tests', () => { await user.click(screen.getByRole('option', { name: SELECT_ALL })); await user.click(screen.getByRole('option', { name: 'Deselect All' })); - expect(screen.getByLabelText('Resources')).toBeInTheDocument(); + expect(screen.getByLabelText('Resources (required)')).toBeInTheDocument(); for (let i = 26; i <= 35; i++) { expect( From 685f27ec56205e6c9ecedd7c6d1ce327852d38e5 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Wed, 11 Dec 2024 16:23:05 +0530 Subject: [PATCH 411/474] upcoming: [DI-20935] - small fix --- .../features/CloudPulse/shared/CloudPulseResourcesSelect.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index b9ef89d35ac..2f5cb3168f7 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -58,7 +58,7 @@ export const CloudPulseResourcesSelect = React.memo( const flags = useFlags(); - const resourceFilterMap: Record = { + const resourceFilterMap: Record = { dbaas: { '+order': 'asc', '+order_by': 'label', platform: 'rdbms-default' }, }; From 07ee64a43737728f640b05f37760774eb2bb6d3e Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Wed, 11 Dec 2024 16:46:02 +0530 Subject: [PATCH 412/474] upcoming: [DI-20935] - small fix --- packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts | 2 +- .../features/CloudPulse/Utils/ReusableDashboardFilterUtils.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts index 960f19f5367..3d82d5788e6 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts @@ -328,7 +328,7 @@ export const checkIfAllMandatoryFiltersAreSelected = ( } const mandatoryFilters = serviceTypeConfig.filters.filter( - (filter) => filter.configuration.filterKey !== TAGS + (filter) => !filter.configuration.isOptional ); return mandatoryFilters.every((filter) => { const filterKey = filter.configuration.filterKey; diff --git a/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.ts b/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.ts index 3de4d309a12..7514723d70d 100644 --- a/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.ts @@ -68,7 +68,7 @@ export const checkMandatoryFiltersSelected = ( } const mandatoryFilters = serviceTypeConfig.filters.filter( - (filter) => filter.configuration.filterKey !== TAGS + (filter) => !filter.configuration.isOptional ); return mandatoryFilters.every(({ configuration }) => { const { filterKey, neededInServicePage } = configuration; From 7edd0997f336a82a67b1927b6663fa412a034e86 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Thu, 12 Dec 2024 11:31:17 +0530 Subject: [PATCH 413/474] upcoming: [DI-20935] - add required field for custom select, update UT --- .../Utils/ReusableDashboardFilterUtils.ts | 1 - .../shared/CloudPulseCustomSelect.test.tsx | 10 ++++++---- .../CloudPulse/shared/CloudPulseCustomSelect.tsx | 3 +++ .../shared/CloudPulseResourcesSelect.test.tsx | 15 ++++++++------- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.ts b/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.ts index 7514723d70d..8f8d5d2d98c 100644 --- a/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.ts +++ b/packages/manager/src/features/CloudPulse/Utils/ReusableDashboardFilterUtils.ts @@ -1,4 +1,3 @@ -import { TAGS } from './constants'; import { FILTER_CONFIG } from './FilterConfig'; import type { DashboardProperties } from '../Dashboard/CloudPulseDashboard'; diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.test.tsx index 59f92338cf9..b8dc68ca117 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.test.tsx @@ -20,6 +20,8 @@ const mockOptions: CloudPulseServiceTypeFiltersOptions[] = [ }, ]; +const LABEL_SUBTITLE = 'Test (required)'; + const queryMocks = vi.hoisted(() => ({ useGetCustomFiltersQuery: vi.fn().mockReturnValue({ data: [ @@ -63,7 +65,7 @@ describe('CloudPulseCustomSelect component tests', () => { /> ); expect(screen.queryByPlaceholderText(testFilter)).toBeNull(); - expect(screen.getByLabelText('Test')).toBeInTheDocument(); + expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); const keyDown = screen.getByTestId(keyboardArrowDownIcon); fireEvent.click(keyDown); fireEvent.click(screen.getByText('Test1')); @@ -85,7 +87,7 @@ describe('CloudPulseCustomSelect component tests', () => { /> ); expect(screen.queryByPlaceholderText(testFilter)).toBeNull(); - expect(screen.getByLabelText('CustomTest')).toBeInTheDocument(); + expect(screen.getByLabelText('CustomTest (required)')).toBeInTheDocument(); const keyDown = screen.getByTestId(keyboardArrowDownIcon); fireEvent.click(keyDown); expect(screen.getAllByText('Test1').length).toEqual(2); // here it should be 2 @@ -115,7 +117,7 @@ describe('CloudPulseCustomSelect component tests', () => { /> ); expect(screen.queryByPlaceholderText(testFilter)).toBeNull(); - expect(screen.getByLabelText('Test')).toBeInTheDocument(); + expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); const keyDown = screen.getByTestId(keyboardArrowDownIcon); fireEvent.click(keyDown); fireEvent.click(screen.getByText('Test1')); @@ -143,7 +145,7 @@ describe('CloudPulseCustomSelect component tests', () => { /> ); expect(screen.queryByPlaceholderText(testFilter)).toBeNull(); - expect(screen.getByLabelText('Test')).toBeInTheDocument(); + expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); const keyDown = screen.getByTestId(keyboardArrowDownIcon); fireEvent.click(keyDown); expect(screen.getAllByText('Test1').length).toEqual(2); // here it should be 2 diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index a68af932c17..32381df088d 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -237,6 +237,9 @@ export const CloudPulseCustomSelect = React.memo( placement: 'bottom', }, }} + textFieldProps={{ + required: true, + }} autoHighlight disabled={isAutoCompleteDisabled} errorText={staticErrorText} diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx index 3f12df66b3e..8565549a72e 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx @@ -23,6 +23,7 @@ const mockResourceHandler = vi.fn(); const SELECT_ALL = 'Select All'; const ARIA_SELECTED = 'aria-selected'; const ARIA_DISABLED = 'aria-disabled'; +const LABEL_SUBTITLE = 'Resources (required)'; describe('CloudPulseResourcesSelect component tests', () => { it('should render disabled component if the the props are undefined or regions and service type does not have any resources', () => { @@ -41,7 +42,7 @@ describe('CloudPulseResourcesSelect component tests', () => { /> ); expect(getByTestId('resource-select')).toBeInTheDocument(); - expect(screen.getByLabelText('Resources (required)')).toBeInTheDocument(); + expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); expect(getByPlaceholderText('Select Resources')).toBeInTheDocument(); }), it('should render resources happy path', () => { @@ -60,7 +61,7 @@ describe('CloudPulseResourcesSelect component tests', () => { /> ); fireEvent.click(screen.getByRole('button', { name: 'Open' })); - expect(screen.getByLabelText('Resources (required)')).toBeInTheDocument(); + expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); expect( screen.getByRole('option', { name: 'linode-3', @@ -89,7 +90,7 @@ describe('CloudPulseResourcesSelect component tests', () => { ); fireEvent.click(screen.getByRole('button', { name: 'Open' })); fireEvent.click(screen.getByRole('option', { name: SELECT_ALL })); - expect(screen.getByLabelText('Resources (required)')).toBeInTheDocument(); + expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); expect( screen.getByRole('option', { name: 'linode-5', @@ -120,7 +121,7 @@ describe('CloudPulseResourcesSelect component tests', () => { fireEvent.click(screen.getByRole('button', { name: 'Open' })); fireEvent.click(screen.getByRole('option', { name: SELECT_ALL })); fireEvent.click(screen.getByRole('option', { name: 'Deselect All' })); - expect(screen.getByLabelText('Resources (required)')).toBeInTheDocument(); + expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); expect( screen.getByRole('option', { name: 'linode-7', @@ -151,7 +152,7 @@ describe('CloudPulseResourcesSelect component tests', () => { fireEvent.click(screen.getByRole('button', { name: 'Open' })); fireEvent.click(screen.getByRole('option', { name: 'linode-9' })); fireEvent.click(screen.getByRole('option', { name: 'linode-10' })); - expect(screen.getByLabelText('Resources (required)')).toBeInTheDocument(); + expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); expect( screen.getByRole('option', { @@ -275,7 +276,7 @@ describe('CloudPulseResourcesSelect component tests', () => { await user.click(screen.getByRole('button', { name: 'Open' })); - expect(screen.getByLabelText('Resources (required)')).toBeInTheDocument(); + expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); expect(screen.getByText('Select up to 10 Resources')).toBeInTheDocument(); for (let i = 14; i <= 23; i++) { @@ -322,7 +323,7 @@ describe('CloudPulseResourcesSelect component tests', () => { await user.click(screen.getByRole('option', { name: SELECT_ALL })); await user.click(screen.getByRole('option', { name: 'Deselect All' })); - expect(screen.getByLabelText('Resources (required)')).toBeInTheDocument(); + expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); for (let i = 26; i <= 35; i++) { expect( From 6498045d5d3e3ddafc541776bad88468fd82a8cd Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Fri, 13 Dec 2024 09:41:07 +0530 Subject: [PATCH 414/474] upcoming: [DI-20935] - PR comments --- .../features/CloudPulse/Utils/FilterBuilder.ts | 5 ++++- .../src/features/CloudPulse/Utils/models.ts | 4 ++++ .../shared/CloudPulseCustomSelect.test.tsx | 10 ++++------ .../CloudPulse/shared/CloudPulseCustomSelect.tsx | 9 ++++++++- .../CloudPulse/shared/CloudPulseRegionSelect.tsx | 4 +--- .../shared/CloudPulseResourcesSelect.test.tsx | 15 +++++++-------- .../shared/CloudPulseResourcesSelect.tsx | 6 ++++-- 7 files changed, 32 insertions(+), 21 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts index 3d82d5788e6..b1c2fe466ea 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts @@ -136,9 +136,10 @@ export const getResourcesProperties = ( handleResourcesSelection: handleResourceChange, label, placeholder, + required: true, resourceType: dashboard.service_type, savePreferences: !isServiceAnalyticsIntegration, - xFilter: buildXFilter(config, dependentFilters ?? {}), + xFilter: buildXFilter(config, dependentFilters ?? {}) }; }; @@ -168,6 +169,7 @@ export const getCustomSelectProperties = ( name: label, options, placeholder, + required, } = props.config.configuration; const { dashboard, @@ -198,6 +200,7 @@ export const getCustomSelectProperties = ( options, placeholder, preferences, + required: true, savePreferences: !isServiceAnalyticsIntegration, type: options ? CloudPulseSelectTypes.static diff --git a/packages/manager/src/features/CloudPulse/Utils/models.ts b/packages/manager/src/features/CloudPulse/Utils/models.ts index 9a7c0300689..04a467733d9 100644 --- a/packages/manager/src/features/CloudPulse/Utils/models.ts +++ b/packages/manager/src/features/CloudPulse/Utils/models.ts @@ -149,6 +149,10 @@ export interface CloudPulseServiceTypeFiltersConfiguration { * This controls the order of rendering the filtering componenents */ priority: number; + /** + * This adds a subtitle after label if input is required + */ + required?: boolean; /** * default is predefined filters like (region, resources, timeduration) or dynamic / static */ diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.test.tsx index b8dc68ca117..59f92338cf9 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.test.tsx @@ -20,8 +20,6 @@ const mockOptions: CloudPulseServiceTypeFiltersOptions[] = [ }, ]; -const LABEL_SUBTITLE = 'Test (required)'; - const queryMocks = vi.hoisted(() => ({ useGetCustomFiltersQuery: vi.fn().mockReturnValue({ data: [ @@ -65,7 +63,7 @@ describe('CloudPulseCustomSelect component tests', () => { /> ); expect(screen.queryByPlaceholderText(testFilter)).toBeNull(); - expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); + expect(screen.getByLabelText('Test')).toBeInTheDocument(); const keyDown = screen.getByTestId(keyboardArrowDownIcon); fireEvent.click(keyDown); fireEvent.click(screen.getByText('Test1')); @@ -87,7 +85,7 @@ describe('CloudPulseCustomSelect component tests', () => { /> ); expect(screen.queryByPlaceholderText(testFilter)).toBeNull(); - expect(screen.getByLabelText('CustomTest (required)')).toBeInTheDocument(); + expect(screen.getByLabelText('CustomTest')).toBeInTheDocument(); const keyDown = screen.getByTestId(keyboardArrowDownIcon); fireEvent.click(keyDown); expect(screen.getAllByText('Test1').length).toEqual(2); // here it should be 2 @@ -117,7 +115,7 @@ describe('CloudPulseCustomSelect component tests', () => { /> ); expect(screen.queryByPlaceholderText(testFilter)).toBeNull(); - expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); + expect(screen.getByLabelText('Test')).toBeInTheDocument(); const keyDown = screen.getByTestId(keyboardArrowDownIcon); fireEvent.click(keyDown); fireEvent.click(screen.getByText('Test1')); @@ -145,7 +143,7 @@ describe('CloudPulseCustomSelect component tests', () => { /> ); expect(screen.queryByPlaceholderText(testFilter)).toBeNull(); - expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); + expect(screen.getByLabelText('Test')).toBeInTheDocument(); const keyDown = screen.getByTestId(keyboardArrowDownIcon); fireEvent.click(keyDown); expect(screen.getAllByText('Test1').length).toEqual(2); // here it should be 2 diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index 32381df088d..9c258cb574a 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -102,6 +102,10 @@ export interface CloudPulseCustomSelectProps { preferences?: AclpConfig; + /** + * This adds a subtitle after label if input is required + */ + required?: boolean; /** * This property controls whether to save the preferences or not */ @@ -135,6 +139,7 @@ export const CloudPulseCustomSelect = React.memo( options, placeholder, preferences, + required, savePreferences, type, } = props; @@ -238,7 +243,9 @@ export const CloudPulseCustomSelect = React.memo( }, }} textFieldProps={{ - required: true, + InputProps: { + required, + }, }} autoHighlight disabled={isAutoCompleteDisabled} diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx index 0f586dba2cc..e906fc15e75 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseRegionSelect.tsx @@ -88,9 +88,6 @@ export const CloudPulseRegionSelect = React.memo( savePreferences ); }} - textFieldProps={{ - required: true, - }} currentCapability={capability} data-testid="region-select" disableClearable={false} @@ -102,6 +99,7 @@ export const CloudPulseRegionSelect = React.memo( noMarginTop placeholder={placeholder ?? 'Select a Region'} regions={supportedRegions ?? []} + required value={selectedRegion} /> ); diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx index 8565549a72e..d6dc9f0c9e5 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx @@ -23,7 +23,6 @@ const mockResourceHandler = vi.fn(); const SELECT_ALL = 'Select All'; const ARIA_SELECTED = 'aria-selected'; const ARIA_DISABLED = 'aria-disabled'; -const LABEL_SUBTITLE = 'Resources (required)'; describe('CloudPulseResourcesSelect component tests', () => { it('should render disabled component if the the props are undefined or regions and service type does not have any resources', () => { @@ -42,7 +41,7 @@ describe('CloudPulseResourcesSelect component tests', () => { /> ); expect(getByTestId('resource-select')).toBeInTheDocument(); - expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); + expect(screen.getByLabelText('Resources')).toBeInTheDocument(); expect(getByPlaceholderText('Select Resources')).toBeInTheDocument(); }), it('should render resources happy path', () => { @@ -61,7 +60,7 @@ describe('CloudPulseResourcesSelect component tests', () => { /> ); fireEvent.click(screen.getByRole('button', { name: 'Open' })); - expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); + expect(screen.getByLabelText('Resources')).toBeInTheDocument(); expect( screen.getByRole('option', { name: 'linode-3', @@ -90,7 +89,7 @@ describe('CloudPulseResourcesSelect component tests', () => { ); fireEvent.click(screen.getByRole('button', { name: 'Open' })); fireEvent.click(screen.getByRole('option', { name: SELECT_ALL })); - expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); + expect(screen.getByLabelText('Resources')).toBeInTheDocument(); expect( screen.getByRole('option', { name: 'linode-5', @@ -121,7 +120,7 @@ describe('CloudPulseResourcesSelect component tests', () => { fireEvent.click(screen.getByRole('button', { name: 'Open' })); fireEvent.click(screen.getByRole('option', { name: SELECT_ALL })); fireEvent.click(screen.getByRole('option', { name: 'Deselect All' })); - expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); + expect(screen.getByLabelText('Resources')).toBeInTheDocument(); expect( screen.getByRole('option', { name: 'linode-7', @@ -152,7 +151,7 @@ describe('CloudPulseResourcesSelect component tests', () => { fireEvent.click(screen.getByRole('button', { name: 'Open' })); fireEvent.click(screen.getByRole('option', { name: 'linode-9' })); fireEvent.click(screen.getByRole('option', { name: 'linode-10' })); - expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); + expect(screen.getByLabelText('Resources')).toBeInTheDocument(); expect( screen.getByRole('option', { @@ -276,7 +275,7 @@ describe('CloudPulseResourcesSelect component tests', () => { await user.click(screen.getByRole('button', { name: 'Open' })); - expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); + expect(screen.getByLabelText('Resources')).toBeInTheDocument(); expect(screen.getByText('Select up to 10 Resources')).toBeInTheDocument(); for (let i = 14; i <= 23; i++) { @@ -323,7 +322,7 @@ describe('CloudPulseResourcesSelect component tests', () => { await user.click(screen.getByRole('option', { name: SELECT_ALL })); await user.click(screen.getByRole('option', { name: 'Deselect All' })); - expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); + expect(screen.getByLabelText('Resources')).toBeInTheDocument(); for (let i = 26; i <= 35; i++) { expect( diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx index 2f5cb3168f7..318eb475977 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.tsx @@ -35,6 +35,7 @@ export interface CloudPulseResourcesSelectProps { label: string; placeholder?: string; region?: string; + required?: boolean; resourceType: string | undefined; savePreferences?: boolean; tags?: string[]; @@ -50,10 +51,11 @@ export const CloudPulseResourcesSelect = React.memo( label, placeholder, region, + required, resourceType, savePreferences, tags, - xFilter, + xFilter } = props; const flags = useFlags(); @@ -186,6 +188,7 @@ export const CloudPulseResourcesSelect = React.memo( }} textFieldProps={{ InputProps: { + required, sx: { '::-webkit-scrollbar': { display: 'none', @@ -199,7 +202,6 @@ export const CloudPulseResourcesSelect = React.memo( }, }, }, - required: true, }} autoHighlight clearOnBlur From 53642aa851fea124f423db45e3ff17ddfd0e8247 Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Fri, 13 Dec 2024 09:53:32 +0530 Subject: [PATCH 415/474] upcoming: [DI-20935] - PR comments --- .../manager/src/features/CloudPulse/Utils/FilterBuilder.ts | 2 +- packages/manager/src/features/CloudPulse/Utils/models.ts | 6 +----- .../features/CloudPulse/shared/CloudPulseCustomSelect.tsx | 1 + .../CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx | 7 ++++--- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts index b1c2fe466ea..dfc4ef96927 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts @@ -299,7 +299,7 @@ export const checkIfWeNeedToDisableFilterByFilterKey = ( return filter.configuration.dependency?.some((dependent) => { const dependentFilter = dependentFilters[dependent]; const optionalFilter = filters.find( - (filter) => filter.configuration.isOptional === true + (filter) => filter.configuration.isOptional )?.configuration.filterKey; return ( diff --git a/packages/manager/src/features/CloudPulse/Utils/models.ts b/packages/manager/src/features/CloudPulse/Utils/models.ts index 04a467733d9..f553882ea99 100644 --- a/packages/manager/src/features/CloudPulse/Utils/models.ts +++ b/packages/manager/src/features/CloudPulse/Utils/models.ts @@ -121,7 +121,7 @@ export interface CloudPulseServiceTypeFiltersConfiguration { isMultiSelect?: boolean; /** - * If this is true, we will pass tags as an optional filter + * If this is true, we will pass filter as an optional filter */ isOptional?: boolean; @@ -149,10 +149,6 @@ export interface CloudPulseServiceTypeFiltersConfiguration { * This controls the order of rendering the filtering componenents */ priority: number; - /** - * This adds a subtitle after label if input is required - */ - required?: boolean; /** * default is predefined filters like (region, resources, timeduration) or dynamic / static */ diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx index 9c258cb574a..33c2ec0f944 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.tsx @@ -106,6 +106,7 @@ export interface CloudPulseCustomSelectProps { * This adds a subtitle after label if input is required */ required?: boolean; + /** * This property controls whether to save the preferences or not */ diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index 8ed14da9083..f878ff5099f 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -131,13 +131,14 @@ export const CloudPulseDashboardFilterBuilder = React.memo( const handleTagsChange = React.useCallback( (tags: CloudPulseTags[], savePref: boolean = false) => { + const selectedTags = tags.map((tag) => tag.label); emitFilterChangeByFilterKey( TAGS, - tags.map((tag) => tag.label), - tags.map((tag) => tag.label), + selectedTags, + selectedTags, savePref, { - [TAGS]: tags.map((tag: { label: string }) => String(tag.label)), + [TAGS]: selectedTags, } ); }, From 6d3057bb0952542e8d495a6026e36d0933e59edb Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Fri, 13 Dec 2024 10:22:43 +0530 Subject: [PATCH 416/474] upcoming: [DI-20935] - small fix --- packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts index dfc4ef96927..c488a9c8cba 100644 --- a/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts +++ b/packages/manager/src/features/CloudPulse/Utils/FilterBuilder.ts @@ -169,7 +169,6 @@ export const getCustomSelectProperties = ( name: label, options, placeholder, - required, } = props.config.configuration; const { dashboard, From 3308085742aa5c521dffebe9abff47a73f7c345d Mon Sep 17 00:00:00 2001 From: agorthi Date: Fri, 13 Dec 2024 12:41:22 +0530 Subject: [PATCH 417/474] DI-2189:Cypress E2E automations for Max limit on resource selection and minior validation changes in applied filters --- .../cloudpulse-applied-filters.spec.ts | 51 ++- .../cloudpulse-resource-limit.spec.ts | 290 ++++++++++++++++++ 2 files changed, 332 insertions(+), 9 deletions(-) create mode 100644 packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-resource-limit.spec.ts diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-applied-filters.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-applied-filters.spec.ts index ca6dd36d107..1340b329893 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-applied-filters.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-applied-filters.spec.ts @@ -189,9 +189,20 @@ describe('Integration Tests for Applied Filters', () => { cy.get('[data-testid="applied-filter"]').within(() => { cy.get(`[data-qa-value="Database Engine ${engine}"]`) - cy.get(`[data-qa-value="Region US, Chicago, IL"]`) - cy.get(`[data-qa-value="Node Type ${nodeType}"]`) - cy.get(`[data-qa-value="Database Clusters ${databaseMock.label}"]`) + .should('be.visible') + .should('have.text', engine); + + cy.get(`[data-qa-value="Region US, Chicago, IL"]`) + .should('be.visible') + .should('have.text', 'US, Chicago, IL'); + + cy.get(`[data-qa-value="Node Type ${nodeType}"]`) + .should('be.visible') + .should('have.text', nodeType); + + cy.get(`[data-qa-value="Database Clusters ${clusterName}"]`) + .should('be.visible') + .should('have.text', clusterName); }); }); @@ -214,7 +225,9 @@ describe('Integration Tests for Applied Filters', () => { //Collapse the Filters section ui.button.findByTitle('Filters').should('be.visible').click(); cy.get('[data-testid="applied-filter"]').within(() => { - cy.get(`[data-qa-value="Database Engine ${engine}"]`) + cy.get(`[data-qa-value="Database Engine ${engine}"]`) + .should('be.visible') + .should('have.text', engine); }); }); @@ -229,7 +242,9 @@ describe('Integration Tests for Applied Filters', () => { //Collapse the Filters section ui.button.findByTitle('Filters').should('be.visible').click(); cy.get('[data-testid="applied-filter"]').within(() => { - cy.get(`[data-qa-value="Region US, Chicago, IL"]`) + cy.get(`[data-qa-value="Region US, Chicago, IL"]`) + .should('be.visible') + .should('have.text', 'US, Chicago, IL'); }); }); @@ -242,8 +257,11 @@ describe('Integration Tests for Applied Filters', () => { //Collapse the Filters section ui.button.findByTitle('Filters').should('be.visible').click(); + cy.get('[data-testid="applied-filter"]').within(() => { cy.get(`[data-qa-value="Node Type ${nodeType}"]`) + .should('be.visible') + .should('have.text', nodeType); }); }); it('should update and verify that the applied global filters are reflected in the filter section', () => { @@ -283,11 +301,26 @@ describe('Integration Tests for Applied Filters', () => { //Collapse the Filters section ui.button.findByTitle('Filters').should('be.visible').click(); cy.get('[data-testid="applied-filter"]').within(() => { - cy.get(`[data-qa-value="Database Engine PostgreSQL"]`) + cy.get(`[data-qa-value="Database Engine ${'PostgreSQL'}"]`) + .should('be.visible') + .should('have.text', 'PostgreSQL'); + cy.get(`[data-qa-value="Region US, Chicago, IL"]`) - cy.get(`[data-qa-value="Node Type Primary"]`) - cy.get(`[data-qa-value="Database Clusters ${databaseMock.label}"]`) - cy.get(`[data-qa-value="Database Clusters ${extendDatabaseMock.label}"]`) + .should('be.visible') + .should('have.text', 'US, Chicago, IL'); + + cy.get(`[data-qa-value="Node Type ${'Primary'}"]`) + .should('be.visible') + .should('have.text', 'Primary'); + + cy.get(`[data-qa-value="Database Clusters ${clusterName}"]`) + .should('be.visible') + .should('have.text', clusterName); + + cy.get(`[data-qa-value="Database Clusters ${extendDatabaseMock.label}"]`) + .should('be.visible') + .should('have.text', extendDatabaseMock.label); + }); }); }); diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-resource-limit.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-resource-limit.spec.ts new file mode 100644 index 00000000000..d1237477163 --- /dev/null +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-resource-limit.spec.ts @@ -0,0 +1,290 @@ +/** + * This test suite validates the behavior of the DBaaS (Database as a Service) Dashboard, + * specifically focusing on how the system handles the maximum resource selection limit + * for database clusters. It contains two main test cases: + * + * Ticket: DI-21897 + * + * 1. **Max Resource Limit Reached**: + * - Verifies that when the maximum number of database clusters (1) is selected, + * the "Select All" option is hidden and only the available clusters (up to the limit) + * are shown in the `Database Clusters` dropdown. + * - Ensures that when a region is selected, the `Database Clusters` dropdown is enabled + * and shows the appropriate helper text indicating the selection limit. + * - Ensures that any additional clusters beyond the limit are disabled in the dropdown. + * + * 2. **Max Resource Limit Not Reached**: + * - Tests the behavior when the maximum selection limit is not reached (e.g., 10 clusters). + * - Confirms that the "Select All" option appears in the dropdown when multiple clusters + * are available and the user can select multiple clusters. + * + * These tests ensure that the user interface correctly enforces selection limits, provides + * accurate feedback through helper text, and prevents exceeding the resource limits, + * thereby validating the system's correctness and user experience. + */ + +import { mockAppendFeatureFlags } from 'support/intercepts/feature-flags'; +import {mockGetCloudPulseDashboard,mockGetCloudPulseDashboards,mockGetCloudPulseServices, +} from 'support/intercepts/cloudpulse'; +import { ui } from 'support/ui'; +import { widgetDetails } from 'support/constants/widgets'; +import {accountFactory,dashboardFactory, databaseFactory,regionFactory,widgetFactory, +} from 'src/factories'; +import { mockGetAccount } from 'support/intercepts/account'; +import { mockGetUserPreferences } from 'support/intercepts/profile'; +import { mockGetRegions } from 'support/intercepts/regions'; +import type { Flags } from 'src/featureFlags'; +import { Database } from '@linode/api-v4'; +import { mockGetDatabases } from 'support/intercepts/databases'; + +const { metrics, id, serviceType, dashboardName, engine, clusterName } = + widgetDetails.dbaas; + +const flags: Partial = { + aclp: { enabled: true, beta: true }, + aclpResourceTypeMap: [ + { + dimensionKey: 'LINODE_ID', + maxResourceSelections: 10, + serviceType: 'linode', + supportedRegionIds: '', + }, + { + dimensionKey: 'cluster_id', + maxResourceSelections: 1, + serviceType: 'dbaas', + supportedRegionIds: 'us-ord', + }, + ], +}; + +const dashboard = dashboardFactory.build({ + label: dashboardName, + service_type: serviceType, + widgets: metrics.map(({ title, yLabel, name, unit }) => { + return widgetFactory.build({ + label: title, + y_label: yLabel, + metric: name, + unit, + }); + }), +}); + +const mockAccount = accountFactory.build(); + +const mockRegion = regionFactory.build({ + capabilities: ['Managed Databases'], + id: 'us-ord', + label: 'Chicago, IL', +}); +const databaseMock: Database = databaseFactory.build({ + label: clusterName, + type: engine, + region: mockRegion.label, + version: '1', + status: 'provisioning', + cluster_size: 1, + engine: 'mysql', + hosts: { + primary: undefined, + secondary: undefined, + }, +}); +const extendDatabaseMock: Database = databaseFactory.build({ + label: 'updated-dbass-mock', + type: engine, + region: mockRegion.label, + version: '1', + status: 'provisioning', + cluster_size: 1, + engine: 'mysql', + hosts: { + primary: undefined, + secondary: undefined, + }, +}); + +describe('DBaaS Dashboard - Max Resource Selection Limit', () => { + beforeEach(() => { + mockGetAccount(mockAccount); + mockGetCloudPulseDashboards(serviceType, [dashboard]).as('fetchDashboard'); + mockGetCloudPulseServices(serviceType).as('fetchServices'); + mockGetCloudPulseDashboard(id, dashboard); + mockGetRegions([mockRegion]).as('fetchRegion'); + mockGetUserPreferences({}); + mockGetDatabases([databaseMock, extendDatabaseMock]).as('fetchtDatabases'); + }); + + it('When the maximum resource limit is reached, the appropriate message is displayed, clusters are disabled, and the Select All option is hidden', () => { + mockAppendFeatureFlags(flags).as('getFeatureFlags'); + cy.visitWithLogin('monitor'); + cy.wait('@getFeatureFlags'); + + // Wait for the services and dashboard API calls to complete before proceeding + cy.wait(['@fetchServices', '@fetchDashboard']); + + // Selecting a dashboard from the autocomplete input. + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') + .type(dashboardName); + + ui.autocompletePopper + .findByTitle(dashboardName) + .should('be.visible') + .click(); + + // Select a Database Engine from the autocomplete input. + ui.autocomplete + .findByLabel('Database Engine') + .should('be.visible') + .type(engine); + + ui.autocompletePopper.findByTitle(engine).should('be.visible').click(); + + // Verify that the autocomplete input for 'Database Clusters' is disabled if no region is selected + ui.autocomplete + .findByLabel('Database Clusters') + .should('have.attr', 'disabled'); + + // Select a region. + ui.regionSelect.find().click().clear(); + ui.regionSelect + .findItemByRegionId(mockRegion.id, [mockRegion]) + .should('be.visible') + .click(); + // Verify the helper text for the cluster selection limit + cy.get('[data-qa-textfield-helper-text="true"]') + .and('be.visible') + .and('have.text', 'Select up to 1 Database Clusters'); + + //Open the autocomplete dropdown by clicking on the input + ui.autocomplete + .findByLabel('Database Clusters') + .should('be.visible') + .click(); + + cy.wait('@fetchtDatabases'); + + // Verify the autocomplete dropdown options + ui.autocompletePopper + .find() + .as('autocompletePopper') + .within(() => { + cy.get('[data-option-index]') + .should('be.visible') + .should('not.have.text', 'Select All') + .should('have.length', 2); + }); + + ui.autocomplete + .findByLabel('Database Clusters') + .should('be.visible') + .type(databaseMock.label); + + // Select the desired cluster from the filtered dropdown options + ui.autocompletePopper + .findByTitle(databaseMock.label) + .should('be.visible') + .click(); + + // Verify that a specific cluster is disabled in the dropdown + cy.get('@autocompletePopper') + .contains('[role="option"]', extendDatabaseMock.label) + .should('have.attr', 'aria-disabled', 'true'); + }); + + it('When the maximum resource limit is not reached, the "Select All" option is visible under Database Clusters input', () => { + const flags: Partial = { + aclp: { enabled: true, beta: true }, + aclpResourceTypeMap: [ + { + dimensionKey: 'LINODE_ID', + maxResourceSelections: 10, + serviceType: 'linode', + supportedRegionIds: '', + }, + { + dimensionKey: 'cluster_id', + maxResourceSelections: 10, + serviceType: 'dbaas', + supportedRegionIds: 'us-ord', + }, + ], + }; + mockAppendFeatureFlags(flags).as('getFeatureFlags'); + + cy.visitWithLogin('monitor'); + cy.wait('@getFeatureFlags'); + + // Selecting a dashboard from the autocomplete input. + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') + .type(dashboardName); + + ui.autocompletePopper + .findByTitle(dashboardName) + .should('be.visible') + .click(); + + // Select a region. + ui.regionSelect.find().click().clear(); + ui.regionSelect + .findItemByRegionId(mockRegion.id, [mockRegion]) + .should('be.visible') + .click(); + + // Wait for the services and dashboard API calls to complete before proceeding + cy.wait(['@fetchServices', '@fetchDashboard']); + + // Selecting a dashboard from the autocomplete input. + ui.autocomplete + .findByLabel('Dashboard') + .should('be.visible') + .type(dashboardName); + + ui.autocompletePopper + .findByTitle(dashboardName) + .should('be.visible') + .click(); + + // Select a Database Engine from the autocomplete input. + ui.autocomplete + .findByLabel('Database Engine') + .should('be.visible') + .type(engine); + + ui.autocompletePopper.findByTitle(engine).should('be.visible').click(); + + // Select a region. + ui.regionSelect.find().click().clear(); + ui.regionSelect + .findItemByRegionId(mockRegion.id, [mockRegion]) + .should('be.visible') + .click(); + + //Open the autocomplete dropdown by clicking on the input + ui.autocomplete + .findByLabel('Database Clusters') + .should('be.visible') + .click(); + + cy.wait('@fetchtDatabases'); + + // Verify the autocomplete dropdown options + ui.autocompletePopper + .find() + .as('autocompletePopper') + .within(() => { + cy.get('[data-option-index]') + .should('be.visible') + .should( + 'have.text', + 'Select All ' + databaseMock.label + extendDatabaseMock.label + ) + .should('have.length', 3); + }); + }); +}); From bdd97c1836113c6c5b87706a25a8c9fb5a3c2fee Mon Sep 17 00:00:00 2001 From: ankitaakamai Date: Fri, 13 Dec 2024 14:27:09 +0530 Subject: [PATCH 418/474] upcoming: [DI-20935] - test case fix --- .../shared/CloudPulseCustomSelect.test.tsx | 14 ++++++++---- .../shared/CloudPulseResourcesSelect.test.tsx | 22 +++++++++++++------ 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.test.tsx index 59f92338cf9..e5bed15d49c 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseCustomSelect.test.tsx @@ -20,6 +20,8 @@ const mockOptions: CloudPulseServiceTypeFiltersOptions[] = [ }, ]; +const LABEL_SUBTITLE = 'Test (required)'; + const queryMocks = vi.hoisted(() => ({ useGetCustomFiltersQuery: vi.fn().mockReturnValue({ data: [ @@ -59,11 +61,12 @@ describe('CloudPulseCustomSelect component tests', () => { label="Test" options={mockOptions} placeholder={testFilter} + required type={CloudPulseSelectTypes.static} /> ); expect(screen.queryByPlaceholderText(testFilter)).toBeNull(); - expect(screen.getByLabelText('Test')).toBeInTheDocument(); + expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); const keyDown = screen.getByTestId(keyboardArrowDownIcon); fireEvent.click(keyDown); fireEvent.click(screen.getByText('Test1')); @@ -81,11 +84,12 @@ describe('CloudPulseCustomSelect component tests', () => { label="CustomTest" options={[...mockOptions]} placeholder={testFilter} + required type={CloudPulseSelectTypes.static} /> ); expect(screen.queryByPlaceholderText(testFilter)).toBeNull(); - expect(screen.getByLabelText('CustomTest')).toBeInTheDocument(); + expect(screen.getByLabelText('CustomTest (required)')).toBeInTheDocument(); const keyDown = screen.getByTestId(keyboardArrowDownIcon); fireEvent.click(keyDown); expect(screen.getAllByText('Test1').length).toEqual(2); // here it should be 2 @@ -111,11 +115,12 @@ describe('CloudPulseCustomSelect component tests', () => { handleSelectionChange={selectionChnage} label="Test" placeholder={testFilter} + required type={CloudPulseSelectTypes.dynamic} /> ); expect(screen.queryByPlaceholderText(testFilter)).toBeNull(); - expect(screen.getByLabelText('Test')).toBeInTheDocument(); + expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); const keyDown = screen.getByTestId(keyboardArrowDownIcon); fireEvent.click(keyDown); fireEvent.click(screen.getByText('Test1')); @@ -139,11 +144,12 @@ describe('CloudPulseCustomSelect component tests', () => { isMultiSelect={true} label="Test" placeholder={testFilter} + required type={CloudPulseSelectTypes.dynamic} /> ); expect(screen.queryByPlaceholderText(testFilter)).toBeNull(); - expect(screen.getByLabelText('Test')).toBeInTheDocument(); + expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); const keyDown = screen.getByTestId(keyboardArrowDownIcon); fireEvent.click(keyDown); expect(screen.getAllByText('Test1').length).toEqual(2); // here it should be 2 diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx index d6dc9f0c9e5..e9867863258 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseResourcesSelect.test.tsx @@ -23,6 +23,7 @@ const mockResourceHandler = vi.fn(); const SELECT_ALL = 'Select All'; const ARIA_SELECTED = 'aria-selected'; const ARIA_DISABLED = 'aria-disabled'; +const LABEL_SUBTITLE = 'Resources (required)'; describe('CloudPulseResourcesSelect component tests', () => { it('should render disabled component if the the props are undefined or regions and service type does not have any resources', () => { @@ -37,11 +38,12 @@ describe('CloudPulseResourcesSelect component tests', () => { handleResourcesSelection={mockResourceHandler} label="Resources" region={undefined} + required resourceType={undefined} /> ); expect(getByTestId('resource-select')).toBeInTheDocument(); - expect(screen.getByLabelText('Resources')).toBeInTheDocument(); + expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); expect(getByPlaceholderText('Select Resources')).toBeInTheDocument(); }), it('should render resources happy path', () => { @@ -56,11 +58,12 @@ describe('CloudPulseResourcesSelect component tests', () => { handleResourcesSelection={mockResourceHandler} label="Resources" region={'us-east'} + required resourceType={'us-east'} /> ); fireEvent.click(screen.getByRole('button', { name: 'Open' })); - expect(screen.getByLabelText('Resources')).toBeInTheDocument(); + expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); expect( screen.getByRole('option', { name: 'linode-3', @@ -84,12 +87,13 @@ describe('CloudPulseResourcesSelect component tests', () => { handleResourcesSelection={mockResourceHandler} label="Resources" region={'us-east'} + required resourceType={'linode'} /> ); fireEvent.click(screen.getByRole('button', { name: 'Open' })); fireEvent.click(screen.getByRole('option', { name: SELECT_ALL })); - expect(screen.getByLabelText('Resources')).toBeInTheDocument(); + expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); expect( screen.getByRole('option', { name: 'linode-5', @@ -114,13 +118,14 @@ describe('CloudPulseResourcesSelect component tests', () => { handleResourcesSelection={mockResourceHandler} label="Resources" region={'us-east'} + required resourceType={'linode'} /> ); fireEvent.click(screen.getByRole('button', { name: 'Open' })); fireEvent.click(screen.getByRole('option', { name: SELECT_ALL })); fireEvent.click(screen.getByRole('option', { name: 'Deselect All' })); - expect(screen.getByLabelText('Resources')).toBeInTheDocument(); + expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); expect( screen.getByRole('option', { name: 'linode-7', @@ -145,13 +150,14 @@ describe('CloudPulseResourcesSelect component tests', () => { handleResourcesSelection={mockResourceHandler} label="Resources" region={'us-east'} + required resourceType={'linode'} /> ); fireEvent.click(screen.getByRole('button', { name: 'Open' })); fireEvent.click(screen.getByRole('option', { name: 'linode-9' })); fireEvent.click(screen.getByRole('option', { name: 'linode-10' })); - expect(screen.getByLabelText('Resources')).toBeInTheDocument(); + expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); expect( screen.getByRole('option', { @@ -269,13 +275,14 @@ describe('CloudPulseResourcesSelect component tests', () => { handleResourcesSelection={mockResourceHandler} label="Resources" region="us-east" + required resourceType="linode" /> ); await user.click(screen.getByRole('button', { name: 'Open' })); - expect(screen.getByLabelText('Resources')).toBeInTheDocument(); + expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); expect(screen.getByText('Select up to 10 Resources')).toBeInTheDocument(); for (let i = 14; i <= 23; i++) { @@ -314,6 +321,7 @@ describe('CloudPulseResourcesSelect component tests', () => { handleResourcesSelection={mockResourceHandler} label="Resources" region={'us-east'} + required resourceType={'linode'} /> ); @@ -322,7 +330,7 @@ describe('CloudPulseResourcesSelect component tests', () => { await user.click(screen.getByRole('option', { name: SELECT_ALL })); await user.click(screen.getByRole('option', { name: 'Deselect All' })); - expect(screen.getByLabelText('Resources')).toBeInTheDocument(); + expect(screen.getByLabelText(LABEL_SUBTITLE)).toBeInTheDocument(); for (let i = 26; i <= 35; i++) { expect( From aa424bdc92e9750197f2adb68f0461c376827400 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Fri, 13 Dec 2024 13:36:15 +0530 Subject: [PATCH 419/474] change: [DI-22390] - Added disabled dashboard select in contextual view --- .../CloudPulseDashboardWithFilters.tsx | 65 +++++++++++----- .../CloudPulseDashboardFilterBuilder.tsx | 74 +++++++++---------- .../shared/CloudPulseDashboardSelect.tsx | 16 +++- 3 files changed, 91 insertions(+), 64 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx index 13821781375..a62771f7638 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx @@ -1,4 +1,4 @@ -import { Box, CircleProgress, Paper } from '@linode/ui'; +import { Box, CircleProgress, Divider, Paper } from '@linode/ui'; import { Grid } from '@mui/material'; import React from 'react'; @@ -7,6 +7,7 @@ import { useCloudPulseDashboardByIdQuery } from 'src/queries/cloudpulse/dashboar import { CloudPulseAppliedFilterRenderer } from '../shared/CloudPulseAppliedFilterRenderer'; import { CloudPulseDashboardFilterBuilder } from '../shared/CloudPulseDashboardFilterBuilder'; +import { CloudPulseDashboardSelect } from '../shared/CloudPulseDashboardSelect'; import { CloudPulseErrorPlaceholder } from '../shared/CloudPulseErrorPlaceholder'; import { CloudPulseTimeRangeSelect } from '../shared/CloudPulseTimeRangeSelect'; import { FILTER_CONFIG } from '../Utils/FilterConfig'; @@ -118,28 +119,52 @@ export const CloudPulseDashboardWithFilters = React.memo( }); return ( - - - - - - - + + + + + + + + + + + + + + + + ({ + borderColor: theme.color.grey5, + margin: 0, + })} + /> + + {isFilterBuilderNeeded && ( )} @@ -150,8 +175,8 @@ export const CloudPulseDashboardWithFilters = React.memo( /> )} - - + + {isMandatoryFiltersSelected ? ( ; // in this we don't want to show the filters at all } - // Count number of filters to be render - const filterCount = getFilters(dashboard, isServiceAnalyticsIntegration) - ?.length; - return ( - {filterCount && filterCount > 1 && ( - + - - )} + Filters + + ; - handleDashboardChange: ( + disabled?: boolean; + handleDashboardChange?: ( dashboard: Dashboard | undefined, savePref?: boolean ) => void; savePreferences?: boolean; + serviceIntegration?: boolean; } export const CloudPulseDashboardSelect = React.memo( (props: CloudPulseDashboardSelectProps) => { - const { defaultValue, handleDashboardChange, savePreferences } = props; + const { + defaultValue, + disabled, + handleDashboardChange = () => {}, + savePreferences, + serviceIntegration: isServiceIntegration, + } = props; const { data: serviceTypesList, @@ -74,7 +82,7 @@ export const CloudPulseDashboardSelect = React.memo( React.useEffect(() => { // only call this code when the component is rendered initially if ( - savePreferences && + (savePreferences || isServiceIntegration) && dashboardsList.length > 0 && selectedDashboard === undefined ) { @@ -103,7 +111,7 @@ export const CloudPulseDashboardSelect = React.memo( autoHighlight clearOnBlur data-testid="cloudpulse-dashboard-select" - disabled={!dashboardsList} + disabled={disabled || !dashboardsList} errorText={Boolean(dashboardsList?.length) ? '' : errorText} fullWidth groupBy={(option: Dashboard) => option.service_type} From 12aef547d0c8f4716da70b4eeadebd916b1c377c Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Fri, 13 Dec 2024 17:38:38 +0530 Subject: [PATCH 420/474] change: [DI-22390] - Updated test cases --- .../CloudPulseDashboardWithFilters.test.tsx | 39 ++++++++++++++++++- .../CloudPulseDashboardWithFilters.tsx | 3 +- .../shared/CloudPulseDashboardSelect.tsx | 22 ++++++++--- 3 files changed, 55 insertions(+), 9 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.test.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.test.tsx index e4c64282ec7..aba654fc8e3 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.test.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.test.tsx @@ -1,13 +1,16 @@ import { fireEvent } from '@testing-library/react'; import React from 'react'; -import { dashboardFactory } from 'src/factories'; +import { dashboardFactory, serviceTypesFactory } from 'src/factories'; +import * as utils from 'src/features/CloudPulse/Utils/utils'; import { renderWithTheme } from 'src/utilities/testHelpers'; import { CloudPulseDashboardWithFilters } from './CloudPulseDashboardWithFilters'; const queryMocks = vi.hoisted(() => ({ useCloudPulseDashboardByIdQuery: vi.fn().mockReturnValue({}), + useCloudPulseDashboardsQuery: vi.fn().mockReturnValue({}), + useCloudPulseServiceTypes: vi.fn().mockReturnValue({}), })); const circleProgress = 'circle-progress'; @@ -18,10 +21,20 @@ vi.mock('src/queries/cloudpulse/dashboards', async () => { return { ...actual, useCloudPulseDashboardByIdQuery: queryMocks.useCloudPulseDashboardByIdQuery, + useCloudPulseDashboardsQuery: queryMocks.useCloudPulseDashboardsQuery, }; }); -const mockDashboard = dashboardFactory.build(); +vi.mock('src/queries/cloudpulse/services.ts', async () => { + const actual = await vi.importActual('src/queries/cloudpulse/services'); + + return { + ...actual, + useCloudPulseServiceTypes: queryMocks.useCloudPulseServiceTypes, + }; +}); +const mockDashboard = dashboardFactory.build(); +const mockServiceTypesList = serviceTypesFactory.build(); queryMocks.useCloudPulseDashboardByIdQuery.mockReturnValue({ data: { data: mockDashboard, @@ -30,6 +43,28 @@ queryMocks.useCloudPulseDashboardByIdQuery.mockReturnValue({ isLoading: false, }); +queryMocks.useCloudPulseDashboardsQuery.mockReturnValue({ + data: { + data: [mockDashboard], + }, + error: false, + isLoading: false, +}); + +queryMocks.useCloudPulseServiceTypes.mockReturnValue({ + data: { + data: [mockServiceTypesList], + }, + error: false, + isLoading: false, +}); + +vi.spyOn(utils, 'getAllDashboards').mockReturnValue({ + data: [mockDashboard], + error: '', + isLoading: false, +}); + describe('CloudPulseDashboardWithFilters component tests', () => { it('renders a CloudPulseDashboardWithFilters component with error placeholder', () => { queryMocks.useCloudPulseDashboardByIdQuery.mockReturnValue({ diff --git a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx index a62771f7638..d91391163e7 100644 --- a/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx +++ b/packages/manager/src/features/CloudPulse/Dashboard/CloudPulseDashboardWithFilters.tsx @@ -137,8 +137,7 @@ export const CloudPulseDashboardWithFilters = React.memo( diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx index 9b72de6613e..03a1e25deff 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardSelect.tsx @@ -9,24 +9,36 @@ import { formattedServiceTypes, getAllDashboards } from '../Utils/utils'; import type { Dashboard, FilterValue } from '@linode/api-v4'; export interface CloudPulseDashboardSelectProps { + /** + * default value selected on initial render + */ defaultValue?: Partial; - disabled?: boolean; + /** + * + * @param dashboard latest dashboard object selected from dropdown + * @param savePref boolean value to check whether changes to be saved on preferences or not + */ handleDashboardChange?: ( dashboard: Dashboard | undefined, savePref?: boolean ) => void; + /** + * flag value to identify whether this component is being used in service level integration or not + */ + isServiceIntegration?: boolean; + /** + * boolean value to identify whether changes to be saved on preferences or not + */ savePreferences?: boolean; - serviceIntegration?: boolean; } export const CloudPulseDashboardSelect = React.memo( (props: CloudPulseDashboardSelectProps) => { const { defaultValue, - disabled, handleDashboardChange = () => {}, + isServiceIntegration, savePreferences, - serviceIntegration: isServiceIntegration, } = props; const { @@ -111,7 +123,7 @@ export const CloudPulseDashboardSelect = React.memo( autoHighlight clearOnBlur data-testid="cloudpulse-dashboard-select" - disabled={disabled || !dashboardsList} + disabled={isServiceIntegration || !dashboardsList} errorText={Boolean(dashboardsList?.length) ? '' : errorText} fullWidth groupBy={(option: Dashboard) => option.service_type} From 0701c2aed35c3b78b12267010272aba7993030ac Mon Sep 17 00:00:00 2001 From: agorthi Date: Mon, 16 Dec 2024 12:24:42 +0530 Subject: [PATCH 421/474] DI-22390:Cypress E2E automations: ACLP Contextual view enhancement - Latest Feedback --- ...ntextual-dbaas-widget-verification.spec.ts | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/contextual-dbaas-widget-verification.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/contextual-dbaas-widget-verification.spec.ts index 46852835f96..9a1107cb831 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/contextual-dbaas-widget-verification.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/contextual-dbaas-widget-verification.spec.ts @@ -7,6 +7,8 @@ import { mockGetCloudPulseDashboard, mockCreateCloudPulseMetrics, mockGetCloudPulseMetricDefinitions, + mockGetCloudPulseDashboards, + mockGetCloudPulseServices, } from 'support/intercepts/cloudpulse'; import { ui } from 'support/ui'; import { widgetDetails } from 'support/constants/widgets'; @@ -157,6 +159,9 @@ describe('Integration Tests for DBaaS Dashboard ', () => { mockCreateCloudPulseMetrics(serviceType, metricsAPIResponsePayload).as( 'getMetrics' ); + mockGetCloudPulseMetricDefinitions(serviceType, metricDefinitions); + mockGetCloudPulseDashboards(serviceType, [dashboard]).as('fetchDashboard'); + mockGetCloudPulseServices(serviceType).as('fetchServices'); mockGetDatabase(databaseMock).as('getDatabase'); mockGetDatabaseTypes(mockDatabaseNodeTypes).as('getDatabaseTypes'); @@ -164,23 +169,31 @@ describe('Integration Tests for DBaaS Dashboard ', () => { cy.visitWithLogin('/linodes'); // navigate to the Databases - cy.get('[data-testid="menu-item-Databases"]') - .should('be.visible') - .click(); + cy.get('[data-testid="menu-item-Databases"]').should('be.visible').click(); // navigate to the Monitor cy.visitWithLogin( `/databases/${databaseMock.engine}/${databaseMock.id}/monitor` ); - cy.wait(['@getDashboard', '@getServiceType','@getDatabase']); + cy.wait(['@getDashboard', '@getServiceType', '@getDatabase']); + + // Use findByPlaceholderText to locate the input field + cy.findByPlaceholderText('Select a Dashboard') + .should('be.visible') + .and('be.disabled') // Check if disabled + .and('have.value', 'Dbaas Dashboard'); // Ensure value is set // Select a time duration from the autocomplete input. ui.autocomplete .findByLabel('Time Range') .should('be.visible') - .type(`${timeDurationToSelect}{enter}`) - .should('be.visible'); + .type(timeDurationToSelect); + + ui.autocompletePopper + .findByTitle(timeDurationToSelect) + .should('be.visible') + .click(); //Select a Node from the autocomplete input. ui.autocomplete @@ -188,6 +201,15 @@ describe('Integration Tests for DBaaS Dashboard ', () => { .should('be.visible') .type(`${nodeType}{enter}`); + //Collapse the Filters section + ui.button.findByTitle('Filters').should('be.visible').click(); + + cy.get('[data-testid="applied-filter"]').within(() => { + cy.get(`[data-qa-value="Node Type ${nodeType}"]`) + .should('be.visible') + .should('have.text', nodeType); + }); + // Wait for all metrics query requests to resolve. cy.wait(['@getMetrics', '@getMetrics', '@getMetrics', '@getMetrics']); }); From 50496cb659e661047c826a280c232a683870c583 Mon Sep 17 00:00:00 2001 From: agorthi Date: Mon, 16 Dec 2024 12:37:31 +0530 Subject: [PATCH 422/474] DI-22390:Cypress E2E automations: ACLP Contextual view enhancement - Latest Feedback --- .../e2e/core/cloudpulse/cloudpulse-applied-filters.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-applied-filters.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-applied-filters.spec.ts index 1340b329893..41444f84df9 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-applied-filters.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-applied-filters.spec.ts @@ -309,7 +309,7 @@ describe('Integration Tests for Applied Filters', () => { .should('be.visible') .should('have.text', 'US, Chicago, IL'); - cy.get(`[data-qa-value="Node Type ${'Primary'}"]`) + cy.get('[data-qa-value="Node Type Primary"]') .should('be.visible') .should('have.text', 'Primary'); From d51f9400b2d2b6b880522f1951b131f23e960c03 Mon Sep 17 00:00:00 2001 From: nikhagra-akamai Date: Mon, 16 Dec 2024 12:40:19 +0530 Subject: [PATCH 423/474] change: [DI-22125] - Updated styling --- .../shared/CloudPulseDashboardFilterBuilder.tsx | 8 ++------ .../CloudPulse/shared/CloudPulseDashboardSelect.tsx | 8 ++++++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx index 8561ea4d78a..2cce38b2500 100644 --- a/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx +++ b/packages/manager/src/features/CloudPulse/shared/CloudPulseDashboardFilterBuilder.tsx @@ -297,13 +297,9 @@ export const CloudPulseDashboardFilterBuilder = React.memo(