Quick options (#814)

* refactor: link start is quick option

* refactor: add default duration

* chore: use last time by default
This commit is contained in:
Carlos Valente
2024-03-19 17:23:32 +01:00
committed by GitHub
parent dfade25a7c
commit 8156da03d5
11 changed files with 123 additions and 83 deletions
+21 -18
View File
@@ -25,9 +25,7 @@ import { forgivingStringToMillis } from '../utils/dateConfig';
*/ */
export const useEventAction = () => { export const useEventAction = () => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const eventSettings = useEditorSettings((state) => state.eventSettings); const { defaultPublic, linkPrevious, defaultDuration } = useEditorSettings((state) => state.eventSettings);
const defaultPublic = eventSettings.defaultPublic;
const startTimeIsLastEnd = eventSettings.startTimeIsLastEnd;
/** /**
* Calls mutation to add new event * Calls mutation to add new event
@@ -45,11 +43,12 @@ export const useEventAction = () => {
after?: string; after?: string;
}; };
type EventOptions = BaseOptions & { type EventOptions = BaseOptions &
defaultPublic?: boolean; Partial<{
lastEventId?: string; defaultPublic: boolean;
startTimeIsLastEnd?: boolean; linkPrevious: boolean;
}; lastEventId: string;
}>;
/** /**
* Adds an event to rundown * Adds an event to rundown
@@ -61,27 +60,31 @@ export const useEventAction = () => {
// ************* CHECK OPTIONS specific to events // ************* CHECK OPTIONS specific to events
if (isOntimeEvent(newEvent)) { if (isOntimeEvent(newEvent)) {
const applicationOptions = { const applicationOptions = {
defaultPublic: options?.defaultPublic ?? defaultPublic,
startTimeIsLastEnd: options?.startTimeIsLastEnd ?? startTimeIsLastEnd,
lastEventId: options?.lastEventId,
after: options?.after, after: options?.after,
defaultPublic: options?.defaultPublic ?? defaultPublic,
lastEventId: options?.lastEventId,
linkPrevious: options?.linkPrevious ?? linkPrevious,
}; };
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- we know this has a value if (applicationOptions.linkPrevious && applicationOptions?.lastEventId) {
const rundownData = queryClient.getQueryData<RundownCached>(RUNDOWN)!; newEvent.linkStart = applicationOptions.lastEventId;
const { rundown } = rundownData; } else if (applicationOptions?.lastEventId) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- we know this is a value
if (applicationOptions.startTimeIsLastEnd && applicationOptions?.lastEventId) { const rundownData = queryClient.getQueryData<RundownCached>(RUNDOWN)!;
const { rundown } = rundownData;
const previousEvent = rundown[applicationOptions.lastEventId]; const previousEvent = rundown[applicationOptions.lastEventId];
if (isOntimeEvent(previousEvent)) { if (isOntimeEvent(previousEvent)) {
newEvent.timeStart = previousEvent.timeEnd; newEvent.timeStart = previousEvent.timeEnd;
newEvent.timeEnd = previousEvent.timeEnd;
} }
} }
if (applicationOptions.defaultPublic) { if (applicationOptions.defaultPublic) {
newEvent.isPublic = true; newEvent.isPublic = true;
} }
if (newEvent.duration === undefined && newEvent.timeEnd === undefined) {
newEvent.duration = forgivingStringToMillis(defaultDuration);
}
} }
// handle adding options that concern all event type // handle adding options that concern all event type
@@ -95,7 +98,7 @@ export const useEventAction = () => {
logAxiosError('Failed adding event', error); logAxiosError('Failed adding event', error);
} }
}, },
[_addEventMutation, defaultPublic, queryClient, startTimeIsLastEnd], [_addEventMutation, defaultDuration, defaultPublic, linkPrevious],
); );
/** /**
@@ -4,35 +4,39 @@ import { booleanFromLocalStorage } from '../utils/localStorage';
type EditorSettings = { type EditorSettings = {
showQuickEntry: boolean; showQuickEntry: boolean;
startTimeIsLastEnd: boolean; linkPrevious: boolean;
defaultPublic: boolean; defaultPublic: boolean;
defaultDuration: string;
}; };
type EditorSettingsStore = { type EditorSettingsStore = {
eventSettings: EditorSettings; eventSettings: EditorSettings;
setLocalEventSettings: (newState: EditorSettings) => void; setLocalEventSettings: (newState: EditorSettings) => void;
setShowQuickEntry: (showQuickEntry: boolean) => void; setShowQuickEntry: (showQuickEntry: boolean) => void;
setStartTimeIsLastEnd: (startTimeIsLastEnd: boolean) => void; setLinkPrevious: (linkPrevious: boolean) => void;
setDefaultPublic: (defaultPublic: boolean) => void; setDefaultPublic: (defaultPublic: boolean) => void;
setDefaultDuration: (defaultDuration: string) => void;
}; };
enum EditorSettingsKeys { enum EditorSettingsKeys {
ShowQuickEntry = 'ontime-show-quick-entry', ShowQuickEntry = 'ontime-show-quick-entry',
StartTimeIsLastEnd = 'ontime-start-is-last-end', LinkPrevious = 'ontime-link-previous',
DefaultPublic = 'ontime-default-public', DefaultPublic = 'ontime-default-public',
DefaultDuration = 'ontime-default-duration',
} }
export const useEditorSettings = create<EditorSettingsStore>((set) => ({ export const useEditorSettings = create<EditorSettingsStore>((set) => ({
eventSettings: { eventSettings: {
showQuickEntry: booleanFromLocalStorage(EditorSettingsKeys.ShowQuickEntry, false), showQuickEntry: booleanFromLocalStorage(EditorSettingsKeys.ShowQuickEntry, false),
startTimeIsLastEnd: booleanFromLocalStorage(EditorSettingsKeys.ShowQuickEntry, true), linkPrevious: booleanFromLocalStorage(EditorSettingsKeys.LinkPrevious, true),
defaultPublic: booleanFromLocalStorage(EditorSettingsKeys.ShowQuickEntry, true), defaultPublic: booleanFromLocalStorage(EditorSettingsKeys.DefaultPublic, true),
defaultDuration: localStorage.getItem(EditorSettingsKeys.DefaultDuration) ?? '00:10:00',
}, },
setLocalEventSettings: (value) => setLocalEventSettings: (value) =>
set(() => { set(() => {
localStorage.setItem(EditorSettingsKeys.ShowQuickEntry, String(value.showQuickEntry)); localStorage.setItem(EditorSettingsKeys.ShowQuickEntry, String(value.showQuickEntry));
localStorage.setItem(EditorSettingsKeys.StartTimeIsLastEnd, String(value.startTimeIsLastEnd)); localStorage.setItem(EditorSettingsKeys.LinkPrevious, String(value.linkPrevious));
localStorage.setItem(EditorSettingsKeys.DefaultPublic, String(value.defaultPublic)); localStorage.setItem(EditorSettingsKeys.DefaultPublic, String(value.defaultPublic));
return { eventSettings: value }; return { eventSettings: value };
}), }),
@@ -43,10 +47,10 @@ export const useEditorSettings = create<EditorSettingsStore>((set) => ({
return { eventSettings: { ...state.eventSettings, showQuickEntry } }; return { eventSettings: { ...state.eventSettings, showQuickEntry } };
}), }),
setStartTimeIsLastEnd: (startTimeIsLastEnd) => setLinkPrevious: (linkPrevious) =>
set((state) => { set((state) => {
localStorage.setItem(EditorSettingsKeys.StartTimeIsLastEnd, String(startTimeIsLastEnd)); localStorage.setItem(EditorSettingsKeys.LinkPrevious, String(linkPrevious));
return { eventSettings: { ...state.eventSettings, startTimeIsLastEnd } }; return { eventSettings: { ...state.eventSettings, linkPrevious } };
}), }),
setDefaultPublic: (defaultPublic) => setDefaultPublic: (defaultPublic) =>
@@ -54,4 +58,10 @@ export const useEditorSettings = create<EditorSettingsStore>((set) => ({
localStorage.setItem(EditorSettingsKeys.DefaultPublic, String(defaultPublic)); localStorage.setItem(EditorSettingsKeys.DefaultPublic, String(defaultPublic));
return { eventSettings: { ...state.eventSettings, defaultPublic } }; return { eventSettings: { ...state.eventSettings, defaultPublic } };
}), }),
setDefaultDuration: (defaultDuration) =>
set((state) => {
localStorage.setItem(EditorSettingsKeys.DefaultDuration, String(defaultDuration));
return { eventSettings: { ...state.eventSettings, defaultDuration } };
}),
})); }));
@@ -1,13 +1,18 @@
import { Switch } from '@chakra-ui/react'; import { Switch } from '@chakra-ui/react';
import TimeInput from '../../../../common/components/input/time-input/TimeInput';
import { useEditorSettings } from '../../../../common/stores/editorSettings'; import { useEditorSettings } from '../../../../common/stores/editorSettings';
import { forgivingStringToMillis } from '../../../../common/utils/dateConfig';
import * as Panel from '../PanelUtils'; import * as Panel from '../PanelUtils';
export default function EditorSettingsForm() { export default function EditorSettingsForm() {
const eventSettings = useEditorSettings((state) => state.eventSettings); const eventSettings = useEditorSettings((state) => state.eventSettings);
const setShowQuickEntry = useEditorSettings((state) => state.setShowQuickEntry); const setShowQuickEntry = useEditorSettings((state) => state.setShowQuickEntry);
const setStartTimeIsLastEnd = useEditorSettings((state) => state.setStartTimeIsLastEnd); const setLinkPrevious = useEditorSettings((state) => state.setLinkPrevious);
const setDefaultPublic = useEditorSettings((state) => state.setDefaultPublic); const setDefaultPublic = useEditorSettings((state) => state.setDefaultPublic);
const setDefaultDuration = useEditorSettings((state) => state.setDefaultDuration);
const durationInMs = forgivingStringToMillis(eventSettings.defaultDuration);
return ( return (
<Panel.Section> <Panel.Section>
@@ -29,14 +34,26 @@ export default function EditorSettingsForm() {
</Panel.ListItem> </Panel.ListItem>
<Panel.ListItem> <Panel.ListItem>
<Panel.Field <Panel.Field
title='Start time is last end' title='Link previous'
description='New events start time will be the previous event end' description='New events start time will be linked to the previous event'
/> />
<Switch <Switch
variant='ontime' variant='ontime'
size='lg' size='lg'
defaultChecked={eventSettings.startTimeIsLastEnd} defaultChecked={eventSettings.linkPrevious}
onChange={(event) => setStartTimeIsLastEnd(event.target.checked)} onChange={(event) => setLinkPrevious(event.target.checked)}
/>
</Panel.ListItem>
<Panel.ListItem>
<Panel.Field
title='Default duration'
description='When creating a new event, what is the default duration'
/>
<TimeInput<'defaultDuration'>
name='defaultDuration'
submitHandler={(_field, value) => setDefaultDuration(value)}
time={durationInMs}
placeholder='00:10:00'
/> />
</Panel.ListItem> </Panel.ListItem>
<Panel.ListItem> <Panel.ListItem>
+5 -5
View File
@@ -38,7 +38,7 @@ export default function Rundown({ data }: RundownProps) {
const { addEvent, reorderEvent } = useEventAction(); const { addEvent, reorderEvent } = useEventAction();
const eventSettings = useEditorSettings((state) => state.eventSettings); const eventSettings = useEditorSettings((state) => state.eventSettings);
const defaultPublic = eventSettings.defaultPublic; const defaultPublic = eventSettings.defaultPublic;
const startTimeIsLastEnd = eventSettings.startTimeIsLastEnd; const linkPrevious = eventSettings.linkPrevious;
const showQuickEntry = eventSettings.showQuickEntry; const showQuickEntry = eventSettings.showQuickEntry;
// cursor // cursor
@@ -74,17 +74,17 @@ export default function Rundown({ data }: RundownProps) {
type: SupportedEvent.Event, type: SupportedEvent.Event,
}; };
const options = { const options = {
defaultPublic,
startTimeIsLastEnd,
lastEventId: cursor,
after: cursor, after: cursor,
defaultPublic,
lastEventId: cursor,
linkPrevious,
}; };
addEvent(newEvent, options); addEvent(newEvent, options);
} else { } else {
addEvent({ type }, { after: cursor }); addEvent({ type }, { after: cursor });
} }
}, },
[addEvent, rundown, defaultPublic, startTimeIsLastEnd], [addEvent, rundown, defaultPublic, linkPrevious],
); );
// Handle keyboard shortcuts // Handle keyboard shortcuts
@@ -52,7 +52,7 @@ export default function RundownEntry(props: RundownEntryProps) {
const eventSettings = useEditorSettings((state) => state.eventSettings); const eventSettings = useEditorSettings((state) => state.eventSettings);
const defaultPublic = eventSettings.defaultPublic; const defaultPublic = eventSettings.defaultPublic;
const startTimeIsLastEnd = eventSettings.startTimeIsLastEnd; const linkPrevious = eventSettings.linkPrevious;
const removeOpenEvent = useCallback(() => { const removeOpenEvent = useCallback(() => {
if (selectedEvents.has(data.id)) { if (selectedEvents.has(data.id)) {
@@ -63,7 +63,7 @@ export default function RundownEntry(props: RundownEntryProps) {
if (cursor === data.id) { if (cursor === data.id) {
setCursor(null); setCursor(null);
} }
}, [clearSelectedEvents, cursor, data.id, selectedEvents, setCursor]); }, [selectedEvents, data.id, cursor, clearSelectedEvents, setCursor]);
// Create / delete new events // Create / delete new events
type FieldValue = { type FieldValue = {
@@ -76,10 +76,10 @@ export default function RundownEntry(props: RundownEntryProps) {
case 'event': { case 'event': {
const newEvent = { type: SupportedEvent.Event }; const newEvent = { type: SupportedEvent.Event };
const options = { const options = {
startTimeIsLastEnd, after: data.id,
defaultPublic, defaultPublic,
lastEventId: previousEventId, lastEventId: previousEventId,
after: data.id, linkPrevious,
}; };
return addEvent(newEvent, options); return addEvent(newEvent, options);
} }
@@ -23,26 +23,24 @@ const QuickAddBlock = (props: QuickAddBlockProps) => {
const { addEvent } = useEventAction(); const { addEvent } = useEventAction();
const { emitError } = useEmitLog(); const { emitError } = useEmitLog();
const doStartTime = useRef<HTMLInputElement | null>(null); const doLinkPrevious = useRef<HTMLInputElement | null>(null);
const doPublic = useRef<HTMLInputElement | null>(null); const doPublic = useRef<HTMLInputElement | null>(null);
const eventSettings = useEditorSettings((state) => state.eventSettings); const { defaultPublic, linkPrevious } = useEditorSettings((state) => state.eventSettings);
const defaultPublic = eventSettings.defaultPublic;
const startTimeIsLastEnd = eventSettings.startTimeIsLastEnd;
const handleCreateEvent = useCallback( const handleCreateEvent = useCallback(
(eventType: SupportedEvent) => { (eventType: SupportedEvent) => {
switch (eventType) { switch (eventType) {
case 'event': { case 'event': {
const isPublicOption = doPublic?.current?.checked; const defaultPublic = doPublic?.current?.checked;
const startTimeIsLastEndOption = doStartTime?.current?.checked; const linkPrevious = doLinkPrevious?.current?.checked;
const newEvent = { type: SupportedEvent.Event }; const newEvent = { type: SupportedEvent.Event };
const options = { const options = {
defaultPublic: isPublicOption,
startTimeIsLastEnd: startTimeIsLastEndOption,
lastEventId: previousEventId,
after: previousEventId, after: previousEventId,
defaultPublic,
lastEventId: previousEventId,
linkPrevious,
}; };
addEvent(newEvent, options); addEvent(newEvent, options);
break; break;
@@ -115,8 +113,8 @@ const QuickAddBlock = (props: QuickAddBlockProps) => {
</Tooltip> </Tooltip>
</div> </div>
<div className={style.options}> <div className={style.options}>
<Checkbox ref={doStartTime} size='sm' variant='ontime-ondark' defaultChecked={startTimeIsLastEnd}> <Checkbox ref={doLinkPrevious} size='sm' variant='ontime-ondark' defaultChecked={linkPrevious}>
Start time is last end Link to previous
</Checkbox> </Checkbox>
<Checkbox ref={doPublic} size='sm' variant='ontime-ondark' defaultChecked={defaultPublic}> <Checkbox ref={doPublic} size='sm' variant='ontime-ondark' defaultChecked={defaultPublic}>
Event is public Event is public
+1 -3
View File
@@ -67,9 +67,7 @@ test('delays are show correctly', async ({ page }) => {
await page.getByTestId('block__title').click(); await page.getByTestId('block__title').click();
await page.getByTestId('block__title').fill('test'); await page.getByTestId('block__title').fill('test');
await page.getByTestId('block__title').press('Enter'); await page.getByTestId('block__title').press('Enter');
await expect(page.getByTestId('entry-1').locator('#block-status')).toHaveAttribute('data-ispublic', 'true');
await page.locator('#event-block').getByText('1').click({ button: 'right' });
await page.getByRole('menuitem', { name: 'Toggle public' }).click();
// add a delay // add a delay
await page.getByRole('button', { name: 'Rundown menu' }).click(); await page.getByRole('button', { name: 'Rundown menu' }).click();
+3 -3
View File
@@ -18,12 +18,12 @@ test('CRUD operations on the rundown', async ({ page }) => {
// test quick add options - start is last end // test quick add options - start is last end
await page.getByTestId('entry-2').getByTestId('time-input-duration').fill('20m'); await page.getByTestId('entry-2').getByTestId('time-input-duration').fill('20m');
await page.getByText('Start time is last end').click();
await page.getByTestId('quick-add-event').click(); await page.getByTestId('quick-add-event').click();
expect(await page.getByTestId('entry-3').getByTestId('time-input-timeStart').inputValue()).toContain('00:20:00'); await expect(page.getByLabel('Link to previous')).toBeChecked();
expect(await page.getByTestId('entry-3').getByTestId('time-input-timeStart').inputValue()).toContain('00:30:00');
// test quick add options - event is public // test quick add options - event is public
await page.locator('label').filter({ hasText: 'Event is public' }).click(); await expect(page.getByLabel('Event is public')).toBeChecked();
await page.getByTestId('quick-add-event').click(); await page.getByTestId('quick-add-event').click();
await expect(page.getByTestId('entry-4').locator('#block-status')).toHaveAttribute('data-ispublic', 'true'); await expect(page.getByTestId('entry-4').locator('#block-status')).toHaveAttribute('data-ispublic', 'true');
-2
View File
@@ -13,14 +13,12 @@ test('smoke test operator', async ({ page }) => {
await page.getByTestId('time-input-duration').fill('1m'); await page.getByTestId('time-input-duration').fill('1m');
await page.getByTestId('time-input-duration').press('Enter'); await page.getByTestId('time-input-duration').press('Enter');
await page.getByText('Start time is last end').click();
await page.getByTestId('quick-add-event').click(); await page.getByTestId('quick-add-event').click();
await page.getByTestId('entry-2').getByTestId('lock__duration').click(); await page.getByTestId('entry-2').getByTestId('lock__duration').click();
await page.getByTestId('entry-2').getByTestId('time-input-duration').fill('1m'); await page.getByTestId('entry-2').getByTestId('time-input-duration').fill('1m');
await page.getByTestId('entry-2').getByTestId('time-input-duration').press('Enter'); await page.getByTestId('entry-2').getByTestId('time-input-duration').press('Enter');
await page.getByTestId('entry-2').getByTestId('time-input-duration').press('Enter'); await page.getByTestId('entry-2').getByTestId('time-input-duration').press('Enter');
await page.getByText('Start time is last end').click();
await page.getByTestId('quick-add-event').click(); await page.getByTestId('quick-add-event').click();
await page.getByTestId('entry-3').getByTestId('lock__duration').click(); await page.getByTestId('entry-3').getByTestId('lock__duration').click();
await page.getByTestId('entry-3').getByTestId('time-input-duration').fill('1m'); await page.getByTestId('entry-3').getByTestId('time-input-duration').fill('1m');
+2 -2
View File
@@ -41,14 +41,14 @@
"cleanup": "rm -rf node_modules && rm -rf **/node_modules && rm -rf **/**/node_modules" "cleanup": "rm -rf node_modules && rm -rf **/node_modules && rm -rf **/**/node_modules"
}, },
"devDependencies": { "devDependencies": {
"@playwright/test": "^1.34.3", "@playwright/test": "^1.42.1",
"@types/node": "^18.11.18", "@types/node": "^18.11.18",
"@typescript-eslint/eslint-plugin": "^6.10.0", "@typescript-eslint/eslint-plugin": "^6.10.0",
"@typescript-eslint/parser": "^6.10.0", "@typescript-eslint/parser": "^6.10.0",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"eslint": "^8.53.0", "eslint": "^8.53.0",
"eslint-config-prettier": "^9.0.0", "eslint-config-prettier": "^9.0.0",
"eslint-plugin-playwright": "^0.12.0", "eslint-plugin-playwright": "^1.5.2",
"husky": "^8.0.3", "husky": "^8.0.3",
"lint-staged": "^15.1.0", "lint-staged": "^15.1.0",
"prettier": "^3.0.3", "prettier": "^3.0.3",
+37 -21
View File
@@ -9,8 +9,8 @@ importers:
.: .:
devDependencies: devDependencies:
'@playwright/test': '@playwright/test':
specifier: ^1.34.3 specifier: ^1.42.1
version: 1.34.3 version: 1.42.1
'@types/node': '@types/node':
specifier: ^18.11.18 specifier: ^18.11.18
version: 18.11.18 version: 18.11.18
@@ -30,8 +30,8 @@ importers:
specifier: ^9.0.0 specifier: ^9.0.0
version: 9.0.0(eslint@8.53.0) version: 9.0.0(eslint@8.53.0)
eslint-plugin-playwright: eslint-plugin-playwright:
specifier: ^0.12.0 specifier: ^1.5.2
version: 0.12.0(eslint@8.53.0) version: 1.5.2(eslint@8.53.0)
husky: husky:
specifier: ^8.0.3 specifier: ^8.0.3
version: 8.0.3 version: 8.0.3
@@ -700,8 +700,8 @@ packages:
regenerator-runtime: 0.13.11 regenerator-runtime: 0.13.11
dev: false dev: false
/@babel/runtime@7.23.9: /@babel/runtime@7.24.0:
resolution: {integrity: sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==} resolution: {integrity: sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dependencies: dependencies:
regenerator-runtime: 0.14.1 regenerator-runtime: 0.14.1
@@ -2471,15 +2471,12 @@ packages:
tslib: 2.6.2 tslib: 2.6.2
dev: true dev: true
/@playwright/test@1.34.3: /@playwright/test@1.42.1:
resolution: {integrity: sha512-zPLef6w9P6T/iT6XDYG3mvGOqOyb6eHaV9XtkunYs0+OzxBtrPAAaHotc0X+PJ00WPPnLfFBTl7mf45Mn8DBmw==} resolution: {integrity: sha512-Gq9rmS54mjBL/7/MvBaNOBwbfnh7beHvS6oS4srqXFcQHpQCV1+c8JXWE8VLPyRDhgS3H8x8A7hztqI9VnwrAQ==}
engines: {node: '>=14'} engines: {node: '>=16'}
hasBin: true hasBin: true
dependencies: dependencies:
'@types/node': 18.11.18 playwright: 1.42.1
playwright-core: 1.34.3
optionalDependencies:
fsevents: 2.3.2
dev: true dev: true
/@popperjs/core@2.11.8: /@popperjs/core@2.11.8:
@@ -3080,7 +3077,7 @@ packages:
engines: {node: '>=14'} engines: {node: '>=14'}
dependencies: dependencies:
'@babel/code-frame': 7.23.5 '@babel/code-frame': 7.23.5
'@babel/runtime': 7.23.9 '@babel/runtime': 7.24.0
'@types/aria-query': 5.0.4 '@types/aria-query': 5.0.4
aria-query: 5.1.3 aria-query: 5.1.3
chalk: 4.1.2 chalk: 4.1.2
@@ -5309,16 +5306,18 @@ packages:
- typescript - typescript
dev: true dev: true
/eslint-plugin-playwright@0.12.0(eslint@8.53.0): /eslint-plugin-playwright@1.5.2(eslint@8.53.0):
resolution: {integrity: sha512-KXuzQjVzca5irMT/7rvzJKsVDGbQr43oQPc8i+SLEBqmfrTxlwMwRqfv9vtZqh4hpU0jmrnA/EOfwtls+5QC1w==} resolution: {integrity: sha512-TMzLrLGQMccngU8GogtzIc9u5RzXGnfsQEUjLfEfshINuVR2fS4SHfDtU7xYP90Vwm5vflHECf610KTdGvO53w==}
engines: {node: '>=16.6.0'}
peerDependencies: peerDependencies:
eslint: '>=7' eslint: '>=8.40.0'
eslint-plugin-jest: '>=24' eslint-plugin-jest: '>=25'
peerDependenciesMeta: peerDependenciesMeta:
eslint-plugin-jest: eslint-plugin-jest:
optional: true optional: true
dependencies: dependencies:
eslint: 8.53.0 eslint: 8.53.0
globals: 13.24.0
dev: true dev: true
/eslint-plugin-prettier@5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.0.3): /eslint-plugin-prettier@5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.0.3):
@@ -6098,6 +6097,13 @@ packages:
type-fest: 0.20.2 type-fest: 0.20.2
dev: true dev: true
/globals@13.24.0:
resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
engines: {node: '>=8'}
dependencies:
type-fest: 0.20.2
dev: true
/globalthis@1.0.3: /globalthis@1.0.3:
resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
@@ -7687,12 +7693,22 @@ packages:
pathe: 1.1.1 pathe: 1.1.1
dev: true dev: true
/playwright-core@1.34.3: /playwright-core@1.42.1:
resolution: {integrity: sha512-2pWd6G7OHKemc5x1r1rp8aQcpvDh7goMBZlJv6Co5vCNLVcQJdhxRL09SGaY6HcyHH9aT4tiynZabMofVasBYw==} resolution: {integrity: sha512-mxz6zclokgrke9p1vtdy/COWBH+eOZgYUVVU34C73M+4j4HLlQJHtfcqiqqxpP0o8HhMkflvfbquLX5dg6wlfA==}
engines: {node: '>=14'} engines: {node: '>=16'}
hasBin: true hasBin: true
dev: true dev: true
/playwright@1.42.1:
resolution: {integrity: sha512-PgwB03s2DZBcNRoW+1w9E+VkLBxweib6KTXM0M3tkiT4jVxKSi6PmVJ591J+0u10LUrgxB7dLRbiJqO5s2QPMg==}
engines: {node: '>=16'}
hasBin: true
dependencies:
playwright-core: 1.42.1
optionalDependencies:
fsevents: 2.3.2
dev: true
/plist@3.1.0: /plist@3.1.0:
resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==}
engines: {node: '>=10.4.0'} engines: {node: '>=10.4.0'}