Merge remote-tracking branch 'misskey/release/2024.5.0' into future
This commit is contained in:
commit
3372e0ffe1
181 changed files with 4057 additions and 891 deletions
|
|
@ -63,3 +63,26 @@ export async function lookupUserByEmail() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function lookupFile() {
|
||||
const { canceled, result: q } = await os.inputText({
|
||||
title: i18n.ts.fileIdOrUrl,
|
||||
minLength: 1,
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
const show = (file) => {
|
||||
os.pageWindow(`/admin/file/${file.id}`);
|
||||
};
|
||||
|
||||
misskeyApi('admin/drive/show-file', q.startsWith('http://') || q.startsWith('https://') ? { url: q.trim() } : { fileId: q.trim() }).then(file => {
|
||||
show(file);
|
||||
}).catch(err => {
|
||||
if (err.code === 'NO_SUCH_FILE') {
|
||||
os.alert({
|
||||
type: 'error',
|
||||
text: i18n.ts.notFound,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -6,15 +6,16 @@
|
|||
import * as Misskey from 'misskey-js';
|
||||
|
||||
export function shouldCollapsed(note: Misskey.entities.Note, urls: string[]): boolean {
|
||||
const collapsed = note.cw == null && note.text != null && (
|
||||
(note.text.includes('$[x2')) ||
|
||||
(note.text.includes('$[x3')) ||
|
||||
(note.text.includes('$[x4')) ||
|
||||
(note.text.includes('$[scale')) ||
|
||||
(note.text.split('\n').length > 9) ||
|
||||
(note.text.length > 500) ||
|
||||
(note.files.length >= 5) ||
|
||||
(urls.length >= 4)
|
||||
const collapsed = note.cw == null && (
|
||||
note.text != null && (
|
||||
(note.text.includes('$[x2')) ||
|
||||
(note.text.includes('$[x3')) ||
|
||||
(note.text.includes('$[x4')) ||
|
||||
(note.text.includes('$[scale')) ||
|
||||
(note.text.split('\n').length > 9) ||
|
||||
(note.text.length > 500) ||
|
||||
(urls.length >= 4)
|
||||
) || note.files.length >= 5
|
||||
);
|
||||
|
||||
return collapsed;
|
||||
|
|
|
|||
|
|
@ -3,18 +3,22 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import * as Misskey from 'misskey-js';
|
||||
|
||||
type EnumItem = string | {
|
||||
label: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
type Hidden = boolean | ((v: any) => boolean);
|
||||
|
||||
export type FormItem = {
|
||||
label?: string;
|
||||
type: 'string';
|
||||
default: string | null;
|
||||
description?: string;
|
||||
required?: boolean;
|
||||
hidden?: boolean;
|
||||
hidden?: Hidden;
|
||||
multiline?: boolean;
|
||||
treatAsMfm?: boolean;
|
||||
} | {
|
||||
|
|
@ -23,27 +27,27 @@ export type FormItem = {
|
|||
default: number | null;
|
||||
description?: string;
|
||||
required?: boolean;
|
||||
hidden?: boolean;
|
||||
hidden?: Hidden;
|
||||
step?: number;
|
||||
} | {
|
||||
label?: string;
|
||||
type: 'boolean';
|
||||
default: boolean | null;
|
||||
description?: string;
|
||||
hidden?: boolean;
|
||||
hidden?: Hidden;
|
||||
} | {
|
||||
label?: string;
|
||||
type: 'enum';
|
||||
default: string | null;
|
||||
required?: boolean;
|
||||
hidden?: boolean;
|
||||
hidden?: Hidden;
|
||||
enum: EnumItem[];
|
||||
} | {
|
||||
label?: string;
|
||||
type: 'radio';
|
||||
default: unknown | null;
|
||||
required?: boolean;
|
||||
hidden?: boolean;
|
||||
hidden?: Hidden;
|
||||
options: {
|
||||
label: string;
|
||||
value: unknown;
|
||||
|
|
@ -58,20 +62,27 @@ export type FormItem = {
|
|||
min: number;
|
||||
max: number;
|
||||
textConverter?: (value: number) => string;
|
||||
hidden?: Hidden;
|
||||
} | {
|
||||
label?: string;
|
||||
type: 'object';
|
||||
default: Record<string, unknown> | null;
|
||||
hidden: boolean;
|
||||
hidden: Hidden;
|
||||
} | {
|
||||
label?: string;
|
||||
type: 'array';
|
||||
default: unknown[] | null;
|
||||
hidden: boolean;
|
||||
hidden: Hidden;
|
||||
} | {
|
||||
type: 'button';
|
||||
content?: string;
|
||||
hidden?: Hidden;
|
||||
action: (ev: MouseEvent, v: any) => void;
|
||||
} | {
|
||||
type: 'drive-file';
|
||||
defaultFileId?: string | null;
|
||||
hidden?: Hidden;
|
||||
validate?: (v: Misskey.entities.DriveFile) => Promise<boolean>;
|
||||
};
|
||||
|
||||
export type Form = Record<string, FormItem>;
|
||||
|
|
@ -84,8 +95,9 @@ type GetItemType<Item extends FormItem> =
|
|||
Item['type'] extends 'range' ? number :
|
||||
Item['type'] extends 'enum' ? string :
|
||||
Item['type'] extends 'array' ? unknown[] :
|
||||
Item['type'] extends 'object' ? Record<string, unknown>
|
||||
: never;
|
||||
Item['type'] extends 'object' ? Record<string, unknown> :
|
||||
Item['type'] extends 'drive-file' ? Misskey.entities.DriveFile | undefined :
|
||||
never;
|
||||
|
||||
export type GetFormResultType<F extends Form> = {
|
||||
[P in keyof F]: GetItemType<F[P]>;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import { url } from '@/config.js';
|
|||
import { defaultStore, noteActions } from '@/store.js';
|
||||
import { miLocalStorage } from '@/local-storage.js';
|
||||
import { getUserMenu } from '@/scripts/get-user-menu.js';
|
||||
import { clipsCache } from '@/cache.js';
|
||||
import { clipsCache, favoritedChannelsCache } from '@/cache.js';
|
||||
import { MenuItem } from '@/types/menu.js';
|
||||
import MkRippleEffect from '@/components/MkRippleEffect.vue';
|
||||
import { isSupportShare } from '@/scripts/navigator.js';
|
||||
|
|
@ -552,6 +552,7 @@ export function getRenoteMenu(props: {
|
|||
|
||||
const channelRenoteItems: MenuItem[] = [];
|
||||
const normalRenoteItems: MenuItem[] = [];
|
||||
const normalExternalChannelRenoteItems: MenuItem[] = [];
|
||||
|
||||
if (appearNote.channel) {
|
||||
channelRenoteItems.push(...[{
|
||||
|
|
@ -630,12 +631,47 @@ export function getRenoteMenu(props: {
|
|||
});
|
||||
},
|
||||
}]);
|
||||
|
||||
normalExternalChannelRenoteItems.push({
|
||||
type: 'parent',
|
||||
icon: 'ti ti-repeat',
|
||||
text: appearNote.channel ? i18n.ts.renoteToOtherChannel : i18n.ts.renoteToChannel,
|
||||
children: async () => {
|
||||
const channels = await favoritedChannelsCache.fetch();
|
||||
return channels.filter((channel) => {
|
||||
if (!appearNote.channelId) return true;
|
||||
return channel.id !== appearNote.channelId;
|
||||
}).map((channel) => ({
|
||||
text: channel.name,
|
||||
action: () => {
|
||||
const el = props.renoteButton.value;
|
||||
if (el) {
|
||||
const rect = el.getBoundingClientRect();
|
||||
const x = rect.left + (el.offsetWidth / 2);
|
||||
const y = rect.top + (el.offsetHeight / 2);
|
||||
os.popup(MkRippleEffect, { x, y }, {}, 'end');
|
||||
}
|
||||
|
||||
if (!props.mock) {
|
||||
misskeyApi('notes/create', {
|
||||
renoteId: appearNote.id,
|
||||
channelId: channel.id,
|
||||
}).then(() => {
|
||||
os.toast(i18n.tsx.renotedToX({ name: channel.name }));
|
||||
});
|
||||
}
|
||||
},
|
||||
}));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const renoteItems = [
|
||||
...normalRenoteItems,
|
||||
...(channelRenoteItems.length > 0 && normalRenoteItems.length > 0) ? [{ type: 'divider' }] as MenuItem[] : [],
|
||||
...channelRenoteItems,
|
||||
...(normalExternalChannelRenoteItems.length > 0 && (normalRenoteItems.length > 0 || channelRenoteItems.length > 0)) ? [{ type: 'divider' }] as MenuItem[] : [],
|
||||
...normalExternalChannelRenoteItems,
|
||||
];
|
||||
|
||||
return {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue