forked from mirrors/misskey
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
This commit is contained in:
@@ -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';
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ const paginator = markRaw(new Paginator('admin/abuse-user-reports', {
|
||||
})),
|
||||
}));
|
||||
|
||||
function resolved(reportId) {
|
||||
function resolved(reportId: string) {
|
||||
paginator.removeItem(reportId);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -294,7 +294,7 @@ function invite() {
|
||||
});
|
||||
}
|
||||
|
||||
function adminLookup(ev: MouseEvent) {
|
||||
function adminLookup(ev: PointerEvent) {
|
||||
os.popupMenu([{
|
||||
text: i18n.ts.user,
|
||||
icon: 'ti ti-user',
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -104,7 +104,7 @@ const filesPagination = {
|
||||
noPaging: true,
|
||||
};
|
||||
|
||||
function onInstanceClick(i) {
|
||||
function onInstanceClick(i: Misskey.entities.FederationInstance) {
|
||||
os.pageWindow(`/instance-info/${i.host}`);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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}`);
|
||||
}
|
||||
|
||||
|
||||
@@ -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),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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' ? '' :
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -67,7 +67,7 @@ function accepted() {
|
||||
}
|
||||
}
|
||||
|
||||
function onLogin(res) {
|
||||
function onLogin(res: Misskey.entities.SigninFlowResponse & { finished: true }) {
|
||||
login(res.i);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 }),
|
||||
|
||||
@@ -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,
|
||||
}, {
|
||||
|
||||
@@ -191,7 +191,7 @@ async function archive() {
|
||||
});
|
||||
}
|
||||
|
||||
function setBannerImage(evt) {
|
||||
function setBannerImage(evt: PointerEvent) {
|
||||
selectFile({
|
||||
anchorElement: evt.currentTarget ?? evt.target,
|
||||
multiple: false,
|
||||
|
||||
@@ -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') {
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -167,7 +167,7 @@ function onKeydown(ev: KeyboardEvent) {
|
||||
}
|
||||
}
|
||||
|
||||
function chooseFile(ev: MouseEvent) {
|
||||
function chooseFile(ev: PointerEvent) {
|
||||
selectFile({
|
||||
anchorElement: ev.currentTarget ?? ev.target,
|
||||
multiple: false,
|
||||
|
||||
@@ -391,7 +391,7 @@ async function leaveRoom() {
|
||||
router.push('/chat');
|
||||
}
|
||||
|
||||
function showMenu(ev: MouseEvent) {
|
||||
function showMenu(ev: PointerEvent) {
|
||||
const menuItems: MenuItem[] = [];
|
||||
|
||||
if (room.value) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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: () => {
|
||||
|
||||
@@ -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[] = [
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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[] = [];
|
||||
|
||||
@@ -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([{
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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[] = [];
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(); },
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
@@ -113,7 +113,7 @@ watch(wallpaper, () => {
|
||||
suggestReload();
|
||||
});
|
||||
|
||||
function setWallpaper(ev: MouseEvent) {
|
||||
function setWallpaper(ev: PointerEvent) {
|
||||
selectFile({
|
||||
anchorElement: ev.currentTarget ?? ev.target,
|
||||
multiple: false,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ async function edit() {
|
||||
});
|
||||
}
|
||||
|
||||
function del(ev: MouseEvent) {
|
||||
function del(ev: PointerEvent) {
|
||||
os.popupMenu([{
|
||||
text: i18n.ts.delete,
|
||||
action: () => {
|
||||
|
||||
@@ -52,7 +52,7 @@ async function edit() {
|
||||
});
|
||||
}
|
||||
|
||||
function del(ev: MouseEvent) {
|
||||
function del(ev: PointerEvent) {
|
||||
os.popupMenu([{
|
||||
text: i18n.ts.delete,
|
||||
action: () => {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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: () => {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
},
|
||||
}, {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
},
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user