diff options
| author | syuilo <4439005+syuilo@users.noreply.github.com> | 2026-01-09 22:06:40 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-09 22:06:40 +0900 |
| commit | 41592eafb363e3c62ab2d3e5f41b38d7d083d3fb (patch) | |
| tree | 8f69243a5482ad4161eb28b69769684a221aa05c /packages/frontend/src/pages | |
| parent | fix(frontend): popupのemit型が正しく利用できるように修正 (#16... (diff) | |
| download | misskey-41592eafb363e3c62ab2d3e5f41b38d7d083d3fb.tar.gz misskey-41592eafb363e3c62ab2d3e5f41b38d7d083d3fb.tar.bz2 misskey-41592eafb363e3c62ab2d3e5f41b38d7d083d3fb.zip | |
refactor: make noImplicitAny true (#17083)
* wip
* Update emojis.emoji.vue
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* Update manager.ts
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* Update analytics.ts
Diffstat (limited to 'packages/frontend/src/pages')
79 files changed, 332 insertions, 253 deletions
diff --git a/packages/frontend/src/pages/about.federation.vue b/packages/frontend/src/pages/about.federation.vue index bbfb9a3b7c..c109000108 100644 --- a/packages/frontend/src/pages/about.federation.vue +++ b/packages/frontend/src/pages/about.federation.vue @@ -97,7 +97,7 @@ const paginator = markRaw(new Paginator('federation/instances', { })), })); -function getStatus(instance) { +function getStatus(instance: Misskey.entities.FederationInstance) { if (instance.isSuspended) return 'Suspended'; if (instance.isBlocked) return 'Blocked'; if (instance.isSilenced) return 'Silenced'; diff --git a/packages/frontend/src/pages/admin-user.vue b/packages/frontend/src/pages/admin-user.vue index 22e377c75d..b084eb5ab2 100644 --- a/packages/frontend/src/pages/admin-user.vue +++ b/packages/frontend/src/pages/admin-user.vue @@ -105,7 +105,7 @@ SPDX-License-Identifier: AGPL-3.0-only <template #label>{{ i18n.ts._role.policies }}</template> <div class="_gaps"> <div v-for="policy in Object.keys(info.policies)" :key="policy"> - {{ policy }} ... {{ info.policies[policy] }} + {{ policy }} ... {{ info.policies[policy as keyof typeof info.policies] }} </div> </div> </MkFolder> @@ -209,6 +209,7 @@ SPDX-License-Identifier: AGPL-3.0-only import { computed, defineAsyncComponent, watch, ref, markRaw } from 'vue'; import * as Misskey from 'misskey-js'; import { url } from '@@/js/config.js'; +import type { ChartSrc } from '@/components/MkChart.vue'; import MkChart from '@/components/MkChart.vue'; import MkObjectView from '@/components/MkObjectView.vue'; import MkTextarea from '@/components/MkTextarea.vue'; @@ -231,7 +232,6 @@ import { ensureSignin, iAmAdmin, iAmModerator } from '@/i.js'; import MkRolePreview from '@/components/MkRolePreview.vue'; import MkPagination from '@/components/MkPagination.vue'; import { Paginator } from '@/utility/paginator.js'; -import type { ChartSrc } from '@/components/MkChart.vue'; const $i = ensureSignin(); @@ -251,7 +251,7 @@ const { } = useMkSelect({ items: [ { label: i18n.ts.notes, value: 'per-user-notes' }, -], + ], initialValue: 'per-user-notes', }); const user = ref(result.user); @@ -344,7 +344,7 @@ async function resetPassword() { } } -async function toggleSuspend(v) { +async function toggleSuspend(v: boolean) { const confirm = await os.confirm({ type: 'warning', text: v ? i18n.ts.suspendConfirm : i18n.ts.unsuspendConfirm, @@ -475,7 +475,7 @@ async function assignRole() { refreshUser(); } -async function unassignRole(role: typeof info.value.roles[number], ev: MouseEvent) { +async function unassignRole(role: typeof info.value.roles[number], ev: PointerEvent) { os.popupMenu([{ text: i18n.ts.unassign, icon: 'ti ti-x', @@ -503,7 +503,7 @@ async function createAnnouncement() { }); } -async function editAnnouncement(announcement) { +async function editAnnouncement(announcement: Misskey.entities.AdminAnnouncementsListResponse[number]) { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkUserAnnouncementEditDialog.vue').then(x => x.default), { user: user.value, announcement, diff --git a/packages/frontend/src/pages/admin/RolesEditorFormula.vue b/packages/frontend/src/pages/admin/RolesEditorFormula.vue index 9eeedd5c1d..13f66662d0 100644 --- a/packages/frontend/src/pages/admin/RolesEditorFormula.vue +++ b/packages/frontend/src/pages/admin/RolesEditorFormula.vue @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only <template> <div class="_gaps"> <div :class="$style.header"> - <MkSelect v-model="type" :items="typeDef" :class="$style.typeSelect"> + <MkSelect v-model="typeModelForMkSelect" :items="typeDef" :class="$style.typeSelect"> </MkSelect> <button v-if="draggable" class="_button" :class="$style.dragHandle" :draggable="true" @dragstart.stop="dragStartCallback"> <i class="ti ti-menu-2"></i> @@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only </button> </div> - <div v-if="type === 'and' || type === 'or'" class="_gaps"> + <div v-if="v.type === 'and' || v.type === 'or'" class="_gaps"> <MkDraggable v-model="v.values" direction="vertical" @@ -32,33 +32,34 @@ SPDX-License-Identifier: AGPL-3.0-only :modelValue="item" :dragStartCallback="dragStart" draggable - @update:modelValue="updated => valuesItemUpdated(updated)" - @remove="removeItem(item.id)" + @update:modelValue="updated => childValuesItemUpdated(updated)" + @remove="removeChildItem(item.id)" /> </div> </template> </MkDraggable> - <MkButton rounded style="margin: 0 auto;" @click="addValue"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton> + <MkButton rounded style="margin: 0 auto;" @click="addChildValue"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton> </div> - <div v-else-if="type === 'not'" :class="$style.item"> + <div v-else-if="v.type === 'not'" :class="$style.item"> <RolesEditorFormula v-model="v.value"/> </div> - <MkInput v-else-if="type === 'createdLessThan' || type === 'createdMoreThan'" v-model="v.sec" type="number"> + <MkInput v-else-if="v.type === 'createdLessThan' || v.type === 'createdMoreThan'" v-model="v.sec" type="number"> <template #suffix>sec</template> </MkInput> - <MkInput v-else-if="['followersLessThanOrEq', 'followersMoreThanOrEq', 'followingLessThanOrEq', 'followingMoreThanOrEq', 'notesLessThanOrEq', 'notesMoreThanOrEq'].includes(type)" v-model="v.value" type="number"> + <MkInput v-else-if="v.type === 'followersLessThanOrEq' || v.type === 'followersMoreThanOrEq' || v.type === 'followingLessThanOrEq' || v.type === 'followingMoreThanOrEq' || v.type === 'notesLessThanOrEq' || v.type === 'notesMoreThanOrEq'" v-model="v.value" type="number"> </MkInput> - <MkSelect v-else-if="type === 'roleAssignedTo'" v-model="v.roleId" :items="assignedToDef"> + <MkSelect v-else-if="v.type === 'roleAssignedTo'" v-model="v.roleId" :items="assignedToDef"> </MkSelect> </div> </template> <script lang="ts" setup> import { computed, ref, watch } from 'vue'; +import * as Misskey from 'misskey-js'; import type { GetMkSelectValueTypesFromDef, MkSelectItem } from '@/components/MkSelect.vue'; import { genId } from '@/utility/id.js'; import MkInput from '@/components/MkInput.vue'; @@ -70,12 +71,12 @@ import { deepClone } from '@/utility/clone.js'; import { rolesCache } from '@/cache.js'; const emit = defineEmits<{ - (ev: 'update:modelValue', value: any): void; + (ev: 'update:modelValue', value: Misskey.entities.Role['condFormula']): void; (ev: 'remove'): void; }>(); const props = defineProps<{ - modelValue: any; + modelValue: Misskey.entities.Role['condFormula']; draggable?: boolean; dragStartCallback?: (ev: DragEvent) => void; }>(); @@ -115,37 +116,50 @@ const typeDef = [ { label: i18n.ts._role._condition.not, value: 'not' }, ] as const satisfies MkSelectItem[]; -const type = computed<GetMkSelectValueTypesFromDef<typeof typeDef>>({ +type KeyOfUnion<T> = T extends T ? keyof T : never; + +type DistributiveOmit<T, K extends KeyOfUnion<T>> = T extends T + ? Omit<T, K> + : never; + +const typeModelForMkSelect = computed<GetMkSelectValueTypesFromDef<typeof typeDef>>({ get: () => v.value.type, set: (t) => { - if (t === 'and') v.value.values = []; - if (t === 'or') v.value.values = []; - if (t === 'not') v.value.value = { id: genId(), type: 'isRemote' }; - if (t === 'roleAssignedTo') v.value.roleId = ''; - if (t === 'createdLessThan') v.value.sec = 86400; - if (t === 'createdMoreThan') v.value.sec = 86400; - if (t === 'followersLessThanOrEq') v.value.value = 10; - if (t === 'followersMoreThanOrEq') v.value.value = 10; - if (t === 'followingLessThanOrEq') v.value.value = 10; - if (t === 'followingMoreThanOrEq') v.value.value = 10; - if (t === 'notesLessThanOrEq') v.value.value = 10; - if (t === 'notesMoreThanOrEq') v.value.value = 10; - v.value.type = t; + let newValue: DistributiveOmit<Misskey.entities.Role['condFormula'], 'id'>; + switch (t) { + case 'and': newValue = { type: 'and', values: [] }; break; + case 'or': newValue = { type: 'or', values: [] }; break; + case 'not': newValue = { type: 'not', value: { id: genId(), type: 'isRemote' } }; break; + case 'roleAssignedTo': newValue = { type: 'roleAssignedTo', roleId: '' }; break; + case 'createdLessThan': newValue = { type: 'createdLessThan', sec: 86400 }; break; + case 'createdMoreThan': newValue = { type: 'createdMoreThan', sec: 86400 }; break; + case 'followersLessThanOrEq': newValue = { type: 'followersLessThanOrEq', value: 10 }; break; + case 'followersMoreThanOrEq': newValue = { type: 'followersMoreThanOrEq', value: 10 }; break; + case 'followingLessThanOrEq': newValue = { type: 'followingLessThanOrEq', value: 10 }; break; + case 'followingMoreThanOrEq': newValue = { type: 'followingMoreThanOrEq', value: 10 }; break; + case 'notesLessThanOrEq': newValue = { type: 'notesLessThanOrEq', value: 10 }; break; + case 'notesMoreThanOrEq': newValue = { type: 'notesMoreThanOrEq', value: 10 }; break; + default: newValue = { type: t }; break; + } + v.value = { id: v.value.id, ...newValue }; }, }); const assignedToDef = computed(() => roles.filter(r => r.target === 'manual').map(r => ({ label: r.name, value: r.id })) satisfies MkSelectItem[]); -function addValue() { +function addChildValue() { + if (v.value.type !== 'and' && v.value.type !== 'or') return; v.value.values.push({ id: genId(), type: 'isRemote' }); } -function valuesItemUpdated(item) { +function childValuesItemUpdated(item: Misskey.entities.Role['condFormula']) { + if (v.value.type !== 'and' && v.value.type !== 'or') return; const i = v.value.values.findIndex(_item => _item.id === item.id); v.value.values[i] = item; } -function removeItem(itemId) { +function removeChildItem(itemId: string) { + if (v.value.type !== 'and' && v.value.type !== 'or') return; v.value.values = v.value.values.filter(_item => _item.id !== itemId); } diff --git a/packages/frontend/src/pages/admin/abuses.vue b/packages/frontend/src/pages/admin/abuses.vue index 76bf20b409..2d204987cb 100644 --- a/packages/frontend/src/pages/admin/abuses.vue +++ b/packages/frontend/src/pages/admin/abuses.vue @@ -105,7 +105,7 @@ const paginator = markRaw(new Paginator('admin/abuse-user-reports', { })), })); -function resolved(reportId) { +function resolved(reportId: string) { paginator.removeItem(reportId); } diff --git a/packages/frontend/src/pages/admin/announcements.vue b/packages/frontend/src/pages/admin/announcements.vue index 4a5c83e9df..ddf458b268 100644 --- a/packages/frontend/src/pages/admin/announcements.vue +++ b/packages/frontend/src/pages/admin/announcements.vue @@ -83,6 +83,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref, computed, watch } from 'vue'; +import * as Misskey from 'misskey-js'; import MkButton from '@/components/MkButton.vue'; import MkInput from '@/components/MkInput.vue'; import MkSelect from '@/components/MkSelect.vue'; @@ -112,7 +113,12 @@ const { const loading = ref(true); const loadingMore = ref(false); -const announcements = ref<any[]>([]); +const announcements = ref<(Omit<Misskey.entities.AdminAnnouncementsListResponse[number], 'id' | 'createdAt' | 'updatedAt' | 'reads' | 'isActive'> & { + id: string | null; + _id?: string; + isActive?: Misskey.entities.AdminAnnouncementsListResponse[number]['isActive']; + reads?: Misskey.entities.AdminAnnouncementsListResponse[number]['reads']; +})[]>([]); watch(announcementsStatus, (to) => { loading.value = true; @@ -136,42 +142,55 @@ function add() { forExistingUsers: false, silence: false, needConfirmationToRead: false, + userId: null, }); } -function del(announcement) { - os.confirm({ +async function del(announcement: (typeof announcements)['value'][number]) { + if (announcement.id == null) return; + const { canceled } = await os.confirm({ type: 'warning', text: i18n.tsx.deleteAreYouSure({ x: announcement.title }), - }).then(({ canceled }) => { - if (canceled) return; - announcements.value = announcements.value.filter(x => x !== announcement); - misskeyApi('admin/announcements/delete', announcement); + }); + if (canceled) return; + announcements.value = announcements.value.filter(x => x !== announcement); + misskeyApi('admin/announcements/delete', { + id: announcement.id, }); } -async function archive(announcement) { +async function archive(announcement: (typeof announcements)['value'][number]) { + if (announcement.id == null) return; + const { _id, ...data } = announcement; // _idを消す await os.apiWithDialog('admin/announcements/update', { - ...announcement, + ...data, + id: announcement.id, // TSを黙らすため isActive: false, }); refresh(); } -async function unarchive(announcement) { +async function unarchive(announcement: (typeof announcements)['value'][number]) { + if (announcement.id == null) return; + const { _id, ...data } = announcement; // _idを消す await os.apiWithDialog('admin/announcements/update', { - ...announcement, + ...data, + id: announcement.id, // TSを黙らすため isActive: true, }); refresh(); } -async function save(announcement) { +async function save(announcement: (typeof announcements)['value'][number]) { + const { _id, ...data } = announcement; // _idを消す if (announcement.id == null) { - await os.apiWithDialog('admin/announcements/create', announcement); + await os.apiWithDialog('admin/announcements/create', data); refresh(); } else { - os.apiWithDialog('admin/announcements/update', announcement); + os.apiWithDialog('admin/announcements/update', { + ...data, + id: announcement.id, // TSを黙らすため + }); } } @@ -179,7 +198,7 @@ function more() { loadingMore.value = true; misskeyApi('admin/announcements/list', { status: announcementsStatus.value, - untilId: announcements.value.reduce((acc, announcement) => announcement.id != null ? announcement : acc).id, + untilId: announcements.value.reduce((acc, announcement) => announcement.id != null ? announcement : acc).id!, }).then(announcementResponse => { announcements.value = announcements.value.concat(announcementResponse); loadingMore.value = false; diff --git a/packages/frontend/src/pages/admin/custom-emojis-manager.local.list.vue b/packages/frontend/src/pages/admin/custom-emojis-manager.local.list.vue index 250abeebe2..6f58ab9857 100644 --- a/packages/frontend/src/pages/admin/custom-emojis-manager.local.list.vue +++ b/packages/frontend/src/pages/admin/custom-emojis-manager.local.list.vue @@ -51,6 +51,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts"> import type { SortOrder } from '@/components/MkSortOrderEditor.define.js'; import type { GridSortOrderKey } from './custom-emojis-manager.impl.js'; +import type { PageHeaderItem } from '@/types/page-header.js'; export type EmojiSearchQuery = { name: string | null; @@ -250,7 +251,7 @@ function setupGrid(): GridSetting { icon: 'ti ti-trash', action: () => { removeDataFromGrid(context, (cell) => { - gridItems.value[cell.row.index][cell.column.setting.bindTo] = undefined; + (gridItems.value[cell.row.index] as any)[cell.column.setting.bindTo] = undefined; }); }, }, @@ -454,7 +455,7 @@ function onGridCellValidation(event: GridCellValidationEvent) { function onGridCellValueChange(event: GridCellValueChangeEvent) { const { row, column, newValue } = event; if (gridItems.value.length > row.index && column.setting.bindTo in gridItems.value[row.index]) { - gridItems.value[row.index][column.setting.bindTo] = newValue; + (gridItems.value[row.index] as any)[column.setting.bindTo] = newValue; } } @@ -525,7 +526,7 @@ const headerPageMetadata = computed(() => ({ icon: 'ti ti-icons', })); -const headerActions = computed(() => [{ +const headerActions = computed<PageHeaderItem[]>(() => [{ icon: 'ti ti-search', text: i18n.ts.search, handler: async () => { @@ -552,7 +553,7 @@ const headerActions = computed(() => [{ }, { icon: 'ti ti-list-numbers', text: i18n.ts._customEmojisManager._gridCommon.searchLimit, - handler: (ev: MouseEvent) => { + handler: (ev) => { async function changeSearchLimit(to: number) { if (updatedItemsCount.value > 0) { const { canceled } = await os.confirm({ diff --git a/packages/frontend/src/pages/admin/custom-emojis-manager.register.vue b/packages/frontend/src/pages/admin/custom-emojis-manager.register.vue index c343d88eb1..7ccb166481 100644 --- a/packages/frontend/src/pages/admin/custom-emojis-manager.register.vue +++ b/packages/frontend/src/pages/admin/custom-emojis-manager.register.vue @@ -58,7 +58,6 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script setup lang="ts"> -/* eslint-disable @typescript-eslint/no-non-null-assertion */ import * as Misskey from 'misskey-js'; import { computed, onMounted, ref, useCssModule } from 'vue'; import type { RequestLogItem } from '@/pages/admin/custom-emojis-manager.impl.js'; @@ -339,7 +338,7 @@ function onGridCellValidation(event: GridCellValidationEvent) { function onGridCellValueChange(event: GridCellValueChangeEvent) { const { row, column, newValue } = event; if (gridItems.value.length > row.index && column.setting.bindTo in gridItems.value[row.index]) { - gridItems.value[row.index][column.setting.bindTo] = newValue; + (gridItems.value[row.index] as any)[column.setting.bindTo] = newValue; } } diff --git a/packages/frontend/src/pages/admin/custom-emojis-manager.remote.vue b/packages/frontend/src/pages/admin/custom-emojis-manager.remote.vue index 6317fc0b47..d5bfdffe34 100644 --- a/packages/frontend/src/pages/admin/custom-emojis-manager.remote.vue +++ b/packages/frontend/src/pages/admin/custom-emojis-manager.remote.vue @@ -306,7 +306,7 @@ function onGridEvent(event: GridEvent) { function onGridCellValueChange(event: GridCellValueChangeEvent) { const { row, column, newValue } = event; if (gridItems.value.length > row.index && column.setting.bindTo in gridItems.value[row.index]) { - gridItems.value[row.index][column.setting.bindTo] = newValue; + (gridItems.value[row.index] as any)[column.setting.bindTo] = newValue; } } diff --git a/packages/frontend/src/pages/admin/federation-job-queue.chart.chart.vue b/packages/frontend/src/pages/admin/federation-job-queue.chart.chart.vue index 420219c22c..04de781a28 100644 --- a/packages/frontend/src/pages/admin/federation-job-queue.chart.chart.vue +++ b/packages/frontend/src/pages/admin/federation-job-queue.chart.chart.vue @@ -28,7 +28,7 @@ const { handler: externalTooltipHandler } = useChartTooltip(); let chartInstance: Chart | null = null; -function setData(values) { +function setData(values: number[]) { if (chartInstance == null || chartInstance.data.labels == null) return; for (const value of values) { chartInstance.data.labels.push(''); @@ -41,7 +41,7 @@ function setData(values) { chartInstance.update(); } -function pushData(value) { +function pushData(value: number) { if (chartInstance == null || chartInstance.data.labels == null) return; chartInstance.data.labels.push(''); chartInstance.data.datasets[0].data.push(value); diff --git a/packages/frontend/src/pages/admin/index.vue b/packages/frontend/src/pages/admin/index.vue index 94994dc94c..b3a929faf4 100644 --- a/packages/frontend/src/pages/admin/index.vue +++ b/packages/frontend/src/pages/admin/index.vue @@ -294,7 +294,7 @@ function invite() { }); } -function adminLookup(ev: MouseEvent) { +function adminLookup(ev: PointerEvent) { os.popupMenu([{ text: i18n.ts.user, icon: 'ti ti-user', diff --git a/packages/frontend/src/pages/admin/overview.active-users.vue b/packages/frontend/src/pages/admin/overview.active-users.vue index 32a5a6976e..9854ca7fc6 100644 --- a/packages/frontend/src/pages/admin/overview.active-users.vue +++ b/packages/frontend/src/pages/admin/overview.active-users.vue @@ -47,7 +47,7 @@ async function renderChart() { return new Date(y, m, d - ago); }; - const format = (arr) => { + const format = (arr: number[]) => { return arr.map((v, i) => ({ x: getDate(i).getTime(), y: v, diff --git a/packages/frontend/src/pages/admin/overview.vue b/packages/frontend/src/pages/admin/overview.vue index 2c550bd9c3..90799647ff 100644 --- a/packages/frontend/src/pages/admin/overview.vue +++ b/packages/frontend/src/pages/admin/overview.vue @@ -104,7 +104,7 @@ const filesPagination = { noPaging: true, }; -function onInstanceClick(i) { +function onInstanceClick(i: Misskey.entities.FederationInstance) { os.pageWindow(`/instance-info/${i.host}`); } diff --git a/packages/frontend/src/pages/admin/roles.edit.vue b/packages/frontend/src/pages/admin/roles.edit.vue index b24b640527..e806f68162 100644 --- a/packages/frontend/src/pages/admin/roles.edit.vue +++ b/packages/frontend/src/pages/admin/roles.edit.vue @@ -21,8 +21,8 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { computed, ref } from 'vue'; import * as Misskey from 'misskey-js'; -import { genId } from '@/utility/id.js'; import XEditor from './roles.editor.vue'; +import { genId } from '@/utility/id.js'; import * as os from '@/os.js'; import { misskeyApi } from '@/utility/misskey-api.js'; import { i18n } from '@/i18n.js'; @@ -37,8 +37,13 @@ const props = defineProps<{ id?: string; }>(); +type RoleLike = Pick<Misskey.entities.Role, 'name' | 'description' | 'isAdministrator' | 'isModerator' | 'color' | 'iconUrl' | 'target' | 'isPublic' | 'isExplorable' | 'asBadge' | 'canEditMembersByModerator' | 'displayOrder' | 'preserveAssignmentOnMoveAccount'> & { + condFormula: any; + policies: any; +}; + const role = ref<Misskey.entities.Role | null>(null); -const data = ref<any>(null); +const data = ref<RoleLike | null>(null); if (props.id) { role.value = await misskeyApi('admin/roles/show', { @@ -61,11 +66,13 @@ if (props.id) { asBadge: false, canEditMembersByModerator: false, displayOrder: 0, + preserveAssignmentOnMoveAccount: false, policies: {}, }; } async function save() { + if (data.value === null) return; rolesCache.delete(); if (role.value) { os.apiWithDialog('admin/roles/update', { @@ -75,7 +82,7 @@ async function save() { router.push('/admin/roles/:id', { params: { id: role.value.id, - } + }, }); } else { const created = await os.apiWithDialog('admin/roles/create', { @@ -84,7 +91,7 @@ async function save() { router.push('/admin/roles/:id', { params: { id: created.id, - } + }, }); } } diff --git a/packages/frontend/src/pages/admin/roles.editor.vue b/packages/frontend/src/pages/admin/roles.editor.vue index 5f8950f07e..7de973a394 100644 --- a/packages/frontend/src/pages/admin/roles.editor.vue +++ b/packages/frontend/src/pages/admin/roles.editor.vue @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only <template> <div class="_gaps"> - <MkInput v-if="readonly" :modelValue="role.id" :readonly="true"> + <MkInput v-if="readonly && role.id != null" :modelValue="role.id" :readonly="true"> <template #label>ID</template> </MkInput> @@ -866,12 +866,18 @@ import { i18n } from '@/i18n.js'; import { instance } from '@/instance.js'; import { deepClone } from '@/utility/clone.js'; +type RoleLike = Pick<Misskey.entities.Role, 'name' | 'description' | 'isAdministrator' | 'isModerator' | 'color' | 'iconUrl' | 'target' | 'isPublic' | 'isExplorable' | 'asBadge' | 'canEditMembersByModerator' | 'displayOrder' | 'preserveAssignmentOnMoveAccount'> & { + id?: Misskey.entities.Role['id'] | null; + condFormula: any; + policies: any; +}; + const emit = defineEmits<{ - (ev: 'update:modelValue', v: any): void; + (ev: 'update:modelValue', v: RoleLike): void; }>(); const props = defineProps<{ - modelValue: any; + modelValue: RoleLike; readonly?: boolean; }>(); @@ -910,7 +916,7 @@ const rolePermission = computed<GetMkSelectValueTypesFromDef<typeof rolePermissi const q = ref(''); -function getPriorityIcon(option) { +function getPriorityIcon(option: { priority: number }): string { if (option.priority === 2) return 'ti ti-arrows-up'; if (option.priority === 1) return 'ti ti-arrow-narrow-up'; return 'ti ti-point'; @@ -936,6 +942,7 @@ const save = throttle(100, () => { isExplorable: role.value.isExplorable, asBadge: role.value.asBadge, canEditMembersByModerator: role.value.canEditMembersByModerator, + preserveAssignmentOnMoveAccount: role.value.preserveAssignmentOnMoveAccount, policies: role.value.policies, }; diff --git a/packages/frontend/src/pages/admin/roles.role.vue b/packages/frontend/src/pages/admin/roles.role.vue index 2e249eee50..7fc51979af 100644 --- a/packages/frontend/src/pages/admin/roles.role.vue +++ b/packages/frontend/src/pages/admin/roles.role.vue @@ -28,15 +28,15 @@ SPDX-License-Identifier: AGPL-3.0-only <template #default="{ items }"> <div class="_gaps_s"> - <div v-for="item in items" :key="item.user.id" :class="[$style.userItem, { [$style.userItemOpened]: expandedItems.includes(item.id) }]"> + <div v-for="item in items" :key="item.user.id" :class="[$style.userItem, { [$style.userItemOpened]: expandedItemIds.includes(item.id) }]"> <div :class="$style.userItemMain"> <MkA :class="$style.userItemMainBody" :to="`/admin/user/${item.user.id}`"> <MkUserCardMini :user="item.user"/> </MkA> - <button class="_button" :class="$style.userToggle" @click="toggleItem(item)"><i :class="$style.chevron" class="ti ti-chevron-down"></i></button> - <button class="_button" :class="$style.unassign" @click="unassign(item.user, $event)"><i class="ti ti-x"></i></button> + <button class="_button" :class="$style.userToggle" @click="toggleItem(item.id)"><i :class="$style.chevron" class="ti ti-chevron-down"></i></button> + <button class="_button" :class="$style.unassign" @click="unassign(item.user.id, $event)"><i class="ti ti-x"></i></button> </div> - <div v-if="expandedItems.includes(item.id)" :class="$style.userItemSub"> + <div v-if="expandedItemIds.includes(item.id)" :class="$style.userItemSub"> <div>Assigned: <MkTime :time="item.createdAt" mode="detail"/></div> <div v-if="item.expiresAt">Period: {{ new Date(item.expiresAt).toLocaleString() }}</div> <div v-else>Period: {{ i18n.ts.indefinitely }}</div> @@ -55,6 +55,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { computed, markRaw, reactive, ref } from 'vue'; +import * as Misskey from 'misskey-js'; import XEditor from './roles.editor.vue'; import MkFolder from '@/components/MkFolder.vue'; import * as os from '@/os.js'; @@ -81,7 +82,7 @@ const usersPaginator = markRaw(new Paginator('admin/roles/users', { }) : undefined), })); -const expandedItems = ref<string[]>([]); +const expandedItemIds = ref<Misskey.entities.AdminRolesUsersResponse[number]['id'][]>([]); const role = reactive(await misskeyApi('admin/roles/show', { roleId: props.id, @@ -91,7 +92,7 @@ function edit() { router.push('/admin/roles/:id/edit', { params: { id: role.id, - } + }, }); } @@ -140,23 +141,23 @@ async function assign() { //role.users.push(user); } -async function unassign(user, ev) { +async function unassign(userId: Misskey.entities.User['id'], ev: PointerEvent) { os.popupMenu([{ text: i18n.ts.unassign, icon: 'ti ti-x', danger: true, action: async () => { - await os.apiWithDialog('admin/roles/unassign', { roleId: role.id, userId: user.id }); - //role.users = role.users.filter(u => u.id !== user.id); + await os.apiWithDialog('admin/roles/unassign', { roleId: role.id, userId: userId }); + //role.users = role.users.filter(u => u.id !== userId); }, }], ev.currentTarget ?? ev.target); } -async function toggleItem(item) { - if (expandedItems.value.includes(item.id)) { - expandedItems.value = expandedItems.value.filter(x => x !== item.id); +async function toggleItem(itemId: string) { + if (expandedItemIds.value.includes(itemId)) { + expandedItemIds.value = expandedItemIds.value.filter(x => x !== itemId); } else { - expandedItems.value.push(item.id); + expandedItemIds.value.push(itemId); } } diff --git a/packages/frontend/src/pages/admin/users.vue b/packages/frontend/src/pages/admin/users.vue index 2f7ecca521..eb9806d668 100644 --- a/packages/frontend/src/pages/admin/users.vue +++ b/packages/frontend/src/pages/admin/users.vue @@ -46,6 +46,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { computed, markRaw, ref, watchEffect } from 'vue'; +import * as Misskey from 'misskey-js'; import { defaultMemoryStorage } from '@/memory-storage'; import MkButton from '@/components/MkButton.vue'; import MkInput from '@/components/MkInput.vue'; @@ -146,7 +147,7 @@ async function addUser() { }); } -function show(user) { +function show(user: Misskey.entities.UserDetailed) { os.pageWindow(`/admin/user/${user.id}`); } diff --git a/packages/frontend/src/pages/announcements.vue b/packages/frontend/src/pages/announcements.vue index 4c34c3c74b..150808fcbd 100644 --- a/packages/frontend/src/pages/announcements.vue +++ b/packages/frontend/src/pages/announcements.vue @@ -33,7 +33,7 @@ SPDX-License-Identifier: AGPL-3.0-only </div> </MkA> </div> - <div v-if="tab !== 'past' && $i && !announcement.silence && !announcement.isRead" :class="$style.footer"> + <div v-if="tab !== 'past' && $i != null && !announcement.silence && !announcement.isRead" :class="$style.footer"> <MkButton primary @click="read(announcement)"><i class="ti ti-check"></i> {{ i18n.ts.gotIt }}</MkButton> </div> </section> @@ -45,6 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref, computed, markRaw } from 'vue'; +import * as Misskey from 'misskey-js'; import MkPagination from '@/components/MkPagination.vue'; import MkButton from '@/components/MkButton.vue'; import MkInfo from '@/components/MkInfo.vue'; @@ -65,7 +66,9 @@ const paginator = markRaw(new Paginator('announcements', { const tab = ref('current'); -async function read(target) { +async function read(target: Misskey.entities.Announcement) { + if ($i == null) return; + if (target.needConfirmationToRead) { const confirm = await os.confirm({ type: 'question', @@ -81,7 +84,7 @@ async function read(target) { })); misskeyApi('i/read-announcement', { announcementId: target.id }); updateCurrentAccountPartial({ - unreadAnnouncements: $i!.unreadAnnouncements.filter(a => a.id !== target.id), + unreadAnnouncements: $i.unreadAnnouncements.filter(a => a.id !== target.id), }); } diff --git a/packages/frontend/src/pages/api-console.vue b/packages/frontend/src/pages/api-console.vue index f436fc72fa..8377dc074d 100644 --- a/packages/frontend/src/pages/api-console.vue +++ b/packages/frontend/src/pages/api-console.vue @@ -73,7 +73,7 @@ function onEndpointChange() { return; } - const endpointBody = {}; + const endpointBody = {} as Record<string, unknown>; for (const p of resp.params) { endpointBody[p.name] = p.type === 'String' ? '' : diff --git a/packages/frontend/src/pages/auth.form.vue b/packages/frontend/src/pages/auth.form.vue index 1a0c9b36c4..6e9f5dd1eb 100644 --- a/packages/frontend/src/pages/auth.form.vue +++ b/packages/frontend/src/pages/auth.form.vue @@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div v-if="app.permission.length > 0"> <p>{{ i18n.tsx._auth.permission({ name }) }}</p> <ul> - <li v-for="p in app.permission" :key="p">{{ i18n.ts._permissions[p] }}</li> + <li v-for="p in app.permission" :key="p">{{ (i18n.ts._permissions as any)[p] ?? p }}</li> </ul> </div> <div>{{ i18n.tsx._auth.shareAccess({ name: `${name} (${app.id})` }) }}</div> diff --git a/packages/frontend/src/pages/auth.vue b/packages/frontend/src/pages/auth.vue index 83bf7221d0..14b13e511a 100644 --- a/packages/frontend/src/pages/auth.vue +++ b/packages/frontend/src/pages/auth.vue @@ -67,7 +67,7 @@ function accepted() { } } -function onLogin(res) { +function onLogin(res: Misskey.entities.SigninFlowResponse & { finished: true }) { login(res.i); } diff --git a/packages/frontend/src/pages/avatar-decoration-edit-dialog.vue b/packages/frontend/src/pages/avatar-decoration-edit-dialog.vue index a8ce527523..68e8d6a4d0 100644 --- a/packages/frontend/src/pages/avatar-decoration-edit-dialog.vue +++ b/packages/frontend/src/pages/avatar-decoration-edit-dialog.vue @@ -78,7 +78,7 @@ import { ensureSignin } from '@/i.js'; const $i = ensureSignin(); const props = defineProps<{ - avatarDecoration?: any, + avatarDecoration?: Misskey.entities.AdminAvatarDecorationsListResponse[number], }>(); const emit = defineEmits<{ @@ -109,7 +109,7 @@ async function addRole() { rolesThatCanBeUsedThisDecoration.value.push(roles.find(r => r.id === roleId)!); } -async function removeRole(role, ev) { +async function removeRole(role: Misskey.entities.Role, ev: PointerEvent) { rolesThatCanBeUsedThisDecoration.value = rolesThatCanBeUsedThisDecoration.value.filter(x => x.id !== role.id); } @@ -147,6 +147,8 @@ async function done() { } async function del() { + if (props.avatarDecoration == null) return; + const { canceled } = await os.confirm({ type: 'warning', text: i18n.tsx.removeAreYouSure({ x: name.value }), diff --git a/packages/frontend/src/pages/avatar-decorations.vue b/packages/frontend/src/pages/avatar-decorations.vue index f96c02a567..4c5457504e 100644 --- a/packages/frontend/src/pages/avatar-decorations.vue +++ b/packages/frontend/src/pages/avatar-decorations.vue @@ -45,7 +45,7 @@ function load() { load(); -async function add(ev: MouseEvent) { +async function add(ev: PointerEvent) { const { dispose } = await os.popupAsyncWithDialog(import('./avatar-decoration-edit-dialog.vue').then(x => x.default), { }, { done: result => { @@ -57,7 +57,7 @@ async function add(ev: MouseEvent) { }); } -async function edit(avatarDecoration) { +async function edit(avatarDecoration: Misskey.entities.AdminAvatarDecorationsListResponse[number]) { const { dispose } = await os.popupAsyncWithDialog(import('./avatar-decoration-edit-dialog.vue').then(x => x.default), { avatarDecoration: avatarDecoration, }, { diff --git a/packages/frontend/src/pages/channel-editor.vue b/packages/frontend/src/pages/channel-editor.vue index 16b01937c0..4b73b6c6b3 100644 --- a/packages/frontend/src/pages/channel-editor.vue +++ b/packages/frontend/src/pages/channel-editor.vue @@ -191,7 +191,7 @@ async function archive() { }); } -function setBannerImage(evt) { +function setBannerImage(evt: PointerEvent) { selectFile({ anchorElement: evt.currentTarget ?? evt.target, multiple: false, diff --git a/packages/frontend/src/pages/chat/XMessage.vue b/packages/frontend/src/pages/chat/XMessage.vue index cd984f6fb5..f759e45e48 100644 --- a/packages/frontend/src/pages/chat/XMessage.vue +++ b/packages/frontend/src/pages/chat/XMessage.vue @@ -94,7 +94,7 @@ provide(DI.mfmEmojiReactCallback, (reaction) => { }); }); -function react(ev: MouseEvent) { +function react(ev: PointerEvent) { if ($i.policies.chatAvailability !== 'available') return; const targetEl = getHTMLElementOrNull(ev.currentTarget ?? ev.target); @@ -128,14 +128,14 @@ function onReactionClick(record: Misskey.entities.ChatMessage['reactions'][0]) { } } -function onContextmenu(ev: MouseEvent) { +function onContextmenu(ev: PointerEvent) { if (ev.target && isLink(ev.target as HTMLElement)) return; if (window.getSelection()?.toString() !== '') return; showMenu(ev, true); } -function showMenu(ev: MouseEvent, contextmenu = false) { +function showMenu(ev: PointerEvent, contextmenu = false) { const menu: MenuItem[] = []; if (!isMe.value && $i.policies.chatAvailability === 'available') { diff --git a/packages/frontend/src/pages/chat/home.home.vue b/packages/frontend/src/pages/chat/home.home.vue index 756bf8a342..ed04253046 100644 --- a/packages/frontend/src/pages/chat/home.home.vue +++ b/packages/frontend/src/pages/chat/home.home.vue @@ -64,7 +64,7 @@ const searchQuery = ref(''); const searched = ref(false); const searchResults = ref<Misskey.entities.ChatMessage[]>([]); -function start(ev: MouseEvent) { +function start(ev: PointerEvent) { os.popupMenu([{ text: i18n.ts._chat.individualChat, caption: i18n.ts._chat.individualChat_description, @@ -89,7 +89,7 @@ async function startUser() { router.push('/chat/user/:userId', { params: { userId: user.id, - } + }, }); }); } @@ -108,7 +108,7 @@ async function createRoom() { router.push('/chat/room/:roomId', { params: { roomId: room.id, - } + }, }); } diff --git a/packages/frontend/src/pages/chat/room.form.vue b/packages/frontend/src/pages/chat/room.form.vue index 17b68d6eb9..72aeba0a45 100644 --- a/packages/frontend/src/pages/chat/room.form.vue +++ b/packages/frontend/src/pages/chat/room.form.vue @@ -167,7 +167,7 @@ function onKeydown(ev: KeyboardEvent) { } } -function chooseFile(ev: MouseEvent) { +function chooseFile(ev: PointerEvent) { selectFile({ anchorElement: ev.currentTarget ?? ev.target, multiple: false, diff --git a/packages/frontend/src/pages/chat/room.vue b/packages/frontend/src/pages/chat/room.vue index ef9191b4a5..a4204435b3 100644 --- a/packages/frontend/src/pages/chat/room.vue +++ b/packages/frontend/src/pages/chat/room.vue @@ -391,7 +391,7 @@ async function leaveRoom() { router.push('/chat'); } -function showMenu(ev: MouseEvent) { +function showMenu(ev: PointerEvent) { const menuItems: MenuItem[] = []; if (room.value) { diff --git a/packages/frontend/src/pages/clip.vue b/packages/frontend/src/pages/clip.vue index 8176fb519b..8feddf70b0 100644 --- a/packages/frontend/src/pages/clip.vue +++ b/packages/frontend/src/pages/clip.vue @@ -34,6 +34,7 @@ import { computed, watch, provide, ref, markRaw } from 'vue'; import * as Misskey from 'misskey-js'; import { url } from '@@/js/config.js'; import type { MenuItem } from '@/types/menu.js'; +import type { PageHeaderItem } from '@/types/page-header.js'; import MkNotesTimeline from '@/components/MkNotesTimeline.vue'; import { $i } from '@/i.js'; import { i18n } from '@/i18n.js'; @@ -105,7 +106,7 @@ async function unfavorite() { }); } -const headerActions = computed(() => clip.value && isOwned.value ? [{ +const headerActions = computed<PageHeaderItem[] | null>(() => clip.value && isOwned.value ? [{ icon: 'ti ti-pencil', text: i18n.ts.edit, handler: async (): Promise<void> => { @@ -144,7 +145,7 @@ const headerActions = computed(() => clip.value && isOwned.value ? [{ }, ...(clip.value.isPublic ? [{ icon: 'ti ti-share', text: i18n.ts.share, - handler: (ev: MouseEvent): void => { + handler: (ev): void => { const menuItems: MenuItem[] = []; menuItems.push({ @@ -177,7 +178,7 @@ const headerActions = computed(() => clip.value && isOwned.value ? [{ os.popupMenu(menuItems, ev.currentTarget ?? ev.target); }, -}] : []), { +}] satisfies PageHeaderItem[] : []), { icon: 'ti ti-trash', text: i18n.ts.delete, danger: true, @@ -196,7 +197,7 @@ const headerActions = computed(() => clip.value && isOwned.value ? [{ clipsCache.delete(); }, -}] : null); +}] satisfies PageHeaderItem[] : null); definePage(() => ({ title: clip.value ? clip.value.name : i18n.ts.clip, diff --git a/packages/frontend/src/pages/custom-emojis-manager.vue b/packages/frontend/src/pages/custom-emojis-manager.vue index 9bc8992155..5cb88f0b1a 100644 --- a/packages/frontend/src/pages/custom-emojis-manager.vue +++ b/packages/frontend/src/pages/custom-emojis-manager.vue @@ -54,7 +54,7 @@ SPDX-License-Identifier: AGPL-3.0-only <template #empty><span>{{ i18n.ts.noCustomEmojis }}</span></template> <template #default="{items}"> <div class="ldhfsamy"> - <div v-for="emoji in items" :key="emoji.id" class="emoji _panel _button" @click="remoteMenu(emoji, $event)"> + <div v-for="emoji in items" :key="emoji.id" class="emoji _panel _button" @click="remoteMenu(emoji as RemoteEmoji, $event)"> <img :src="getProxiedImageUrl(emoji.url, 'emoji')" class="img" :alt="emoji.name"/> <div class="body"> <div class="name _monospace">{{ emoji.name }}</div> @@ -94,6 +94,8 @@ const host = ref<string | null>(null); const selectMode = ref(false); const selectedEmojis = ref<string[]>([]); +type RemoteEmoji = Misskey.entities.AdminEmojiListRemoteResponse[number] & { host: string }; + const paginator = markRaw(new Paginator('admin/emoji/list', { limit: 30, computedParams: computed(() => ({ @@ -159,7 +161,13 @@ const edit = async (emoji: Misskey.entities.EmojiDetailed) => { }); }; -const detailRemoteEmoji = (emoji) => { +const detailRemoteEmoji = (emoji: { + id: string, + name: string, + host: string, + license: string | null, + url: string +}) => { const { dispose } = os.popup(MkRemoteEmojiEditDialog, { emoji: emoji, }, { @@ -172,13 +180,19 @@ const detailRemoteEmoji = (emoji) => { }); }; -const importEmoji = (emoji) => { +const importEmoji = (emojiId: string) => { os.apiWithDialog('admin/emoji/copy', { - emojiId: emoji.id, + emojiId: emojiId, }); }; -const remoteMenu = (emoji, ev: MouseEvent) => { +const remoteMenu = (emoji: { + id: string, + name: string, + host: string, + license: string | null, + url: string +}, ev: PointerEvent) => { os.popupMenu([{ type: 'label', text: ':' + emoji.name + ':', @@ -189,11 +203,11 @@ const remoteMenu = (emoji, ev: MouseEvent) => { }, { text: i18n.ts.import, icon: 'ti ti-plus', - action: () => { importEmoji(emoji); }, + action: () => { importEmoji(emoji.id); }, }], ev.currentTarget ?? ev.target); }; -const menu = (ev: MouseEvent) => { +const menu = (ev: PointerEvent) => { os.popupMenu([{ icon: 'ti ti-download', text: i18n.ts.export, diff --git a/packages/frontend/src/pages/drop-and-fusion.game.vue b/packages/frontend/src/pages/drop-and-fusion.game.vue index 88300d8a74..4c677a8d09 100644 --- a/packages/frontend/src/pages/drop-and-fusion.game.vue +++ b/packages/frontend/src/pages/drop-and-fusion.game.vue @@ -729,7 +729,7 @@ async function start() { }, 1500); } -function onClick(ev: MouseEvent) { +function onClick(ev: PointerEvent) { if (!containerElRect) return; if (replaying.value) return; const x = (ev.clientX - containerElRect.left) / viewScale; diff --git a/packages/frontend/src/pages/emoji-edit-dialog.vue b/packages/frontend/src/pages/emoji-edit-dialog.vue index 4b6c5e1c51..edd3987524 100644 --- a/packages/frontend/src/pages/emoji-edit-dialog.vue +++ b/packages/frontend/src/pages/emoji-edit-dialog.vue @@ -58,7 +58,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div v-for="role in rolesThatCanBeUsedThisEmojiAsReaction" :key="role.id" :class="$style.roleItem"> <MkRolePreview :class="$style.role" :role="role" :forModeration="true" :detailed="false" style="pointer-events: none;"/> - <button v-if="role.target === 'manual'" class="_button" :class="$style.roleUnassign" @click="removeRole(role, $event)"><i class="ti ti-x"></i></button> + <button v-if="role.target === 'manual'" class="_button" :class="$style.roleUnassign" @click="removeRole(role)"><i class="ti ti-x"></i></button> <button v-else class="_button" :class="$style.roleUnassign" disabled><i class="ti ti-ban"></i></button> </div> @@ -120,7 +120,7 @@ watch(roleIdsThatCanBeUsedThisEmojiAsReaction, async () => { const imgUrl = computed(() => file.value ? file.value.url : props.emoji ? props.emoji.url : null); -async function changeImage(ev: Event) { +async function changeImage(ev: PointerEvent) { file.value = await selectFile({ anchorElement: ev.currentTarget ?? ev.target, multiple: false, @@ -143,7 +143,7 @@ async function addRole() { rolesThatCanBeUsedThisEmojiAsReaction.value.push(roles.find(r => r.id === roleId)!); } -async function removeRole(role: Misskey.entities.RoleLite, ev: Event) { +async function removeRole(role: Misskey.entities.RoleLite) { rolesThatCanBeUsedThisEmojiAsReaction.value = rolesThatCanBeUsedThisEmojiAsReaction.value.filter(x => x.id !== role.id); } diff --git a/packages/frontend/src/pages/emojis.emoji.vue b/packages/frontend/src/pages/emojis.emoji.vue index aaf433e78e..bed7f2166a 100644 --- a/packages/frontend/src/pages/emojis.emoji.vue +++ b/packages/frontend/src/pages/emojis.emoji.vue @@ -15,7 +15,6 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import * as Misskey from 'misskey-js'; -import { defineAsyncComponent } from 'vue'; import type { MenuItem } from '@/types/menu.js'; import * as os from '@/os.js'; import { misskeyApiGet } from '@/utility/misskey-api.js'; @@ -28,7 +27,7 @@ const props = defineProps<{ emoji: Misskey.entities.EmojiSimple; }>(); -function menu(ev) { +function menu(ev: PointerEvent) { const menuItems: MenuItem[] = []; menuItems.push({ type: 'label', @@ -57,22 +56,21 @@ function menu(ev) { menuItems.push({ text: i18n.ts.edit, icon: 'ti ti-pencil', - action: () => { - edit(props.emoji); + action: async () => { + const detailedEmoji = await misskeyApiGet('emoji', { + name: props.emoji.name, + }); + const { dispose } = await os.popupAsyncWithDialog(import('@/pages/emoji-edit-dialog.vue').then(x => x.default), { + emoji: detailedEmoji, + }, { + closed: () => dispose(), + }); }, }); } os.popupMenu(menuItems, ev.currentTarget ?? ev.target); } - -const edit = async (emoji) => { - const { dispose } = await os.popupAsyncWithDialog(import('@/pages/emoji-edit-dialog.vue').then(x => x.default), { - emoji: emoji, - }, { - closed: () => dispose(), - }); -}; </script> <style lang="scss" module> diff --git a/packages/frontend/src/pages/flash/flash-edit.vue b/packages/frontend/src/pages/flash/flash-edit.vue index b3e8e88c23..3d9de0584a 100644 --- a/packages/frontend/src/pages/flash/flash-edit.vue +++ b/packages/frontend/src/pages/flash/flash-edit.vue @@ -395,7 +395,7 @@ const { }); const script = ref(flash.value?.script ?? PRESET_DEFAULT); -function selectPreset(ev: MouseEvent) { +function selectPreset(ev: PointerEvent) { os.popupMenu([{ text: 'Omikuji', action: () => { diff --git a/packages/frontend/src/pages/flash/flash.vue b/packages/frontend/src/pages/flash/flash.vue index f5e51dc72f..43a1e8e426 100644 --- a/packages/frontend/src/pages/flash/flash.vue +++ b/packages/frontend/src/pages/flash/flash.vue @@ -104,7 +104,7 @@ function fetchFlash() { }); } -function share(ev: MouseEvent) { +function share(ev: PointerEvent) { if (!flash.value) return; const menuItems: MenuItem[] = []; @@ -229,10 +229,10 @@ async function run() { THIS_URL: values.STR(`${url}/play/${flash.value.id}`), }, { in: aiScriptReadline, - out: (value) => { + out: () => { // nop }, - log: (type, params) => { + log: () => { // nop }, }); @@ -273,7 +273,7 @@ async function reportAbuse() { }); } -function showMenu(ev: MouseEvent) { +function showMenu(ev: PointerEvent) { if (!flash.value) return; const menu: MenuItem[] = [ diff --git a/packages/frontend/src/pages/follow-requests.vue b/packages/frontend/src/pages/follow-requests.vue index ba24d7abc6..1b729837a7 100644 --- a/packages/frontend/src/pages/follow-requests.vue +++ b/packages/frontend/src/pages/follow-requests.vue @@ -89,7 +89,7 @@ async function cancel(user: Misskey.entities.UserLite) { }); } -function displayUser(req) { +function displayUser(req: Misskey.entities.FollowingRequestsListResponse[number]) { return tab.value === 'list' ? req.follower : req.followee; } diff --git a/packages/frontend/src/pages/gallery/edit.root.vue b/packages/frontend/src/pages/gallery/edit.root.vue index 45493ab561..ec0a293494 100644 --- a/packages/frontend/src/pages/gallery/edit.root.vue +++ b/packages/frontend/src/pages/gallery/edit.root.vue @@ -58,7 +58,7 @@ const description = ref(props.post?.description ?? null); const title = ref(props.post?.title ?? ''); const isSensitive = ref(props.post?.isSensitive ?? false); -function chooseFile(evt) { +function chooseFile(evt: MouseEvent) { selectFile({ anchorElement: evt.currentTarget ?? evt.target, multiple: true, @@ -67,7 +67,7 @@ function chooseFile(evt) { }); } -function remove(file) { +function remove(file: NonNullable<Misskey.entities.GalleryPost['files']>[number]) { files.value = files.value.filter(f => f.id !== file.id); } diff --git a/packages/frontend/src/pages/gallery/post.vue b/packages/frontend/src/pages/gallery/post.vue index f60bbc0b74..92cb663ee1 100644 --- a/packages/frontend/src/pages/gallery/post.vue +++ b/packages/frontend/src/pages/gallery/post.vue @@ -30,7 +30,7 @@ SPDX-License-Identifier: AGPL-3.0-only <button v-tooltip="i18n.ts.shareWithNote" v-click-anime class="_button" @click="shareWithNote"><i class="ti ti-repeat ti-fw"></i></button> <button v-tooltip="i18n.ts.copyLink" v-click-anime class="_button" @click="copyLink"><i class="ti ti-link ti-fw"></i></button> <button v-if="isSupportShare()" v-tooltip="i18n.ts.share" v-click-anime class="_button" @click="share"><i class="ti ti-share ti-fw"></i></button> - <button v-if="$i && $i.id !== post.user.id" v-click-anime class="_button" @mousedown="showMenu"><i class="ti ti-dots ti-fw"></i></button> + <button v-if="$i && $i.id !== post.user.id" v-click-anime class="_button" @click="showMenu"><i class="ti ti-dots ti-fw"></i></button> </div> </div> <div class="user"> @@ -175,7 +175,7 @@ async function reportAbuse() { }); } -function showMenu(ev: MouseEvent) { +function showMenu(ev: PointerEvent) { if (!post.value) return; const menuItems: MenuItem[] = []; diff --git a/packages/frontend/src/pages/my-lists/list.vue b/packages/frontend/src/pages/my-lists/list.vue index 132c55571a..92a5d25983 100644 --- a/packages/frontend/src/pages/my-lists/list.vue +++ b/packages/frontend/src/pages/my-lists/list.vue @@ -110,7 +110,7 @@ function addUser() { }); } -async function removeUser(item, ev) { +async function removeUser(item: Misskey.entities.UsersListsGetMembershipsResponse[number], ev: PointerEvent) { os.popupMenu([{ text: i18n.ts.remove, icon: 'ti ti-x', @@ -127,7 +127,7 @@ async function removeUser(item, ev) { }], ev.currentTarget ?? ev.target); } -async function showMembershipMenu(item, ev) { +async function showMembershipMenu(item: Misskey.entities.UsersListsGetMembershipsResponse[number], ev: PointerEvent) { const withRepliesRef = ref(item.withReplies); os.popupMenu([{ diff --git a/packages/frontend/src/pages/notifications.vue b/packages/frontend/src/pages/notifications.vue index 5d308e6b29..37ec6284a3 100644 --- a/packages/frontend/src/pages/notifications.vue +++ b/packages/frontend/src/pages/notifications.vue @@ -22,6 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { computed, markRaw, ref } from 'vue'; import { notificationTypes } from 'misskey-js'; +import type { PageHeaderItem } from '@/types/page-header.js'; import MkStreamingNotificationsTimeline from '@/components/MkStreamingNotificationsTimeline.vue'; import MkNotesTimeline from '@/components/MkNotesTimeline.vue'; import * as os from '@/os.js'; @@ -44,7 +45,7 @@ const directNotesPaginator = markRaw(new Paginator('notes/mentions', { }, })); -function setFilter(ev) { +function setFilter(ev: PointerEvent) { const typeItems = notificationTypes.map(t => ({ text: i18n.ts._notification._types[t], active: (includeTypes.value && includeTypes.value.includes(t)) ?? false, @@ -62,7 +63,7 @@ function setFilter(ev) { os.popupMenu(items, ev.currentTarget ?? ev.target); } -const headerActions = computed(() => [tab.value === 'all' ? { +const headerActions = computed<PageHeaderItem[]>(() => ([tab.value === 'all' ? { text: i18n.ts.filter, icon: 'ti ti-filter', highlighted: includeTypes.value != null, @@ -73,7 +74,7 @@ const headerActions = computed(() => [tab.value === 'all' ? { handler: () => { os.apiWithDialog('notifications/mark-all-as-read', {}); }, -} : undefined].filter(x => x !== undefined)); +} : undefined] as (PageHeaderItem | undefined)[]).filter(x => x !== undefined)); const headerTabs = computed(() => [{ key: 'all', diff --git a/packages/frontend/src/pages/page-editor/page-editor.blocks.vue b/packages/frontend/src/pages/page-editor/page-editor.blocks.vue index f18eb7e4f0..891d29e1df 100644 --- a/packages/frontend/src/pages/page-editor/page-editor.blocks.vue +++ b/packages/frontend/src/pages/page-editor/page-editor.blocks.vue @@ -47,7 +47,7 @@ const emit = defineEmits<{ (ev: 'update:modelValue', value: Misskey.entities.Page['content']): void; }>(); -function updateItem(v) { +function updateItem(v: Misskey.entities.PageBlock) { const i = props.modelValue.findIndex(x => x.id === v.id); const newValue = [ ...props.modelValue.slice(0, i), @@ -57,8 +57,8 @@ function updateItem(v) { emit('update:modelValue', newValue); } -function removeItem(el) { - const i = props.modelValue.findIndex(x => x.id === el.id); +function removeItem(v: Misskey.entities.PageBlock) { + const i = props.modelValue.findIndex(x => x.id === v.id); const newValue = [ ...props.modelValue.slice(0, i), ...props.modelValue.slice(i + 1), diff --git a/packages/frontend/src/pages/page-editor/page-editor.vue b/packages/frontend/src/pages/page-editor/page-editor.vue index 3b36f7fa2d..85871c993c 100644 --- a/packages/frontend/src/pages/page-editor/page-editor.vue +++ b/packages/frontend/src/pages/page-editor/page-editor.vue @@ -247,9 +247,9 @@ async function add() { } } -function setEyeCatchingImage(img: Event) { +function setEyeCatchingImage(ev: PointerEvent) { selectFile({ - anchorElement: img.currentTarget ?? img.target, + anchorElement: ev.currentTarget ?? ev.target, multiple: false, }).then(file => { eyeCatchingImageId.value = file.id; diff --git a/packages/frontend/src/pages/page.vue b/packages/frontend/src/pages/page.vue index c3b52a24fd..212c8140c8 100644 --- a/packages/frontend/src/pages/page.vue +++ b/packages/frontend/src/pages/page.vue @@ -64,7 +64,7 @@ SPDX-License-Identifier: AGPL-3.0-only <MkA v-if="page.userId === $i?.id" v-tooltip="i18n.ts._pages.editThisPage" :to="`/pages/edit/${page.id}`" class="_button" :class="$style.generalActionButton"><i class="ti ti-pencil ti-fw"></i></MkA> <button v-tooltip="i18n.ts.copyLink" class="_button" :class="$style.generalActionButton" @click="copyLink"><i class="ti ti-link ti-fw"></i></button> <button v-tooltip="i18n.ts.share" class="_button" :class="$style.generalActionButton" @click="share"><i class="ti ti-share ti-fw"></i></button> - <button v-if="$i" v-click-anime class="_button" :class="$style.generalActionButton" @mousedown="showMenu"><i class="ti ti-dots ti-fw"></i></button> + <button v-if="$i" v-click-anime class="_button" :class="$style.generalActionButton" @click="showMenu"><i class="ti ti-dots ti-fw"></i></button> </div> </div> <div :class="$style.pageUser"> @@ -163,7 +163,7 @@ function fetchPage() { }); } -function share(ev: MouseEvent) { +function share(ev: PointerEvent) { if (!page.value) return; const menuItems: MenuItem[] = []; @@ -237,7 +237,7 @@ async function unlike() { }); } -function pin(pin) { +function pin(pin: boolean) { if (!page.value) return; os.apiWithDialog('i/update', { @@ -258,7 +258,7 @@ async function reportAbuse() { }); } -function showMenu(ev: MouseEvent) { +function showMenu(ev: PointerEvent) { if (!page.value) return; const menuItems: MenuItem[] = []; diff --git a/packages/frontend/src/pages/reversi/game.board.vue b/packages/frontend/src/pages/reversi/game.board.vue index aae638641a..61bd95d051 100644 --- a/packages/frontend/src/pages/reversi/game.board.vue +++ b/packages/frontend/src/pages/reversi/game.board.vue @@ -308,7 +308,7 @@ if (!props.game.isEnded) { }, TIMER_INTERVAL_SEC * 1000, { immediate: false, afterMounted: true }); } -async function onStreamLog(log) { +async function onStreamLog(log: Reversi.Serializer.Log & { id: string | null }) { game.value.logs = Reversi.Serializer.serializeLogs([ ...Reversi.Serializer.deserializeLogs(game.value.logs), log, @@ -348,7 +348,10 @@ async function onStreamLog(log) { } } -function onStreamEnded(x) { +function onStreamEnded(x: { + winnerId: Misskey.entities.User['id'] | null; + game: Misskey.entities.ReversiGameDetailed; +}) { game.value = deepClone(x.game); if (game.value.winnerId === $i.id) { @@ -384,7 +387,7 @@ function checkEnd() { } } -function restoreGame(_game) { +function restoreGame(_game: Misskey.entities.ReversiGameDetailed) { game.value = deepClone(_game); engine.value = Reversi.Serializer.restoreGame({ diff --git a/packages/frontend/src/pages/reversi/game.setting.vue b/packages/frontend/src/pages/reversi/game.setting.vue index 1e01496bbb..b987a8e911 100644 --- a/packages/frontend/src/pages/reversi/game.setting.vue +++ b/packages/frontend/src/pages/reversi/game.setting.vue @@ -113,6 +113,7 @@ SPDX-License-Identifier: AGPL-3.0-only import { computed, watch, ref, onMounted, shallowRef, onUnmounted } from 'vue'; import * as Misskey from 'misskey-js'; import * as Reversi from 'misskey-reversi'; +import type { MenuItem } from '@/types/menu.js'; import { i18n } from '@/i18n.js'; import { ensureSignin } from '@/i.js'; import { deepClone } from '@/utility/clone.js'; @@ -121,7 +122,6 @@ import MkRadios from '@/components/MkRadios.vue'; import MkSwitch from '@/components/MkSwitch.vue'; import MkFolder from '@/components/MkFolder.vue'; import * as os from '@/os.js'; -import type { MenuItem } from '@/types/menu.js'; import { useRouter } from '@/router.js'; const $i = ensureSignin(); @@ -165,7 +165,7 @@ watch(() => game.value.timeLimitForEachTurn, () => { updateSettings('timeLimitForEachTurn'); }); -function chooseMap(ev: MouseEvent) { +function chooseMap(ev: PointerEvent) { const menu: MenuItem[] = []; for (const c of mapCategories) { @@ -212,7 +212,10 @@ function unready() { props.connection.send('ready', false); } -function onChangeReadyStates(states) { +function onChangeReadyStates(states: { + user1: boolean; + user2: boolean; +}) { game.value.user1Ready = states.user1; game.value.user2Ready = states.user2; } diff --git a/packages/frontend/src/pages/reversi/index.vue b/packages/frontend/src/pages/reversi/index.vue index 8438943126..9a737e93ac 100644 --- a/packages/frontend/src/pages/reversi/index.vue +++ b/packages/frontend/src/pages/reversi/index.vue @@ -208,7 +208,7 @@ async function matchUser() { matchHeatbeat(); } -async function matchAny(ev: MouseEvent) { +async function matchAny(ev: PointerEvent) { const isLoggedIn = await pleaseLogin(); if (!isLoggedIn) return; @@ -239,11 +239,11 @@ function cancelMatching() { } } -async function accept(user) { +async function accept(user: Misskey.entities.UserLite) { const game = await misskeyApi('reversi/match', { userId: user.id, }); - if (game) { + if (game != null) { startGame(game); } } diff --git a/packages/frontend/src/pages/scratchpad.vue b/packages/frontend/src/pages/scratchpad.vue index 4e02556c83..b3b899517e 100644 --- a/packages/frontend/src/pages/scratchpad.vue +++ b/packages/frontend/src/pages/scratchpad.vue @@ -97,7 +97,7 @@ watch(code, () => { miLocalStorage.setItem('scratchpad', code.value); }); -function stringifyUiProps(uiProps) { +function stringifyUiProps(uiProps: AsUiComponent) { return JSON.stringify( { ...uiProps, type: undefined, id: undefined }, (k, v) => typeof v === 'function' ? '<function>' : v, diff --git a/packages/frontend/src/pages/settings/2fa.vue b/packages/frontend/src/pages/settings/2fa.vue index 2cc13744b1..fcd598fe76 100644 --- a/packages/frontend/src/pages/settings/2fa.vue +++ b/packages/frontend/src/pages/settings/2fa.vue @@ -85,6 +85,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { defineAsyncComponent, computed } from 'vue'; import { supported as webAuthnSupported, create as webAuthnCreate, parseCreationOptionsFromJSON } from '@github/webauthn-json/browser-ponyfill'; +import * as Misskey from 'misskey-js'; import MkButton from '@/components/MkButton.vue'; import MkInfo from '@/components/MkInfo.vue'; import MkSwitch from '@/components/MkSwitch.vue'; @@ -156,7 +157,7 @@ function renewTOTP(): void { }); } -async function unregisterKey(key) { +async function unregisterKey(key: NonNullable<Misskey.entities.MeDetailedOnly['securityKeysList']>[number]) { const confirm = await os.confirm({ type: 'question', title: i18n.ts._2fa.removeKey, @@ -175,7 +176,7 @@ async function unregisterKey(key) { os.success(); } -async function renameKey(key) { +async function renameKey(key: NonNullable<Misskey.entities.MeDetailedOnly['securityKeysList']>[number]) { const name = await os.inputText({ title: i18n.ts.rename, default: key.name, diff --git a/packages/frontend/src/pages/settings/account-data.vue b/packages/frontend/src/pages/settings/account-data.vue index c75667b06b..b07515a49a 100644 --- a/packages/frontend/src/pages/settings/account-data.vue +++ b/packages/frontend/src/pages/settings/account-data.vue @@ -189,7 +189,7 @@ const onImportSuccess = () => { }); }; -const onError = (ev) => { +const onError = (ev: Error) => { os.alert({ type: 'error', text: ev.message, @@ -232,7 +232,7 @@ const exportAntennas = () => { misskeyApi('i/export-antennas', {}).then(onExportSuccess).catch(onError); }; -const importFollowing = async (ev) => { +const importFollowing = async (ev: PointerEvent) => { const file = await selectFile({ anchorElement: ev.currentTarget ?? ev.target, multiple: false, @@ -243,7 +243,7 @@ const importFollowing = async (ev) => { }).then(onImportSuccess).catch(onError); }; -const importUserLists = async (ev) => { +const importUserLists = async (ev: PointerEvent) => { const file = await selectFile({ anchorElement: ev.currentTarget ?? ev.target, multiple: false, @@ -251,7 +251,7 @@ const importUserLists = async (ev) => { misskeyApi('i/import-user-lists', { fileId: file.id }).then(onImportSuccess).catch(onError); }; -const importMuting = async (ev) => { +const importMuting = async (ev: PointerEvent) => { const file = await selectFile({ anchorElement: ev.currentTarget ?? ev.target, multiple: false, @@ -259,7 +259,7 @@ const importMuting = async (ev) => { misskeyApi('i/import-muting', { fileId: file.id }).then(onImportSuccess).catch(onError); }; -const importBlocking = async (ev) => { +const importBlocking = async (ev: PointerEvent) => { const file = await selectFile({ anchorElement: ev.currentTarget ?? ev.target, multiple: false, @@ -267,7 +267,7 @@ const importBlocking = async (ev) => { misskeyApi('i/import-blocking', { fileId: file.id }).then(onImportSuccess).catch(onError); }; -const importAntennas = async (ev) => { +const importAntennas = async (ev: PointerEvent) => { const file = await selectFile({ anchorElement: ev.currentTarget ?? ev.target, multiple: false, diff --git a/packages/frontend/src/pages/settings/accounts.vue b/packages/frontend/src/pages/settings/accounts.vue index 764ec72652..55a81bbf38 100644 --- a/packages/frontend/src/pages/settings/accounts.vue +++ b/packages/frontend/src/pages/settings/accounts.vue @@ -38,7 +38,7 @@ function refreshAllAccounts() { // TODO } -function showMenu(host: string, id: string, ev: MouseEvent) { +function showMenu(host: string, id: string, ev: PointerEvent) { let menu: MenuItem[]; menu = [{ @@ -54,7 +54,7 @@ function showMenu(host: string, id: string, ev: MouseEvent) { os.popupMenu(menu, ev.currentTarget ?? ev.target); } -function addAccount(ev: MouseEvent) { +function addAccount(ev: PointerEvent) { os.popupMenu([{ text: i18n.ts.existingAccount, action: () => { addExistingAccount(); }, diff --git a/packages/frontend/src/pages/settings/apps.vue b/packages/frontend/src/pages/settings/apps.vue index 10901f737b..e9857b1e0b 100644 --- a/packages/frontend/src/pages/settings/apps.vue +++ b/packages/frontend/src/pages/settings/apps.vue @@ -37,7 +37,7 @@ SPDX-License-Identifier: AGPL-3.0-only <template #label>{{ i18n.ts.permission }}</template> <template #suffix>{{ Object.keys(token.permission).length === 0 ? i18n.ts.none : Object.keys(token.permission).length }}</template> <ul> - <li v-for="p in token.permission" :key="p">{{ i18n.ts._permissions[p] }}</li> + <li v-for="p in token.permission" :key="p">{{ (i18n.ts._permissions as any)[p] ?? p }}</li> </ul> </MkFolder> </div> @@ -68,7 +68,7 @@ const paginator = markRaw(new Paginator('i/apps', { }, })); -function revoke(token) { +function revoke(token: Misskey.entities.IAppsResponse[number]) { misskeyApi('i/revoke-token', { tokenId: token.id }).then(() => { paginator.reload(); }); diff --git a/packages/frontend/src/pages/settings/deck.vue b/packages/frontend/src/pages/settings/deck.vue index 7a19b0495b..6ff08b5499 100644 --- a/packages/frontend/src/pages/settings/deck.vue +++ b/packages/frontend/src/pages/settings/deck.vue @@ -113,7 +113,7 @@ watch(wallpaper, () => { suggestReload(); }); -function setWallpaper(ev: MouseEvent) { +function setWallpaper(ev: PointerEvent) { selectFile({ anchorElement: ev.currentTarget ?? ev.target, multiple: false, diff --git a/packages/frontend/src/pages/settings/drive-cleaner.vue b/packages/frontend/src/pages/settings/drive-cleaner.vue index 3aeb356bd3..7189e19780 100644 --- a/packages/frontend/src/pages/settings/drive-cleaner.vue +++ b/packages/frontend/src/pages/settings/drive-cleaner.vue @@ -116,11 +116,11 @@ function genUsageBar(fsize: number): StyleValue { }; } -function onClick(ev: MouseEvent, file) { +function onClick(ev: PointerEvent, file: Misskey.entities.DriveFile) { os.popupMenu(getDriveFileMenu(file), (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined); } -function onContextMenu(ev: MouseEvent, file): void { +function onContextMenu(ev: PointerEvent, file: Misskey.entities.DriveFile): void { os.contextMenu(getDriveFileMenu(file), ev); } diff --git a/packages/frontend/src/pages/settings/drive.ImageFrameItem.vue b/packages/frontend/src/pages/settings/drive.ImageFrameItem.vue index 62922fc964..f92e87375f 100644 --- a/packages/frontend/src/pages/settings/drive.ImageFrameItem.vue +++ b/packages/frontend/src/pages/settings/drive.ImageFrameItem.vue @@ -52,7 +52,7 @@ async function edit() { }); } -function del(ev: MouseEvent) { +function del(ev: PointerEvent) { os.popupMenu([{ text: i18n.ts.delete, action: () => { diff --git a/packages/frontend/src/pages/settings/drive.WatermarkItem.vue b/packages/frontend/src/pages/settings/drive.WatermarkItem.vue index 0c03a4493a..9e80d719de 100644 --- a/packages/frontend/src/pages/settings/drive.WatermarkItem.vue +++ b/packages/frontend/src/pages/settings/drive.WatermarkItem.vue @@ -52,7 +52,7 @@ async function edit() { }); } -function del(ev: MouseEvent) { +function del(ev: PointerEvent) { os.popupMenu([{ text: i18n.ts.delete, action: () => { diff --git a/packages/frontend/src/pages/settings/email.vue b/packages/frontend/src/pages/settings/email.vue index 469a3c2f1c..85fea7ae66 100644 --- a/packages/frontend/src/pages/settings/email.vue +++ b/packages/frontend/src/pages/settings/email.vue @@ -76,11 +76,11 @@ const $i = ensureSignin(); const emailAddress = ref($i.email ?? ''); -const onChangeReceiveAnnouncementEmail = (v) => { +function onChangeReceiveAnnouncementEmail(v: boolean) { misskeyApi('i/update', { receiveAnnouncementEmail: v, }); -}; +} async function saveEmailAddress() { const auth = await os.authenticateDialog(); diff --git a/packages/frontend/src/pages/settings/emoji-palette.palette.vue b/packages/frontend/src/pages/settings/emoji-palette.palette.vue index 0282f62fb8..d8a5f16b7d 100644 --- a/packages/frontend/src/pages/settings/emoji-palette.palette.vue +++ b/packages/frontend/src/pages/settings/emoji-palette.palette.vue @@ -76,7 +76,7 @@ watch(emojis, () => { emit('updateEmojis', emojis.value); }, { deep: true }); -function remove(reaction: string, ev: MouseEvent) { +function remove(reaction: string, ev: PointerEvent) { os.popupMenu([{ text: i18n.ts.remove, action: () => { @@ -85,7 +85,7 @@ function remove(reaction: string, ev: MouseEvent) { }], getHTMLElement(ev)); } -function pick(ev: MouseEvent) { +function pick(ev: PointerEvent) { os.pickEmoji(getHTMLElement(ev), { showPinned: false, }).then(it => { @@ -96,7 +96,7 @@ function pick(ev: MouseEvent) { }); } -function getHTMLElement(ev: MouseEvent): HTMLElement { +function getHTMLElement(ev: PointerEvent): HTMLElement { const target = ev.currentTarget ?? ev.target; return target as HTMLElement; } @@ -124,7 +124,7 @@ function paste() { }); } -function del(ev: MouseEvent) { +function del(ev: PointerEvent) { os.popupMenu([{ text: i18n.ts.delete, action: () => { diff --git a/packages/frontend/src/pages/settings/emoji-palette.vue b/packages/frontend/src/pages/settings/emoji-palette.vue index 7f31699ed1..0f41d9b777 100644 --- a/packages/frontend/src/pages/settings/emoji-palette.vue +++ b/packages/frontend/src/pages/settings/emoji-palette.vue @@ -226,12 +226,12 @@ function delPalette(id: string) { } } -function getHTMLElement(ev: MouseEvent): HTMLElement { +function getHTMLElement(ev: PointerEvent): HTMLElement { const target = ev.currentTarget ?? ev.target; return target as HTMLElement; } -function previewPicker(ev: MouseEvent) { +function previewPicker(ev: PointerEvent) { emojiPicker.show(getHTMLElement(ev)); } diff --git a/packages/frontend/src/pages/settings/index.vue b/packages/frontend/src/pages/settings/index.vue index 39c32d347f..57c7cb6989 100644 --- a/packages/frontend/src/pages/settings/index.vue +++ b/packages/frontend/src/pages/settings/index.vue @@ -166,7 +166,7 @@ const menuDef = computed<SuperMenuDef[]>(() => [{ type: 'button', icon: 'ti ti-settings-2', text: i18n.ts.preferencesProfile, - action: async (ev: MouseEvent) => { + action: async (ev) => { os.popupMenu(getPreferencesProfileMenu(), ev.currentTarget ?? ev.target); }, }, { diff --git a/packages/frontend/src/pages/settings/mute-block.emoji-mute.vue b/packages/frontend/src/pages/settings/mute-block.emoji-mute.vue index ea131381a1..37cd9fa67d 100644 --- a/packages/frontend/src/pages/settings/mute-block.emoji-mute.vue +++ b/packages/frontend/src/pages/settings/mute-block.emoji-mute.vue @@ -55,12 +55,12 @@ import { const emojis = prefer.model('mutingEmojis'); -function getHTMLElement(ev: MouseEvent): HTMLElement { +function getHTMLElement(ev: PointerEvent): HTMLElement { const target = ev.currentTarget ?? ev.target; return target as HTMLElement; } -function add(ev: MouseEvent) { +function add(ev: PointerEvent) { os.pickEmoji(getHTMLElement(ev), { showPinned: false }).then((emoji) => { if (emoji) { muteEmoji(emoji); @@ -68,7 +68,7 @@ function add(ev: MouseEvent) { }); } -function onEmojiClick(ev: MouseEvent, emoji: string) { +function onEmojiClick(ev: PointerEvent, emoji: string) { const menuItems : MenuItem[] = [{ type: 'label', text: emoji, diff --git a/packages/frontend/src/pages/settings/mute-block.vue b/packages/frontend/src/pages/settings/mute-block.vue index 6fd9f07a47..433969f474 100644 --- a/packages/frontend/src/pages/settings/mute-block.vue +++ b/packages/frontend/src/pages/settings/mute-block.vue @@ -173,6 +173,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref, computed, watch, markRaw } from 'vue'; +import * as Misskey from 'misskey-js'; import XEmojiMute from './mute-block.emoji-mute.vue'; import XInstanceMute from './mute-block.instance-mute.vue'; import XWordMute from './mute-block.word-mute.vue'; @@ -218,7 +219,7 @@ watch([ suggestReload(); }); -async function unrenoteMute(user, ev) { +async function unrenoteMute(user: Misskey.entities.UserDetailed, ev: PointerEvent) { os.popupMenu([{ text: i18n.ts.renoteUnmute, icon: 'ti ti-x', @@ -229,7 +230,7 @@ async function unrenoteMute(user, ev) { }], ev.currentTarget ?? ev.target); } -async function unmute(user, ev) { +async function unmute(user: Misskey.entities.UserDetailed, ev: PointerEvent) { os.popupMenu([{ text: i18n.ts.unmute, icon: 'ti ti-x', @@ -240,7 +241,7 @@ async function unmute(user, ev) { }], ev.currentTarget ?? ev.target); } -async function unblock(user, ev) { +async function unblock(user: Misskey.entities.UserDetailed, ev: PointerEvent) { os.popupMenu([{ text: i18n.ts.unblock, icon: 'ti ti-x', diff --git a/packages/frontend/src/pages/settings/mute-block.word-mute.vue b/packages/frontend/src/pages/settings/mute-block.word-mute.vue index f5837abe98..49d8ecd92d 100644 --- a/packages/frontend/src/pages/settings/mute-block.word-mute.vue +++ b/packages/frontend/src/pages/settings/mute-block.word-mute.vue @@ -30,7 +30,7 @@ const emit = defineEmits<{ (ev: 'save', value: (string[] | string)[]): void; }>(); -const render = (mutedWords) => mutedWords.map(x => { +const render = (mutedWords: (string | string[])[]) => mutedWords.map(x => { if (Array.isArray(x)) { return x.join(' '); } else { @@ -46,13 +46,13 @@ watch(mutedWords, () => { }); async function save() { - const parseMutes = (mutes) => { + const parseMutes = (mutes: string) => { // split into lines, remove empty lines and unnecessary whitespace - let lines = mutes.trim().split('\n').map(line => line.trim()).filter(line => line !== ''); + let lines = mutes.trim().split('\n').map(line => line.trim()).filter(line => line !== '') as (string | string[])[]; // check each line if it is a RegExp or not for (let i = 0; i < lines.length; i++) { - const line = lines[i]; + const line = lines[i] as string; const regexp = line.match(/^\/(.+)\/(.*)$/); if (regexp) { // check that the RegExp is valid diff --git a/packages/frontend/src/pages/settings/notifications.vue b/packages/frontend/src/pages/settings/notifications.vue index 2802d3263e..3787e07626 100644 --- a/packages/frontend/src/pages/settings/notifications.vue +++ b/packages/frontend/src/pages/settings/notifications.vue @@ -13,16 +13,16 @@ SPDX-License-Identifier: AGPL-3.0-only <FormSection first> <template #label>{{ i18n.ts.notificationRecieveConfig }}</template> <div class="_gaps_s"> - <MkFolder v-for="type in notificationTypes.filter(x => !nonConfigurableNotificationTypes.includes(x))" :key="type"> + <MkFolder v-for="type in configurableNotificationTypes" :key="type"> <template #label>{{ i18n.ts._notification._types[type] }}</template> <template #suffix> {{ - $i.notificationRecieveConfig[type]?.type === 'never' ? i18n.ts.none : - $i.notificationRecieveConfig[type]?.type === 'following' ? i18n.ts.following : - $i.notificationRecieveConfig[type]?.type === 'follower' ? i18n.ts.followers : - $i.notificationRecieveConfig[type]?.type === 'mutualFollow' ? i18n.ts.mutualFollow : - $i.notificationRecieveConfig[type]?.type === 'followingOrFollower' ? i18n.ts.followingOrFollower : - $i.notificationRecieveConfig[type]?.type === 'list' ? i18n.ts.userList : + $i.notificationRecieveConfig[type as (typeof configurableNotificationTypes)[number]]?.type === 'never' ? i18n.ts.none : + $i.notificationRecieveConfig[type as (typeof configurableNotificationTypes)[number]]?.type === 'following' ? i18n.ts.following : + $i.notificationRecieveConfig[type as (typeof configurableNotificationTypes)[number]]?.type === 'follower' ? i18n.ts.followers : + $i.notificationRecieveConfig[type as (typeof configurableNotificationTypes)[number]]?.type === 'mutualFollow' ? i18n.ts.mutualFollow : + $i.notificationRecieveConfig[type as (typeof configurableNotificationTypes)[number]]?.type === 'followingOrFollower' ? i18n.ts.followingOrFollower : + $i.notificationRecieveConfig[type as (typeof configurableNotificationTypes)[number]]?.type === 'list' ? i18n.ts.userList : i18n.ts.all }} </template> @@ -30,7 +30,7 @@ SPDX-License-Identifier: AGPL-3.0-only <XNotificationConfig :userLists="userLists" :value="$i.notificationRecieveConfig[type] ?? { type: 'all' }" - :configurableTypes="onlyOnOrOffNotificationTypes.includes(type) ? ['all', 'never'] : undefined" + :configurableTypes="(onlyOnOrOffNotificationTypes as string[]).includes(type) ? ['all', 'never'] : undefined" @update="(res) => updateReceiveConfig(type, res)" /> </MkFolder> @@ -83,9 +83,11 @@ import MkFeatureBanner from '@/components/MkFeatureBanner.vue'; const $i = ensureSignin(); -const nonConfigurableNotificationTypes = ['note', 'roleAssigned', 'followRequestAccepted', 'test', 'exportCompleted'] satisfies (typeof notificationTypes[number])[] as string[]; +const nonConfigurableNotificationTypes = ['note', 'roleAssigned', 'followRequestAccepted', 'test', 'exportCompleted'] as const satisfies (typeof notificationTypes[number])[]; -const onlyOnOrOffNotificationTypes = ['app', 'achievementEarned', 'login', 'createToken', 'scheduledNotePosted', 'scheduledNotePostFailed'] satisfies (typeof notificationTypes[number])[] as string[]; +const configurableNotificationTypes = notificationTypes.filter(type => !nonConfigurableNotificationTypes.includes(type as any)) as Exclude<typeof notificationTypes[number], typeof nonConfigurableNotificationTypes[number]>[]; + +const onlyOnOrOffNotificationTypes = ['app', 'achievementEarned', 'login', 'createToken', 'scheduledNotePosted', 'scheduledNotePostFailed'] as const satisfies (typeof notificationTypes[number])[]; const allowButton = useTemplateRef('allowButton'); const pushRegistrationInServer = computed(() => allowButton.value?.pushRegistrationInServer); diff --git a/packages/frontend/src/pages/settings/other.vue b/packages/frontend/src/pages/settings/other.vue index d4097bde94..3d149c3ab6 100644 --- a/packages/frontend/src/pages/settings/other.vue +++ b/packages/frontend/src/pages/settings/other.vue @@ -40,7 +40,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div class="_gaps_s"> <div v-for="policy in Object.keys($i.policies)" :key="policy"> - {{ policy }} ... {{ $i.policies[policy] }} + {{ policy }} ... {{ $i.policies[policy as keyof typeof $i.policies] }} </div> </div> </MkFolder> diff --git a/packages/frontend/src/pages/settings/plugin.vue b/packages/frontend/src/pages/settings/plugin.vue index 7c6ce90e7e..16c764001e 100644 --- a/packages/frontend/src/pages/settings/plugin.vue +++ b/packages/frontend/src/pages/settings/plugin.vue @@ -58,7 +58,7 @@ SPDX-License-Identifier: AGPL-3.0-only <template #key>{{ i18n.ts.permission }}</template> <template #value> <ul style="margin-top: 0; margin-bottom: 0;"> - <li v-for="permission in plugin.permissions" :key="permission">{{ i18n.ts._permissions[permission] }}</li> + <li v-for="permission in plugin.permissions" :key="permission">{{ (i18n.ts._permissions as any)[permission] ?? permission }}</li> <li v-if="!plugin.permissions || plugin.permissions.length === 0">{{ i18n.ts.none }}</li> </ul> </template> @@ -96,6 +96,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { nextTick, ref, computed } from 'vue'; +import { isSafeMode } from '@@/js/config.js'; import type { Plugin } from '@/plugin.js'; import FormLink from '@/components/form/link.vue'; import MkSwitch from '@/components/MkSwitch.vue'; @@ -110,7 +111,6 @@ import { i18n } from '@/i18n.js'; import { definePage } from '@/page.js'; import { changePluginActive, configPlugin, pluginLogs, uninstallPlugin, reloadPlugin } from '@/plugin.js'; import { prefer } from '@/preferences.js'; -import { isSafeMode } from '@@/js/config.js'; import * as os from '@/os.js'; const plugins = prefer.r.plugins; diff --git a/packages/frontend/src/pages/settings/preferences.vue b/packages/frontend/src/pages/settings/preferences.vue index aa7f0dabbb..76b84795f6 100644 --- a/packages/frontend/src/pages/settings/preferences.vue +++ b/packages/frontend/src/pages/settings/preferences.vue @@ -1042,7 +1042,7 @@ function removePinnedList() { function enableAllDataSaver() { const g = { ...prefer.s.dataSaver }; - Object.keys(g).forEach((key) => { g[key] = true; }); + Object.keys(g).forEach((key) => { (g as any)[key] = true; }); dataSaver.value = g; } @@ -1050,7 +1050,7 @@ function enableAllDataSaver() { function disableAllDataSaver() { const g = { ...prefer.s.dataSaver }; - Object.keys(g).forEach((key) => { g[key] = false; }); + Object.keys(g).forEach((key) => { (g as any)[key] = false; }); dataSaver.value = g; } diff --git a/packages/frontend/src/pages/settings/profile.vue b/packages/frontend/src/pages/settings/profile.vue index 27a1ed279b..a7aea9bde4 100644 --- a/packages/frontend/src/pages/settings/profile.vue +++ b/packages/frontend/src/pages/settings/profile.vue @@ -163,6 +163,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { computed, reactive, ref, watch } from 'vue'; +import * as Misskey from 'misskey-js'; import MkButton from '@/components/MkButton.vue'; import MkInput from '@/components/MkInput.vue'; import MkSwitch from '@/components/MkSwitch.vue'; @@ -266,8 +267,8 @@ function save() { } } -function changeAvatar(ev) { - async function done(driveFile) { +function changeAvatar(ev: PointerEvent) { + async function done(driveFile: Misskey.entities.DriveFile) { const i = await os.apiWithDialog('i/update', { avatarId: driveFile.id, }); @@ -315,8 +316,8 @@ function changeAvatar(ev) { }], ev.currentTarget ?? ev.target); } -function changeBanner(ev) { - async function done(driveFile) { +function changeBanner(ev: PointerEvent) { + async function done(driveFile: Misskey.entities.DriveFile) { const i = await os.apiWithDialog('i/update', { bannerId: driveFile.id, }); diff --git a/packages/frontend/src/pages/settings/profiles.vue b/packages/frontend/src/pages/settings/profiles.vue index 4804c11f7a..b3d02ba3fe 100644 --- a/packages/frontend/src/pages/settings/profiles.vue +++ b/packages/frontend/src/pages/settings/profiles.vue @@ -15,21 +15,16 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { ref, computed } from 'vue'; -import type { MenuItem } from '@/types/menu.js'; +import { computed } from 'vue'; import MkButton from '@/components/MkButton.vue'; import MkFolder from '@/components/MkFolder.vue'; -import * as os from '@/os.js'; -import { misskeyApi } from '@/utility/misskey-api.js'; -import { $i } from '@/i.js'; import { i18n } from '@/i18n.js'; import { definePage } from '@/page.js'; -import { prefer } from '@/preferences.js'; import { deleteCloudBackup, listCloudBackups } from '@/preferences/utility.js'; const backups = await listCloudBackups(); -function del(backup) { +function del(backup: { name: string }): void { deleteCloudBackup(backup.name); } diff --git a/packages/frontend/src/pages/settings/sounds.sound.vue b/packages/frontend/src/pages/settings/sounds.sound.vue index 31fe9a64db..050586c2e1 100644 --- a/packages/frontend/src/pages/settings/sounds.sound.vue +++ b/packages/frontend/src/pages/settings/sounds.sound.vue @@ -32,6 +32,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref, computed, watch } from 'vue'; import type { SoundType } from '@/utility/sound.js'; +import type { SoundStore } from '@/preferences/def.js'; import MkSelect from '@/components/MkSelect.vue'; import MkButton from '@/components/MkButton.vue'; import MkRange from '@/components/MkRange.vue'; @@ -41,7 +42,6 @@ import { useMkSelect } from '@/composables/use-mkselect.js'; import { misskeyApi } from '@/utility/misskey-api.js'; import { playMisskeySfxFile, soundsTypes, getSoundDuration } from '@/utility/sound.js'; import { selectFile } from '@/utility/drive.js'; -import type { SoundStore } from '@/preferences/def.js'; const props = defineProps<{ def: SoundStore; @@ -100,7 +100,7 @@ const friendlyFileName = computed<string>(() => { return i18n.ts._soundSettings.driveFileWarn; }); -function selectSound(ev) { +function selectSound(ev: PointerEvent) { selectFile({ anchorElement: ev.currentTarget ?? ev.target, multiple: false, diff --git a/packages/frontend/src/pages/settings/sounds.vue b/packages/frontend/src/pages/settings/sounds.vue index 1b851825d6..0d0623f11f 100644 --- a/packages/frontend/src/pages/settings/sounds.vue +++ b/packages/frontend/src/pages/settings/sounds.vue @@ -100,11 +100,14 @@ function getSoundTypeName(f: SoundType): string { } } -async function updated(type: keyof typeof sounds.value, sound) { - const v: SoundStore = { +async function updated(type: keyof typeof sounds.value, sound: { type: SoundType; fileId?: string; fileUrl?: string; volume: number; }) { + const v: SoundStore = sound.type === '_driveFile_' ? { + type: sound.type, + fileId: sound.fileId!, + fileUrl: sound.fileUrl!, + volume: sound.volume, + } : { type: sound.type, - fileId: sound.fileId, - fileUrl: sound.fileUrl, volume: sound.volume, }; diff --git a/packages/frontend/src/pages/settings/theme.vue b/packages/frontend/src/pages/settings/theme.vue index 0129aebe94..46b537f866 100644 --- a/packages/frontend/src/pages/settings/theme.vue +++ b/packages/frontend/src/pages/settings/theme.vue @@ -306,7 +306,7 @@ function changeThemesSyncEnabled(value: boolean) { } } -function onThemeContextmenu(theme: Theme, ev: MouseEvent) { +function onThemeContextmenu(theme: Theme, ev: PointerEvent) { os.contextMenu([{ type: 'label', text: theme.name, diff --git a/packages/frontend/src/pages/tag.vue b/packages/frontend/src/pages/tag.vue index 047e68f583..1e268e64d2 100644 --- a/packages/frontend/src/pages/tag.vue +++ b/packages/frontend/src/pages/tag.vue @@ -20,6 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { computed, markRaw, ref } from 'vue'; +import type { PageHeaderItem } from '@/types/page-header.js'; import MkNotesTimeline from '@/components/MkNotesTimeline.vue'; import MkButton from '@/components/MkButton.vue'; import { definePage } from '@/page.js'; @@ -50,10 +51,10 @@ async function post() { paginator.reload(); } -const headerActions = computed(() => [{ +const headerActions = computed<PageHeaderItem[]>(() => [{ icon: 'ti ti-dots', text: i18n.ts.more, - handler: (ev: MouseEvent) => { + handler: (ev) => { os.popupMenu([{ text: i18n.ts.embed, icon: 'ti ti-code', diff --git a/packages/frontend/src/pages/theme-editor.vue b/packages/frontend/src/pages/theme-editor.vue index af3891ac8e..2d2b8ed292 100644 --- a/packages/frontend/src/pages/theme-editor.vue +++ b/packages/frontend/src/pages/theme-editor.vue @@ -160,11 +160,11 @@ function setBgColor(color: typeof bgColors[number]) { } } -function setAccentColor(color) { +function setAccentColor(color: string) { theme.value.props.accent = color; } -function setFgColor(color) { +function setFgColor(color: typeof fgColors[number]) { theme.value.props.fg = theme.value.base === 'light' ? color.forLight : color.forDark; } diff --git a/packages/frontend/src/pages/timeline.vue b/packages/frontend/src/pages/timeline.vue index 89d0991bc0..64c2b2eee3 100644 --- a/packages/frontend/src/pages/timeline.vue +++ b/packages/frontend/src/pages/timeline.vue @@ -31,6 +31,7 @@ import { computed, watch, provide, useTemplateRef, ref, onMounted, onActivated } import type { Tab } from '@/components/global/MkPageHeader.tabs.vue'; import type { MenuItem } from '@/types/menu.js'; import type { BasicTimelineType } from '@/timelines.js'; +import type { PageHeaderItem } from '@/types/page-header.js'; import MkStreamingNotesTimeline from '@/components/MkStreamingNotesTimeline.vue'; import MkPostForm from '@/components/MkPostForm.vue'; import * as os from '@/os.js'; @@ -105,7 +106,7 @@ const withSensitive = computed<boolean>({ const showFixedPostForm = prefer.model('showFixedPostForm'); -async function chooseList(ev: MouseEvent): Promise<void> { +async function chooseList(ev: PointerEvent): Promise<void> { const lists = await userListsCache.fetch(); const items: (MenuItem | undefined)[] = [ ...lists.map(list => ({ @@ -124,7 +125,7 @@ async function chooseList(ev: MouseEvent): Promise<void> { os.popupMenu(items.filter(i => i != null), ev.currentTarget ?? ev.target); } -async function chooseAntenna(ev: MouseEvent): Promise<void> { +async function chooseAntenna(ev: PointerEvent): Promise<void> { const antennas = await antennasCache.fetch(); const items: (MenuItem | undefined)[] = [ ...antennas.map(antenna => ({ @@ -144,7 +145,7 @@ async function chooseAntenna(ev: MouseEvent): Promise<void> { os.popupMenu(items.filter(i => i != null), ev.currentTarget ?? ev.target); } -async function chooseChannel(ev: MouseEvent): Promise<void> { +async function chooseChannel(ev: PointerEvent): Promise<void> { const channels = await favoritedChannelsCache.fetch(); const items: (MenuItem | undefined)[] = [ ...channels.map(channel => { @@ -203,8 +204,8 @@ onActivated(() => { switchTlIfNeeded(); }); -const headerActions = computed(() => { - const items = [{ +const headerActions = computed<PageHeaderItem[]>(() => { + const items: PageHeaderItem[] = [{ icon: 'ti ti-dots', text: i18n.ts.options, handler: (ev) => { @@ -254,7 +255,7 @@ const headerActions = computed(() => { items.unshift({ icon: 'ti ti-refresh', text: i18n.ts.reload, - handler: (ev: Event) => { + handler: () => { tlComponent.value?.reloadTimeline(); }, }); diff --git a/packages/frontend/src/pages/user/activity.following.vue b/packages/frontend/src/pages/user/activity.following.vue index 4310c7ad85..f9a2eed6b9 100644 --- a/packages/frontend/src/pages/user/activity.following.vue +++ b/packages/frontend/src/pages/user/activity.following.vue @@ -57,7 +57,7 @@ async function renderChart() { return new Date(y, m, d - ago); }; - const format = (arr) => { + const format = (arr: number[]) => { return arr.map((v, i) => ({ x: getDate(i).getTime(), y: v, diff --git a/packages/frontend/src/pages/user/activity.notes.vue b/packages/frontend/src/pages/user/activity.notes.vue index 6d9c1bedd9..00bfe25430 100644 --- a/packages/frontend/src/pages/user/activity.notes.vue +++ b/packages/frontend/src/pages/user/activity.notes.vue @@ -57,7 +57,7 @@ async function renderChart() { return new Date(y, m, d - ago); }; - const format = (arr) => { + const format = (arr: number[]) => { return arr.map((v, i) => ({ x: getDate(i).getTime(), y: v, diff --git a/packages/frontend/src/pages/user/activity.pv.vue b/packages/frontend/src/pages/user/activity.pv.vue index 76df53becd..451f8ba0f7 100644 --- a/packages/frontend/src/pages/user/activity.pv.vue +++ b/packages/frontend/src/pages/user/activity.pv.vue @@ -57,7 +57,7 @@ async function renderChart() { return new Date(y, m, d - ago); }; - const format = (arr) => { + const format = (arr: number[]) => { return arr.map((v, i) => ({ x: getDate(i).getTime(), y: v, diff --git a/packages/frontend/src/pages/user/home.vue b/packages/frontend/src/pages/user/home.vue index ee04ca9e4a..c472c4da7b 100644 --- a/packages/frontend/src/pages/user/home.vue +++ b/packages/frontend/src/pages/user/home.vue @@ -252,7 +252,7 @@ const age = computed(() => { return props.user.birthday ? calcAge(props.user.birthday) : NaN; }); -function menu(ev: MouseEvent) { +function menu(ev: PointerEvent) { const { menu, cleanup } = getUserMenu(user.value, router); os.popupMenu(menu, ev.currentTarget ?? ev.target).finally(cleanup); } diff --git a/packages/frontend/src/pages/user/index.activity.vue b/packages/frontend/src/pages/user/index.activity.vue index 210021618e..10b0582143 100644 --- a/packages/frontend/src/pages/user/index.activity.vue +++ b/packages/frontend/src/pages/user/index.activity.vue @@ -36,7 +36,7 @@ const props = withDefaults(defineProps<{ const chartSrc = ref<'per-user-notes' | 'per-user-pv'>('per-user-notes'); -function showMenu(ev: MouseEvent) { +function showMenu(ev: PointerEvent) { os.popupMenu([{ text: i18n.ts.notes, active: chartSrc.value === 'per-user-notes', diff --git a/packages/frontend/src/pages/welcome.setup.vue b/packages/frontend/src/pages/welcome.setup.vue index 393ba98d30..3a4a558605 100644 --- a/packages/frontend/src/pages/welcome.setup.vue +++ b/packages/frontend/src/pages/welcome.setup.vue @@ -89,7 +89,7 @@ SPDX-License-Identifier: AGPL-3.0-only <Suspense> <template #default> - <MkServerSetupWizard :token="token" @finished="onWizardFinished"/> + <MkServerSetupWizard :token="token!" @finished="onWizardFinished"/> </template> <template #fallback> <MkLoading/> @@ -124,8 +124,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { computed, ref } from 'vue'; -import * as Misskey from 'misskey-js'; +import { ref } from 'vue'; import { host, version } from '@@/js/config.js'; import MkButton from '@/components/MkButton.vue'; import MkInput from '@/components/MkInput.vue'; @@ -143,7 +142,7 @@ const accountCreating = ref(false); const accountCreated = ref(false); const step = ref(0); -let token; +let token: string | null = null; function createAccount() { if (accountCreating.value) return; @@ -191,6 +190,7 @@ function skipSettings() { } function finish() { + if (token == null) return; login(token); } </script> |