Merge branch 'develop' into signinRequiredForShowContents

This commit is contained in:
syuilo 2024-10-20 16:38:36 +09:00
commit a593459b58
6 changed files with 64 additions and 21 deletions

View File

@ -6,6 +6,7 @@
### Client ### Client
- Enhance: Bull DashboardでRelationship Queueの状態も確認できるように - Enhance: Bull DashboardでRelationship Queueの状態も確認できるように
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/751) (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/751)
- Enhance: ドライブでソートができるように
### Server ### Server
- -

View File

@ -157,7 +157,12 @@ const ilFilesObserver = new IntersectionObserver(
(entries) => entries.some((entry) => entry.isIntersecting) && !fetching.value && moreFiles.value && fetchMoreFiles(), (entries) => entries.some((entry) => entry.isIntersecting) && !fetching.value && moreFiles.value && fetchMoreFiles(),
); );
const sortModeSelect = ref('+createdAt');
watch(folder, () => emit('cd', folder.value)); watch(folder, () => emit('cd', folder.value));
watch(sortModeSelect, () => {
fetch();
});
function onStreamDriveFileCreated(file: Misskey.entities.DriveFile) { function onStreamDriveFileCreated(file: Misskey.entities.DriveFile) {
addFile(file, true); addFile(file, true);
@ -558,6 +563,7 @@ async function fetch() {
folderId: folder.value ? folder.value.id : null, folderId: folder.value ? folder.value.id : null,
type: props.type, type: props.type,
limit: filesMax + 1, limit: filesMax + 1,
sort: sortModeSelect.value,
}).then(fetchedFiles => { }).then(fetchedFiles => {
if (fetchedFiles.length === filesMax + 1) { if (fetchedFiles.length === filesMax + 1) {
moreFiles.value = true; moreFiles.value = true;
@ -607,6 +613,7 @@ function fetchMoreFiles() {
type: props.type, type: props.type,
untilId: files.value.at(-1)?.id, untilId: files.value.at(-1)?.id,
limit: max + 1, limit: max + 1,
sort: sortModeSelect.value,
}).then(files => { }).then(files => {
if (files.length === max + 1) { if (files.length === max + 1) {
moreFiles.value = true; moreFiles.value = true;
@ -642,6 +649,43 @@ function getMenu() {
type: 'label', type: 'label',
}); });
menu.push({
type: 'parent',
text: i18n.ts.sort,
icon: 'ti ti-arrows-sort',
children: [{
text: `${i18n.ts.registeredDate} (${i18n.ts.descendingOrder})`,
icon: 'ti ti-sort-descending-letters',
action: () => { sortModeSelect.value = '+createdAt'; },
active: sortModeSelect.value === '+createdAt',
}, {
text: `${i18n.ts.registeredDate} (${i18n.ts.ascendingOrder})`,
icon: 'ti ti-sort-ascending-letters',
action: () => { sortModeSelect.value = '-createdAt'; },
active: sortModeSelect.value === '-createdAt',
}, {
text: `${i18n.ts.size} (${i18n.ts.descendingOrder})`,
icon: 'ti ti-sort-descending-letters',
action: () => { sortModeSelect.value = '+size'; },
active: sortModeSelect.value === '+size',
}, {
text: `${i18n.ts.size} (${i18n.ts.ascendingOrder})`,
icon: 'ti ti-sort-ascending-letters',
action: () => { sortModeSelect.value = '-size'; },
active: sortModeSelect.value === '-size',
}, {
text: `${i18n.ts.name} (${i18n.ts.descendingOrder})`,
icon: 'ti ti-sort-descending-letters',
action: () => { sortModeSelect.value = '+name'; },
active: sortModeSelect.value === '+name',
}, {
text: `${i18n.ts.name} (${i18n.ts.ascendingOrder})`,
icon: 'ti ti-sort-ascending-letters',
action: () => { sortModeSelect.value = '-name'; },
active: sortModeSelect.value === '-name',
}],
});
if (folder.value) { if (folder.value) {
menu.push({ menu.push({
text: i18n.ts.renameFolder, text: i18n.ts.renameFolder,

View File

@ -5,10 +5,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<template> <template>
<MkStickyContainer> <MkStickyContainer>
<template #header> <template #header><MkPageHeader/></template>
<MkPageHeader/> <MkSpacer v-if="!instance.disableRegistration || !($i && ($i.isAdmin || $i.policies.canInvite))" :contentMax="1200">
</template>
<MKSpacer v-if="!instance.disableRegistration || !($i && ($i.isAdmin || $i.policies.canInvite))" :contentMax="1200">
<div :class="$style.root"> <div :class="$style.root">
<img :class="$style.img" :src="serverErrorImageUrl" class="_ghost"/> <img :class="$style.img" :src="serverErrorImageUrl" class="_ghost"/>
<div :class="$style.text"> <div :class="$style.text">
@ -16,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts.nothing }} {{ i18n.ts.nothing }}
</div> </div>
</div> </div>
</MKSpacer> </MkSpacer>
<MkSpacer v-else :contentMax="800"> <MkSpacer v-else :contentMax="800">
<div class="_gaps_m" style="text-align: center;"> <div class="_gaps_m" style="text-align: center;">
<div v-if="resetCycle && inviteLimit">{{ i18n.tsx.inviteLimitResetCycle({ time: resetCycle, limit: inviteLimit }) }}</div> <div v-if="resetCycle && inviteLimit">{{ i18n.tsx.inviteLimitResetCycle({ time: resetCycle, limit: inviteLimit }) }}</div>

View File

@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template> <template>
<MkStickyContainer> <MkStickyContainer>
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MKSpacer v-if="!(typeof error === 'undefined')" :contentMax="1200"> <MkSpacer v-if="error != null" :contentMax="1200">
<div :class="$style.root"> <div :class="$style.root">
<img :class="$style.img" :src="serverErrorImageUrl" class="_ghost"/> <img :class="$style.img" :src="serverErrorImageUrl" class="_ghost"/>
<p :class="$style.text"> <p :class="$style.text">
@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts.nothing }} {{ i18n.ts.nothing }}
</p> </p>
</div> </div>
</MKSpacer> </MkSpacer>
<MkSpacer v-else-if="list" :contentMax="700" :class="$style.main"> <MkSpacer v-else-if="list" :contentMax="700" :class="$style.main">
<div v-if="list" class="members _margin"> <div v-if="list" class="members _margin">
<div :class="$style.member_text">{{ i18n.ts.members }}</div> <div :class="$style.member_text">{{ i18n.ts.members }}</div>
@ -50,7 +50,7 @@ const props = defineProps<{
}>(); }>();
const list = ref<Misskey.entities.UserList | null>(null); const list = ref<Misskey.entities.UserList | null>(null);
const error = ref(); const error = ref<unknown | null>(null);
const users = ref<Misskey.entities.UserDetailed[]>([]); const users = ref<Misskey.entities.UserDetailed[]>([]);
function fetchList(): void { function fetchList(): void {

View File

@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template> <template>
<MkStickyContainer> <MkStickyContainer>
<template #header><MkPageHeader v-model:tab="tab" :tabs="headerTabs"/></template> <template #header><MkPageHeader v-model:tab="tab" :tabs="headerTabs"/></template>
<MKSpacer v-if="!(typeof error === 'undefined')" :contentMax="1200"> <MkSpacer v-if="error != null" :contentMax="1200">
<div :class="$style.root"> <div :class="$style.root">
<img :class="$style.img" :src="serverErrorImageUrl" class="_ghost"/> <img :class="$style.img" :src="serverErrorImageUrl" class="_ghost"/>
<p :class="$style.text"> <p :class="$style.text">
@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ error }} {{ error }}
</p> </p>
</div> </div>
</MKSpacer> </MkSpacer>
<MkSpacer v-else-if="tab === 'users'" :contentMax="1200"> <MkSpacer v-else-if="tab === 'users'" :contentMax="1200">
<div class="_gaps_s"> <div class="_gaps_s">
<div v-if="role">{{ role.description }}</div> <div v-if="role">{{ role.description }}</div>
@ -26,7 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</MkSpacer> </MkSpacer>
<MkSpacer v-else-if="tab === 'timeline'" :contentMax="700"> <MkSpacer v-else-if="tab === 'timeline'" :contentMax="700">
<MkTimeline v-if="visible" ref="timeline" src="role" :role="props.role"/> <MkTimeline v-if="visible" ref="timeline" src="role" :role="props.roleId"/>
<div v-else-if="!visible" class="_fullinfo"> <div v-else-if="!visible" class="_fullinfo">
<img :src="infoImageUrl" class="_ghost"/> <img :src="infoImageUrl" class="_ghost"/>
<div>{{ i18n.ts.nothing }}</div> <div>{{ i18n.ts.nothing }}</div>
@ -47,23 +47,24 @@ import { instanceName } from '@@/js/config.js';
import { serverErrorImageUrl, infoImageUrl } from '@/instance.js'; import { serverErrorImageUrl, infoImageUrl } from '@/instance.js';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
role: string; roleId: string;
initialTab?: string; initialTab?: string;
}>(), { }>(), {
initialTab: 'users', initialTab: 'users',
}); });
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
const tab = ref(props.initialTab); const tab = ref(props.initialTab);
const role = ref<Misskey.entities.Role>(); const role = ref<Misskey.entities.Role | null>(null);
const error = ref(); const error = ref<string | null>(null);
const visible = ref(false); const visible = ref(false);
watch(() => props.role, () => { watch(() => props.roleId, () => {
misskeyApi('roles/show', { misskeyApi('roles/show', {
roleId: props.role, roleId: props.roleId,
}).then(res => { }).then(res => {
role.value = res; role.value = res;
document.title = `${role.value.name} | ${instanceName}`; error.value = null;
visible.value = res.isExplorable && res.isPublic; visible.value = res.isExplorable && res.isPublic;
}).catch((err) => { }).catch((err) => {
if (err.code === 'NO_SUCH_ROLE') { if (err.code === 'NO_SUCH_ROLE') {
@ -71,7 +72,6 @@ watch(() => props.role, () => {
} else { } else {
error.value = i18n.ts.somethingHappened; error.value = i18n.ts.somethingHappened;
} }
document.title = `${error.value} | ${instanceName}`;
}); });
}, { immediate: true }); }, { immediate: true });
@ -79,7 +79,7 @@ const users = computed(() => ({
endpoint: 'roles/users' as const, endpoint: 'roles/users' as const,
limit: 30, limit: 30,
params: { params: {
roleId: props.role, roleId: props.roleId,
}, },
})); }));
@ -94,7 +94,7 @@ const headerTabs = computed(() => [{
}]); }]);
definePageMetadata(() => ({ definePageMetadata(() => ({
title: role.value ? role.value.name : i18n.ts.role, title: role.value ? role.value.name : (error.value ?? i18n.ts.role),
icon: 'ti ti-badge', icon: 'ti ti-badge',
})); }));
</script> </script>

View File

@ -217,7 +217,7 @@ const routes: RouteDef[] = [{
component: page(() => import('@/pages/theme-editor.vue')), component: page(() => import('@/pages/theme-editor.vue')),
loginRequired: true, loginRequired: true,
}, { }, {
path: '/roles/:role', path: '/roles/:roleId',
component: page(() => import('@/pages/role.vue')), component: page(() => import('@/pages/role.vue')),
}, { }, {
path: '/user-tags/:tag', path: '/user-tags/:tag',