0
0

test(#10336): add components/MkC.* stories (#13830)

* test(storybook): add `components/MkC.*` stories

* test(storybook): add some tests

* test: add sleep

* test: comment-out flaky test

* test(storybook): add test for `MkChannelFollowButton`

* chore(storybook): tweak sleep duration in `MkChannelFollowButton` story test

* fix(chromatic): add delay to `MkChannelList`

* chore: replace `mswDecorator` with `mswLoader`

* fix(storybook): tweak some parameters

* chore: serve static files

* fix(chromatic): add delay to `MkCwButton`

* chore: delete logging for debug

* fix: add right click in `MkContextMenu` play

* refactor: remove unused imports
This commit is contained in:
zyoshoka 2024-06-08 18:00:54 +09:00 committed by GitHub
parent 61fae45390
commit 9849aab402
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 1083 additions and 86 deletions

View File

@ -22,6 +22,66 @@ export function abuseUserReport() {
}; };
} }
export function channel(id = 'somechannelid', name = 'Some Channel', bannerUrl: string | null = 'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/fedi.jpg?raw=true'): entities.Channel {
return {
id,
createdAt: '2016-12-28T22:49:51.000Z',
lastNotedAt: '2016-12-28T22:49:51.000Z',
name,
description: null,
userId: null,
bannerUrl,
pinnedNoteIds: [],
color: '#000',
isArchived: false,
usersCount: 1,
notesCount: 1,
isSensitive: false,
allowRenoteToExternal: false,
};
}
export function clip(id = 'someclipid', name = 'Some Clip'): entities.Clip {
return {
id,
createdAt: '2016-12-28T22:49:51.000Z',
lastClippedAt: null,
userId: 'someuserid',
user: {
id: 'someuserid',
name: 'Misskey User',
username: 'miskist',
host: 'misskey-hub.net',
avatarUrl: 'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/about-icon.png?raw=true',
avatarBlurhash: 'eQFRshof5NWBRi},juayfPju53WB?0ofs;s*a{ofjuay^SoMEJR%ay',
avatarDecorations: [],
emojis: {},
badgeRoles: [],
onlineStatus: 'unknown',
},
notesCount: undefined,
name,
description: 'Some clip description',
isPublic: false,
favoritedCount: 0,
};
}
export function emojiDetailed(id = 'someemojiid', name = 'some_emoji'): entities.EmojiDetailed {
return {
id,
aliases: ['alias1', 'alias2'],
name,
category: 'emojiCategory',
host: null,
url: '/client-assets/about-icon.png',
license: null,
isSensitive: false,
localOnly: false,
roleIdsThatCanBeUsedThisEmojiAsReaction: ['roleId1', 'roleId2'],
};
}
export function galleryPost(isSensitive = false) { export function galleryPost(isSensitive = false) {
return { return {
id: 'somepostid', id: 'somepostid',

View File

@ -397,7 +397,7 @@ function toStories(component: string): Promise<string> {
const globs = await Promise.all([ const globs = await Promise.all([
glob('src/components/global/Mk*.vue'), glob('src/components/global/Mk*.vue'),
glob('src/components/global/RouterView.vue'), glob('src/components/global/RouterView.vue'),
glob('src/components/Mk{A,B}*.vue'), glob('src/components/Mk[A-C]*.vue'),
glob('src/components/MkDigitalClock.vue'), glob('src/components/MkDigitalClock.vue'),
glob('src/components/MkGalleryPostPreview.vue'), glob('src/components/MkGalleryPostPreview.vue'),
glob('src/components/MkSignupServerRules.vue'), glob('src/components/MkSignupServerRules.vue'),

View File

@ -15,6 +15,7 @@ const _dirname = fileURLToPath(new URL('.', import.meta.url));
const config = { const config = {
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
staticDirs: [{ from: '../assets', to: '/client-assets' }],
addons: [ addons: [
getAbsolutePath('@storybook/addon-essentials'), getAbsolutePath('@storybook/addon-essentials'),
getAbsolutePath('@storybook/addon-interactions'), getAbsolutePath('@storybook/addon-interactions'),

View File

@ -7,7 +7,7 @@ import { FORCE_REMOUNT } from '@storybook/core-events';
import { addons } from '@storybook/preview-api'; import { addons } from '@storybook/preview-api';
import { type Preview, setup } from '@storybook/vue3'; import { type Preview, setup } from '@storybook/vue3';
import isChromatic from 'chromatic/isChromatic'; import isChromatic from 'chromatic/isChromatic';
import { initialize, mswDecorator } from 'msw-storybook-addon'; import { initialize, mswLoader } from 'msw-storybook-addon';
import { userDetailed } from './fakes.js'; import { userDetailed } from './fakes.js';
import locale from './locale.js'; import locale from './locale.js';
import { commonHandlers, onUnhandledRequest } from './mocks.js'; import { commonHandlers, onUnhandledRequest } from './mocks.js';
@ -122,7 +122,6 @@ const preview = {
} }
return story; return story;
}, },
mswDecorator,
(Story, context) => { (Story, context) => {
return { return {
setup() { setup() {
@ -137,6 +136,7 @@ const preview = {
}; };
}, },
], ],
loaders: [mswLoader],
parameters: { parameters: {
controls: { controls: {
exclude: /^__/, exclude: /^__/,

View File

@ -104,6 +104,7 @@
"@types/node": "20.12.7", "@types/node": "20.12.7",
"@types/punycode": "2.1.4", "@types/punycode": "2.1.4",
"@types/sanitize-html": "2.11.0", "@types/sanitize-html": "2.11.0",
"@types/seedrandom": "3.0.8",
"@types/throttle-debounce": "5.0.2", "@types/throttle-debounce": "5.0.2",
"@types/tinycolor2": "1.4.6", "@types/tinycolor2": "1.4.6",
"@types/uuid": "9.0.8", "@types/uuid": "9.0.8",
@ -128,6 +129,7 @@
"prettier": "3.2.5", "prettier": "3.2.5",
"react": "18.3.1", "react": "18.3.1",
"react-dom": "18.3.1", "react-dom": "18.3.1",
"seedrandom": "3.0.5",
"start-server-and-test": "2.0.3", "start-server-and-test": "2.0.3",
"storybook": "8.0.9", "storybook": "8.0.9",
"storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme", "storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme",

View File

@ -0,0 +1,77 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable import/no-default-export */
import { StoryObj } from '@storybook/vue3';
import { HttpResponse, http } from 'msw';
import { action } from '@storybook/addon-actions';
import { expect, userEvent, within } from '@storybook/test';
import { channel } from '../../.storybook/fakes.js';
import { commonHandlers } from '../../.storybook/mocks.js';
import MkChannelFollowButton from './MkChannelFollowButton.vue';
import { semaphore } from '@/scripts/test-utils.js';
import { i18n } from '@/i18n.js';
function sleep(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}
const s = semaphore();
export const Default = {
render(args) {
return {
components: {
MkChannelFollowButton,
},
setup() {
return {
args,
};
},
computed: {
props() {
return {
...this.args,
};
},
},
template: '<MkChannelFollowButton v-bind="props" />',
};
},
args: {
channel: channel(),
full: true,
},
async play({ canvasElement }) {
await s.acquire();
await sleep(1000);
const canvas = within(canvasElement);
const buttonElement = canvas.getByRole<HTMLButtonElement>('button');
await expect(buttonElement).toHaveTextContent(i18n.ts.follow);
await userEvent.click(buttonElement);
await sleep(1000);
await expect(buttonElement).toHaveTextContent(i18n.ts.unfollow);
await sleep(100);
await userEvent.click(buttonElement);
s.release();
},
parameters: {
layout: 'centered',
msw: {
handlers: [
...commonHandlers,
http.post('/api/channels/follow', async ({ request }) => {
action('POST /api/channels/follow')(await request.json());
return HttpResponse.json({});
}),
http.post('/api/channels/unfollow', async ({ request }) => {
action('POST /api/channels/unfollow')(await request.json());
return HttpResponse.json({});
}),
],
},
},
} satisfies StoryObj<typeof MkChannelFollowButton>;

View File

@ -26,17 +26,18 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue'; import { ref } from 'vue';
import * as Misskey from 'misskey-js';
import { misskeyApi } from '@/scripts/misskey-api.js'; import { misskeyApi } from '@/scripts/misskey-api.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
channel: Record<string, any>; channel: Misskey.entities.Channel;
full?: boolean; full?: boolean;
}>(), { }>(), {
full: false, full: false,
}); });
const isFollowing = ref<boolean>(props.channel.isFollowing); const isFollowing = ref(props.channel.isFollowing);
const wait = ref(false); const wait = ref(false);
async function onClick() { async function onClick() {

View File

@ -0,0 +1,65 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable import/no-default-export */
import { StoryObj } from '@storybook/vue3';
import { HttpResponse, http } from 'msw';
import { action } from '@storybook/addon-actions';
import { channel } from '../../.storybook/fakes.js';
import { commonHandlers } from '../../.storybook/mocks.js';
import MkChannelList from './MkChannelList.vue';
export const Default = {
render(args) {
return {
components: {
MkChannelList,
},
setup() {
return {
args,
};
},
computed: {
props() {
return {
...this.args,
};
},
},
template: '<MkChannelList v-bind="props" />',
};
},
args: {
pagination: {
endpoint: 'channels/search',
limit: 10,
},
},
parameters: {
chromatic: {
// NOTE: ロードが終わるまで待つ
delay: 3000,
},
layout: 'fullscreen',
msw: {
handlers: [
...commonHandlers,
http.post('/api/channels/search', async ({ request, params }) => {
action('POST /api/channels/search')(await request.json());
return HttpResponse.json(params.untilId === 'lastchannel' ? [] : [
channel(),
channel('lastchannel', 'Last Channel', null),
]);
}),
],
},
},
decorators: [
() => ({
template: '<div style="display: flex; align-items: center; justify-content: center; height: 100vh"><div style="max-width: 700px; width: 100%; margin: 3rem"><story/></div></div>',
}),
],
} satisfies StoryObj<typeof MkChannelList>;

View File

@ -0,0 +1,43 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable import/no-default-export */
import { StoryObj } from '@storybook/vue3';
import { channel } from '../../.storybook/fakes.js';
import MkChannelPreview from './MkChannelPreview.vue';
export const Default = {
render(args) {
return {
components: {
MkChannelPreview,
},
setup() {
return {
args,
};
},
computed: {
props() {
return {
...this.args,
};
},
},
template: '<MkChannelPreview v-bind="props" />',
};
},
args: {
channel: channel(),
},
parameters: {
layout: 'fullscreen',
},
decorators: [
() => ({
template: '<div style="display: flex; align-items: center; justify-content: center; height: 100vh"><div style="max-width: 700px; width: 100%; margin: 3rem"><story/></div></div>',
}),
],
} satisfies StoryObj<typeof MkChannelPreview>;

View File

@ -0,0 +1,117 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable import/no-default-export */
import { StoryObj } from '@storybook/vue3';
import { DefaultBodyType, HttpResponse, HttpResponseResolver, JsonBodyType, PathParams, http } from 'msw';
import seedrandom from 'seedrandom';
import { action } from '@storybook/addon-actions';
import { commonHandlers } from '../../.storybook/mocks.js';
import MkChart from './MkChart.vue';
function getChartArray(seed: string, limit: number, option?: { accumulate?: boolean, mul?: number }): number[] {
const rng = seedrandom(seed);
const max = Math.floor(option?.mul ?? 250 * rng());
let accumulation = 0;
const array: number[] = [];
for (let i = 0; i < limit; i++) {
const num = Math.floor((max + 1) * rng());
if (option?.accumulate) {
accumulation += num;
array.unshift(accumulation);
} else {
array.push(num);
}
}
return array;
}
function getChartResolver(fields: string[], option?: { accumulate?: boolean, mulMap?: Record<string, number> }): HttpResponseResolver<PathParams, DefaultBodyType, JsonBodyType> {
return ({ request }) => {
action(`GET ${request.url}`)();
const limitParam = new URL(request.url).searchParams.get('limit');
const limit = limitParam ? parseInt(limitParam) : 30;
const res = {};
for (const field of fields) {
const layers = field.split('.');
let current = res;
while (layers.length > 1) {
const currentKey = layers.shift()!;
if (current[currentKey] == null) current[currentKey] = {};
current = current[currentKey];
}
current[layers[0]] = getChartArray(field, limit, {
accumulate: option?.accumulate,
mul: option?.mulMap != null && field in option.mulMap ? option.mulMap[field] : undefined,
});
}
return HttpResponse.json(res);
};
}
const Base = {
render(args) {
return {
components: {
MkChart,
},
setup() {
return {
args,
};
},
computed: {
props() {
return {
...this.args,
};
},
},
template: '<MkChart v-bind="props" />',
};
},
args: {
src: 'federation',
span: 'hour',
},
parameters: {
layout: 'centered',
msw: {
handlers: [
...commonHandlers,
http.get('/api/charts/federation', getChartResolver(
['deliveredInstances', 'inboxInstances', 'stalled', 'sub', 'pub', 'pubsub', 'subActive', 'pubActive'],
)),
http.get('/api/charts/notes', getChartResolver(
['local.total', 'remote.total'],
{ accumulate: true },
)),
http.get('/api/charts/drive', getChartResolver(
['local.incSize', 'local.decSize', 'remote.incSize', 'remote.decSize'],
{ mulMap: { 'local.incSize': 1e7, 'local.decSize': 5e6, 'remote.incSize': 1e6, 'remote.decSize': 5e5 } },
)),
],
},
},
} satisfies StoryObj<typeof MkChart>;
export const FederationChart = {
...Base,
args: {
src: 'federation',
},
} satisfies StoryObj<typeof MkChart>;
export const NotesTotalChart = {
...Base,
args: {
src: 'notes-total',
},
} satisfies StoryObj<typeof MkChart>;
export const DriveChart = {
...Base,
args: {
src: 'drive',
},
} satisfies StoryObj<typeof MkChart>;

View File

@ -19,8 +19,9 @@ SPDX-License-Identifier: AGPL-3.0-only
id-denylist violation when setting it. This is causing about 60+ lint issues. id-denylist violation when setting it. This is causing about 60+ lint issues.
As this is part of Chart.js's API it makes sense to disable the check here. As this is part of Chart.js's API it makes sense to disable the check here.
*/ */
import { onMounted, ref, shallowRef, watch, PropType } from 'vue'; import { onMounted, ref, shallowRef, watch } from 'vue';
import { Chart } from 'chart.js'; import { Chart } from 'chart.js';
import * as Misskey from 'misskey-js';
import { misskeyApiGet } from '@/scripts/misskey-api.js'; import { misskeyApiGet } from '@/scripts/misskey-api.js';
import { defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js'; import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
@ -34,44 +35,55 @@ import MkChartLegend from '@/components/MkChartLegend.vue';
initChart(); initChart();
const props = defineProps({ type ChartSrc =
src: { | 'federation'
type: String, | 'ap-request'
required: true, | 'users'
}, | 'users-total'
args: { | 'active-users'
type: Object, | 'notes'
required: false, | 'local-notes'
}, | 'remote-notes'
limit: { | 'notes-total'
type: Number, | 'drive'
required: false, | 'drive-files'
default: 90, | 'instance-requests'
}, | 'instance-users'
span: { | 'instance-users-total'
type: String as PropType<'hour' | 'day'>, | 'instance-notes'
required: true, | 'instance-notes-total'
}, | 'instance-ff'
detailed: { | 'instance-ff-total'
type: Boolean, | 'instance-drive-usage'
required: false, | 'instance-drive-usage-total'
default: false, | 'instance-drive-files'
}, | 'instance-drive-files-total'
stacked: { | 'per-user-notes'
type: Boolean, | 'per-user-pv'
required: false, | 'per-user-following'
default: false, | 'per-user-followers'
}, | 'per-user-drive'
bar: {
type: Boolean, const props = withDefaults(defineProps<{
required: false, src: ChartSrc;
default: false, args?: {
}, host?: string;
aspectRatio: { user?: Misskey.entities.UserLite;
type: Number, withoutAll?: boolean;
required: false, };
default: null, limit?: number;
}, span: 'hour' | 'day';
detailed?: boolean;
stacked?: boolean;
bar?: boolean;
aspectRatio?: number | null;
}>(), {
args: undefined,
limit: 90,
detailed: false,
stacked: false,
bar: false,
aspectRatio: null,
}); });
const legendEl = shallowRef<InstanceType<typeof MkChartLegend>>(); const legendEl = shallowRef<InstanceType<typeof MkChartLegend>>();

View File

@ -0,0 +1,7 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import MkChartLegend from './MkChartLegend.vue';
void MkChartLegend;

View File

@ -0,0 +1,7 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import MkChartTooltip from './MkChartTooltip.vue';
void MkChartTooltip;

View File

@ -0,0 +1,79 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable import/no-default-export */
import { StoryObj } from '@storybook/vue3';
import { HttpResponse, http } from 'msw';
import { action } from '@storybook/addon-actions';
import { expect, within } from '@storybook/test';
import { commonHandlers } from '../../.storybook/mocks.js';
import MkClickerGame from './MkClickerGame.vue';
function sleep(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}
export const Default = {
render(args) {
return {
components: {
MkClickerGame,
},
setup() {
return {
args,
};
},
computed: {
props() {
return {
...this.args,
};
},
},
template: '<MkClickerGame v-bind="props" />',
};
},
async play({ canvasElement }) {
await sleep(1000);
const canvas = within(canvasElement);
const count = canvas.getByTestId('count');
// NOTE: flaky なので N/A も通しておく
await expect(count).toHaveTextContent(/^(0|N\/A)$/);
// FIXME: flaky
// const buttonElement = canvas.getByRole<HTMLButtonElement>('button');
// await userEvent.click(buttonElement);
// await expect(count).toHaveTextContent('1');
},
parameters: {
layout: 'centered',
msw: {
handlers: [
...commonHandlers,
http.post('/api/i/registry/get', async ({ request }) => {
action('POST /api/i/registry/get')(await request.json());
return HttpResponse.json({
error: {
message: 'No such key.',
code: 'NO_SUCH_KEY',
id: 'ac3ed68a-62f0-422b-a7bc-d5e09e8f6a6a',
},
}, {
status: 400,
});
}),
http.post('/api/i/registry/set', async ({ request }) => {
action('POST /api/i/registry/set')(await request.json());
return HttpResponse.json(undefined, { status: 204 });
}),
http.post('/api/i/claim-achievement', async ({ request }) => {
action('POST /api/i/claim-achievement')(await request.json());
return HttpResponse.json(undefined, { status: 204 });
}),
],
},
},
} satisfies StoryObj<typeof MkClickerGame>;

View File

@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div> <div>
<div v-if="game.ready" :class="$style.game"> <div v-if="game.ready" :class="$style.game">
<div :class="$style.cps" class="">{{ number(cps) }}cps</div> <div :class="$style.cps" class="">{{ number(cps) }}cps</div>
<div :class="$style.count" class=""><i class="ti ti-cookie" style="font-size: 70%;"></i> {{ number(cookies) }}</div> <div :class="$style.count" class="" data-testid="count"><i class="ti ti-cookie" style="font-size: 70%;"></i> {{ number(cookies) }}</div>
<button v-click-anime class="_button" @click="onClick"> <button v-click-anime class="_button" @click="onClick">
<img src="/client-assets/cookie.png" :class="$style.img"> <img src="/client-assets/cookie.png" :class="$style.img">
</button> </button>

View File

@ -0,0 +1,43 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable import/no-default-export */
import { StoryObj } from '@storybook/vue3';
import { clip } from '../../.storybook/fakes.js';
import MkClipPreview from './MkClipPreview.vue';
export const Default = {
render(args) {
return {
components: {
MkClipPreview,
},
setup() {
return {
args,
};
},
computed: {
props() {
return {
...this.args,
};
},
},
template: '<MkClipPreview v-bind="props" />',
};
},
args: {
clip: clip(),
},
parameters: {
layout: 'fullscreen',
},
decorators: [
() => ({
template: '<div style="display: flex; align-items: center; justify-content: center; height: 100vh"><div style="max-width: 700px; width: 100%; margin: 3rem"><story/></div></div>',
}),
],
} satisfies StoryObj<typeof MkClipPreview>;

View File

@ -0,0 +1,7 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import MkCode_core from './MkCode.core.vue';
void MkCode_core;

View File

@ -0,0 +1,44 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable import/no-default-export */
import { StoryObj } from '@storybook/vue3';
import MkCode from './MkCode.vue';
const code = `for (let i, 100) {
<: if (i % 15 == 0) "FizzBuzz"
elif (i % 3 == 0) "Fizz"
elif (i % 5 == 0) "Buzz"
else i
}`;
export const Default = {
render(args) {
return {
components: {
MkCode,
},
setup() {
return {
args,
};
},
computed: {
props() {
return {
...this.args,
};
},
},
template: '<MkCode v-bind="props" />',
};
},
args: {
code,
lang: 'is',
},
parameters: {
layout: 'centered',
},
} satisfies StoryObj<typeof MkCode>;

View File

@ -0,0 +1,62 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable import/no-default-export */
import { StoryObj } from '@storybook/vue3';
import { action } from '@storybook/addon-actions';
import MkCodeEditor from './MkCodeEditor.vue';
const code = `for (let i, 100) {
<: if (i % 15 == 0) "FizzBuzz"
elif (i % 3 == 0) "Fizz"
elif (i % 5 == 0) "Buzz"
else i
}`;
export const Default = {
render(args) {
return {
components: {
MkCodeEditor,
},
data() {
return {
code,
};
},
setup() {
return {
args,
};
},
computed: {
props() {
return {
...this.args,
};
},
events() {
return {
'change': action('change'),
'keydown': action('keydown'),
'enter': action('enter'),
'update:modelValue': action('update:modelValue'),
};
},
},
template: '<MkCodeEditor v-model="code" v-bind="props" v-on="events" />',
};
},
args: {
lang: 'aiscript',
},
parameters: {
layout: 'fullscreen',
},
decorators: [
() => ({
template: '<div style="display: flex; align-items: center; justify-content: center; height: 100vh"><div style="max-width: 800px; width: 100%; margin: 3rem"><Suspense><story/></Suspense></div></div>',
}),
],
} satisfies StoryObj<typeof MkCodeEditor>;

View File

@ -0,0 +1,37 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable import/no-default-export */
import { StoryObj } from '@storybook/vue3';
import MkCodeInline from './MkCodeInline.vue';
export const Default = {
render(args) {
return {
components: {
MkCodeInline,
},
setup() {
return {
args,
};
},
computed: {
props() {
return {
...this.args,
};
},
},
template: '<MkCodeInline v-bind="props"/>',
};
},
args: {
code: '<: "Hello, world!"',
},
parameters: {
layout: 'centered',
},
} satisfies StoryObj<typeof MkCodeInline>;

View File

@ -0,0 +1,50 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable import/no-default-export */
import { StoryObj } from '@storybook/vue3';
import { action } from '@storybook/addon-actions';
import MkColorInput from './MkColorInput.vue';
export const Default = {
render(args) {
return {
components: {
MkColorInput,
},
data() {
return {
color: '#cccccc',
};
},
setup() {
return {
args,
};
},
computed: {
props() {
return {
...this.args,
};
},
events() {
return {
'update:modelValue': action('update:modelValue'),
};
},
},
template: '<MkColorInput v-model="color" v-bind="props" v-on="events" />',
};
},
parameters: {
layout: 'fullscreen',
},
decorators: [
() => ({
template: '<div style="display: flex; align-items: center; justify-content: center; height: 100vh"><div style="max-width: 800px; width: 100%; margin: 3rem"><story/></div></div>',
}),
],
} satisfies StoryObj<typeof MkColorInput>;

View File

@ -0,0 +1,7 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import MkContainer from './MkContainer.vue';
void MkContainer;

View File

@ -0,0 +1,58 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable import/no-default-export */
import { StoryObj } from '@storybook/vue3';
import { userEvent, within } from '@storybook/test';
import MkContextMenu from './MkContextMenu.vue';
import * as os from '@/os.js';
export const Empty = {
render(args) {
return {
setup() {
return {
args,
};
},
computed: {
props() {
return {
...this.args,
};
},
},
methods: {
onContextmenu(ev: MouseEvent) {
os.contextMenu(args.items, ev);
},
},
template: '<div @contextmenu.stop="onContextmenu">Right Click Here</div>',
};
},
args: {
items: [],
},
async play({ canvasElement }) {
const canvas = within(canvasElement);
const target = canvas.getByText('Right Click Here');
await userEvent.pointer({ keys: '[MouseRight>]', target });
},
parameters: {
layout: 'centered',
},
} satisfies StoryObj<typeof MkContextMenu>;
export const SomeTabs = {
...Empty,
args: {
items: [
{
text: 'Home',
icon: 'ti ti-home',
action() {},
},
],
},
} satisfies StoryObj<typeof MkContextMenu>;

View File

@ -0,0 +1,75 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable import/no-default-export */
import { StoryObj } from '@storybook/vue3';
import { HttpResponse, http } from 'msw';
import { action } from '@storybook/addon-actions';
import { file } from '../../.storybook/fakes.js';
import { commonHandlers } from '../../.storybook/mocks.js';
import MkCropperDialog from './MkCropperDialog.vue';
export const Default = {
render(args) {
return {
components: {
MkCropperDialog,
},
setup() {
return {
args,
};
},
computed: {
props() {
return {
...this.args,
};
},
events() {
return {
'ok': action('ok'),
'cancel': action('cancel'),
'closed': action('closed'),
};
},
},
template: '<MkCropperDialog v-bind="props" v-on="events" />',
};
},
args: {
file: file(),
aspectRatio: NaN,
},
parameters: {
chromatic: {
// NOTE: ロードが終わるまで待つ
delay: 3000,
},
layout: 'centered',
msw: {
handlers: [
...commonHandlers,
http.get('/proxy/image.webp', async ({ request }) => {
const url = new URL(request.url).searchParams.get('url');
if (url === 'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/fedi.jpg?raw=true') {
const image = await (await fetch('client-assets/fedi.jpg')).blob();
return new HttpResponse(image, {
headers: {
'Content-Type': 'image/jpeg',
},
});
} else {
return new HttpResponse(null, { status: 404 });
}
}),
http.post('/api/drive/files/create', async ({ request }) => {
action('POST /api/drive/files/create')(await request.formData());
return HttpResponse.json(file());
}),
],
},
},
} satisfies StoryObj<typeof MkCropperDialog>;

View File

@ -0,0 +1,38 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable import/no-default-export */
import { StoryObj } from '@storybook/vue3';
import { emojiDetailed } from '../../.storybook/fakes.js';
import MkCustomEmojiDetailedDialog from './MkCustomEmojiDetailedDialog.vue';
export const Default = {
render(args) {
return {
components: {
MkCustomEmojiDetailedDialog,
},
setup() {
return {
args,
};
},
computed: {
props() {
return {
...this.args,
};
},
},
template: '<MkCustomEmojiDetailedDialog v-bind="props" />',
};
},
args: {
emoji: emojiDetailed(),
},
parameters: {
layout: 'centered',
},
} satisfies StoryObj<typeof MkCustomEmojiDetailedDialog>;

View File

@ -0,0 +1,89 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable import/no-default-export */
import { StoryObj } from '@storybook/vue3';
import { action } from '@storybook/addon-actions';
import { expect, userEvent, within } from '@storybook/test';
import { file } from '../../.storybook/fakes.js';
import MkCwButton from './MkCwButton.vue';
import { i18n } from '@/i18n.js';
import { semaphore } from '@/scripts/test-utils.js';
function sleep(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}
const s = semaphore();
export const Default = {
render(args) {
return {
components: {
MkCwButton,
},
data() {
return {
showContent: false,
};
},
setup() {
return {
args,
};
},
computed: {
props() {
return {
...this.args,
};
},
events() {
return {
'update:modelValue': action('update:modelValue'),
};
},
},
template: '<MkCwButton v-model="showContent" v-bind="props" v-on="events" />',
};
},
args: {
text: 'Some CW content',
},
async play({ canvasElement }) {
await s.acquire();
await sleep(1000);
const canvas = within(canvasElement);
const buttonElement = canvas.getByRole<HTMLButtonElement>('button');
await expect(buttonElement).toHaveTextContent(i18n.ts._cw.show);
await expect(buttonElement).toHaveTextContent(i18n.tsx._cw.chars({ count: 15 }));
await userEvent.click(buttonElement);
await expect(buttonElement).toHaveTextContent(i18n.ts._cw.hide);
await userEvent.click(buttonElement);
s.release();
},
parameters: {
chromatic: {
// NOTE: テストが終わるまで待つ
delay: 5000,
},
layout: 'centered',
},
} satisfies StoryObj<typeof MkCwButton>;
export const IncludesTextAndDriveFile = {
...Default,
args: {
text: 'Some CW content',
files: [file()],
},
async play({ canvasElement }) {
const canvas = within(canvasElement);
const buttonElement = canvas.getByRole<HTMLButtonElement>('button');
await expect(buttonElement).toHaveTextContent(i18n.tsx._cw.chars({ count: 15 }));
await expect(buttonElement).toHaveTextContent(' / ');
await expect(buttonElement).toHaveTextContent(i18n.tsx._cw.files({ count: 1 }));
},
} satisfies StoryObj<typeof MkCwButton>;

View File

@ -7,3 +7,13 @@ export async function tick(): Promise<void> {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
await new Promise((globalThis.requestIdleCallback ?? setTimeout) as never); await new Promise((globalThis.requestIdleCallback ?? setTimeout) as never);
} }
/**
* @see https://github.com/misskey-dev/misskey/issues/11267
*/
export function semaphore(counter = 0, waiting: (() => void)[] = []) {
return {
acquire: () => ++counter > 1 && new Promise<void>(resolve => waiting.push(resolve)),
release: () => --counter && waiting.pop()?.(),
};
}

View File

@ -947,6 +947,9 @@ importers:
'@types/sanitize-html': '@types/sanitize-html':
specifier: 2.11.0 specifier: 2.11.0
version: 2.11.0 version: 2.11.0
'@types/seedrandom':
specifier: 3.0.8
version: 3.0.8
'@types/throttle-debounce': '@types/throttle-debounce':
specifier: 5.0.2 specifier: 5.0.2
version: 5.0.2 version: 5.0.2
@ -1019,6 +1022,9 @@ importers:
react-dom: react-dom:
specifier: 18.3.1 specifier: 18.3.1
version: 18.3.1(react@18.3.1) version: 18.3.1(react@18.3.1)
seedrandom:
specifier: 3.0.5
version: 3.0.5
start-server-and-test: start-server-and-test:
specifier: 2.0.3 specifier: 2.0.3
version: 2.0.3 version: 2.0.3
@ -11917,7 +11923,7 @@ snapshots:
'@babel/traverse': 7.23.5 '@babel/traverse': 7.23.5
'@babel/types': 7.23.5 '@babel/types': 7.23.5
convert-source-map: 2.0.0 convert-source-map: 2.0.0
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
gensync: 1.0.0-beta.2 gensync: 1.0.0-beta.2
json5: 2.2.3 json5: 2.2.3
semver: 6.3.1 semver: 6.3.1
@ -11937,7 +11943,7 @@ snapshots:
'@babel/traverse': 7.24.0 '@babel/traverse': 7.24.0
'@babel/types': 7.24.0 '@babel/types': 7.24.0
convert-source-map: 2.0.0 convert-source-map: 2.0.0
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
gensync: 1.0.0-beta.2 gensync: 1.0.0-beta.2
json5: 2.2.3 json5: 2.2.3
semver: 6.3.1 semver: 6.3.1
@ -12007,7 +12013,7 @@ snapshots:
'@babel/core': 7.24.0 '@babel/core': 7.24.0
'@babel/helper-compilation-targets': 7.23.6 '@babel/helper-compilation-targets': 7.23.6
'@babel/helper-plugin-utils': 7.22.5 '@babel/helper-plugin-utils': 7.22.5
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
lodash.debounce: 4.0.8 lodash.debounce: 4.0.8
resolve: 1.22.8 resolve: 1.22.8
transitivePeerDependencies: transitivePeerDependencies:
@ -12778,7 +12784,7 @@ snapshots:
'@babel/helper-split-export-declaration': 7.22.6 '@babel/helper-split-export-declaration': 7.22.6
'@babel/parser': 7.23.9 '@babel/parser': 7.23.9
'@babel/types': 7.23.5 '@babel/types': 7.23.5
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
globals: 11.12.0 globals: 11.12.0
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -12793,7 +12799,7 @@ snapshots:
'@babel/helper-split-export-declaration': 7.22.6 '@babel/helper-split-export-declaration': 7.22.6
'@babel/parser': 7.24.0 '@babel/parser': 7.24.0
'@babel/types': 7.24.0 '@babel/types': 7.24.0
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
globals: 11.12.0 globals: 11.12.0
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -13185,7 +13191,7 @@ snapshots:
'@eslint/eslintrc@2.1.4': '@eslint/eslintrc@2.1.4':
dependencies: dependencies:
ajv: 6.12.6 ajv: 6.12.6
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
espree: 9.6.1 espree: 9.6.1
globals: 13.19.0 globals: 13.19.0
ignore: 5.2.4 ignore: 5.2.4
@ -13336,7 +13342,7 @@ snapshots:
'@humanwhocodes/config-array@0.11.13': '@humanwhocodes/config-array@0.11.13':
dependencies: dependencies:
'@humanwhocodes/object-schema': 2.0.1 '@humanwhocodes/object-schema': 2.0.1
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
minimatch: 3.1.2 minimatch: 3.1.2
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -13344,7 +13350,7 @@ snapshots:
'@humanwhocodes/config-array@0.11.14': '@humanwhocodes/config-array@0.11.14':
dependencies: dependencies:
'@humanwhocodes/object-schema': 2.0.2 '@humanwhocodes/object-schema': 2.0.2
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
minimatch: 3.1.2 minimatch: 3.1.2
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -16198,7 +16204,7 @@ snapshots:
'@typescript-eslint/type-utils': 6.11.0(eslint@8.53.0)(typescript@5.3.3) '@typescript-eslint/type-utils': 6.11.0(eslint@8.53.0)(typescript@5.3.3)
'@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.3.3) '@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.3.3)
'@typescript-eslint/visitor-keys': 6.11.0 '@typescript-eslint/visitor-keys': 6.11.0
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
eslint: 8.53.0 eslint: 8.53.0
graphemer: 1.4.0 graphemer: 1.4.0
ignore: 5.2.4 ignore: 5.2.4
@ -16218,7 +16224,7 @@ snapshots:
'@typescript-eslint/type-utils': 7.1.0(eslint@8.57.0)(typescript@5.3.3) '@typescript-eslint/type-utils': 7.1.0(eslint@8.57.0)(typescript@5.3.3)
'@typescript-eslint/utils': 7.1.0(eslint@8.57.0)(typescript@5.3.3) '@typescript-eslint/utils': 7.1.0(eslint@8.57.0)(typescript@5.3.3)
'@typescript-eslint/visitor-keys': 7.1.0 '@typescript-eslint/visitor-keys': 7.1.0
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
eslint: 8.57.0 eslint: 8.57.0
graphemer: 1.4.0 graphemer: 1.4.0
ignore: 5.2.4 ignore: 5.2.4
@ -16238,7 +16244,7 @@ snapshots:
'@typescript-eslint/type-utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/type-utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5)
'@typescript-eslint/utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5)
'@typescript-eslint/visitor-keys': 7.7.1 '@typescript-eslint/visitor-keys': 7.7.1
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
eslint: 8.57.0 eslint: 8.57.0
graphemer: 1.4.0 graphemer: 1.4.0
ignore: 5.3.1 ignore: 5.3.1
@ -16256,7 +16262,7 @@ snapshots:
'@typescript-eslint/types': 6.11.0 '@typescript-eslint/types': 6.11.0
'@typescript-eslint/typescript-estree': 6.11.0(typescript@5.3.3) '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.3.3)
'@typescript-eslint/visitor-keys': 6.11.0 '@typescript-eslint/visitor-keys': 6.11.0
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
eslint: 8.53.0 eslint: 8.53.0
optionalDependencies: optionalDependencies:
typescript: 5.3.3 typescript: 5.3.3
@ -16269,7 +16275,7 @@ snapshots:
'@typescript-eslint/types': 7.1.0 '@typescript-eslint/types': 7.1.0
'@typescript-eslint/typescript-estree': 7.1.0(typescript@5.3.3) '@typescript-eslint/typescript-estree': 7.1.0(typescript@5.3.3)
'@typescript-eslint/visitor-keys': 7.1.0 '@typescript-eslint/visitor-keys': 7.1.0
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
eslint: 8.57.0 eslint: 8.57.0
optionalDependencies: optionalDependencies:
typescript: 5.3.3 typescript: 5.3.3
@ -16282,7 +16288,7 @@ snapshots:
'@typescript-eslint/types': 7.7.1 '@typescript-eslint/types': 7.7.1
'@typescript-eslint/typescript-estree': 7.7.1(typescript@5.4.5) '@typescript-eslint/typescript-estree': 7.7.1(typescript@5.4.5)
'@typescript-eslint/visitor-keys': 7.7.1 '@typescript-eslint/visitor-keys': 7.7.1
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
eslint: 8.57.0 eslint: 8.57.0
optionalDependencies: optionalDependencies:
typescript: 5.4.5 typescript: 5.4.5
@ -16308,7 +16314,7 @@ snapshots:
dependencies: dependencies:
'@typescript-eslint/typescript-estree': 6.11.0(typescript@5.3.3) '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.3.3)
'@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.3.3) '@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.3.3)
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
eslint: 8.53.0 eslint: 8.53.0
ts-api-utils: 1.0.1(typescript@5.3.3) ts-api-utils: 1.0.1(typescript@5.3.3)
optionalDependencies: optionalDependencies:
@ -16320,7 +16326,7 @@ snapshots:
dependencies: dependencies:
'@typescript-eslint/typescript-estree': 7.1.0(typescript@5.3.3) '@typescript-eslint/typescript-estree': 7.1.0(typescript@5.3.3)
'@typescript-eslint/utils': 7.1.0(eslint@8.57.0)(typescript@5.3.3) '@typescript-eslint/utils': 7.1.0(eslint@8.57.0)(typescript@5.3.3)
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
eslint: 8.57.0 eslint: 8.57.0
ts-api-utils: 1.0.1(typescript@5.3.3) ts-api-utils: 1.0.1(typescript@5.3.3)
optionalDependencies: optionalDependencies:
@ -16332,7 +16338,7 @@ snapshots:
dependencies: dependencies:
'@typescript-eslint/typescript-estree': 7.7.1(typescript@5.4.5) '@typescript-eslint/typescript-estree': 7.7.1(typescript@5.4.5)
'@typescript-eslint/utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5)
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
eslint: 8.57.0 eslint: 8.57.0
ts-api-utils: 1.3.0(typescript@5.4.5) ts-api-utils: 1.3.0(typescript@5.4.5)
optionalDependencies: optionalDependencies:
@ -16350,7 +16356,7 @@ snapshots:
dependencies: dependencies:
'@typescript-eslint/types': 6.11.0 '@typescript-eslint/types': 6.11.0
'@typescript-eslint/visitor-keys': 6.11.0 '@typescript-eslint/visitor-keys': 6.11.0
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
globby: 11.1.0 globby: 11.1.0
is-glob: 4.0.3 is-glob: 4.0.3
semver: 7.5.4 semver: 7.5.4
@ -16364,7 +16370,7 @@ snapshots:
dependencies: dependencies:
'@typescript-eslint/types': 7.1.0 '@typescript-eslint/types': 7.1.0
'@typescript-eslint/visitor-keys': 7.1.0 '@typescript-eslint/visitor-keys': 7.1.0
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
globby: 11.1.0 globby: 11.1.0
is-glob: 4.0.3 is-glob: 4.0.3
minimatch: 9.0.3 minimatch: 9.0.3
@ -16379,7 +16385,7 @@ snapshots:
dependencies: dependencies:
'@typescript-eslint/types': 7.7.1 '@typescript-eslint/types': 7.7.1
'@typescript-eslint/visitor-keys': 7.7.1 '@typescript-eslint/visitor-keys': 7.7.1
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
globby: 11.1.0 globby: 11.1.0
is-glob: 4.0.3 is-glob: 4.0.3
minimatch: 9.0.4 minimatch: 9.0.4
@ -16714,13 +16720,13 @@ snapshots:
agent-base@6.0.2: agent-base@6.0.2:
dependencies: dependencies:
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
agent-base@7.1.0: agent-base@7.1.0:
dependencies: dependencies:
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -16950,7 +16956,7 @@ snapshots:
dependencies: dependencies:
'@fastify/error': 3.4.0 '@fastify/error': 3.4.0
archy: 1.0.0 archy: 1.0.0
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
fastq: 1.17.1 fastq: 1.17.1
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -18058,7 +18064,7 @@ snapshots:
detect-port@1.5.1: detect-port@1.5.1:
dependencies: dependencies:
address: 1.2.2 address: 1.2.2
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -18274,7 +18280,7 @@ snapshots:
esbuild-register@3.5.0(esbuild@0.20.2): esbuild-register@3.5.0(esbuild@0.20.2):
dependencies: dependencies:
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
esbuild: 0.20.2 esbuild: 0.20.2
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -18544,7 +18550,7 @@ snapshots:
ajv: 6.12.6 ajv: 6.12.6
chalk: 4.1.2 chalk: 4.1.2
cross-spawn: 7.0.3 cross-spawn: 7.0.3
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
doctrine: 3.0.0 doctrine: 3.0.0
escape-string-regexp: 4.0.0 escape-string-regexp: 4.0.0
eslint-scope: 7.2.2 eslint-scope: 7.2.2
@ -18587,7 +18593,7 @@ snapshots:
ajv: 6.12.6 ajv: 6.12.6
chalk: 4.1.2 chalk: 4.1.2
cross-spawn: 7.0.3 cross-spawn: 7.0.3
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
doctrine: 3.0.0 doctrine: 3.0.0
escape-string-regexp: 4.0.0 escape-string-regexp: 4.0.0
eslint-scope: 7.2.2 eslint-scope: 7.2.2
@ -19049,7 +19055,7 @@ snapshots:
follow-redirects@1.15.2(debug@4.3.4): follow-redirects@1.15.2(debug@4.3.4):
optionalDependencies: optionalDependencies:
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
for-each@0.3.3: for-each@0.3.3:
dependencies: dependencies:
@ -19504,7 +19510,7 @@ snapshots:
http-proxy-agent@7.0.0: http-proxy-agent@7.0.0:
dependencies: dependencies:
agent-base: 7.1.0 agent-base: 7.1.0
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -19543,14 +19549,14 @@ snapshots:
https-proxy-agent@5.0.1: https-proxy-agent@5.0.1:
dependencies: dependencies:
agent-base: 6.0.2 agent-base: 6.0.2
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
https-proxy-agent@7.0.2: https-proxy-agent@7.0.2:
dependencies: dependencies:
agent-base: 7.1.0 agent-base: 7.1.0
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -19646,7 +19652,7 @@ snapshots:
dependencies: dependencies:
'@ioredis/commands': 1.2.0 '@ioredis/commands': 1.2.0
cluster-key-slot: 1.1.2 cluster-key-slot: 1.1.2
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
denque: 2.1.0 denque: 2.1.0
lodash.defaults: 4.2.0 lodash.defaults: 4.2.0
lodash.isarguments: 3.1.0 lodash.isarguments: 3.1.0
@ -19899,7 +19905,7 @@ snapshots:
istanbul-lib-source-maps@4.0.1: istanbul-lib-source-maps@4.0.1:
dependencies: dependencies:
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
istanbul-lib-coverage: 3.2.2 istanbul-lib-coverage: 3.2.2
source-map: 0.6.1 source-map: 0.6.1
transitivePeerDependencies: transitivePeerDependencies:
@ -20963,7 +20969,7 @@ snapshots:
micromark@4.0.0: micromark@4.0.0:
dependencies: dependencies:
'@types/debug': 4.1.12 '@types/debug': 4.1.12
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
decode-named-character-reference: 1.0.2 decode-named-character-reference: 1.0.2
devlop: 1.1.0 devlop: 1.1.0
micromark-core-commonmark: 2.0.0 micromark-core-commonmark: 2.0.0
@ -22814,7 +22820,7 @@ snapshots:
dependencies: dependencies:
'@hapi/hoek': 10.0.1 '@hapi/hoek': 10.0.1
'@hapi/wreck': 18.0.1 '@hapi/wreck': 18.0.1
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
joi: 17.11.0 joi: 17.11.0
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -22912,7 +22918,7 @@ snapshots:
socks-proxy-agent@8.0.2: socks-proxy-agent@8.0.2:
dependencies: dependencies:
agent-base: 7.1.0 agent-base: 7.1.0
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
socks: 2.7.1 socks: 2.7.1
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -23009,7 +23015,7 @@ snapshots:
arg: 5.0.2 arg: 5.0.2
bluebird: 3.7.2 bluebird: 3.7.2
check-more-types: 2.24.0 check-more-types: 2.24.0
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
execa: 5.1.1 execa: 5.1.1
lazy-ass: 1.6.0 lazy-ass: 1.6.0
ps-tree: 1.2.0 ps-tree: 1.2.0
@ -23522,7 +23528,7 @@ snapshots:
chalk: 4.1.2 chalk: 4.1.2
cli-highlight: 2.1.11 cli-highlight: 2.1.11
dayjs: 1.11.10 dayjs: 1.11.10
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
dotenv: 16.0.3 dotenv: 16.0.3
glob: 10.3.10 glob: 10.3.10
mkdirp: 2.1.6 mkdirp: 2.1.6
@ -23732,7 +23738,7 @@ snapshots:
vite-node@0.34.6(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3): vite-node@0.34.6(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3):
dependencies: dependencies:
cac: 6.7.14 cac: 6.7.14
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
mlly: 1.5.0 mlly: 1.5.0
pathe: 1.1.2 pathe: 1.1.2
picocolors: 1.0.0 picocolors: 1.0.0
@ -23781,7 +23787,7 @@ snapshots:
acorn-walk: 8.3.2 acorn-walk: 8.3.2
cac: 6.7.14 cac: 6.7.14
chai: 4.3.10 chai: 4.3.10
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
local-pkg: 0.4.3 local-pkg: 0.4.3
magic-string: 0.30.7 magic-string: 0.30.7
pathe: 1.1.2 pathe: 1.1.2
@ -23864,7 +23870,7 @@ snapshots:
vue-eslint-parser@9.4.2(eslint@8.57.0): vue-eslint-parser@9.4.2(eslint@8.57.0):
dependencies: dependencies:
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@5.5.0)
eslint: 8.57.0 eslint: 8.57.0
eslint-scope: 7.2.2 eslint-scope: 7.2.2
eslint-visitor-keys: 3.4.3 eslint-visitor-keys: 3.4.3