Merge tag '2023.12.0-beta.3' into merge-upstream
This commit is contained in:
commit
e77ddfce91
423 changed files with 42868 additions and 10814 deletions
|
|
@ -25,7 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { } from 'vue';
|
||||
import { ref, computed } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import { version } from '@/config.js';
|
||||
|
|
@ -42,29 +42,29 @@ const props = withDefaults(defineProps<{
|
|||
}>(), {
|
||||
});
|
||||
|
||||
let loaded = $ref(false);
|
||||
let serverIsDead = $ref(false);
|
||||
let meta = $ref<Misskey.entities.LiteInstanceMetadata | null>(null);
|
||||
const loaded = ref(false);
|
||||
const serverIsDead = ref(false);
|
||||
const meta = ref<Misskey.entities.MetaResponse | null>(null);
|
||||
|
||||
os.api('meta', {
|
||||
detail: false,
|
||||
}).then(res => {
|
||||
loaded = true;
|
||||
serverIsDead = false;
|
||||
meta = res;
|
||||
loaded.value = true;
|
||||
serverIsDead.value = false;
|
||||
meta.value = res;
|
||||
miLocalStorage.setItem('v', res.version);
|
||||
}, () => {
|
||||
loaded = true;
|
||||
serverIsDead = true;
|
||||
loaded.value = true;
|
||||
serverIsDead.value = true;
|
||||
});
|
||||
|
||||
function reload() {
|
||||
unisonReload();
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.error,
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { nextTick, onBeforeUnmount } from 'vue';
|
||||
import { nextTick, onBeforeUnmount, ref, shallowRef, computed } from 'vue';
|
||||
import { version } from '@/config.js';
|
||||
import FormLink from '@/components/form/link.vue';
|
||||
import FormSection from '@/components/form/section.vue';
|
||||
|
|
@ -310,18 +310,18 @@ const patrons = [
|
|||
'SHO SEKIGUCHI',
|
||||
];
|
||||
|
||||
let thereIsTreasure = $ref($i && !claimedAchievements.includes('foundTreasure'));
|
||||
const thereIsTreasure = ref($i && !claimedAchievements.includes('foundTreasure'));
|
||||
|
||||
let easterEggReady = false;
|
||||
let easterEggEmojis = $ref([]);
|
||||
let easterEggEngine = $ref(null);
|
||||
const containerEl = $shallowRef<HTMLElement>();
|
||||
const easterEggEmojis = ref([]);
|
||||
const easterEggEngine = ref(null);
|
||||
const containerEl = shallowRef<HTMLElement>();
|
||||
|
||||
function iconLoaded() {
|
||||
const emojis = defaultStore.state.reactions;
|
||||
const containerWidth = containerEl.offsetWidth;
|
||||
const containerWidth = containerEl.value.offsetWidth;
|
||||
for (let i = 0; i < 32; i++) {
|
||||
easterEggEmojis.push({
|
||||
easterEggEmojis.value.push({
|
||||
id: i.toString(),
|
||||
top: -(128 + (Math.random() * 256)),
|
||||
left: (Math.random() * containerWidth),
|
||||
|
|
@ -337,7 +337,7 @@ function iconLoaded() {
|
|||
function gravity() {
|
||||
if (!easterEggReady) return;
|
||||
easterEggReady = false;
|
||||
easterEggEngine = physics(containerEl);
|
||||
easterEggEngine.value = physics(containerEl.value);
|
||||
}
|
||||
|
||||
function iLoveMisskey() {
|
||||
|
|
@ -348,19 +348,19 @@ function iLoveMisskey() {
|
|||
}
|
||||
|
||||
function getTreasure() {
|
||||
thereIsTreasure = false;
|
||||
thereIsTreasure.value = false;
|
||||
claimAchievement('foundTreasure');
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (easterEggEngine) {
|
||||
easterEggEngine.stop();
|
||||
if (easterEggEngine.value) {
|
||||
easterEggEngine.value.stop();
|
||||
}
|
||||
});
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.aboutMisskey,
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { watch } from 'vue';
|
||||
import { watch, ref } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import XEmoji from './emojis.emoji.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
|
|
@ -47,44 +47,44 @@ import { i18n } from '@/i18n.js';
|
|||
import { $i } from '@/account.js';
|
||||
|
||||
const customEmojiTags = getCustomEmojiTags();
|
||||
let q = $ref('');
|
||||
let searchEmojis = $ref<Misskey.entities.CustomEmoji[]>(null);
|
||||
let selectedTags = $ref(new Set());
|
||||
const q = ref('');
|
||||
const searchEmojis = ref<Misskey.entities.EmojiSimple[]>(null);
|
||||
const selectedTags = ref(new Set());
|
||||
|
||||
function search() {
|
||||
if ((q === '' || q == null) && selectedTags.size === 0) {
|
||||
searchEmojis = null;
|
||||
if ((q.value === '' || q.value == null) && selectedTags.value.size === 0) {
|
||||
searchEmojis.value = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedTags.size === 0) {
|
||||
const queryarry = q.match(/\:([a-z0-9_]*)\:/g);
|
||||
if (selectedTags.value.size === 0) {
|
||||
const queryarry = q.value.match(/\:([a-z0-9_]*)\:/g);
|
||||
|
||||
if (queryarry) {
|
||||
searchEmojis = customEmojis.value.filter(emoji =>
|
||||
searchEmojis.value = customEmojis.value.filter(emoji =>
|
||||
queryarry.includes(`:${emoji.name}:`),
|
||||
);
|
||||
} else {
|
||||
searchEmojis = customEmojis.value.filter(emoji => emoji.name.includes(q) || emoji.aliases.includes(q));
|
||||
searchEmojis.value = customEmojis.value.filter(emoji => emoji.name.includes(q.value) || emoji.aliases.includes(q.value));
|
||||
}
|
||||
} else {
|
||||
searchEmojis = customEmojis.value.filter(emoji => (emoji.name.includes(q) || emoji.aliases.includes(q)) && [...selectedTags].every(t => emoji.aliases.includes(t)));
|
||||
searchEmojis.value = customEmojis.value.filter(emoji => (emoji.name.includes(q.value) || emoji.aliases.includes(q.value)) && [...selectedTags.value].every(t => emoji.aliases.includes(t)));
|
||||
}
|
||||
}
|
||||
|
||||
function toggleTag(tag) {
|
||||
if (selectedTags.has(tag)) {
|
||||
selectedTags.delete(tag);
|
||||
if (selectedTags.value.has(tag)) {
|
||||
selectedTags.value.delete(tag);
|
||||
} else {
|
||||
selectedTags.add(tag);
|
||||
selectedTags.value.add(tag);
|
||||
}
|
||||
}
|
||||
|
||||
watch($$(q), () => {
|
||||
watch(q, () => {
|
||||
search();
|
||||
});
|
||||
|
||||
watch($$(selectedTags), () => {
|
||||
watch(selectedTags, () => {
|
||||
search();
|
||||
}, { deep: true });
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkSelect from '@/components/MkSelect.vue';
|
||||
import MkPagination, { Paging } from '@/components/MkPagination.vue';
|
||||
|
|
@ -59,25 +59,25 @@ import MkInstanceCardMini from '@/components/MkInstanceCardMini.vue';
|
|||
import FormSplit from '@/components/form/split.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
||||
let host = $ref('');
|
||||
let state = $ref('federating');
|
||||
let sort = $ref('+pubSub');
|
||||
const host = ref('');
|
||||
const state = ref('federating');
|
||||
const sort = ref('+pubSub');
|
||||
const pagination = {
|
||||
endpoint: 'federation/instances' as const,
|
||||
limit: 10,
|
||||
displayLimit: 50,
|
||||
offsetMode: true,
|
||||
params: computed(() => ({
|
||||
sort: sort,
|
||||
host: host !== '' ? host : null,
|
||||
sort: sort.value,
|
||||
host: host.value !== '' ? host.value : null,
|
||||
...(
|
||||
state === 'federating' ? { federating: true } :
|
||||
state === 'subscribing' ? { subscribing: true } :
|
||||
state === 'publishing' ? { publishing: true } :
|
||||
state === 'suspended' ? { suspended: true } :
|
||||
state === 'blocked' ? { blocked: true } :
|
||||
state === 'silenced' ? { silenced: true } :
|
||||
state === 'notResponding' ? { notResponding: true } :
|
||||
state.value === 'federating' ? { federating: true } :
|
||||
state.value === 'subscribing' ? { subscribing: true } :
|
||||
state.value === 'publishing' ? { publishing: true } :
|
||||
state.value === 'suspended' ? { suspended: true } :
|
||||
state.value === 'blocked' ? { blocked: true } :
|
||||
state.value === 'silenced' ? { silenced: true } :
|
||||
state.value === 'notResponding' ? { notResponding: true } :
|
||||
{}),
|
||||
})),
|
||||
} as Paging;
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch } from 'vue';
|
||||
import { computed, watch, ref } from 'vue';
|
||||
import XEmojis from './about.emojis.vue';
|
||||
import XFederation from './about.federation.vue';
|
||||
import { version, host } from '@/config.js';
|
||||
|
|
@ -126,23 +126,23 @@ const props = withDefaults(defineProps<{
|
|||
initialTab: 'overview',
|
||||
});
|
||||
|
||||
let stats = $ref(null);
|
||||
let tab = $ref(props.initialTab);
|
||||
const stats = ref(null);
|
||||
const tab = ref(props.initialTab);
|
||||
|
||||
watch($$(tab), () => {
|
||||
if (tab === 'charts') {
|
||||
watch(tab, () => {
|
||||
if (tab.value === 'charts') {
|
||||
claimAchievement('viewInstanceChart');
|
||||
}
|
||||
});
|
||||
|
||||
const initStats = () => os.api('stats', {
|
||||
}).then((res) => {
|
||||
stats = res;
|
||||
stats.value = res;
|
||||
});
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => [{
|
||||
const headerTabs = computed(() => [{
|
||||
key: 'overview',
|
||||
title: i18n.ts.overview,
|
||||
}, {
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import MkObjectView from '@/components/MkObjectView.vue';
|
||||
|
|
@ -82,19 +82,19 @@ import { i18n } from '@/i18n.js';
|
|||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
import { iAmAdmin, iAmModerator } from '@/account.js';
|
||||
|
||||
let tab = $ref('overview');
|
||||
let file: any = $ref(null);
|
||||
let info: any = $ref(null);
|
||||
let isSensitive: boolean = $ref(false);
|
||||
const tab = ref('overview');
|
||||
const file = ref<any>(null);
|
||||
const info = ref<any>(null);
|
||||
const isSensitive = ref<boolean>(false);
|
||||
|
||||
const props = defineProps<{
|
||||
fileId: string,
|
||||
}>();
|
||||
|
||||
async function fetch() {
|
||||
file = await os.api('drive/files/show', { fileId: props.fileId });
|
||||
info = await os.api('admin/drive/show-file', { fileId: props.fileId });
|
||||
isSensitive = file.isSensitive;
|
||||
file.value = await os.api('drive/files/show', { fileId: props.fileId });
|
||||
info.value = await os.api('admin/drive/show-file', { fileId: props.fileId });
|
||||
isSensitive.value = file.value.isSensitive;
|
||||
}
|
||||
|
||||
fetch();
|
||||
|
|
@ -102,29 +102,29 @@ fetch();
|
|||
async function del() {
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'warning',
|
||||
text: i18n.t('removeAreYouSure', { x: file.name }),
|
||||
text: i18n.t('removeAreYouSure', { x: file.value.name }),
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
os.apiWithDialog('drive/files/delete', {
|
||||
fileId: file.id,
|
||||
fileId: file.value.id,
|
||||
});
|
||||
}
|
||||
|
||||
async function toggleIsSensitive(v) {
|
||||
await os.api('drive/files/update', { fileId: props.fileId, isSensitive: v });
|
||||
isSensitive = v;
|
||||
isSensitive.value = v;
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => [{
|
||||
const headerActions = computed(() => [{
|
||||
text: i18n.ts.openInNewTab,
|
||||
icon: 'ti ti-external-link',
|
||||
handler: () => {
|
||||
window.open(file.url, '_blank', 'noopener');
|
||||
window.open(file.value.url, '_blank', 'noopener');
|
||||
},
|
||||
}]);
|
||||
|
||||
const headerTabs = $computed(() => [{
|
||||
const headerTabs = computed(() => [{
|
||||
key: 'overview',
|
||||
title: i18n.ts.overview,
|
||||
icon: 'ti ti-info-circle',
|
||||
|
|
@ -139,7 +139,7 @@ const headerTabs = $computed(() => [{
|
|||
}]);
|
||||
|
||||
definePageMetadata(computed(() => ({
|
||||
title: file ? i18n.ts.file + ': ' + file.name : i18n.ts.file,
|
||||
title: file.value ? i18n.ts.file + ': ' + file.value.name : i18n.ts.file,
|
||||
icon: 'ti ti-file',
|
||||
})));
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, defineAsyncComponent, ref, watch } from 'vue';
|
||||
import { computed, defineAsyncComponent, watch, ref } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import MkChart from '@/components/MkChart.vue';
|
||||
import MkObjectView from '@/components/MkObjectView.vue';
|
||||
|
|
@ -235,18 +235,18 @@ const props = withDefaults(defineProps<{
|
|||
initialTab: 'overview',
|
||||
});
|
||||
|
||||
let tab = $ref(props.initialTab);
|
||||
let chartSrc = $ref('per-user-notes');
|
||||
let user = $ref<null | Misskey.entities.UserDetailed>();
|
||||
let init = $ref<ReturnType<typeof createFetcher>>();
|
||||
let info = $ref();
|
||||
let ips = $ref(null);
|
||||
let ap = $ref(null);
|
||||
let moderator = $ref(false);
|
||||
let silenced = $ref(false);
|
||||
let limited = $ref(false);
|
||||
let suspended = $ref(false);
|
||||
let moderationNote = $ref('');
|
||||
const tab = ref(props.initialTab);
|
||||
const chartSrc = ref('per-user-notes');
|
||||
const user = ref<null | Misskey.entities.UserDetailed>();
|
||||
const init = ref<ReturnType<typeof createFetcher>>();
|
||||
const info = ref();
|
||||
const ips = ref(null);
|
||||
const ap = ref(null);
|
||||
const moderator = ref(false);
|
||||
const silenced = ref(false);
|
||||
const limited = ref(false);
|
||||
const suspended = ref(false);
|
||||
const moderationNote = ref('');
|
||||
const filesPagination = {
|
||||
endpoint: 'admin/drive/files' as const,
|
||||
limit: 10,
|
||||
|
|
@ -263,7 +263,7 @@ const announcementsPagination = {
|
|||
userId: props.userId,
|
||||
})),
|
||||
};
|
||||
let expandedRoles = $ref([]);
|
||||
const expandedRoles = ref([]);
|
||||
|
||||
function createFetcher() {
|
||||
return () => Promise.all([os.api('users/show', {
|
||||
|
|
@ -273,28 +273,28 @@ function createFetcher() {
|
|||
}), iAmAdmin ? os.api('admin/get-user-ips', {
|
||||
userId: props.userId,
|
||||
}) : Promise.resolve(null)]).then(([_user, _info, _ips]) => {
|
||||
user = _user;
|
||||
info = _info;
|
||||
ips = _ips;
|
||||
moderator = info.isModerator;
|
||||
silenced = info.isSilenced;
|
||||
limited = info.isLimited;
|
||||
suspended = info.isSuspended;
|
||||
moderationNote = info.moderationNote;
|
||||
user.value = _user;
|
||||
info.value = _info;
|
||||
ips.value = _ips;
|
||||
moderator.value = info.value.isModerator;
|
||||
silenced.value = info.value.isSilenced;
|
||||
limited.value = info.value.isLimited;
|
||||
suspended.value = info.value.isSuspended;
|
||||
moderationNote.value = info.value.moderationNote;
|
||||
|
||||
watch($$(moderationNote), async () => {
|
||||
await os.api('admin/update-user-note', { userId: user.id, text: moderationNote });
|
||||
watch(moderationNote, async () => {
|
||||
await os.api('admin/update-user-note', { userId: user.value.id, text: moderationNote.value });
|
||||
await refreshUser();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function refreshUser() {
|
||||
init = createFetcher();
|
||||
init.value = createFetcher();
|
||||
}
|
||||
|
||||
async function updateRemoteUser() {
|
||||
await os.apiWithDialog('federation/update-remote-user', { userId: user.id });
|
||||
await os.apiWithDialog('federation/update-remote-user', { userId: user.value.id });
|
||||
refreshUser();
|
||||
}
|
||||
|
||||
|
|
@ -307,7 +307,7 @@ async function resetPassword() {
|
|||
return;
|
||||
} else {
|
||||
const { password } = await os.api('admin/reset-password', {
|
||||
userId: user.id,
|
||||
userId: user.value.id,
|
||||
});
|
||||
os.alert({
|
||||
type: 'success',
|
||||
|
|
@ -322,9 +322,9 @@ async function toggleSuspend(v) {
|
|||
text: v ? i18n.ts.suspendConfirm : i18n.ts.unsuspendConfirm,
|
||||
});
|
||||
if (confirm.canceled) {
|
||||
suspended = !v;
|
||||
suspended.value = !v;
|
||||
} else {
|
||||
await os.api(v ? 'admin/suspend-user' : 'admin/unsuspend-user', { userId: user.id });
|
||||
await os.api(v ? 'admin/suspend-user' : 'admin/unsuspend-user', { userId: user.value.id });
|
||||
await refreshUser();
|
||||
}
|
||||
}
|
||||
|
|
@ -336,7 +336,7 @@ async function unsetUserAvatar() {
|
|||
});
|
||||
if (confirm.canceled) return;
|
||||
const process = async () => {
|
||||
await os.api('admin/unset-user-avatar', { userId: user.id });
|
||||
await os.api('admin/unset-user-avatar', { userId: user.value.id });
|
||||
os.success();
|
||||
};
|
||||
await process().catch(err => {
|
||||
|
|
@ -355,7 +355,7 @@ async function unsetUserBanner() {
|
|||
});
|
||||
if (confirm.canceled) return;
|
||||
const process = async () => {
|
||||
await os.api('admin/unset-user-banner', { userId: user.id });
|
||||
await os.api('admin/unset-user-banner', { userId: user.value.id });
|
||||
os.success();
|
||||
};
|
||||
await process().catch(err => {
|
||||
|
|
@ -374,7 +374,7 @@ async function deleteAllFiles() {
|
|||
});
|
||||
if (confirm.canceled) return;
|
||||
const process = async () => {
|
||||
await os.api('admin/delete-all-files-of-a-user', { userId: user.id });
|
||||
await os.api('admin/delete-all-files-of-a-user', { userId: user.value.id });
|
||||
os.success();
|
||||
};
|
||||
await process().catch(err => {
|
||||
|
|
@ -394,13 +394,13 @@ async function deleteAccount() {
|
|||
if (confirm.canceled) return;
|
||||
|
||||
const typed = await os.inputText({
|
||||
text: i18n.t('typeToConfirm', { x: user?.username }),
|
||||
text: i18n.t('typeToConfirm', { x: user.value?.username }),
|
||||
});
|
||||
if (typed.canceled) return;
|
||||
|
||||
if (typed.result === user?.username) {
|
||||
if (typed.result === user.value?.username) {
|
||||
await os.apiWithDialog('admin/delete-account', {
|
||||
userId: user.id,
|
||||
userId: user.value.id,
|
||||
});
|
||||
} else {
|
||||
os.alert({
|
||||
|
|
@ -443,7 +443,7 @@ async function assignRole() {
|
|||
: period === 'oneMonth' ? Date.now() + (1000 * 60 * 60 * 24 * 30)
|
||||
: null;
|
||||
|
||||
await os.apiWithDialog('admin/roles/assign', { roleId, userId: user.id, expiresAt });
|
||||
await os.apiWithDialog('admin/roles/assign', { roleId, userId: user.value.id, expiresAt });
|
||||
refreshUser();
|
||||
}
|
||||
|
||||
|
|
@ -453,23 +453,23 @@ async function unassignRole(role, ev) {
|
|||
icon: 'ti ti-x',
|
||||
danger: true,
|
||||
action: async () => {
|
||||
await os.apiWithDialog('admin/roles/unassign', { roleId: role.id, userId: user.id });
|
||||
await os.apiWithDialog('admin/roles/unassign', { roleId: role.id, userId: user.value.id });
|
||||
refreshUser();
|
||||
},
|
||||
}], ev.currentTarget ?? ev.target);
|
||||
}
|
||||
|
||||
function toggleRoleItem(role) {
|
||||
if (expandedRoles.includes(role.id)) {
|
||||
expandedRoles = expandedRoles.filter(x => x !== role.id);
|
||||
if (expandedRoles.value.includes(role.id)) {
|
||||
expandedRoles.value = expandedRoles.value.filter(x => x !== role.id);
|
||||
} else {
|
||||
expandedRoles.push(role.id);
|
||||
expandedRoles.value.push(role.id);
|
||||
}
|
||||
}
|
||||
|
||||
function createAnnouncement(): void {
|
||||
os.popup(defineAsyncComponent(() => import('@/components/MkUserAnnouncementEditDialog.vue')), {
|
||||
user,
|
||||
user: user.value,
|
||||
}, {
|
||||
done: async () => {
|
||||
announcementsPaginationEl.value?.reload();
|
||||
|
|
@ -479,7 +479,7 @@ function createAnnouncement(): void {
|
|||
|
||||
function editAnnouncement(announcement): void {
|
||||
os.popup(defineAsyncComponent(() => import('@/components/MkUserAnnouncementEditDialog.vue')), {
|
||||
user,
|
||||
user: user.value,
|
||||
announcement,
|
||||
}, {
|
||||
done: async () => {
|
||||
|
|
@ -489,22 +489,22 @@ function editAnnouncement(announcement): void {
|
|||
}
|
||||
|
||||
watch(() => props.userId, () => {
|
||||
init = createFetcher();
|
||||
init.value = createFetcher();
|
||||
}, {
|
||||
immediate: true,
|
||||
});
|
||||
|
||||
watch($$(user), () => {
|
||||
watch(user, () => {
|
||||
os.api('ap/get', {
|
||||
uri: user.uri ?? `${url}/users/${user.id}`,
|
||||
uri: user.value.uri ?? `${url}/users/${user.value.id}`,
|
||||
}).then(res => {
|
||||
ap = res;
|
||||
ap.value = res;
|
||||
});
|
||||
});
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => [{
|
||||
const headerTabs = computed(() => [{
|
||||
key: 'overview',
|
||||
title: i18n.ts.overview,
|
||||
icon: 'ti ti-info-circle',
|
||||
|
|
@ -531,7 +531,7 @@ const headerTabs = $computed(() => [{
|
|||
}]);
|
||||
|
||||
definePageMetadata(computed(() => ({
|
||||
title: user ? acct(user) : i18n.ts.userInfo,
|
||||
title: user.value ? acct(user.value) : i18n.ts.userInfo,
|
||||
icon: 'ti ti-user-exclamation',
|
||||
})));
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ const metadata = injectPageMetadata();
|
|||
|
||||
const el = shallowRef<HTMLElement>(null);
|
||||
const tabRefs = {};
|
||||
const tabHighlightEl = $shallowRef<HTMLElement | null>(null);
|
||||
const tabHighlightEl = shallowRef<HTMLElement | null>(null);
|
||||
const bg = ref(null);
|
||||
const height = ref(0);
|
||||
const hasTabs = computed(() => {
|
||||
|
|
@ -131,13 +131,13 @@ onMounted(() => {
|
|||
watch(() => [props.tab, props.tabs], () => {
|
||||
nextTick(() => {
|
||||
const tabEl = tabRefs[props.tab];
|
||||
if (tabEl && tabHighlightEl) {
|
||||
if (tabEl && tabHighlightEl.value) {
|
||||
// offsetWidth や offsetLeft は少数を丸めてしまうため getBoundingClientRect を使う必要がある
|
||||
// https://developer.mozilla.org/ja/docs/Web/API/HTMLElement/offsetWidth#%E5%80%A4
|
||||
const parentRect = tabEl.parentElement.getBoundingClientRect();
|
||||
const rect = tabEl.getBoundingClientRect();
|
||||
tabHighlightEl.style.width = rect.width + 'px';
|
||||
tabHighlightEl.style.left = (rect.left - parentRect.left) + 'px';
|
||||
tabHighlightEl.value.style.width = rect.width + 'px';
|
||||
tabHighlightEl.value.style.left = (rect.left - parentRect.left) + 'px';
|
||||
}
|
||||
});
|
||||
}, {
|
||||
|
|
|
|||
|
|
@ -79,7 +79,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { computed, shallowRef, ref } from 'vue';
|
||||
|
||||
import XHeader from './_header_.vue';
|
||||
import MkSelect from '@/components/MkSelect.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
|
|
@ -91,15 +92,15 @@ import { i18n } from '@/i18n.js';
|
|||
import * as os from '@/os.js';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
|
||||
let reports = $shallowRef<InstanceType<typeof MkPagination>>();
|
||||
let resolverPagingComponent = $ref<InstanceType<typeof MkPagination>>();
|
||||
let folderComponent = $ref<InstanceType<typeof MkFolder>>();
|
||||
const reports = shallowRef<InstanceType<typeof MkPagination>>();
|
||||
const resolverPagingComponent = ref<InstanceType<typeof MkPagination>>();
|
||||
const folderComponent = ref<InstanceType<typeof MkFolder>>();
|
||||
|
||||
let state = $ref('unresolved');
|
||||
let reporterOrigin = $ref('combined');
|
||||
let targetUserOrigin = $ref('combined');
|
||||
let tab = $ref('list');
|
||||
let editableResolver: null | string = $ref(null);
|
||||
const state = ref('unresolved');
|
||||
const reporterOrigin = ref('combined');
|
||||
const targetUserOrigin = ref('combined');
|
||||
const tab = ref('list');
|
||||
const editableResolver = ref<null | string>(null);
|
||||
const defaultResolver = {
|
||||
name: '',
|
||||
targetUserPattern: '',
|
||||
|
|
@ -110,7 +111,7 @@ const defaultResolver = {
|
|||
forward: false,
|
||||
};
|
||||
|
||||
let newResolver = $ref<{
|
||||
const newResolver = ref<{
|
||||
name: string;
|
||||
targetUserPattern: string;
|
||||
reporterPattern: string;
|
||||
|
|
@ -120,7 +121,7 @@ let newResolver = $ref<{
|
|||
forward: boolean;
|
||||
}>(defaultResolver);
|
||||
|
||||
let editingResolver = $ref<{
|
||||
const editingResolver = ref<{
|
||||
name: string;
|
||||
targetUserPattern: string;
|
||||
reporterPattern: string;
|
||||
|
|
@ -135,9 +136,9 @@ const pagination = {
|
|||
endpoint: 'admin/abuse-user-reports' as const,
|
||||
limit: 10,
|
||||
params: computed(() => ({
|
||||
state,
|
||||
reporterOrigin,
|
||||
targetUserOrigin,
|
||||
state: state.value,
|
||||
reporterOrigin: reporterOrigin.value,
|
||||
targetUserOrigin: targetUserOrigin.value,
|
||||
})),
|
||||
};
|
||||
|
||||
|
|
@ -147,26 +148,26 @@ const resolverPagination = {
|
|||
};
|
||||
|
||||
function resolved(reportId) {
|
||||
reports!.removeItem(item => item.id === reportId);
|
||||
reports.value!.removeItem(item => item.id === reportId);
|
||||
}
|
||||
|
||||
function edit(id: string) {
|
||||
editableResolver = id;
|
||||
editableResolver.value = id;
|
||||
}
|
||||
|
||||
function save(): void {
|
||||
os.apiWithDialog('admin/abuse-report-resolver/update', {
|
||||
resolverId: editableResolver,
|
||||
name: editingResolver.name,
|
||||
targetUserPattern: editingResolver.targetUserPattern || null,
|
||||
reporterPattern: editingResolver.reporterPattern || null,
|
||||
reportContentPattern: editingResolver.reportContentPattern || null,
|
||||
...(editingResolver.previousExpiresAt && editingResolver.previousExpiresAt === editingResolver.expiresAt ? {} : {
|
||||
expiresAt: editingResolver.expiresAt,
|
||||
resolverId: editableResolver.value,
|
||||
name: editingResolver.value.name,
|
||||
targetUserPattern: editingResolver.value.targetUserPattern || null,
|
||||
reporterPattern: editingResolver.value.reporterPattern || null,
|
||||
reportContentPattern: editingResolver.value.reportContentPattern || null,
|
||||
...(editingResolver.value.previousExpiresAt && editingResolver.value.previousExpiresAt === editingResolver.value.expiresAt ? {} : {
|
||||
expiresAt: editingResolver.value.expiresAt,
|
||||
}),
|
||||
forward: editingResolver.forward,
|
||||
forward: editingResolver.value.forward,
|
||||
}).then(() => {
|
||||
editableResolver = null;
|
||||
editableResolver.value = null;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -174,33 +175,33 @@ function deleteResolver(id: string): void {
|
|||
os.apiWithDialog('admin/abuse-report-resolver/delete', {
|
||||
resolverId: id,
|
||||
}).then(() => {
|
||||
resolverPagingComponent?.reload();
|
||||
resolverPagingComponent.value?.reload();
|
||||
});
|
||||
}
|
||||
|
||||
function create(): void {
|
||||
os.apiWithDialog('admin/abuse-report-resolver/create', {
|
||||
name: newResolver.name,
|
||||
targetUserPattern: newResolver.targetUserPattern || null,
|
||||
reporterPattern: newResolver.reporterPattern || null,
|
||||
reportContentPattern: newResolver.reportContentPattern || null,
|
||||
expiresAt: newResolver.expiresAt,
|
||||
forward: newResolver.forward,
|
||||
name: newResolver.value.name,
|
||||
targetUserPattern: newResolver.value.targetUserPattern || null,
|
||||
reporterPattern: newResolver.value.reporterPattern || null,
|
||||
reportContentPattern: newResolver.value.reportContentPattern || null,
|
||||
expiresAt: newResolver.value.expiresAt,
|
||||
forward: newResolver.value.forward,
|
||||
}).then(() => {
|
||||
folderComponent?.toggle();
|
||||
resolverPagingComponent?.reload();
|
||||
newResolver.name = '';
|
||||
newResolver.targetUserPattern = '';
|
||||
newResolver.reporterPattern = '';
|
||||
newResolver.reportContentPattern = '';
|
||||
newResolver.expiresAt = 'indefinitely';
|
||||
newResolver.forward = false;
|
||||
folderComponent.value?.toggle();
|
||||
resolverPagingComponent.value?.reload();
|
||||
newResolver.value.name = '';
|
||||
newResolver.value.targetUserPattern = '';
|
||||
newResolver.value.reporterPattern = '';
|
||||
newResolver.value.reportContentPattern = '';
|
||||
newResolver.value.expiresAt = 'indefinitely';
|
||||
newResolver.value.forward = false;
|
||||
});
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => [{
|
||||
const headerTabs = computed(() => [{
|
||||
key: 'list',
|
||||
title: i18n.ts._abuse.list,
|
||||
}, {
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { ref, computed } from 'vue';
|
||||
import XHeader from './_header_.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
|
|
@ -98,7 +98,7 @@ import * as os from '@/os.js';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
|
||||
let ads: any[] = $ref([]);
|
||||
const ads = ref<any[]>([]);
|
||||
|
||||
// ISO形式はTZがUTCになってしまうので、TZ分ずらして時間を初期化
|
||||
const localTime = new Date();
|
||||
|
|
@ -109,7 +109,7 @@ let publishing: boolean | null = null;
|
|||
|
||||
os.api('admin/ad/list', { publishing: publishing }).then(adsResponse => {
|
||||
if (adsResponse != null) {
|
||||
ads = adsResponse.map(r => {
|
||||
ads.value = adsResponse.map(r => {
|
||||
const exdate = new Date(r.expiresAt);
|
||||
const stdate = new Date(r.startsAt);
|
||||
exdate.setMilliseconds(exdate.getMilliseconds() - localTimeDiff);
|
||||
|
|
@ -141,7 +141,7 @@ function toggleDayOfWeek(ad, index) {
|
|||
}
|
||||
|
||||
function add() {
|
||||
ads.unshift({
|
||||
ads.value.unshift({
|
||||
id: null,
|
||||
memo: '',
|
||||
place: 'square',
|
||||
|
|
@ -161,7 +161,7 @@ function remove(ad) {
|
|||
text: i18n.t('removeAreYouSure', { x: ad.url }),
|
||||
}).then(({ canceled }) => {
|
||||
if (canceled) return;
|
||||
ads = ads.filter(x => x !== ad);
|
||||
ads.value = ads.value.filter(x => x !== ad);
|
||||
if (ad.id == null) return;
|
||||
os.apiWithDialog('admin/ad/delete', {
|
||||
id: ad.id,
|
||||
|
|
@ -209,9 +209,9 @@ function save(ad) {
|
|||
}
|
||||
|
||||
function more() {
|
||||
os.api('admin/ad/list', { untilId: ads.reduce((acc, ad) => ad.id != null ? ad : acc).id, publishing: publishing }).then(adsResponse => {
|
||||
os.api('admin/ad/list', { untilId: ads.value.reduce((acc, ad) => ad.id != null ? ad : acc).id, publishing: publishing }).then(adsResponse => {
|
||||
if (adsResponse == null) return;
|
||||
ads = ads.concat(adsResponse.map(r => {
|
||||
ads.value = ads.value.concat(adsResponse.map(r => {
|
||||
const exdate = new Date(r.expiresAt);
|
||||
const stdate = new Date(r.startsAt);
|
||||
exdate.setMilliseconds(exdate.getMilliseconds() - localTimeDiff);
|
||||
|
|
@ -228,7 +228,7 @@ function more() {
|
|||
function refresh() {
|
||||
os.api('admin/ad/list', { publishing: publishing }).then(adsResponse => {
|
||||
if (adsResponse == null) return;
|
||||
ads = adsResponse.map(r => {
|
||||
ads.value = adsResponse.map(r => {
|
||||
const exdate = new Date(r.expiresAt);
|
||||
const stdate = new Date(r.startsAt);
|
||||
exdate.setMilliseconds(exdate.getMilliseconds() - localTimeDiff);
|
||||
|
|
@ -244,14 +244,14 @@ function refresh() {
|
|||
|
||||
refresh();
|
||||
|
||||
const headerActions = $computed(() => [{
|
||||
const headerActions = computed(() => [{
|
||||
asFullButton: true,
|
||||
icon: 'ti ti-plus',
|
||||
text: i18n.ts.add,
|
||||
handler: add,
|
||||
}]);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.ads,
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from 'vue';
|
||||
import { ref, shallowRef, watch, computed } from 'vue';
|
||||
import * as misskey from 'misskey-js';
|
||||
import XHeader from './_header_.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
|
|
@ -110,12 +110,12 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
|
|||
import MkFolder from '@/components/MkFolder.vue';
|
||||
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||
|
||||
const announceTitleEl = $shallowRef<HTMLInputElement | null>(null);
|
||||
const announceTitleEl = shallowRef<HTMLInputElement | null>(null);
|
||||
const user = ref<misskey.entities.UserLite | null>(null);
|
||||
const offset = ref(0);
|
||||
const hasMore = ref(false);
|
||||
|
||||
let announcements: any[] = $ref([]);
|
||||
const announcements = ref<any[]>([]);
|
||||
|
||||
function selectUserFilter(): void {
|
||||
os.selectUser().then(_user => {
|
||||
|
|
@ -131,11 +131,11 @@ function editUser(announcement): void {
|
|||
}
|
||||
|
||||
function insertEmoji(ev: MouseEvent): void {
|
||||
os.openEmojiPicker((ev.currentTarget ?? ev.target) as HTMLElement, {}, announceTitleEl);
|
||||
os.openEmojiPicker((ev.currentTarget ?? ev.target) as HTMLElement, {}, announceTitleEl.value);
|
||||
}
|
||||
|
||||
function add() {
|
||||
announcements.unshift({
|
||||
announcements.value.unshift({
|
||||
_id: Math.random().toString(36),
|
||||
id: null,
|
||||
title: 'New announcement',
|
||||
|
|
@ -157,7 +157,7 @@ function del(announcement) {
|
|||
text: i18n.t('deleteAreYouSure', { x: announcement.title }),
|
||||
}).then(({ canceled }) => {
|
||||
if (canceled) return;
|
||||
announcements = announcements.filter(x => x !== announcement);
|
||||
announcements.value = announcements.value.filter(x => x !== announcement);
|
||||
os.api('admin/announcements/delete', announcement);
|
||||
});
|
||||
}
|
||||
|
|
@ -181,7 +181,7 @@ async function save(announcement): Promise<void> {
|
|||
|
||||
function fetch(resetOffset = false): void {
|
||||
if (resetOffset) {
|
||||
announcements = [];
|
||||
announcements.value = [];
|
||||
offset.value = 0;
|
||||
}
|
||||
|
||||
|
|
@ -191,7 +191,7 @@ function fetch(resetOffset = false): void {
|
|||
limit: 10,
|
||||
userId: user.value?.id,
|
||||
}).then(announcementResponse => {
|
||||
announcements = announcements.concat(announcementResponse);
|
||||
announcements.value = announcements.value.concat(announcementResponse);
|
||||
hasMore.value = announcementResponse?.length === 10;
|
||||
offset.value += announcementResponse?.length ?? 0;
|
||||
});
|
||||
|
|
@ -200,14 +200,14 @@ function fetch(resetOffset = false): void {
|
|||
watch(user, () => fetch(true));
|
||||
fetch(true);
|
||||
|
||||
const headerActions = $computed(() => [{
|
||||
const headerActions = computed(() => [{
|
||||
asFullButton: true,
|
||||
icon: 'ti ti-plus',
|
||||
text: i18n.ts.add,
|
||||
handler: add,
|
||||
}]);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.announcements,
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
import { defineAsyncComponent, ref } from 'vue';
|
||||
import MkRadios from '@/components/MkRadios.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
|
|
@ -76,37 +76,37 @@ import { i18n } from '@/i18n.js';
|
|||
|
||||
const MkCaptcha = defineAsyncComponent(() => import('@/components/MkCaptcha.vue'));
|
||||
|
||||
let provider = $ref(null);
|
||||
let hcaptchaSiteKey: string | null = $ref(null);
|
||||
let hcaptchaSecretKey: string | null = $ref(null);
|
||||
let recaptchaSiteKey: string | null = $ref(null);
|
||||
let recaptchaSecretKey: string | null = $ref(null);
|
||||
let turnstileSiteKey: string | null = $ref(null);
|
||||
let turnstileSecretKey: string | null = $ref(null);
|
||||
const provider = ref(null);
|
||||
const hcaptchaSiteKey = ref<string | null>(null);
|
||||
const hcaptchaSecretKey = ref<string | null>(null);
|
||||
const recaptchaSiteKey = ref<string | null>(null);
|
||||
const recaptchaSecretKey = ref<string | null>(null);
|
||||
const turnstileSiteKey = ref<string | null>(null);
|
||||
const turnstileSecretKey = ref<string | null>(null);
|
||||
|
||||
async function init() {
|
||||
const meta = await os.api('admin/meta');
|
||||
hcaptchaSiteKey = meta.hcaptchaSiteKey;
|
||||
hcaptchaSecretKey = meta.hcaptchaSecretKey;
|
||||
recaptchaSiteKey = meta.recaptchaSiteKey;
|
||||
recaptchaSecretKey = meta.recaptchaSecretKey;
|
||||
turnstileSiteKey = meta.turnstileSiteKey;
|
||||
turnstileSecretKey = meta.turnstileSecretKey;
|
||||
hcaptchaSiteKey.value = meta.hcaptchaSiteKey;
|
||||
hcaptchaSecretKey.value = meta.hcaptchaSecretKey;
|
||||
recaptchaSiteKey.value = meta.recaptchaSiteKey;
|
||||
recaptchaSecretKey.value = meta.recaptchaSecretKey;
|
||||
turnstileSiteKey.value = meta.turnstileSiteKey;
|
||||
turnstileSecretKey.value = meta.turnstileSecretKey;
|
||||
|
||||
provider = meta.enableHcaptcha ? 'hcaptcha' : meta.enableRecaptcha ? 'recaptcha' : meta.enableTurnstile ? 'turnstile' : null;
|
||||
provider.value = meta.enableHcaptcha ? 'hcaptcha' : meta.enableRecaptcha ? 'recaptcha' : meta.enableTurnstile ? 'turnstile' : null;
|
||||
}
|
||||
|
||||
function save() {
|
||||
os.apiWithDialog('admin/update-meta', {
|
||||
enableHcaptcha: provider === 'hcaptcha',
|
||||
hcaptchaSiteKey,
|
||||
hcaptchaSecretKey,
|
||||
enableRecaptcha: provider === 'recaptcha',
|
||||
recaptchaSiteKey,
|
||||
recaptchaSecretKey,
|
||||
enableTurnstile: provider === 'turnstile',
|
||||
turnstileSiteKey,
|
||||
turnstileSecretKey,
|
||||
enableHcaptcha: provider.value === 'hcaptcha',
|
||||
hcaptchaSiteKey: hcaptchaSiteKey.value,
|
||||
hcaptchaSecretKey: hcaptchaSecretKey.value,
|
||||
enableRecaptcha: provider.value === 'recaptcha',
|
||||
recaptchaSiteKey: recaptchaSiteKey.value,
|
||||
recaptchaSecretKey: recaptchaSecretKey.value,
|
||||
enableTurnstile: provider.value === 'turnstile',
|
||||
turnstileSiteKey: turnstileSiteKey.value,
|
||||
turnstileSecretKey: turnstileSecretKey.value,
|
||||
}).then(() => {
|
||||
fetchInstance();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { } from 'vue';
|
||||
import { ref, computed } from 'vue';
|
||||
import JSON5 from 'json5';
|
||||
import XHeader from './_header_.vue';
|
||||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
|
|
@ -111,55 +111,55 @@ import MkButton from '@/components/MkButton.vue';
|
|||
import MkColorInput from '@/components/MkColorInput.vue';
|
||||
import { host } from '@/config.js';
|
||||
|
||||
let iconUrl: string | null = $ref(null);
|
||||
let app192IconUrl: string | null = $ref(null);
|
||||
let app512IconUrl: string | null = $ref(null);
|
||||
let bannerUrl: string | null = $ref(null);
|
||||
let backgroundImageUrl: string | null = $ref(null);
|
||||
let themeColor: any = $ref(null);
|
||||
let defaultLightTheme: any = $ref(null);
|
||||
let defaultDarkTheme: any = $ref(null);
|
||||
let serverErrorImageUrl: string | null = $ref(null);
|
||||
let infoImageUrl: string | null = $ref(null);
|
||||
let notFoundImageUrl: string | null = $ref(null);
|
||||
let manifestJsonOverride: string = $ref('{}');
|
||||
const iconUrl = ref<string | null>(null);
|
||||
const app192IconUrl = ref<string | null>(null);
|
||||
const app512IconUrl = ref<string | null>(null);
|
||||
const bannerUrl = ref<string | null>(null);
|
||||
const backgroundImageUrl = ref<string | null>(null);
|
||||
const themeColor = ref<any>(null);
|
||||
const defaultLightTheme = ref<any>(null);
|
||||
const defaultDarkTheme = ref<any>(null);
|
||||
const serverErrorImageUrl = ref<string | null>(null);
|
||||
const infoImageUrl = ref<string | null>(null);
|
||||
const notFoundImageUrl = ref<string | null>(null);
|
||||
const manifestJsonOverride = ref<string>('{}');
|
||||
|
||||
async function init() {
|
||||
const meta = await os.api('admin/meta');
|
||||
iconUrl = meta.iconUrl;
|
||||
app192IconUrl = meta.app192IconUrl;
|
||||
app512IconUrl = meta.app512IconUrl;
|
||||
bannerUrl = meta.bannerUrl;
|
||||
backgroundImageUrl = meta.backgroundImageUrl;
|
||||
themeColor = meta.themeColor;
|
||||
defaultLightTheme = meta.defaultLightTheme;
|
||||
defaultDarkTheme = meta.defaultDarkTheme;
|
||||
serverErrorImageUrl = meta.serverErrorImageUrl;
|
||||
infoImageUrl = meta.infoImageUrl;
|
||||
notFoundImageUrl = meta.notFoundImageUrl;
|
||||
manifestJsonOverride = meta.manifestJsonOverride === '' ? '{}' : JSON.stringify(JSON.parse(meta.manifestJsonOverride), null, '\t');
|
||||
iconUrl.value = meta.iconUrl;
|
||||
app192IconUrl.value = meta.app192IconUrl;
|
||||
app512IconUrl.value = meta.app512IconUrl;
|
||||
bannerUrl.value = meta.bannerUrl;
|
||||
backgroundImageUrl.value = meta.backgroundImageUrl;
|
||||
themeColor.value = meta.themeColor;
|
||||
defaultLightTheme.value = meta.defaultLightTheme;
|
||||
defaultDarkTheme.value = meta.defaultDarkTheme;
|
||||
serverErrorImageUrl.value = meta.serverErrorImageUrl;
|
||||
infoImageUrl.value = meta.infoImageUrl;
|
||||
notFoundImageUrl.value = meta.notFoundImageUrl;
|
||||
manifestJsonOverride.value = meta.manifestJsonOverride === '' ? '{}' : JSON.stringify(JSON.parse(meta.manifestJsonOverride), null, '\t');
|
||||
}
|
||||
|
||||
function save() {
|
||||
os.apiWithDialog('admin/update-meta', {
|
||||
iconUrl,
|
||||
app192IconUrl,
|
||||
app512IconUrl,
|
||||
bannerUrl,
|
||||
backgroundImageUrl,
|
||||
themeColor: themeColor === '' ? null : themeColor,
|
||||
defaultLightTheme: defaultLightTheme === '' ? null : defaultLightTheme,
|
||||
defaultDarkTheme: defaultDarkTheme === '' ? null : defaultDarkTheme,
|
||||
infoImageUrl,
|
||||
notFoundImageUrl,
|
||||
serverErrorImageUrl,
|
||||
manifestJsonOverride: manifestJsonOverride === '' ? '{}' : JSON.stringify(JSON5.parse(manifestJsonOverride)),
|
||||
iconUrl: iconUrl.value,
|
||||
app192IconUrl: app192IconUrl.value,
|
||||
app512IconUrl: app512IconUrl.value,
|
||||
bannerUrl: bannerUrl.value,
|
||||
backgroundImageUrl: backgroundImageUrl.value,
|
||||
themeColor: themeColor.value === '' ? null : themeColor.value,
|
||||
defaultLightTheme: defaultLightTheme.value === '' ? null : defaultLightTheme.value,
|
||||
defaultDarkTheme: defaultDarkTheme.value === '' ? null : defaultDarkTheme.value,
|
||||
infoImageUrl: infoImageUrl.value,
|
||||
notFoundImageUrl: notFoundImageUrl.value,
|
||||
serverErrorImageUrl: serverErrorImageUrl.value,
|
||||
manifestJsonOverride: manifestJsonOverride.value === '' ? '{}' : JSON.stringify(JSON5.parse(manifestJsonOverride.value)),
|
||||
}).then(() => {
|
||||
fetchInstance();
|
||||
});
|
||||
}
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.branding,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
import FormSuspense from '@/components/form/suspense.vue';
|
||||
import MkKeyValue from '@/components/MkKeyValue.vue';
|
||||
import * as os from '@/os.js';
|
||||
|
|
@ -29,9 +29,9 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
|
|||
|
||||
const databasePromiseFactory = () => os.api('admin/get-table-stats').then(res => Object.entries(res).sort((a, b) => b[1].size - a[1].size));
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.database,
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { } from 'vue';
|
||||
import { ref, computed } from 'vue';
|
||||
import XHeader from './_header_.vue';
|
||||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
|
|
@ -78,23 +78,23 @@ import { i18n } from '@/i18n.js';
|
|||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
|
||||
let enableEmail: boolean = $ref(false);
|
||||
let email: any = $ref(null);
|
||||
let smtpSecure: boolean = $ref(false);
|
||||
let smtpHost: string = $ref('');
|
||||
let smtpPort: number = $ref(0);
|
||||
let smtpUser: string = $ref('');
|
||||
let smtpPass: string = $ref('');
|
||||
const enableEmail = ref<boolean>(false);
|
||||
const email = ref<any>(null);
|
||||
const smtpSecure = ref<boolean>(false);
|
||||
const smtpHost = ref<string>('');
|
||||
const smtpPort = ref<number>(0);
|
||||
const smtpUser = ref<string>('');
|
||||
const smtpPass = ref<string>('');
|
||||
|
||||
async function init() {
|
||||
const meta = await os.api('admin/meta');
|
||||
enableEmail = meta.enableEmail;
|
||||
email = meta.email;
|
||||
smtpSecure = meta.smtpSecure;
|
||||
smtpHost = meta.smtpHost;
|
||||
smtpPort = meta.smtpPort;
|
||||
smtpUser = meta.smtpUser;
|
||||
smtpPass = meta.smtpPass;
|
||||
enableEmail.value = meta.enableEmail;
|
||||
email.value = meta.email;
|
||||
smtpSecure.value = meta.smtpSecure;
|
||||
smtpHost.value = meta.smtpHost;
|
||||
smtpPort.value = meta.smtpPort;
|
||||
smtpUser.value = meta.smtpUser;
|
||||
smtpPass.value = meta.smtpPass;
|
||||
}
|
||||
|
||||
async function testEmail() {
|
||||
|
|
@ -115,19 +115,19 @@ async function testEmail() {
|
|||
|
||||
function save() {
|
||||
os.apiWithDialog('admin/update-meta', {
|
||||
enableEmail,
|
||||
email,
|
||||
smtpSecure,
|
||||
smtpHost,
|
||||
smtpPort,
|
||||
smtpUser,
|
||||
smtpPass,
|
||||
enableEmail: enableEmail.value,
|
||||
email: email.value,
|
||||
smtpSecure: smtpSecure.value,
|
||||
smtpHost: smtpHost.value,
|
||||
smtpPort: smtpPort.value,
|
||||
smtpUser: smtpUser.value,
|
||||
smtpPass: smtpPass.value,
|
||||
}).then(() => {
|
||||
fetchInstance();
|
||||
});
|
||||
}
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.emailServer,
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { } from 'vue';
|
||||
import { ref, computed } from 'vue';
|
||||
import XHeader from './_header_.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
|
|
@ -46,27 +46,27 @@ import { fetchInstance } from '@/instance.js';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
|
||||
let deeplAuthKey: string = $ref('');
|
||||
let deeplIsPro: boolean = $ref(false);
|
||||
const deeplAuthKey = ref<string>('');
|
||||
const deeplIsPro = ref<boolean>(false);
|
||||
|
||||
async function init() {
|
||||
const meta = await os.api('admin/meta');
|
||||
deeplAuthKey = meta.deeplAuthKey;
|
||||
deeplIsPro = meta.deeplIsPro;
|
||||
deeplAuthKey.value = meta.deeplAuthKey;
|
||||
deeplIsPro.value = meta.deeplIsPro;
|
||||
}
|
||||
|
||||
function save() {
|
||||
os.apiWithDialog('admin/update-meta', {
|
||||
deeplAuthKey,
|
||||
deeplIsPro,
|
||||
deeplAuthKey: deeplAuthKey.value,
|
||||
deeplIsPro: deeplIsPro.value,
|
||||
}).then(() => {
|
||||
fetchInstance();
|
||||
});
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.externalServices,
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import XHeader from './_header_.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkSelect from '@/components/MkSelect.vue';
|
||||
|
|
@ -68,24 +68,24 @@ import FormSplit from '@/components/form/split.vue';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
|
||||
let host = $ref('');
|
||||
let state = $ref('federating');
|
||||
let sort = $ref('+pubSub');
|
||||
const host = ref('');
|
||||
const state = ref('federating');
|
||||
const sort = ref('+pubSub');
|
||||
const pagination = {
|
||||
endpoint: 'federation/instances' as const,
|
||||
limit: 10,
|
||||
offsetMode: true,
|
||||
params: computed(() => ({
|
||||
sort: sort,
|
||||
host: host !== '' ? host : null,
|
||||
sort: sort.value,
|
||||
host: host.value !== '' ? host.value : null,
|
||||
...(
|
||||
state === 'federating' ? { federating: true } :
|
||||
state === 'subscribing' ? { subscribing: true } :
|
||||
state === 'publishing' ? { publishing: true } :
|
||||
state === 'suspended' ? { suspended: true } :
|
||||
state === 'blocked' ? { blocked: true } :
|
||||
state === 'silenced' ? { silenced: true } :
|
||||
state === 'notResponding' ? { notResponding: true } :
|
||||
state.value === 'federating' ? { federating: true } :
|
||||
state.value === 'subscribing' ? { subscribing: true } :
|
||||
state.value === 'publishing' ? { publishing: true } :
|
||||
state.value === 'suspended' ? { suspended: true } :
|
||||
state.value === 'blocked' ? { blocked: true } :
|
||||
state.value === 'silenced' ? { silenced: true } :
|
||||
state.value === 'notResponding' ? { notResponding: true } :
|
||||
{}),
|
||||
})),
|
||||
};
|
||||
|
|
@ -98,9 +98,9 @@ function getStatus(instance) {
|
|||
return 'Alive';
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata(computed(() => ({
|
||||
title: i18n.ts.federation,
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import XHeader from './_header_.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkSelect from '@/components/MkSelect.vue';
|
||||
|
|
@ -45,19 +45,19 @@ import * as os from '@/os.js';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
|
||||
let origin = $ref('local');
|
||||
let type = $ref(null);
|
||||
let searchHost = $ref('');
|
||||
let userId = $ref('');
|
||||
let viewMode = $ref('grid');
|
||||
const origin = ref('local');
|
||||
const type = ref(null);
|
||||
const searchHost = ref('');
|
||||
const userId = ref('');
|
||||
const viewMode = ref('grid');
|
||||
const pagination = {
|
||||
endpoint: 'admin/drive/files' as const,
|
||||
limit: 10,
|
||||
params: computed(() => ({
|
||||
type: (type && type !== '') ? type : null,
|
||||
userId: (userId && userId !== '') ? userId : null,
|
||||
origin: origin,
|
||||
hostname: (searchHost && searchHost !== '') ? searchHost : null,
|
||||
type: (type.value && type.value !== '') ? type.value : null,
|
||||
userId: (userId.value && userId.value !== '') ? userId.value : null,
|
||||
origin: origin.value,
|
||||
hostname: (searchHost.value && searchHost.value !== '') ? searchHost.value : null,
|
||||
})),
|
||||
};
|
||||
|
||||
|
|
@ -95,7 +95,7 @@ async function find() {
|
|||
});
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => [{
|
||||
const headerActions = computed(() => [{
|
||||
text: i18n.ts.lookup,
|
||||
icon: 'ti ti-search',
|
||||
handler: find,
|
||||
|
|
@ -105,7 +105,7 @@ const headerActions = $computed(() => [{
|
|||
handler: clear,
|
||||
}]);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata(computed(() => ({
|
||||
title: i18n.ts.files,
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onActivated, onMounted, onUnmounted, provide, watch } from 'vue';
|
||||
import { onActivated, onMounted, onUnmounted, provide, watch, ref, computed } from 'vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import MkSuperMenu from '@/components/MkSuperMenu.vue';
|
||||
import MkInfo from '@/components/MkInfo.vue';
|
||||
|
|
@ -50,32 +50,32 @@ const indexInfo = {
|
|||
|
||||
provide('shouldOmitHeaderTitle', false);
|
||||
|
||||
let INFO = $ref(indexInfo);
|
||||
let childInfo = $ref(null);
|
||||
let narrow = $ref(false);
|
||||
let view = $ref(null);
|
||||
let el = $ref(null);
|
||||
let pageProps = $ref({});
|
||||
const INFO = ref(indexInfo);
|
||||
const childInfo = ref(null);
|
||||
const narrow = ref(false);
|
||||
const view = ref(null);
|
||||
const el = ref(null);
|
||||
const pageProps = ref({});
|
||||
let noMaintainerInformation = isEmpty(instance.maintainerName) || isEmpty(instance.maintainerEmail);
|
||||
let noBotProtection = !instance.disableRegistration && !instance.enableHcaptcha && !instance.enableRecaptcha && !instance.enableTurnstile;
|
||||
let noEmailServer = !instance.enableEmail;
|
||||
let thereIsUnresolvedAbuseReport = $ref(false);
|
||||
let currentPage = $computed(() => router.currentRef.value.child);
|
||||
const thereIsUnresolvedAbuseReport = ref(false);
|
||||
const currentPage = computed(() => router.currentRef.value.child);
|
||||
|
||||
os.api('admin/abuse-user-reports', {
|
||||
state: 'unresolved',
|
||||
limit: 1,
|
||||
}).then(reports => {
|
||||
if (reports.length > 0) thereIsUnresolvedAbuseReport = true;
|
||||
if (reports.length > 0) thereIsUnresolvedAbuseReport.value = true;
|
||||
});
|
||||
|
||||
const NARROW_THRESHOLD = 600;
|
||||
const ro = new ResizeObserver((entries, observer) => {
|
||||
if (entries.length === 0) return;
|
||||
narrow = entries[0].borderBoxSize[0].inlineSize < NARROW_THRESHOLD;
|
||||
narrow.value = entries[0].borderBoxSize[0].inlineSize < NARROW_THRESHOLD;
|
||||
});
|
||||
|
||||
const menuDef = $computed(() => [{
|
||||
const menuDef = computed(() => [{
|
||||
title: i18n.ts.quickAction,
|
||||
items: [{
|
||||
type: 'button',
|
||||
|
|
@ -94,67 +94,67 @@ const menuDef = $computed(() => [{
|
|||
icon: 'ti ti-dashboard',
|
||||
text: i18n.ts.dashboard,
|
||||
to: '/admin/overview',
|
||||
active: currentPage?.route.name === 'overview',
|
||||
active: currentPage.value?.route.name === 'overview',
|
||||
}, {
|
||||
icon: 'ti ti-users',
|
||||
text: i18n.ts.users,
|
||||
to: '/admin/users',
|
||||
active: currentPage?.route.name === 'users',
|
||||
active: currentPage.value?.route.name === 'users',
|
||||
}, {
|
||||
icon: 'ti ti-user-plus',
|
||||
text: i18n.ts.invite,
|
||||
to: '/admin/invites',
|
||||
active: currentPage?.route.name === 'invites',
|
||||
active: currentPage.value?.route.name === 'invites',
|
||||
}, {
|
||||
icon: 'ti ti-badges',
|
||||
text: i18n.ts.roles,
|
||||
to: '/admin/roles',
|
||||
active: currentPage?.route.name === 'roles',
|
||||
active: currentPage.value?.route.name === 'roles',
|
||||
}, {
|
||||
icon: 'ti ti-icons',
|
||||
text: i18n.ts.customEmojis,
|
||||
to: '/admin/emojis',
|
||||
active: currentPage?.route.name === 'emojis',
|
||||
active: currentPage.value?.route.name === 'emojis',
|
||||
}, {
|
||||
icon: 'ti ti-sparkles',
|
||||
text: i18n.ts.avatarDecorations,
|
||||
to: '/admin/avatar-decorations',
|
||||
active: currentPage?.route.name === 'avatarDecorations',
|
||||
active: currentPage.value?.route.name === 'avatarDecorations',
|
||||
}, {
|
||||
icon: 'ti ti-whirl',
|
||||
text: i18n.ts.federation,
|
||||
to: '/admin/federation',
|
||||
active: currentPage?.route.name === 'federation',
|
||||
active: currentPage.value?.route.name === 'federation',
|
||||
}, {
|
||||
icon: 'ti ti-clock-play',
|
||||
text: i18n.ts.jobQueue,
|
||||
to: '/admin/queue',
|
||||
active: currentPage?.route.name === 'queue',
|
||||
active: currentPage.value?.route.name === 'queue',
|
||||
}, {
|
||||
icon: 'ti ti-cloud',
|
||||
text: i18n.ts.files,
|
||||
to: '/admin/files',
|
||||
active: currentPage?.route.name === 'files',
|
||||
active: currentPage.value?.route.name === 'files',
|
||||
}, {
|
||||
icon: 'ti ti-speakerphone',
|
||||
text: i18n.ts.announcements,
|
||||
to: '/admin/announcements',
|
||||
active: currentPage?.route.name === 'announcements',
|
||||
active: currentPage.value?.route.name === 'announcements',
|
||||
}, {
|
||||
icon: 'ti ti-ad',
|
||||
text: i18n.ts.ads,
|
||||
to: '/admin/ads',
|
||||
active: currentPage?.route.name === 'ads',
|
||||
active: currentPage.value?.route.name === 'ads',
|
||||
}, {
|
||||
icon: 'ti ti-exclamation-circle',
|
||||
text: i18n.ts.abuseReports,
|
||||
to: '/admin/abuses',
|
||||
active: currentPage?.route.name === 'abuses',
|
||||
active: currentPage.value?.route.name === 'abuses',
|
||||
}, {
|
||||
icon: 'ti ti-list-search',
|
||||
text: i18n.ts.moderationLogs,
|
||||
to: '/admin/modlog',
|
||||
active: currentPage?.route.name === 'modlog',
|
||||
active: currentPage.value?.route.name === 'modlog',
|
||||
}],
|
||||
}, {
|
||||
title: i18n.ts.settings,
|
||||
|
|
@ -162,57 +162,57 @@ const menuDef = $computed(() => [{
|
|||
icon: 'ti ti-settings',
|
||||
text: i18n.ts.general,
|
||||
to: '/admin/settings',
|
||||
active: currentPage?.route.name === 'settings',
|
||||
active: currentPage.value?.route.name === 'settings',
|
||||
}, {
|
||||
icon: 'ti ti-paint',
|
||||
text: i18n.ts.branding,
|
||||
to: '/admin/branding',
|
||||
active: currentPage?.route.name === 'branding',
|
||||
active: currentPage.value?.route.name === 'branding',
|
||||
}, {
|
||||
icon: 'ti ti-shield',
|
||||
text: i18n.ts.moderation,
|
||||
to: '/admin/moderation',
|
||||
active: currentPage?.route.name === 'moderation',
|
||||
active: currentPage.value?.route.name === 'moderation',
|
||||
}, {
|
||||
icon: 'ti ti-mail',
|
||||
text: i18n.ts.emailServer,
|
||||
to: '/admin/email-settings',
|
||||
active: currentPage?.route.name === 'email-settings',
|
||||
active: currentPage.value?.route.name === 'email-settings',
|
||||
}, {
|
||||
icon: 'ti ti-cloud',
|
||||
text: i18n.ts.objectStorage,
|
||||
to: '/admin/object-storage',
|
||||
active: currentPage?.route.name === 'object-storage',
|
||||
active: currentPage.value?.route.name === 'object-storage',
|
||||
}, {
|
||||
icon: 'ti ti-lock',
|
||||
text: i18n.ts.security,
|
||||
to: '/admin/security',
|
||||
active: currentPage?.route.name === 'security',
|
||||
active: currentPage.value?.route.name === 'security',
|
||||
}, {
|
||||
icon: 'ti ti-planet',
|
||||
text: i18n.ts.relays,
|
||||
to: '/admin/relays',
|
||||
active: currentPage?.route.name === 'relays',
|
||||
active: currentPage.value?.route.name === 'relays',
|
||||
}, {
|
||||
icon: 'ti ti-ban',
|
||||
text: i18n.ts.instanceBlocking,
|
||||
to: '/admin/instance-block',
|
||||
active: currentPage?.route.name === 'instance-block',
|
||||
active: currentPage.value?.route.name === 'instance-block',
|
||||
}, {
|
||||
icon: 'ti ti-ghost',
|
||||
text: i18n.ts.proxyAccount,
|
||||
to: '/admin/proxy-account',
|
||||
active: currentPage?.route.name === 'proxy-account',
|
||||
active: currentPage.value?.route.name === 'proxy-account',
|
||||
}, {
|
||||
icon: 'ti ti-link',
|
||||
text: i18n.ts.externalServices,
|
||||
to: '/admin/external-services',
|
||||
active: currentPage?.route.name === 'external-services',
|
||||
active: currentPage.value?.route.name === 'external-services',
|
||||
}, {
|
||||
icon: 'ti ti-adjustments',
|
||||
text: i18n.ts.other,
|
||||
to: '/admin/other-settings',
|
||||
active: currentPage?.route.name === 'other-settings',
|
||||
active: currentPage.value?.route.name === 'other-settings',
|
||||
}],
|
||||
}, {
|
||||
title: i18n.ts.info,
|
||||
|
|
@ -220,28 +220,28 @@ const menuDef = $computed(() => [{
|
|||
icon: 'ti ti-database',
|
||||
text: i18n.ts.database,
|
||||
to: '/admin/database',
|
||||
active: currentPage?.route.name === 'database',
|
||||
active: currentPage.value?.route.name === 'database',
|
||||
}],
|
||||
}]);
|
||||
|
||||
watch(narrow, () => {
|
||||
if (currentPage?.route.name == null && !narrow) {
|
||||
watch(narrow.value, () => {
|
||||
if (currentPage.value?.route.name == null && !narrow.value) {
|
||||
router.push('/admin/overview');
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
ro.observe(el);
|
||||
ro.observe(el.value);
|
||||
|
||||
narrow = el.offsetWidth < NARROW_THRESHOLD;
|
||||
if (currentPage?.route.name == null && !narrow) {
|
||||
narrow.value = el.value.offsetWidth < NARROW_THRESHOLD;
|
||||
if (currentPage.value?.route.name == null && !narrow.value) {
|
||||
router.push('/admin/overview');
|
||||
}
|
||||
});
|
||||
|
||||
onActivated(() => {
|
||||
narrow = el.offsetWidth < NARROW_THRESHOLD;
|
||||
if (currentPage?.route.name == null && !narrow) {
|
||||
narrow.value = el.value.offsetWidth < NARROW_THRESHOLD;
|
||||
if (currentPage.value?.route.name == null && !narrow.value) {
|
||||
router.push('/admin/overview');
|
||||
}
|
||||
});
|
||||
|
|
@ -251,16 +251,17 @@ onUnmounted(() => {
|
|||
});
|
||||
|
||||
watch(router.currentRef, (to) => {
|
||||
if (to.route.path === '/admin' && to.child?.route.name == null && !narrow) {
|
||||
if (to.route.path === '/admin' && to.child?.route.name == null && !narrow.value) {
|
||||
router.replace('/admin/overview');
|
||||
}
|
||||
});
|
||||
|
||||
provideMetadataReceiver((info) => {
|
||||
if (info == null) {
|
||||
childInfo = null;
|
||||
childInfo.value = null;
|
||||
} else {
|
||||
childInfo = info;
|
||||
childInfo.value = info;
|
||||
INFO.value.needWideArea = info.value.needWideArea ?? undefined;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -268,7 +269,7 @@ function invite() {
|
|||
os.api('admin/invite/create').then(x => {
|
||||
os.alert({
|
||||
type: 'info',
|
||||
text: x?.[0].code,
|
||||
text: x[0].code,
|
||||
});
|
||||
}).catch(err => {
|
||||
os.alert({
|
||||
|
|
@ -312,11 +313,11 @@ function lookup(ev: MouseEvent) {
|
|||
}], ev.currentTarget ?? ev.target);
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata(INFO);
|
||||
definePageMetadata(INFO.value);
|
||||
|
||||
defineExpose({
|
||||
header: {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import XHeader from './_header_.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkTextarea from '@/components/MkTextarea.vue';
|
||||
|
|
@ -32,29 +33,29 @@ import { fetchInstance } from '@/instance.js';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
|
||||
let blockedHosts: string = $ref('');
|
||||
let silencedHosts: string = $ref('');
|
||||
let tab = $ref('block');
|
||||
const blockedHosts = ref<string>('');
|
||||
const silencedHosts = ref<string>('');
|
||||
const tab = ref('block');
|
||||
|
||||
async function init() {
|
||||
const meta = await os.api('admin/meta');
|
||||
blockedHosts = meta.blockedHosts.join('\n');
|
||||
silencedHosts = meta.silencedHosts.join('\n');
|
||||
blockedHosts.value = meta.blockedHosts.join('\n');
|
||||
silencedHosts.value = meta.silencedHosts.join('\n');
|
||||
}
|
||||
|
||||
function save() {
|
||||
os.apiWithDialog('admin/update-meta', {
|
||||
blockedHosts: blockedHosts.split('\n') || [],
|
||||
silencedHosts: silencedHosts.split('\n') || [],
|
||||
blockedHosts: blockedHosts.value.split('\n') || [],
|
||||
silencedHosts: silencedHosts.value.split('\n') || [],
|
||||
|
||||
}).then(() => {
|
||||
fetchInstance();
|
||||
});
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => [{
|
||||
const headerTabs = computed(() => [{
|
||||
key: 'block',
|
||||
title: i18n.ts.block,
|
||||
icon: 'ti ti-ban',
|
||||
|
|
|
|||
|
|
@ -70,8 +70,8 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
|
|||
|
||||
const pagingComponent = shallowRef<InstanceType<typeof MkPagination>>();
|
||||
|
||||
let type = ref('all');
|
||||
let sort = ref('+createdAt');
|
||||
const type = ref('all');
|
||||
const sort = ref('+createdAt');
|
||||
|
||||
const pagination: Paging = {
|
||||
endpoint: 'admin/invite/list' as const,
|
||||
|
|
@ -109,8 +109,8 @@ function deleted(id: string) {
|
|||
}
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.invite,
|
||||
|
|
|
|||
|
|
@ -44,6 +44,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<template #label>{{ i18n.ts.urlPreviewDenyList }}</template>
|
||||
<template #caption>{{ i18n.ts.urlPreviewDenyListDescription }}</template>
|
||||
</MkTextarea>
|
||||
|
||||
<MkTextarea v-model="hiddenTags">
|
||||
<template #label>{{ i18n.ts.hiddenTags }}</template>
|
||||
<template #caption>{{ i18n.ts.hiddenTagsDescription }}</template>
|
||||
</MkTextarea>
|
||||
</div>
|
||||
</FormSuspense>
|
||||
</MkSpacer>
|
||||
|
|
@ -59,7 +64,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { } from 'vue';
|
||||
import { ref, computed } from 'vue';
|
||||
import XHeader from './_header_.vue';
|
||||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
|
|
@ -74,40 +79,43 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
|
|||
import MkButton from '@/components/MkButton.vue';
|
||||
import FormLink from '@/components/form/link.vue';
|
||||
|
||||
let enableRegistration: boolean = $ref(false);
|
||||
let emailRequiredForSignup: boolean = $ref(false);
|
||||
let sensitiveWords: string = $ref('');
|
||||
let preservedUsernames: string = $ref('');
|
||||
let tosUrl: string | null = $ref(null);
|
||||
let privacyPolicyUrl: string | null = $ref(null);
|
||||
let urlPreviewDenyList: string = $ref('');
|
||||
const enableRegistration = ref<boolean>(false);
|
||||
const emailRequiredForSignup = ref<boolean>(false);
|
||||
const sensitiveWords = ref<string>('');
|
||||
const hiddenTags = ref<string>('');
|
||||
const preservedUsernames = ref<string>('');
|
||||
const tosUrl = ref<string | null>(null);
|
||||
const privacyPolicyUrl = ref<string | null>(null);
|
||||
const urlPreviewDenyList = ref<string | undefined>('');
|
||||
|
||||
async function init() {
|
||||
const meta = await os.api('admin/meta');
|
||||
enableRegistration = !meta.disableRegistration;
|
||||
emailRequiredForSignup = meta.emailRequiredForSignup;
|
||||
sensitiveWords = meta.sensitiveWords.join('\n');
|
||||
preservedUsernames = meta.preservedUsernames.join('\n');
|
||||
tosUrl = meta.tosUrl;
|
||||
privacyPolicyUrl = meta.privacyPolicyUrl;
|
||||
urlPreviewDenyList = meta.urlPreviewDenyList.join('\n');
|
||||
enableRegistration.value = !meta.disableRegistration;
|
||||
emailRequiredForSignup.value = meta.emailRequiredForSignup;
|
||||
sensitiveWords.value = meta.sensitiveWords.join('\n');
|
||||
hiddenTags.value = meta.hiddenTags.join('\n');
|
||||
preservedUsernames.value = meta.preservedUsernames.join('\n');
|
||||
tosUrl.value = meta.tosUrl;
|
||||
privacyPolicyUrl.value = meta.privacyPolicyUrl;
|
||||
urlPreviewDenyList.value = meta.urlPreviewDenyList?.join('\n');
|
||||
}
|
||||
|
||||
function save() {
|
||||
os.apiWithDialog('admin/update-meta', {
|
||||
disableRegistration: !enableRegistration,
|
||||
emailRequiredForSignup,
|
||||
tosUrl,
|
||||
privacyPolicyUrl,
|
||||
sensitiveWords: sensitiveWords.split('\n'),
|
||||
preservedUsernames: preservedUsernames.split('\n'),
|
||||
urlPreviewDenyList: urlPreviewDenyList.split('\n'),
|
||||
disableRegistration: !enableRegistration.value,
|
||||
emailRequiredForSignup: emailRequiredForSignup.value,
|
||||
tosUrl: tosUrl.value,
|
||||
privacyPolicyUrl: privacyPolicyUrl.value,
|
||||
sensitiveWords: sensitiveWords.value.split('\n'),
|
||||
hiddenTags: hiddenTags.value.split('\n'),
|
||||
preservedUsernames: preservedUsernames.value.split('\n'),
|
||||
urlPreviewDenyList: urlPreviewDenyList.value?.split('\n'),
|
||||
}).then(() => {
|
||||
fetchInstance();
|
||||
});
|
||||
}
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.moderation,
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { computed, shallowRef, ref } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import XHeader from './_header_.vue';
|
||||
import XModLog from './modlog.ModLog.vue';
|
||||
|
|
@ -40,25 +40,25 @@ import MkPagination from '@/components/MkPagination.vue';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
|
||||
let logs = $shallowRef<InstanceType<typeof MkPagination>>();
|
||||
const logs = shallowRef<InstanceType<typeof MkPagination>>();
|
||||
|
||||
let type = $ref(null);
|
||||
let moderatorId = $ref('');
|
||||
const type = ref(null);
|
||||
const moderatorId = ref('');
|
||||
|
||||
const pagination = {
|
||||
endpoint: 'admin/show-moderation-logs' as const,
|
||||
limit: 30,
|
||||
params: computed(() => ({
|
||||
type,
|
||||
userId: moderatorId === '' ? null : moderatorId,
|
||||
type: type.value,
|
||||
userId: moderatorId.value === '' ? null : moderatorId.value,
|
||||
})),
|
||||
};
|
||||
|
||||
console.log(Misskey);
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.moderationLogs,
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { } from 'vue';
|
||||
import { ref, computed } from 'vue';
|
||||
import XHeader from './_header_.vue';
|
||||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
|
|
@ -95,58 +95,58 @@ import { i18n } from '@/i18n.js';
|
|||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
|
||||
let useObjectStorage: boolean = $ref(false);
|
||||
let objectStorageBaseUrl: string | null = $ref(null);
|
||||
let objectStorageBucket: string | null = $ref(null);
|
||||
let objectStoragePrefix: string | null = $ref(null);
|
||||
let objectStorageEndpoint: string | null = $ref(null);
|
||||
let objectStorageRegion: string | null = $ref(null);
|
||||
let objectStoragePort: number | null = $ref(null);
|
||||
let objectStorageAccessKey: string | null = $ref(null);
|
||||
let objectStorageSecretKey: string | null = $ref(null);
|
||||
let objectStorageUseSSL: boolean = $ref(false);
|
||||
let objectStorageUseProxy: boolean = $ref(false);
|
||||
let objectStorageSetPublicRead: boolean = $ref(false);
|
||||
let objectStorageS3ForcePathStyle: boolean = $ref(true);
|
||||
const useObjectStorage = ref<boolean>(false);
|
||||
const objectStorageBaseUrl = ref<string | null>(null);
|
||||
const objectStorageBucket = ref<string | null>(null);
|
||||
const objectStoragePrefix = ref<string | null>(null);
|
||||
const objectStorageEndpoint = ref<string | null>(null);
|
||||
const objectStorageRegion = ref<string | null>(null);
|
||||
const objectStoragePort = ref<number | null>(null);
|
||||
const objectStorageAccessKey = ref<string | null>(null);
|
||||
const objectStorageSecretKey = ref<string | null>(null);
|
||||
const objectStorageUseSSL = ref<boolean>(false);
|
||||
const objectStorageUseProxy = ref<boolean>(false);
|
||||
const objectStorageSetPublicRead = ref<boolean>(false);
|
||||
const objectStorageS3ForcePathStyle = ref<boolean>(true);
|
||||
|
||||
async function init() {
|
||||
const meta = await os.api('admin/meta');
|
||||
useObjectStorage = meta.useObjectStorage;
|
||||
objectStorageBaseUrl = meta.objectStorageBaseUrl;
|
||||
objectStorageBucket = meta.objectStorageBucket;
|
||||
objectStoragePrefix = meta.objectStoragePrefix;
|
||||
objectStorageEndpoint = meta.objectStorageEndpoint;
|
||||
objectStorageRegion = meta.objectStorageRegion;
|
||||
objectStoragePort = meta.objectStoragePort;
|
||||
objectStorageAccessKey = meta.objectStorageAccessKey;
|
||||
objectStorageSecretKey = meta.objectStorageSecretKey;
|
||||
objectStorageUseSSL = meta.objectStorageUseSSL;
|
||||
objectStorageUseProxy = meta.objectStorageUseProxy;
|
||||
objectStorageSetPublicRead = meta.objectStorageSetPublicRead;
|
||||
objectStorageS3ForcePathStyle = meta.objectStorageS3ForcePathStyle;
|
||||
useObjectStorage.value = meta.useObjectStorage;
|
||||
objectStorageBaseUrl.value = meta.objectStorageBaseUrl;
|
||||
objectStorageBucket.value = meta.objectStorageBucket;
|
||||
objectStoragePrefix.value = meta.objectStoragePrefix;
|
||||
objectStorageEndpoint.value = meta.objectStorageEndpoint;
|
||||
objectStorageRegion.value = meta.objectStorageRegion;
|
||||
objectStoragePort.value = meta.objectStoragePort;
|
||||
objectStorageAccessKey.value = meta.objectStorageAccessKey;
|
||||
objectStorageSecretKey.value = meta.objectStorageSecretKey;
|
||||
objectStorageUseSSL.value = meta.objectStorageUseSSL;
|
||||
objectStorageUseProxy.value = meta.objectStorageUseProxy;
|
||||
objectStorageSetPublicRead.value = meta.objectStorageSetPublicRead;
|
||||
objectStorageS3ForcePathStyle.value = meta.objectStorageS3ForcePathStyle;
|
||||
}
|
||||
|
||||
function save() {
|
||||
os.apiWithDialog('admin/update-meta', {
|
||||
useObjectStorage,
|
||||
objectStorageBaseUrl,
|
||||
objectStorageBucket,
|
||||
objectStoragePrefix,
|
||||
objectStorageEndpoint,
|
||||
objectStorageRegion,
|
||||
objectStoragePort,
|
||||
objectStorageAccessKey,
|
||||
objectStorageSecretKey,
|
||||
objectStorageUseSSL,
|
||||
objectStorageUseProxy,
|
||||
objectStorageSetPublicRead,
|
||||
objectStorageS3ForcePathStyle,
|
||||
useObjectStorage: useObjectStorage.value,
|
||||
objectStorageBaseUrl: objectStorageBaseUrl.value,
|
||||
objectStorageBucket: objectStorageBucket.value,
|
||||
objectStoragePrefix: objectStoragePrefix.value,
|
||||
objectStorageEndpoint: objectStorageEndpoint.value,
|
||||
objectStorageRegion: objectStorageRegion.value,
|
||||
objectStoragePort: objectStoragePort.value,
|
||||
objectStorageAccessKey: objectStorageAccessKey.value,
|
||||
objectStorageSecretKey: objectStorageSecretKey.value,
|
||||
objectStorageUseSSL: objectStorageUseSSL.value,
|
||||
objectStorageUseProxy: objectStorageUseProxy.value,
|
||||
objectStorageSetPublicRead: objectStorageSetPublicRead.value,
|
||||
objectStorageS3ForcePathStyle: objectStorageS3ForcePathStyle.value,
|
||||
}).then(() => {
|
||||
fetchInstance();
|
||||
});
|
||||
}
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.objectStorage,
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { } from 'vue';
|
||||
import { ref, computed } from 'vue';
|
||||
import XHeader from './_header_.vue';
|
||||
import FormSuspense from '@/components/form/suspense.vue';
|
||||
import * as os from '@/os.js';
|
||||
|
|
@ -52,38 +52,38 @@ import { i18n } from '@/i18n.js';
|
|||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
|
||||
let enableServerMachineStats: boolean = $ref(false);
|
||||
let enableIdenticonGeneration: boolean = $ref(false);
|
||||
let enableChartsForRemoteUser: boolean = $ref(false);
|
||||
let enableChartsForFederatedInstances: boolean = $ref(false);
|
||||
const enableServerMachineStats = ref<boolean>(false);
|
||||
const enableIdenticonGeneration = ref<boolean>(false);
|
||||
const enableChartsForRemoteUser = ref<boolean>(false);
|
||||
const enableChartsForFederatedInstances = ref<boolean>(false);
|
||||
|
||||
async function init() {
|
||||
const meta = await os.api('admin/meta');
|
||||
enableServerMachineStats = meta.enableServerMachineStats;
|
||||
enableIdenticonGeneration = meta.enableIdenticonGeneration;
|
||||
enableChartsForRemoteUser = meta.enableChartsForRemoteUser;
|
||||
enableChartsForFederatedInstances = meta.enableChartsForFederatedInstances;
|
||||
enableServerMachineStats.value = meta.enableServerMachineStats;
|
||||
enableIdenticonGeneration.value = meta.enableIdenticonGeneration;
|
||||
enableChartsForRemoteUser.value = meta.enableChartsForRemoteUser;
|
||||
enableChartsForFederatedInstances.value = meta.enableChartsForFederatedInstances;
|
||||
}
|
||||
|
||||
function save() {
|
||||
os.apiWithDialog('admin/update-meta', {
|
||||
enableServerMachineStats,
|
||||
enableIdenticonGeneration,
|
||||
enableChartsForRemoteUser,
|
||||
enableChartsForFederatedInstances,
|
||||
enableServerMachineStats: enableServerMachineStats.value,
|
||||
enableIdenticonGeneration: enableIdenticonGeneration.value,
|
||||
enableChartsForRemoteUser: enableChartsForRemoteUser.value,
|
||||
enableChartsForFederatedInstances: enableChartsForFederatedInstances.value,
|
||||
}).then(() => {
|
||||
fetchInstance();
|
||||
});
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => [{
|
||||
const headerActions = computed(() => [{
|
||||
asFullButton: true,
|
||||
icon: 'ti ti-check',
|
||||
text: i18n.ts.save,
|
||||
handler: save,
|
||||
}]);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.other,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted } from 'vue';
|
||||
import { onMounted, shallowRef, ref } from 'vue';
|
||||
import { Chart } from 'chart.js';
|
||||
import gradient from 'chartjs-plugin-gradient';
|
||||
import * as os from '@/os.js';
|
||||
|
|
@ -24,11 +24,11 @@ import { initChart } from '@/scripts/init-chart.js';
|
|||
|
||||
initChart();
|
||||
|
||||
const chartEl = $shallowRef<HTMLCanvasElement>(null);
|
||||
const chartEl = shallowRef<HTMLCanvasElement>(null);
|
||||
const now = new Date();
|
||||
let chartInstance: Chart = null;
|
||||
const chartLimit = 7;
|
||||
let fetching = $ref(true);
|
||||
const fetching = ref(true);
|
||||
|
||||
const { handler: externalTooltipHandler } = useChartTooltip();
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ async function renderChart() {
|
|||
|
||||
const max = Math.max(...raw.read);
|
||||
|
||||
chartInstance = new Chart(chartEl, {
|
||||
chartInstance = new Chart(chartEl.value, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
datasets: [{
|
||||
|
|
@ -155,7 +155,7 @@ async function renderChart() {
|
|||
plugins: [chartVLine(vLineColor)],
|
||||
});
|
||||
|
||||
fetching = false;
|
||||
fetching.value = false;
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted } from 'vue';
|
||||
import { onMounted, shallowRef, ref } from 'vue';
|
||||
import { Chart } from 'chart.js';
|
||||
import gradient from 'chartjs-plugin-gradient';
|
||||
import * as os from '@/os.js';
|
||||
|
|
@ -33,9 +33,9 @@ import { initChart } from '@/scripts/init-chart.js';
|
|||
initChart();
|
||||
|
||||
const chartLimit = 50;
|
||||
const chartEl = $shallowRef<HTMLCanvasElement>();
|
||||
const chartEl2 = $shallowRef<HTMLCanvasElement>();
|
||||
let fetching = $ref(true);
|
||||
const chartEl = shallowRef<HTMLCanvasElement>();
|
||||
const chartEl2 = shallowRef<HTMLCanvasElement>();
|
||||
const fetching = ref(true);
|
||||
|
||||
const { handler: externalTooltipHandler } = useChartTooltip();
|
||||
const { handler: externalTooltipHandler2 } = useChartTooltip();
|
||||
|
|
@ -74,7 +74,7 @@ onMounted(async () => {
|
|||
const succMax = Math.max(...raw.deliverSucceeded);
|
||||
const failMax = Math.max(...raw.deliverFailed);
|
||||
|
||||
new Chart(chartEl, {
|
||||
new Chart(chartEl.value, {
|
||||
type: 'line',
|
||||
data: {
|
||||
datasets: [{
|
||||
|
|
@ -178,7 +178,7 @@ onMounted(async () => {
|
|||
plugins: [chartVLine(vLineColor)],
|
||||
});
|
||||
|
||||
new Chart(chartEl2, {
|
||||
new Chart(chartEl2.value, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
datasets: [{
|
||||
|
|
@ -265,7 +265,7 @@ onMounted(async () => {
|
|||
plugins: [chartVLine(vLineColor)],
|
||||
});
|
||||
|
||||
fetching = false;
|
||||
fetching.value = false;
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted } from 'vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import XPie from './overview.pie.vue';
|
||||
import * as os from '@/os.js';
|
||||
import number from '@/filters/number.js';
|
||||
|
|
@ -54,25 +54,25 @@ import MkNumberDiff from '@/components/MkNumberDiff.vue';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
|
||||
|
||||
let topSubInstancesForPie: any = $ref(null);
|
||||
let topPubInstancesForPie: any = $ref(null);
|
||||
let federationPubActive = $ref<number | null>(null);
|
||||
let federationPubActiveDiff = $ref<number | null>(null);
|
||||
let federationSubActive = $ref<number | null>(null);
|
||||
let federationSubActiveDiff = $ref<number | null>(null);
|
||||
let fetching = $ref(true);
|
||||
const topSubInstancesForPie = ref<any>(null);
|
||||
const topPubInstancesForPie = ref<any>(null);
|
||||
const federationPubActive = ref<number | null>(null);
|
||||
const federationPubActiveDiff = ref<number | null>(null);
|
||||
const federationSubActive = ref<number | null>(null);
|
||||
const federationSubActiveDiff = ref<number | null>(null);
|
||||
const fetching = ref(true);
|
||||
|
||||
const { handler: externalTooltipHandler } = useChartTooltip();
|
||||
|
||||
onMounted(async () => {
|
||||
const chart = await os.apiGet('charts/federation', { limit: 2, span: 'day' });
|
||||
federationPubActive = chart.pubActive[0];
|
||||
federationPubActiveDiff = chart.pubActive[0] - chart.pubActive[1];
|
||||
federationSubActive = chart.subActive[0];
|
||||
federationSubActiveDiff = chart.subActive[0] - chart.subActive[1];
|
||||
federationPubActive.value = chart.pubActive[0];
|
||||
federationPubActiveDiff.value = chart.pubActive[0] - chart.pubActive[1];
|
||||
federationSubActive.value = chart.subActive[0];
|
||||
federationSubActiveDiff.value = chart.subActive[0] - chart.subActive[1];
|
||||
|
||||
os.apiGet('federation/stats', { limit: 10 }).then(res => {
|
||||
topSubInstancesForPie = res.topSubInstances.map(x => ({
|
||||
topSubInstancesForPie.value = res.topSubInstances.map(x => ({
|
||||
name: x.host,
|
||||
color: x.themeColor,
|
||||
value: x.followersCount,
|
||||
|
|
@ -80,7 +80,7 @@ onMounted(async () => {
|
|||
os.pageWindow(`/instance-info/${x.host}`);
|
||||
},
|
||||
})).concat([{ name: '(other)', color: '#80808080', value: res.otherFollowersCount }]);
|
||||
topPubInstancesForPie = res.topPubInstances.map(x => ({
|
||||
topPubInstancesForPie.value = res.topPubInstances.map(x => ({
|
||||
name: x.host,
|
||||
color: x.themeColor,
|
||||
value: x.followingCount,
|
||||
|
|
@ -90,7 +90,7 @@ onMounted(async () => {
|
|||
})).concat([{ name: '(other)', color: '#80808080', value: res.otherFollowingCount }]);
|
||||
});
|
||||
|
||||
fetching = false;
|
||||
fetching.value = false;
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -17,10 +17,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import MkHeatmap from '@/components/MkHeatmap.vue';
|
||||
import MkSelect from '@/components/MkSelect.vue';
|
||||
|
||||
let src = $ref('active-users');
|
||||
const src = ref('active-users');
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
|
|
|
|||
|
|
@ -17,21 +17,21 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted } from 'vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import * as os from '@/os.js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
|
||||
let moderators: any = $ref(null);
|
||||
let fetching = $ref(true);
|
||||
const moderators = ref<any>(null);
|
||||
const fetching = ref(true);
|
||||
|
||||
onMounted(async () => {
|
||||
moderators = await os.api('admin/show-users', {
|
||||
moderators.value = await os.api('admin/show-users', {
|
||||
sort: '+lastActiveDate',
|
||||
state: 'adminOrModerator',
|
||||
limit: 30,
|
||||
});
|
||||
|
||||
fetching = false;
|
||||
fetching.value = false;
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { markRaw, onMounted, onUnmounted, ref } from 'vue';
|
||||
import { markRaw, onMounted, onUnmounted, ref, shallowRef } from 'vue';
|
||||
import XChart from './overview.queue.chart.vue';
|
||||
import number from '@/filters/number.js';
|
||||
import { useStream } from '@/stream.js';
|
||||
|
|
@ -46,10 +46,10 @@ const activeSincePrevTick = ref(0);
|
|||
const active = ref(0);
|
||||
const delayed = ref(0);
|
||||
const waiting = ref(0);
|
||||
let chartProcess = $shallowRef<InstanceType<typeof XChart>>();
|
||||
let chartActive = $shallowRef<InstanceType<typeof XChart>>();
|
||||
let chartDelayed = $shallowRef<InstanceType<typeof XChart>>();
|
||||
let chartWaiting = $shallowRef<InstanceType<typeof XChart>>();
|
||||
const chartProcess = shallowRef<InstanceType<typeof XChart>>();
|
||||
const chartActive = shallowRef<InstanceType<typeof XChart>>();
|
||||
const chartDelayed = shallowRef<InstanceType<typeof XChart>>();
|
||||
const chartWaiting = shallowRef<InstanceType<typeof XChart>>();
|
||||
|
||||
const props = defineProps<{
|
||||
domain: string;
|
||||
|
|
@ -61,10 +61,10 @@ const onStats = (stats) => {
|
|||
delayed.value = stats[props.domain].delayed;
|
||||
waiting.value = stats[props.domain].waiting;
|
||||
|
||||
chartProcess.pushData(stats[props.domain].activeSincePrevTick);
|
||||
chartActive.pushData(stats[props.domain].active);
|
||||
chartDelayed.pushData(stats[props.domain].delayed);
|
||||
chartWaiting.pushData(stats[props.domain].waiting);
|
||||
chartProcess.value.pushData(stats[props.domain].activeSincePrevTick);
|
||||
chartActive.value.pushData(stats[props.domain].active);
|
||||
chartDelayed.value.pushData(stats[props.domain].delayed);
|
||||
chartWaiting.value.pushData(stats[props.domain].waiting);
|
||||
};
|
||||
|
||||
const onStatsLog = (statsLog) => {
|
||||
|
|
@ -80,10 +80,10 @@ const onStatsLog = (statsLog) => {
|
|||
dataWaiting.push(stats[props.domain].waiting);
|
||||
}
|
||||
|
||||
chartProcess.setData(dataProcess);
|
||||
chartActive.setData(dataActive);
|
||||
chartDelayed.setData(dataDelayed);
|
||||
chartWaiting.setData(dataWaiting);
|
||||
chartProcess.value.setData(dataProcess);
|
||||
chartActive.value.setData(dataActive);
|
||||
chartDelayed.value.setData(dataDelayed);
|
||||
chartWaiting.value.setData(dataWaiting);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted } from 'vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import * as os from '@/os.js';
|
||||
import MkNumberDiff from '@/components/MkNumberDiff.vue';
|
||||
import MkNumber from '@/components/MkNumber.vue';
|
||||
|
|
@ -69,29 +69,29 @@ import { i18n } from '@/i18n.js';
|
|||
import { customEmojis } from '@/custom-emojis.js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
|
||||
let stats: any = $ref(null);
|
||||
let usersComparedToThePrevDay = $ref<number>();
|
||||
let notesComparedToThePrevDay = $ref<number>();
|
||||
let onlineUsersCount = $ref(0);
|
||||
let fetching = $ref(true);
|
||||
const stats = ref<any>(null);
|
||||
const usersComparedToThePrevDay = ref<number>();
|
||||
const notesComparedToThePrevDay = ref<number>();
|
||||
const onlineUsersCount = ref(0);
|
||||
const fetching = ref(true);
|
||||
|
||||
onMounted(async () => {
|
||||
const [_stats, _onlineUsersCount] = await Promise.all([
|
||||
os.api('stats', {}),
|
||||
os.apiGet('get-online-users-count').then(res => res.count),
|
||||
]);
|
||||
stats = _stats;
|
||||
onlineUsersCount = _onlineUsersCount;
|
||||
stats.value = _stats;
|
||||
onlineUsersCount.value = _onlineUsersCount;
|
||||
|
||||
os.apiGet('charts/users', { limit: 2, span: 'day' }).then(chart => {
|
||||
usersComparedToThePrevDay = stats.originalUsersCount - chart.local.total[1];
|
||||
usersComparedToThePrevDay.value = stats.value.originalUsersCount - chart.local.total[1];
|
||||
});
|
||||
|
||||
os.apiGet('charts/notes', { limit: 2, span: 'day' }).then(chart => {
|
||||
notesComparedToThePrevDay = stats.originalNotesCount - chart.local.total[1];
|
||||
notesComparedToThePrevDay.value = stats.value.originalNotesCount - chart.local.total[1];
|
||||
});
|
||||
|
||||
fetching = false;
|
||||
fetching.value = false;
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -17,13 +17,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import * as os from '@/os.js';
|
||||
import { useInterval } from '@/scripts/use-interval.js';
|
||||
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||
import { defaultStore } from '@/store.js';
|
||||
|
||||
let newUsers = $ref(null);
|
||||
let fetching = $ref(true);
|
||||
const newUsers = ref(null);
|
||||
const fetching = ref(true);
|
||||
|
||||
const fetch = async () => {
|
||||
const _newUsers = await os.api('admin/show-users', {
|
||||
|
|
@ -31,8 +32,8 @@ const fetch = async () => {
|
|||
sort: '+createdAt',
|
||||
origin: 'local',
|
||||
});
|
||||
newUsers = _newUsers;
|
||||
fetching = false;
|
||||
newUsers.value = _newUsers;
|
||||
fetching.value = false;
|
||||
};
|
||||
|
||||
useInterval(fetch, 1000 * 60, {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { markRaw, onMounted, onBeforeUnmount, nextTick } from 'vue';
|
||||
import { markRaw, onMounted, onBeforeUnmount, nextTick, shallowRef, ref, computed } from 'vue';
|
||||
import XFederation from './overview.federation.vue';
|
||||
import XInstances from './overview.instances.vue';
|
||||
import XQueue from './overview.queue.vue';
|
||||
|
|
@ -82,16 +82,16 @@ import { i18n } from '@/i18n.js';
|
|||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
||||
|
||||
const rootEl = $shallowRef<HTMLElement>();
|
||||
let serverInfo: any = $ref(null);
|
||||
let topSubInstancesForPie: any = $ref(null);
|
||||
let topPubInstancesForPie: any = $ref(null);
|
||||
let federationPubActive = $ref<number | null>(null);
|
||||
let federationPubActiveDiff = $ref<number | null>(null);
|
||||
let federationSubActive = $ref<number | null>(null);
|
||||
let federationSubActiveDiff = $ref<number | null>(null);
|
||||
let newUsers = $ref(null);
|
||||
let activeInstances = $shallowRef(null);
|
||||
const rootEl = shallowRef<HTMLElement>();
|
||||
const serverInfo = ref<any>(null);
|
||||
const topSubInstancesForPie = ref<any>(null);
|
||||
const topPubInstancesForPie = ref<any>(null);
|
||||
const federationPubActive = ref<number | null>(null);
|
||||
const federationPubActiveDiff = ref<number | null>(null);
|
||||
const federationSubActive = ref<number | null>(null);
|
||||
const federationSubActiveDiff = ref<number | null>(null);
|
||||
const newUsers = ref(null);
|
||||
const activeInstances = shallowRef(null);
|
||||
const queueStatsConnection = markRaw(useStream().useChannel('queueStats'));
|
||||
const now = new Date();
|
||||
const filesPagination = {
|
||||
|
|
@ -116,14 +116,14 @@ onMounted(async () => {
|
|||
*/
|
||||
|
||||
os.apiGet('charts/federation', { limit: 2, span: 'day' }).then(chart => {
|
||||
federationPubActive = chart.pubActive[0];
|
||||
federationPubActiveDiff = chart.pubActive[0] - chart.pubActive[1];
|
||||
federationSubActive = chart.subActive[0];
|
||||
federationSubActiveDiff = chart.subActive[0] - chart.subActive[1];
|
||||
federationPubActive.value = chart.pubActive[0];
|
||||
federationPubActiveDiff.value = chart.pubActive[0] - chart.pubActive[1];
|
||||
federationSubActive.value = chart.subActive[0];
|
||||
federationSubActiveDiff.value = chart.subActive[0] - chart.subActive[1];
|
||||
});
|
||||
|
||||
os.apiGet('federation/stats', { limit: 10 }).then(res => {
|
||||
topSubInstancesForPie = res.topSubInstances.map(x => ({
|
||||
topSubInstancesForPie.value = res.topSubInstances.map(x => ({
|
||||
name: x.host,
|
||||
color: x.themeColor,
|
||||
value: x.followersCount,
|
||||
|
|
@ -131,7 +131,7 @@ onMounted(async () => {
|
|||
os.pageWindow(`/instance-info/${x.host}`);
|
||||
},
|
||||
})).concat([{ name: '(other)', color: '#80808080', value: res.otherFollowersCount }]);
|
||||
topPubInstancesForPie = res.topPubInstances.map(x => ({
|
||||
topPubInstancesForPie.value = res.topPubInstances.map(x => ({
|
||||
name: x.host,
|
||||
color: x.themeColor,
|
||||
value: x.followingCount,
|
||||
|
|
@ -142,21 +142,21 @@ onMounted(async () => {
|
|||
});
|
||||
|
||||
os.api('admin/server-info').then(serverInfoResponse => {
|
||||
serverInfo = serverInfoResponse;
|
||||
serverInfo.value = serverInfoResponse;
|
||||
});
|
||||
|
||||
os.api('admin/show-users', {
|
||||
limit: 5,
|
||||
sort: '+createdAt',
|
||||
}).then(res => {
|
||||
newUsers = res;
|
||||
newUsers.value = res;
|
||||
});
|
||||
|
||||
os.api('federation/instances', {
|
||||
sort: '+latestRequestReceivedAt',
|
||||
limit: 25,
|
||||
}).then(res => {
|
||||
activeInstances = res;
|
||||
activeInstances.value = res;
|
||||
});
|
||||
|
||||
nextTick(() => {
|
||||
|
|
@ -171,9 +171,9 @@ onBeforeUnmount(() => {
|
|||
queueStatsConnection.dispose();
|
||||
});
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.dashboard,
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { } from 'vue';
|
||||
import { ref, computed } from 'vue';
|
||||
import MkKeyValue from '@/components/MkKeyValue.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkInfo from '@/components/MkInfo.vue';
|
||||
|
|
@ -31,36 +31,36 @@ import { fetchInstance } from '@/instance.js';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
|
||||
let proxyAccount: any = $ref(null);
|
||||
let proxyAccountId: any = $ref(null);
|
||||
const proxyAccount = ref<any>(null);
|
||||
const proxyAccountId = ref<any>(null);
|
||||
|
||||
async function init() {
|
||||
const meta = await os.api('admin/meta');
|
||||
proxyAccountId = meta.proxyAccountId;
|
||||
if (proxyAccountId) {
|
||||
proxyAccount = await os.api('users/show', { userId: proxyAccountId });
|
||||
proxyAccountId.value = meta.proxyAccountId;
|
||||
if (proxyAccountId.value) {
|
||||
proxyAccount.value = await os.api('users/show', { userId: proxyAccountId.value });
|
||||
}
|
||||
}
|
||||
|
||||
function chooseProxyAccount() {
|
||||
os.selectUser().then(user => {
|
||||
proxyAccount = user;
|
||||
proxyAccountId = user.id;
|
||||
proxyAccount.value = user;
|
||||
proxyAccountId.value = user.id;
|
||||
save();
|
||||
});
|
||||
}
|
||||
|
||||
function save() {
|
||||
os.apiWithDialog('admin/update-meta', {
|
||||
proxyAccountId: proxyAccountId,
|
||||
proxyAccountId: proxyAccountId.value,
|
||||
}).then(() => {
|
||||
fetchInstance();
|
||||
});
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.proxyAccount,
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { markRaw, onMounted, onUnmounted, ref } from 'vue';
|
||||
import { markRaw, onMounted, onUnmounted, ref, shallowRef } from 'vue';
|
||||
import XChart from './queue.chart.chart.vue';
|
||||
import number from '@/filters/number.js';
|
||||
import * as os from '@/os.js';
|
||||
|
|
@ -63,10 +63,10 @@ const active = ref(0);
|
|||
const delayed = ref(0);
|
||||
const waiting = ref(0);
|
||||
const jobs = ref([]);
|
||||
let chartProcess = $shallowRef<InstanceType<typeof XChart>>();
|
||||
let chartActive = $shallowRef<InstanceType<typeof XChart>>();
|
||||
let chartDelayed = $shallowRef<InstanceType<typeof XChart>>();
|
||||
let chartWaiting = $shallowRef<InstanceType<typeof XChart>>();
|
||||
const chartProcess = shallowRef<InstanceType<typeof XChart>>();
|
||||
const chartActive = shallowRef<InstanceType<typeof XChart>>();
|
||||
const chartDelayed = shallowRef<InstanceType<typeof XChart>>();
|
||||
const chartWaiting = shallowRef<InstanceType<typeof XChart>>();
|
||||
|
||||
const props = defineProps<{
|
||||
domain: string;
|
||||
|
|
@ -78,10 +78,10 @@ const onStats = (stats) => {
|
|||
delayed.value = stats[props.domain].delayed;
|
||||
waiting.value = stats[props.domain].waiting;
|
||||
|
||||
chartProcess.pushData(stats[props.domain].activeSincePrevTick);
|
||||
chartActive.pushData(stats[props.domain].active);
|
||||
chartDelayed.pushData(stats[props.domain].delayed);
|
||||
chartWaiting.pushData(stats[props.domain].waiting);
|
||||
chartProcess.value.pushData(stats[props.domain].activeSincePrevTick);
|
||||
chartActive.value.pushData(stats[props.domain].active);
|
||||
chartDelayed.value.pushData(stats[props.domain].delayed);
|
||||
chartWaiting.value.pushData(stats[props.domain].waiting);
|
||||
};
|
||||
|
||||
const onStatsLog = (statsLog) => {
|
||||
|
|
@ -97,10 +97,10 @@ const onStatsLog = (statsLog) => {
|
|||
dataWaiting.push(stats[props.domain].waiting);
|
||||
}
|
||||
|
||||
chartProcess.setData(dataProcess);
|
||||
chartActive.setData(dataActive);
|
||||
chartDelayed.setData(dataDelayed);
|
||||
chartWaiting.setData(dataWaiting);
|
||||
chartProcess.value.setData(dataProcess);
|
||||
chartActive.value.setData(dataActive);
|
||||
chartDelayed.value.setData(dataDelayed);
|
||||
chartWaiting.value.setData(dataWaiting);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import XQueue from './queue.chart.vue';
|
||||
import XHeader from './_header_.vue';
|
||||
import * as os from '@/os.js';
|
||||
|
|
@ -24,7 +25,7 @@ import { i18n } from '@/i18n.js';
|
|||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
|
||||
let tab = $ref('deliver');
|
||||
const tab = ref('deliver');
|
||||
|
||||
function clear() {
|
||||
os.confirm({
|
||||
|
|
@ -46,11 +47,11 @@ function promoteAllQueues() {
|
|||
}).then(({ canceled }) => {
|
||||
if (canceled) return;
|
||||
|
||||
os.apiWithDialog('admin/queue/promote', { type: tab });
|
||||
os.apiWithDialog('admin/queue/promote', { type: tab.value });
|
||||
});
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => [{
|
||||
const headerActions = computed(() => [{
|
||||
asFullButton: true,
|
||||
icon: 'ti ti-external-link',
|
||||
text: i18n.ts.dashboard,
|
||||
|
|
@ -59,7 +60,7 @@ const headerActions = $computed(() => [{
|
|||
},
|
||||
}]);
|
||||
|
||||
const headerTabs = $computed(() => [{
|
||||
const headerTabs = computed(() => [{
|
||||
key: 'deliver',
|
||||
title: 'Deliver',
|
||||
}, {
|
||||
|
|
|
|||
|
|
@ -24,14 +24,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { } from 'vue';
|
||||
import { ref, computed } from 'vue';
|
||||
import XHeader from './_header_.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
|
||||
let relays: any[] = $ref([]);
|
||||
const relays = ref<any[]>([]);
|
||||
|
||||
async function addRelay() {
|
||||
const { canceled, result: inbox } = await os.inputText({
|
||||
|
|
@ -67,20 +67,20 @@ function remove(inbox: string) {
|
|||
|
||||
function refresh() {
|
||||
os.api('admin/relays/list').then((relayList: any) => {
|
||||
relays = relayList;
|
||||
relays.value = relayList;
|
||||
});
|
||||
}
|
||||
|
||||
refresh();
|
||||
|
||||
const headerActions = $computed(() => [{
|
||||
const headerActions = computed(() => [{
|
||||
asFullButton: true,
|
||||
icon: 'ti ti-plus',
|
||||
text: i18n.ts.addRelay,
|
||||
handler: addRelay,
|
||||
}]);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.relays,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import XHeader from './_header_.vue';
|
||||
import XEditor from './roles.editor.vue';
|
||||
|
|
@ -39,17 +39,17 @@ const props = defineProps<{
|
|||
id?: string;
|
||||
}>();
|
||||
|
||||
let role = $ref(null);
|
||||
let data = $ref(null);
|
||||
const role = ref(null);
|
||||
const data = ref(null);
|
||||
|
||||
if (props.id) {
|
||||
role = await os.api('admin/roles/show', {
|
||||
role.value = await os.api('admin/roles/show', {
|
||||
roleId: props.id,
|
||||
});
|
||||
|
||||
data = role;
|
||||
data.value = role.value;
|
||||
} else {
|
||||
data = {
|
||||
data.value = {
|
||||
name: 'New Role',
|
||||
description: '',
|
||||
isAdministrator: false,
|
||||
|
|
@ -69,24 +69,24 @@ if (props.id) {
|
|||
|
||||
async function save() {
|
||||
rolesCache.delete();
|
||||
if (role) {
|
||||
if (role.value) {
|
||||
os.apiWithDialog('admin/roles/update', {
|
||||
roleId: role.id,
|
||||
...data,
|
||||
roleId: role.value.id,
|
||||
...data.value,
|
||||
});
|
||||
router.push('/admin/roles/' + role.id);
|
||||
router.push('/admin/roles/' + role.value.id);
|
||||
} else {
|
||||
const created = await os.apiWithDialog('admin/roles/create', {
|
||||
...data,
|
||||
...data.value,
|
||||
});
|
||||
router.push('/admin/roles/' + created.id);
|
||||
}
|
||||
}
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata(computed(() => role ? {
|
||||
title: i18n.ts._role.edit + ': ' + role.name,
|
||||
definePageMetadata(computed(() => role.value ? {
|
||||
title: i18n.ts._role.edit + ': ' + role.value.name,
|
||||
icon: 'ti ti-badge',
|
||||
} : {
|
||||
title: i18n.ts._role.new,
|
||||
|
|
|
|||
|
|
@ -597,7 +597,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { watch } from 'vue';
|
||||
import { watch, ref, computed } from 'vue';
|
||||
import { throttle } from 'throttle-debounce';
|
||||
import RolesEditorFormula from './RolesEditorFormula.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
|
|
@ -622,12 +622,12 @@ const props = defineProps<{
|
|||
readonly?: boolean;
|
||||
}>();
|
||||
|
||||
let role = $ref(deepClone(props.modelValue));
|
||||
const role = ref(deepClone(props.modelValue));
|
||||
|
||||
// fill missing policy
|
||||
for (const ROLE_POLICY of ROLE_POLICIES) {
|
||||
if (role.policies[ROLE_POLICY] == null) {
|
||||
role.policies[ROLE_POLICY] = {
|
||||
if (role.value.policies[ROLE_POLICY] == null) {
|
||||
role.value.policies[ROLE_POLICY] = {
|
||||
useDefault: true,
|
||||
priority: 0,
|
||||
value: instance.policies[ROLE_POLICY],
|
||||
|
|
@ -635,15 +635,15 @@ for (const ROLE_POLICY of ROLE_POLICIES) {
|
|||
}
|
||||
}
|
||||
|
||||
let rolePermission = $computed({
|
||||
get: () => role.isAdministrator ? 'administrator' : role.isModerator ? 'moderator' : 'normal',
|
||||
const rolePermission = computed({
|
||||
get: () => role.value.isAdministrator ? 'administrator' : role.value.isModerator ? 'moderator' : 'normal',
|
||||
set: (val) => {
|
||||
role.isAdministrator = val === 'administrator';
|
||||
role.isModerator = val === 'moderator';
|
||||
role.value.isAdministrator = val === 'administrator';
|
||||
role.value.isModerator = val === 'moderator';
|
||||
},
|
||||
});
|
||||
|
||||
let q = $ref('');
|
||||
const q = ref('');
|
||||
|
||||
function getPriorityIcon(option) {
|
||||
if (option.priority === 2) return 'ti ti-arrows-up';
|
||||
|
|
@ -652,32 +652,32 @@ function getPriorityIcon(option) {
|
|||
}
|
||||
|
||||
function matchQuery(keywords: string[]): boolean {
|
||||
if (q.trim().length === 0) return true;
|
||||
return keywords.some(keyword => keyword.toLowerCase().includes(q.toLowerCase()));
|
||||
if (q.value.trim().length === 0) return true;
|
||||
return keywords.some(keyword => keyword.toLowerCase().includes(q.value.toLowerCase()));
|
||||
}
|
||||
|
||||
const save = throttle(100, () => {
|
||||
const data = {
|
||||
name: role.name,
|
||||
description: role.description,
|
||||
color: role.color === '' ? null : role.color,
|
||||
iconUrl: role.iconUrl === '' ? null : role.iconUrl,
|
||||
displayOrder: role.displayOrder,
|
||||
target: role.target,
|
||||
condFormula: role.condFormula,
|
||||
isAdministrator: role.isAdministrator,
|
||||
isModerator: role.isModerator,
|
||||
isPublic: role.isPublic,
|
||||
isExplorable: role.isExplorable,
|
||||
asBadge: role.asBadge,
|
||||
canEditMembersByModerator: role.canEditMembersByModerator,
|
||||
policies: role.policies,
|
||||
name: role.value.name,
|
||||
description: role.value.description,
|
||||
color: role.value.color === '' ? null : role.value.color,
|
||||
iconUrl: role.value.iconUrl === '' ? null : role.value.iconUrl,
|
||||
displayOrder: role.value.displayOrder,
|
||||
target: role.value.target,
|
||||
condFormula: role.value.condFormula,
|
||||
isAdministrator: role.value.isAdministrator,
|
||||
isModerator: role.value.isModerator,
|
||||
isPublic: role.value.isPublic,
|
||||
isExplorable: role.value.isExplorable,
|
||||
asBadge: role.value.asBadge,
|
||||
canEditMembersByModerator: role.value.canEditMembersByModerator,
|
||||
policies: role.value.policies,
|
||||
};
|
||||
|
||||
emit('update:modelValue', data);
|
||||
});
|
||||
|
||||
watch($$(role), save, { deep: true });
|
||||
watch(role, save, { deep: true });
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, reactive } from 'vue';
|
||||
import { computed, reactive, ref } from 'vue';
|
||||
import XHeader from './_header_.vue';
|
||||
import XEditor from './roles.editor.vue';
|
||||
import MkFolder from '@/components/MkFolder.vue';
|
||||
|
|
@ -90,7 +90,7 @@ const usersPagination = {
|
|||
})),
|
||||
};
|
||||
|
||||
let expandedItems = $ref([]);
|
||||
const expandedItems = ref([]);
|
||||
|
||||
const role = reactive(await os.api('admin/roles/show', {
|
||||
roleId: props.id,
|
||||
|
|
@ -160,16 +160,16 @@ async function unassign(user, ev) {
|
|||
}
|
||||
|
||||
async function toggleItem(item) {
|
||||
if (expandedItems.includes(item.id)) {
|
||||
expandedItems = expandedItems.filter(x => x !== item.id);
|
||||
if (expandedItems.value.includes(item.id)) {
|
||||
expandedItems.value = expandedItems.value.filter(x => x !== item.id);
|
||||
} else {
|
||||
expandedItems.push(item.id);
|
||||
expandedItems.value.push(item.id);
|
||||
}
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata(computed(() => ({
|
||||
title: i18n.ts.role + ': ' + role.name,
|
||||
|
|
|
|||
|
|
@ -282,9 +282,9 @@ function create() {
|
|||
router.push('/admin/roles/new');
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata(computed(() => ({
|
||||
title: i18n.ts.roles,
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { } from 'vue';
|
||||
import { ref, computed } from 'vue';
|
||||
import XBotProtection from './bot-protection.vue';
|
||||
import XHeader from './_header_.vue';
|
||||
import MkFolder from '@/components/MkFolder.vue';
|
||||
|
|
@ -129,65 +129,65 @@ import { fetchInstance } from '@/instance.js';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
|
||||
let summalyProxy: string = $ref('');
|
||||
let enableHcaptcha: boolean = $ref(false);
|
||||
let enableRecaptcha: boolean = $ref(false);
|
||||
let enableTurnstile: boolean = $ref(false);
|
||||
let sensitiveMediaDetection: string = $ref('none');
|
||||
let sensitiveMediaDetectionSensitivity: number = $ref(0);
|
||||
let setSensitiveFlagAutomatically: boolean = $ref(false);
|
||||
let enableSensitiveMediaDetectionForVideos: boolean = $ref(false);
|
||||
let enableIpLogging: boolean = $ref(false);
|
||||
let enableActiveEmailValidation: boolean = $ref(false);
|
||||
let enableVerifymailApi: boolean = $ref(false);
|
||||
let verifymailAuthKey: string | null = $ref(null);
|
||||
const summalyProxy = ref<string>('');
|
||||
const enableHcaptcha = ref<boolean>(false);
|
||||
const enableRecaptcha = ref<boolean>(false);
|
||||
const enableTurnstile = ref<boolean>(false);
|
||||
const sensitiveMediaDetection = ref<string>('none');
|
||||
const sensitiveMediaDetectionSensitivity = ref<number>(0);
|
||||
const setSensitiveFlagAutomatically = ref<boolean>(false);
|
||||
const enableSensitiveMediaDetectionForVideos = ref<boolean>(false);
|
||||
const enableIpLogging = ref<boolean>(false);
|
||||
const enableActiveEmailValidation = ref<boolean>(false);
|
||||
const enableVerifymailApi = ref<boolean>(false);
|
||||
const verifymailAuthKey = ref<string | null>(null);
|
||||
|
||||
async function init() {
|
||||
const meta = await os.api('admin/meta');
|
||||
summalyProxy = meta.summalyProxy;
|
||||
enableHcaptcha = meta.enableHcaptcha;
|
||||
enableRecaptcha = meta.enableRecaptcha;
|
||||
enableTurnstile = meta.enableTurnstile;
|
||||
sensitiveMediaDetection = meta.sensitiveMediaDetection;
|
||||
sensitiveMediaDetectionSensitivity =
|
||||
summalyProxy.value = meta.summalyProxy;
|
||||
enableHcaptcha.value = meta.enableHcaptcha;
|
||||
enableRecaptcha.value = meta.enableRecaptcha;
|
||||
enableTurnstile.value = meta.enableTurnstile;
|
||||
sensitiveMediaDetection.value = meta.sensitiveMediaDetection;
|
||||
sensitiveMediaDetectionSensitivity.value =
|
||||
meta.sensitiveMediaDetectionSensitivity === 'veryLow' ? 0 :
|
||||
meta.sensitiveMediaDetectionSensitivity === 'low' ? 1 :
|
||||
meta.sensitiveMediaDetectionSensitivity === 'medium' ? 2 :
|
||||
meta.sensitiveMediaDetectionSensitivity === 'high' ? 3 :
|
||||
meta.sensitiveMediaDetectionSensitivity === 'veryHigh' ? 4 : 0;
|
||||
setSensitiveFlagAutomatically = meta.setSensitiveFlagAutomatically;
|
||||
enableSensitiveMediaDetectionForVideos = meta.enableSensitiveMediaDetectionForVideos;
|
||||
enableIpLogging = meta.enableIpLogging;
|
||||
enableActiveEmailValidation = meta.enableActiveEmailValidation;
|
||||
enableVerifymailApi = meta.enableVerifymailApi;
|
||||
verifymailAuthKey = meta.verifymailAuthKey;
|
||||
setSensitiveFlagAutomatically.value = meta.setSensitiveFlagAutomatically;
|
||||
enableSensitiveMediaDetectionForVideos.value = meta.enableSensitiveMediaDetectionForVideos;
|
||||
enableIpLogging.value = meta.enableIpLogging;
|
||||
enableActiveEmailValidation.value = meta.enableActiveEmailValidation;
|
||||
enableVerifymailApi.value = meta.enableVerifymailApi;
|
||||
verifymailAuthKey.value = meta.verifymailAuthKey;
|
||||
}
|
||||
|
||||
function save() {
|
||||
os.apiWithDialog('admin/update-meta', {
|
||||
summalyProxy,
|
||||
sensitiveMediaDetection,
|
||||
summalyProxy: summalyProxy.value,
|
||||
sensitiveMediaDetection: sensitiveMediaDetection.value,
|
||||
sensitiveMediaDetectionSensitivity:
|
||||
sensitiveMediaDetectionSensitivity === 0 ? 'veryLow' :
|
||||
sensitiveMediaDetectionSensitivity === 1 ? 'low' :
|
||||
sensitiveMediaDetectionSensitivity === 2 ? 'medium' :
|
||||
sensitiveMediaDetectionSensitivity === 3 ? 'high' :
|
||||
sensitiveMediaDetectionSensitivity === 4 ? 'veryHigh' :
|
||||
sensitiveMediaDetectionSensitivity.value === 0 ? 'veryLow' :
|
||||
sensitiveMediaDetectionSensitivity.value === 1 ? 'low' :
|
||||
sensitiveMediaDetectionSensitivity.value === 2 ? 'medium' :
|
||||
sensitiveMediaDetectionSensitivity.value === 3 ? 'high' :
|
||||
sensitiveMediaDetectionSensitivity.value === 4 ? 'veryHigh' :
|
||||
0,
|
||||
setSensitiveFlagAutomatically,
|
||||
enableSensitiveMediaDetectionForVideos,
|
||||
enableIpLogging,
|
||||
enableActiveEmailValidation,
|
||||
enableVerifymailApi,
|
||||
verifymailAuthKey,
|
||||
setSensitiveFlagAutomatically: setSensitiveFlagAutomatically.value,
|
||||
enableSensitiveMediaDetectionForVideos: enableSensitiveMediaDetectionForVideos.value,
|
||||
enableIpLogging: enableIpLogging.value,
|
||||
enableActiveEmailValidation: enableActiveEmailValidation.value,
|
||||
enableVerifymailApi: enableVerifymailApi.value,
|
||||
verifymailAuthKey: verifymailAuthKey.value,
|
||||
}).then(() => {
|
||||
fetchInstance();
|
||||
});
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.security,
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
import { defineAsyncComponent, ref, computed } from 'vue';
|
||||
import XHeader from './_header_.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { fetchInstance, instance } from '@/instance.js';
|
||||
|
|
@ -52,20 +52,20 @@ import MkInput from '@/components/MkInput.vue';
|
|||
|
||||
const Sortable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default));
|
||||
|
||||
let serverRules: string[] = $ref(instance.serverRules);
|
||||
const serverRules = ref<string[]>(instance.serverRules);
|
||||
|
||||
const save = async () => {
|
||||
await os.apiWithDialog('admin/update-meta', {
|
||||
serverRules,
|
||||
serverRules: serverRules.value,
|
||||
});
|
||||
fetchInstance();
|
||||
};
|
||||
|
||||
const remove = (index: number): void => {
|
||||
serverRules.splice(index, 1);
|
||||
serverRules.value.splice(index, 1);
|
||||
};
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.serverRules,
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { } from 'vue';
|
||||
import { ref, computed } from 'vue';
|
||||
import XHeader from './_header_.vue';
|
||||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
|
|
@ -163,76 +163,76 @@ import { i18n } from '@/i18n.js';
|
|||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
|
||||
let name: string | null = $ref(null);
|
||||
let shortName: string | null = $ref(null);
|
||||
let description: string | null = $ref(null);
|
||||
let maintainerName: string | null = $ref(null);
|
||||
let maintainerEmail: string | null = $ref(null);
|
||||
let impressumUrl: string | null = $ref(null);
|
||||
let pinnedUsers: string = $ref('');
|
||||
let cacheRemoteFiles: boolean = $ref(false);
|
||||
let cacheRemoteSensitiveFiles: boolean = $ref(false);
|
||||
let enableServiceWorker: boolean = $ref(false);
|
||||
let swPublicKey: any = $ref(null);
|
||||
let swPrivateKey: any = $ref(null);
|
||||
let enableFanoutTimeline: boolean = $ref(false);
|
||||
let enableFanoutTimelineDbFallback: boolean = $ref(false);
|
||||
let perLocalUserUserTimelineCacheMax: number = $ref(0);
|
||||
let perRemoteUserUserTimelineCacheMax: number = $ref(0);
|
||||
let perUserHomeTimelineCacheMax: number = $ref(0);
|
||||
let perUserListTimelineCacheMax: number = $ref(0);
|
||||
let notesPerOneAd: number = $ref(0);
|
||||
const name = ref<string | null>(null);
|
||||
const shortName = ref<string | null>(null);
|
||||
const description = ref<string | null>(null);
|
||||
const maintainerName = ref<string | null>(null);
|
||||
const maintainerEmail = ref<string | null>(null);
|
||||
const impressumUrl = ref<string | null>(null);
|
||||
const pinnedUsers = ref<string>('');
|
||||
const cacheRemoteFiles = ref<boolean>(false);
|
||||
const cacheRemoteSensitiveFiles = ref<boolean>(false);
|
||||
const enableServiceWorker = ref<boolean>(false);
|
||||
const swPublicKey = ref<any>(null);
|
||||
const swPrivateKey = ref<any>(null);
|
||||
const enableFanoutTimeline = ref<boolean>(false);
|
||||
const enableFanoutTimelineDbFallback = ref<boolean>(false);
|
||||
const perLocalUserUserTimelineCacheMax = ref<number>(0);
|
||||
const perRemoteUserUserTimelineCacheMax = ref<number>(0);
|
||||
const perUserHomeTimelineCacheMax = ref<number>(0);
|
||||
const perUserListTimelineCacheMax = ref<number>(0);
|
||||
const notesPerOneAd = ref<number>(0);
|
||||
|
||||
async function init(): Promise<void> {
|
||||
const meta = await os.api('admin/meta');
|
||||
name = meta.name;
|
||||
shortName = meta.shortName;
|
||||
description = meta.description;
|
||||
maintainerName = meta.maintainerName;
|
||||
maintainerEmail = meta.maintainerEmail;
|
||||
impressumUrl = meta.impressumUrl;
|
||||
pinnedUsers = meta.pinnedUsers.join('\n');
|
||||
cacheRemoteFiles = meta.cacheRemoteFiles;
|
||||
cacheRemoteSensitiveFiles = meta.cacheRemoteSensitiveFiles;
|
||||
enableServiceWorker = meta.enableServiceWorker;
|
||||
swPublicKey = meta.swPublickey;
|
||||
swPrivateKey = meta.swPrivateKey;
|
||||
enableFanoutTimeline = meta.enableFanoutTimeline;
|
||||
enableFanoutTimelineDbFallback = meta.enableFanoutTimelineDbFallback;
|
||||
perLocalUserUserTimelineCacheMax = meta.perLocalUserUserTimelineCacheMax;
|
||||
perRemoteUserUserTimelineCacheMax = meta.perRemoteUserUserTimelineCacheMax;
|
||||
perUserHomeTimelineCacheMax = meta.perUserHomeTimelineCacheMax;
|
||||
perUserListTimelineCacheMax = meta.perUserListTimelineCacheMax;
|
||||
notesPerOneAd = meta.notesPerOneAd;
|
||||
name.value = meta.name;
|
||||
shortName.value = meta.shortName;
|
||||
description.value = meta.description;
|
||||
maintainerName.value = meta.maintainerName;
|
||||
maintainerEmail.value = meta.maintainerEmail;
|
||||
impressumUrl.value = meta.impressumUrl;
|
||||
pinnedUsers.value = meta.pinnedUsers.join('\n');
|
||||
cacheRemoteFiles.value = meta.cacheRemoteFiles;
|
||||
cacheRemoteSensitiveFiles.value = meta.cacheRemoteSensitiveFiles;
|
||||
enableServiceWorker.value = meta.enableServiceWorker;
|
||||
swPublicKey.value = meta.swPublickey;
|
||||
swPrivateKey.value = meta.swPrivateKey;
|
||||
enableFanoutTimeline.value = meta.enableFanoutTimeline;
|
||||
enableFanoutTimelineDbFallback.value = meta.enableFanoutTimelineDbFallback;
|
||||
perLocalUserUserTimelineCacheMax.value = meta.perLocalUserUserTimelineCacheMax;
|
||||
perRemoteUserUserTimelineCacheMax.value = meta.perRemoteUserUserTimelineCacheMax;
|
||||
perUserHomeTimelineCacheMax.value = meta.perUserHomeTimelineCacheMax;
|
||||
perUserListTimelineCacheMax.value = meta.perUserListTimelineCacheMax;
|
||||
notesPerOneAd.value = meta.notesPerOneAd;
|
||||
}
|
||||
|
||||
async function save(): void {
|
||||
await os.apiWithDialog('admin/update-meta', {
|
||||
name,
|
||||
shortName: shortName === '' ? null : shortName,
|
||||
description,
|
||||
maintainerName,
|
||||
maintainerEmail,
|
||||
impressumUrl,
|
||||
pinnedUsers: pinnedUsers.split('\n'),
|
||||
cacheRemoteFiles,
|
||||
cacheRemoteSensitiveFiles,
|
||||
enableServiceWorker,
|
||||
swPublicKey,
|
||||
swPrivateKey,
|
||||
enableFanoutTimeline,
|
||||
enableFanoutTimelineDbFallback,
|
||||
perLocalUserUserTimelineCacheMax,
|
||||
perRemoteUserUserTimelineCacheMax,
|
||||
perUserHomeTimelineCacheMax,
|
||||
perUserListTimelineCacheMax,
|
||||
notesPerOneAd,
|
||||
name: name.value,
|
||||
shortName: shortName.value === '' ? null : shortName.value,
|
||||
description: description.value,
|
||||
maintainerName: maintainerName.value,
|
||||
maintainerEmail: maintainerEmail.value,
|
||||
impressumUrl: impressumUrl.value,
|
||||
pinnedUsers: pinnedUsers.value.split('\n'),
|
||||
cacheRemoteFiles: cacheRemoteFiles.value,
|
||||
cacheRemoteSensitiveFiles: cacheRemoteSensitiveFiles.value,
|
||||
enableServiceWorker: enableServiceWorker.value,
|
||||
swPublicKey: swPublicKey.value,
|
||||
swPrivateKey: swPrivateKey.value,
|
||||
enableFanoutTimeline: enableFanoutTimeline.value,
|
||||
enableFanoutTimelineDbFallback: enableFanoutTimelineDbFallback.value,
|
||||
perLocalUserUserTimelineCacheMax: perLocalUserUserTimelineCacheMax.value,
|
||||
perRemoteUserUserTimelineCacheMax: perRemoteUserUserTimelineCacheMax.value,
|
||||
perUserHomeTimelineCacheMax: perUserHomeTimelineCacheMax.value,
|
||||
perUserListTimelineCacheMax: perUserListTimelineCacheMax.value,
|
||||
notesPerOneAd: notesPerOneAd.value,
|
||||
});
|
||||
|
||||
fetchInstance();
|
||||
}
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.general,
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { computed, shallowRef, ref } from 'vue';
|
||||
import XHeader from './_header_.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkSelect from '@/components/MkSelect.vue';
|
||||
|
|
@ -69,22 +69,22 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
|
|||
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||
import { dateString } from '@/filters/date.js';
|
||||
|
||||
let paginationComponent = $shallowRef<InstanceType<typeof MkPagination>>();
|
||||
const paginationComponent = shallowRef<InstanceType<typeof MkPagination>>();
|
||||
|
||||
let sort = $ref('+createdAt');
|
||||
let state = $ref('all');
|
||||
let origin = $ref('local');
|
||||
let searchUsername = $ref('');
|
||||
let searchHost = $ref('');
|
||||
const sort = ref('+createdAt');
|
||||
const state = ref('all');
|
||||
const origin = ref('local');
|
||||
const searchUsername = ref('');
|
||||
const searchHost = ref('');
|
||||
const pagination = {
|
||||
endpoint: 'admin/show-users' as const,
|
||||
limit: 10,
|
||||
params: computed(() => ({
|
||||
sort: sort,
|
||||
state: state,
|
||||
origin: origin,
|
||||
username: searchUsername,
|
||||
hostname: searchHost,
|
||||
sort: sort.value,
|
||||
state: state.value,
|
||||
origin: origin.value,
|
||||
username: searchUsername.value,
|
||||
hostname: searchHost.value,
|
||||
})),
|
||||
offsetMode: true,
|
||||
};
|
||||
|
|
@ -111,7 +111,7 @@ async function addUser() {
|
|||
username: username,
|
||||
password: password,
|
||||
}).then(res => {
|
||||
paginationComponent.reload();
|
||||
paginationComponent.value.reload();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -119,7 +119,7 @@ function show(user) {
|
|||
os.pageWindow(`/admin/user/${user.id}`);
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => [{
|
||||
const headerActions = computed(() => [{
|
||||
icon: 'ti ti-search',
|
||||
text: i18n.ts.search,
|
||||
handler: searchUser,
|
||||
|
|
@ -135,7 +135,7 @@ const headerActions = $computed(() => [{
|
|||
handler: lookupUser,
|
||||
}]);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata(computed(() => ({
|
||||
title: i18n.ts.users,
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from 'vue';
|
||||
import { ref, computed, watch } from 'vue';
|
||||
import MkPagination from '@/components/MkPagination.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkInfo from '@/components/MkInfo.vue';
|
||||
|
|
@ -94,9 +94,9 @@ async function read(announcement): Promise<void> {
|
|||
}
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => [{
|
||||
const headerTabs = computed(() => [{
|
||||
key: 'current',
|
||||
title: i18n.ts.currentAnnouncements,
|
||||
icon: 'ti ti-flare',
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch } from 'vue';
|
||||
import { computed, watch, ref, shallowRef } from 'vue';
|
||||
import MkTimeline from '@/components/MkTimeline.vue';
|
||||
import { scroll } from '@/scripts/scroll.js';
|
||||
import * as os from '@/os.js';
|
||||
|
|
@ -38,20 +38,20 @@ const props = defineProps<{
|
|||
antennaId: string;
|
||||
}>();
|
||||
|
||||
let antenna = $ref(null);
|
||||
let queue = $ref(0);
|
||||
let rootEl = $shallowRef<HTMLElement>();
|
||||
let tlEl = $shallowRef<InstanceType<typeof MkTimeline>>();
|
||||
const keymap = $computed(() => ({
|
||||
const antenna = ref(null);
|
||||
const queue = ref(0);
|
||||
const rootEl = shallowRef<HTMLElement>();
|
||||
const tlEl = shallowRef<InstanceType<typeof MkTimeline>>();
|
||||
const keymap = computed(() => ({
|
||||
't': focus,
|
||||
}));
|
||||
|
||||
function queueUpdated(q) {
|
||||
queue = q;
|
||||
queue.value = q;
|
||||
}
|
||||
|
||||
function top() {
|
||||
scroll(rootEl, { top: 0 });
|
||||
scroll(rootEl.value, { top: 0 });
|
||||
}
|
||||
|
||||
async function timetravel() {
|
||||
|
|
@ -60,7 +60,7 @@ async function timetravel() {
|
|||
});
|
||||
if (canceled) return;
|
||||
|
||||
tlEl.timetravel(date);
|
||||
tlEl.value.timetravel(date);
|
||||
}
|
||||
|
||||
function settings() {
|
||||
|
|
@ -68,16 +68,16 @@ function settings() {
|
|||
}
|
||||
|
||||
function focus() {
|
||||
tlEl.focus();
|
||||
tlEl.value.focus();
|
||||
}
|
||||
|
||||
watch(() => props.antennaId, async () => {
|
||||
antenna = await os.api('antennas/show', {
|
||||
antenna.value = await os.api('antennas/show', {
|
||||
antennaId: props.antennaId,
|
||||
});
|
||||
}, { immediate: true });
|
||||
|
||||
const headerActions = $computed(() => antenna ? [{
|
||||
const headerActions = computed(() => antenna.value ? [{
|
||||
icon: 'ti ti-calendar-time',
|
||||
text: i18n.ts.jumpToSpecifiedDate,
|
||||
handler: timetravel,
|
||||
|
|
@ -87,10 +87,10 @@ const headerActions = $computed(() => antenna ? [{
|
|||
handler: settings,
|
||||
}] : []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata(computed(() => antenna ? {
|
||||
title: antenna.name,
|
||||
definePageMetadata(computed(() => antenna.value ? {
|
||||
title: antenna.value.name,
|
||||
icon: 'ti ti-antenna',
|
||||
} : null));
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { ref, computed } from 'vue';
|
||||
import JSON5 from 'json5';
|
||||
import { Endpoints } from 'misskey-js';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
|
|
@ -83,9 +83,9 @@ function onEndpointChange() {
|
|||
});
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: 'API console',
|
||||
|
|
|
|||
|
|
@ -20,14 +20,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
||||
const props = defineProps<{
|
||||
session: Misskey.entities.AuthSession;
|
||||
session: Misskey.entities.AuthSessionShowResponse;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
|
|
@ -35,11 +35,11 @@ const emit = defineEmits<{
|
|||
(event: 'denied'): void;
|
||||
}>();
|
||||
|
||||
const app = $computed(() => props.session.app);
|
||||
const app = computed(() => props.session.app);
|
||||
|
||||
const name = $computed(() => {
|
||||
const name = computed(() => {
|
||||
const el = document.createElement('div');
|
||||
el.textContent = app.name;
|
||||
el.textContent = app.value.name;
|
||||
return el.innerHTML;
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted } from 'vue';
|
||||
import { onMounted, ref, computed } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import XForm from './auth.form.vue';
|
||||
import MkSignin from '@/components/MkSignin.vue';
|
||||
|
|
@ -55,15 +55,15 @@ const props = defineProps<{
|
|||
token: string;
|
||||
}>();
|
||||
|
||||
let state = $ref<'waiting' | 'accepted' | 'fetch-session-error' | 'denied' | null>(null);
|
||||
let session = $ref<Misskey.entities.AuthSession | null>(null);
|
||||
const state = ref<'waiting' | 'accepted' | 'fetch-session-error' | 'denied' | null>(null);
|
||||
const session = ref<Misskey.entities.AuthSessionShowResponse | null>(null);
|
||||
|
||||
function accepted() {
|
||||
state = 'accepted';
|
||||
if (session && session.app.callbackUrl) {
|
||||
const url = new URL(session.app.callbackUrl);
|
||||
state.value = 'accepted';
|
||||
if (session.value && session.value.app.callbackUrl) {
|
||||
const url = new URL(session.value.app.callbackUrl);
|
||||
if (['javascript:', 'file:', 'data:', 'mailto:', 'tel:'].includes(url.protocol)) throw new Error('invalid url');
|
||||
location.href = `${session.app.callbackUrl}?token=${session.token}`;
|
||||
location.href = `${session.value.app.callbackUrl}?token=${session.value.token}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -75,27 +75,27 @@ onMounted(async () => {
|
|||
if (!$i) return;
|
||||
|
||||
try {
|
||||
session = await os.api('auth/session/show', {
|
||||
session.value = await os.api('auth/session/show', {
|
||||
token: props.token,
|
||||
});
|
||||
|
||||
// 既に連携していた場合
|
||||
if (session.app.isAuthorized) {
|
||||
if (session.value.app.isAuthorized) {
|
||||
await os.api('auth/accept', {
|
||||
token: session.token,
|
||||
token: session.value.token,
|
||||
});
|
||||
accepted();
|
||||
} else {
|
||||
state = 'waiting';
|
||||
state.value = 'waiting';
|
||||
}
|
||||
} catch (err) {
|
||||
state = 'fetch-session-error';
|
||||
state.value = 'fetch-session-error';
|
||||
}
|
||||
});
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts._auth.shareAccessTitle,
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { } from 'vue';
|
||||
import { ref, computed } from 'vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkTextarea from '@/components/MkTextarea.vue';
|
||||
|
|
@ -46,10 +46,10 @@ import { i18n } from '@/i18n.js';
|
|||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
import MkFolder from '@/components/MkFolder.vue';
|
||||
|
||||
let avatarDecorations: any[] = $ref([]);
|
||||
const avatarDecorations = ref<any[]>([]);
|
||||
|
||||
function add() {
|
||||
avatarDecorations.unshift({
|
||||
avatarDecorations.value.unshift({
|
||||
_id: Math.random().toString(36),
|
||||
id: null,
|
||||
name: '',
|
||||
|
|
@ -64,7 +64,7 @@ function del(avatarDecoration) {
|
|||
text: i18n.t('deleteAreYouSure', { x: avatarDecoration.name }),
|
||||
}).then(({ canceled }) => {
|
||||
if (canceled) return;
|
||||
avatarDecorations = avatarDecorations.filter(x => x !== avatarDecoration);
|
||||
avatarDecorations.value = avatarDecorations.value.filter(x => x !== avatarDecoration);
|
||||
os.api('admin/avatar-decorations/delete', avatarDecoration);
|
||||
});
|
||||
}
|
||||
|
|
@ -80,20 +80,20 @@ async function save(avatarDecoration) {
|
|||
|
||||
function load() {
|
||||
os.api('admin/avatar-decorations/list').then(_avatarDecorations => {
|
||||
avatarDecorations = _avatarDecorations;
|
||||
avatarDecorations.value = _avatarDecorations;
|
||||
});
|
||||
}
|
||||
|
||||
load();
|
||||
|
||||
const headerActions = $computed(() => [{
|
||||
const headerActions = computed(() => [{
|
||||
asFullButton: true,
|
||||
icon: 'ti ti-plus',
|
||||
text: i18n.ts.add,
|
||||
handler: add,
|
||||
}]);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.avatarDecorations,
|
||||
|
|
|
|||
|
|
@ -90,22 +90,22 @@ const props = defineProps<{
|
|||
channelId?: string;
|
||||
}>();
|
||||
|
||||
let channel = $ref(null);
|
||||
let name = $ref(null);
|
||||
let description = $ref(null);
|
||||
let bannerUrl = $ref<string | null>(null);
|
||||
let bannerId = $ref<string | null>(null);
|
||||
let color = $ref('#000');
|
||||
let isSensitive = $ref(false);
|
||||
let allowRenoteToExternal = $ref(true);
|
||||
const channel = ref(null);
|
||||
const name = ref(null);
|
||||
const description = ref(null);
|
||||
const bannerUrl = ref<string | null>(null);
|
||||
const bannerId = ref<string | null>(null);
|
||||
const color = ref('#000');
|
||||
const isSensitive = ref(false);
|
||||
const allowRenoteToExternal = ref(true);
|
||||
const pinnedNotes = ref([]);
|
||||
|
||||
watch(() => bannerId, async () => {
|
||||
if (bannerId == null) {
|
||||
bannerUrl = null;
|
||||
watch(() => bannerId.value, async () => {
|
||||
if (bannerId.value == null) {
|
||||
bannerUrl.value = null;
|
||||
} else {
|
||||
bannerUrl = (await os.api('drive/files/show', {
|
||||
fileId: bannerId,
|
||||
bannerUrl.value = (await os.api('drive/files/show', {
|
||||
fileId: bannerId.value,
|
||||
})).url;
|
||||
}
|
||||
});
|
||||
|
|
@ -113,20 +113,20 @@ watch(() => bannerId, async () => {
|
|||
async function fetchChannel() {
|
||||
if (props.channelId == null) return;
|
||||
|
||||
channel = await os.api('channels/show', {
|
||||
channel.value = await os.api('channels/show', {
|
||||
channelId: props.channelId,
|
||||
});
|
||||
|
||||
name = channel.name;
|
||||
description = channel.description;
|
||||
bannerId = channel.bannerId;
|
||||
bannerUrl = channel.bannerUrl;
|
||||
isSensitive = channel.isSensitive;
|
||||
pinnedNotes.value = channel.pinnedNoteIds.map(id => ({
|
||||
name.value = channel.value.name;
|
||||
description.value = channel.value.description;
|
||||
bannerId.value = channel.value.bannerId;
|
||||
bannerUrl.value = channel.value.bannerUrl;
|
||||
isSensitive.value = channel.value.isSensitive;
|
||||
pinnedNotes.value = channel.value.pinnedNoteIds.map(id => ({
|
||||
id,
|
||||
}));
|
||||
color = channel.color;
|
||||
allowRenoteToExternal = channel.allowRenoteToExternal;
|
||||
color.value = channel.value.color;
|
||||
allowRenoteToExternal.value = channel.value.allowRenoteToExternal;
|
||||
}
|
||||
|
||||
fetchChannel();
|
||||
|
|
@ -150,13 +150,13 @@ function removePinnedNote(index: number) {
|
|||
|
||||
function save() {
|
||||
const params = {
|
||||
name: name,
|
||||
description: description,
|
||||
bannerId: bannerId,
|
||||
name: name.value,
|
||||
description: description.value,
|
||||
bannerId: bannerId.value,
|
||||
pinnedNoteIds: pinnedNotes.value.map(x => x.id),
|
||||
color: color,
|
||||
isSensitive: isSensitive,
|
||||
allowRenoteToExternal: allowRenoteToExternal,
|
||||
color: color.value,
|
||||
isSensitive: isSensitive.value,
|
||||
allowRenoteToExternal: allowRenoteToExternal.value,
|
||||
};
|
||||
|
||||
if (props.channelId) {
|
||||
|
|
@ -172,7 +172,7 @@ function save() {
|
|||
async function archive() {
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'warning',
|
||||
title: i18n.t('channelArchiveConfirmTitle', { name: name }),
|
||||
title: i18n.t('channelArchiveConfirmTitle', { name: name.value }),
|
||||
text: i18n.ts.channelArchiveConfirmDescription,
|
||||
});
|
||||
|
||||
|
|
@ -188,17 +188,17 @@ async function archive() {
|
|||
|
||||
function setBannerImage(evt) {
|
||||
selectFile(evt.currentTarget ?? evt.target, null).then(file => {
|
||||
bannerId = file.id;
|
||||
bannerId.value = file.id;
|
||||
});
|
||||
}
|
||||
|
||||
function removeBannerImage() {
|
||||
bannerId = null;
|
||||
bannerId.value = null;
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata(computed(() => props.channelId ? {
|
||||
title: i18n.ts._channel.edit,
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch } from 'vue';
|
||||
import { computed, watch, ref } from 'vue';
|
||||
import MkPostForm from '@/components/MkPostForm.vue';
|
||||
import MkTimeline from '@/components/MkTimeline.vue';
|
||||
import XChannelFollowButton from '@/components/MkChannelFollowButton.vue';
|
||||
|
|
@ -86,6 +86,9 @@ import { defaultStore } from '@/store.js';
|
|||
import MkNote from '@/components/MkNote.vue';
|
||||
import MkInfo from '@/components/MkInfo.vue';
|
||||
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
||||
import { PageHeaderItem } from '@/types/page-header.js';
|
||||
import { isSupportShare } from '@/scripts/navigator.js';
|
||||
import copyToClipboard from '@/scripts/copy-to-clipboard.js';
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
|
|
@ -93,13 +96,13 @@ const props = defineProps<{
|
|||
channelId: string;
|
||||
}>();
|
||||
|
||||
let tab = $ref('overview');
|
||||
let channel = $ref(null);
|
||||
let favorited = $ref(false);
|
||||
let searchQuery = $ref('');
|
||||
let searchPagination = $ref();
|
||||
let searchKey = $ref('');
|
||||
const featuredPagination = $computed(() => ({
|
||||
const tab = ref('overview');
|
||||
const channel = ref(null);
|
||||
const favorited = ref(false);
|
||||
const searchQuery = ref('');
|
||||
const searchPagination = ref();
|
||||
const searchKey = ref('');
|
||||
const featuredPagination = computed(() => ({
|
||||
endpoint: 'notes/featured' as const,
|
||||
limit: 10,
|
||||
params: {
|
||||
|
|
@ -108,30 +111,30 @@ const featuredPagination = $computed(() => ({
|
|||
}));
|
||||
|
||||
watch(() => props.channelId, async () => {
|
||||
channel = await os.api('channels/show', {
|
||||
channel.value = await os.api('channels/show', {
|
||||
channelId: props.channelId,
|
||||
});
|
||||
favorited = channel.isFavorited;
|
||||
if (favorited || channel.isFollowing) {
|
||||
tab = 'timeline';
|
||||
favorited.value = channel.value.isFavorited;
|
||||
if (favorited.value || channel.value.isFollowing) {
|
||||
tab.value = 'timeline';
|
||||
}
|
||||
}, { immediate: true });
|
||||
|
||||
function edit() {
|
||||
router.push(`/channels/${channel.id}/edit`);
|
||||
router.push(`/channels/${channel.value.id}/edit`);
|
||||
}
|
||||
|
||||
function openPostForm() {
|
||||
os.post({
|
||||
channel,
|
||||
channel: channel.value,
|
||||
});
|
||||
}
|
||||
|
||||
function favorite() {
|
||||
os.apiWithDialog('channels/favorite', {
|
||||
channelId: channel.id,
|
||||
channelId: channel.value.id,
|
||||
}).then(() => {
|
||||
favorited = true;
|
||||
favorited.value = true;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -142,55 +145,71 @@ async function unfavorite() {
|
|||
});
|
||||
if (confirm.canceled) return;
|
||||
os.apiWithDialog('channels/unfavorite', {
|
||||
channelId: channel.id,
|
||||
channelId: channel.value.id,
|
||||
}).then(() => {
|
||||
favorited = false;
|
||||
favorited.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
async function search() {
|
||||
const query = searchQuery.toString().trim();
|
||||
const query = searchQuery.value.toString().trim();
|
||||
|
||||
if (query == null) return;
|
||||
|
||||
searchPagination = {
|
||||
searchPagination.value = {
|
||||
endpoint: 'notes/search',
|
||||
limit: 10,
|
||||
params: {
|
||||
query: query,
|
||||
channelId: channel.id,
|
||||
channelId: channel.value.id,
|
||||
},
|
||||
};
|
||||
|
||||
searchKey = query;
|
||||
searchKey.value = query;
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => {
|
||||
if (channel && channel.userId) {
|
||||
const share = {
|
||||
icon: 'ti ti-share',
|
||||
text: i18n.ts.share,
|
||||
handler: async (): Promise<void> => {
|
||||
navigator.share({
|
||||
title: channel.name,
|
||||
text: channel.description,
|
||||
url: `${url}/channels/${channel.id}`,
|
||||
});
|
||||
},
|
||||
};
|
||||
const headerActions = computed(() => {
|
||||
if (channel.value && channel.value.userId) {
|
||||
const headerItems: PageHeaderItem[] = [];
|
||||
|
||||
const canEdit = ($i && $i.id === channel.userId) || iAmModerator;
|
||||
return canEdit ? [share, {
|
||||
icon: 'ti ti-settings',
|
||||
text: i18n.ts.edit,
|
||||
handler: edit,
|
||||
}] : [share];
|
||||
headerItems.push({
|
||||
icon: 'ti ti-link',
|
||||
text: i18n.ts.copyUrl,
|
||||
handler: async (): Promise<void> => {
|
||||
copyToClipboard(`${url}/channels/${channel.value.id}`);
|
||||
os.success();
|
||||
},
|
||||
});
|
||||
|
||||
if (isSupportShare()) {
|
||||
headerItems.push({
|
||||
icon: 'ti ti-share',
|
||||
text: i18n.ts.share,
|
||||
handler: async (): Promise<void> => {
|
||||
navigator.share({
|
||||
title: channel.value.name,
|
||||
text: channel.value.description,
|
||||
url: `${url}/channels/${channel.value.id}`,
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (($i && $i.id === channel.value.userId) || iAmModerator) {
|
||||
headerItems.push({
|
||||
icon: 'ti ti-settings',
|
||||
text: i18n.ts.edit,
|
||||
handler: edit,
|
||||
});
|
||||
}
|
||||
|
||||
return headerItems.length > 0 ? headerItems : null;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
const headerTabs = $computed(() => [{
|
||||
const headerTabs = computed(() => [{
|
||||
key: 'overview',
|
||||
title: i18n.ts.overview,
|
||||
icon: 'ti ti-info-circle',
|
||||
|
|
@ -208,8 +227,8 @@ const headerTabs = $computed(() => [{
|
|||
icon: 'ti ti-search',
|
||||
}]);
|
||||
|
||||
definePageMetadata(computed(() => channel ? {
|
||||
title: channel.name,
|
||||
definePageMetadata(computed(() => channel.value ? {
|
||||
title: channel.value.name,
|
||||
icon: 'ti ti-device-tv',
|
||||
} : null));
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted } from 'vue';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import MkChannelPreview from '@/components/MkChannelPreview.vue';
|
||||
import MkChannelList from '@/components/MkChannelList.vue';
|
||||
import MkPagination from '@/components/MkPagination.vue';
|
||||
|
|
@ -69,15 +69,15 @@ const props = defineProps<{
|
|||
type?: string;
|
||||
}>();
|
||||
|
||||
let key = $ref('');
|
||||
let tab = $ref('featured');
|
||||
let searchQuery = $ref('');
|
||||
let searchType = $ref('nameAndDescription');
|
||||
let channelPagination = $ref();
|
||||
const key = ref('');
|
||||
const tab = ref('featured');
|
||||
const searchQuery = ref('');
|
||||
const searchType = ref('nameAndDescription');
|
||||
const channelPagination = ref();
|
||||
|
||||
onMounted(() => {
|
||||
searchQuery = props.query ?? '';
|
||||
searchType = props.type ?? 'nameAndDescription';
|
||||
searchQuery.value = props.query ?? '';
|
||||
searchType.value = props.type ?? 'nameAndDescription';
|
||||
});
|
||||
|
||||
const featuredPagination = {
|
||||
|
|
@ -99,35 +99,35 @@ const ownedPagination = {
|
|||
};
|
||||
|
||||
async function search() {
|
||||
const query = searchQuery.toString().trim();
|
||||
const query = searchQuery.value.toString().trim();
|
||||
|
||||
if (query == null) return;
|
||||
|
||||
const type = searchType.toString().trim();
|
||||
const type = searchType.value.toString().trim();
|
||||
|
||||
channelPagination = {
|
||||
channelPagination.value = {
|
||||
endpoint: 'channels/search',
|
||||
limit: 10,
|
||||
params: {
|
||||
query: searchQuery,
|
||||
query: searchQuery.value,
|
||||
type: type,
|
||||
},
|
||||
};
|
||||
|
||||
key = query + type;
|
||||
key.value = query + type;
|
||||
}
|
||||
|
||||
function create() {
|
||||
router.push('/channels/new');
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => [{
|
||||
const headerActions = computed(() => [{
|
||||
icon: 'ti ti-plus',
|
||||
text: i18n.ts.create,
|
||||
handler: create,
|
||||
}]);
|
||||
|
||||
const headerTabs = $computed(() => [{
|
||||
const headerTabs = computed(() => [{
|
||||
key: 'search',
|
||||
title: i18n.ts.search,
|
||||
icon: 'ti ti-search',
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch, provide } from 'vue';
|
||||
import { computed, watch, provide, ref } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import MkNotes from '@/components/MkNotes.vue';
|
||||
import { $i } from '@/account.js';
|
||||
|
|
@ -36,13 +36,15 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
|
|||
import { url } from '@/config.js';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import { clipsCache } from '@/cache';
|
||||
import { isSupportShare } from '@/scripts/navigator.js';
|
||||
import copyToClipboard from '@/scripts/copy-to-clipboard.js';
|
||||
|
||||
const props = defineProps<{
|
||||
clipId: string,
|
||||
}>();
|
||||
|
||||
let clip: Misskey.entities.Clip = $ref<Misskey.entities.Clip>();
|
||||
let favorited = $ref(false);
|
||||
const clip = ref<Misskey.entities.Clip | null>(null);
|
||||
const favorited = ref(false);
|
||||
const pagination = {
|
||||
endpoint: 'clips/notes' as const,
|
||||
limit: 10,
|
||||
|
|
@ -51,24 +53,24 @@ const pagination = {
|
|||
})),
|
||||
};
|
||||
|
||||
const isOwned: boolean | null = $computed<boolean | null>(() => $i && clip && ($i.id === clip.userId));
|
||||
const isOwned = computed<boolean | null>(() => $i && clip.value && ($i.id === clip.value.userId));
|
||||
|
||||
watch(() => props.clipId, async () => {
|
||||
clip = await os.api('clips/show', {
|
||||
clip.value = await os.api('clips/show', {
|
||||
clipId: props.clipId,
|
||||
});
|
||||
favorited = clip.isFavorited;
|
||||
favorited.value = clip.value.isFavorited;
|
||||
}, {
|
||||
immediate: true,
|
||||
});
|
||||
|
||||
provide('currentClip', $$(clip));
|
||||
provide('currentClip', clip);
|
||||
|
||||
function favorite() {
|
||||
os.apiWithDialog('clips/favorite', {
|
||||
clipId: props.clipId,
|
||||
}).then(() => {
|
||||
favorited = true;
|
||||
favorited.value = true;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -81,50 +83,57 @@ async function unfavorite() {
|
|||
os.apiWithDialog('clips/unfavorite', {
|
||||
clipId: props.clipId,
|
||||
}).then(() => {
|
||||
favorited = false;
|
||||
favorited.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => clip && isOwned ? [{
|
||||
const headerActions = computed(() => clip.value && isOwned.value ? [{
|
||||
icon: 'ti ti-pencil',
|
||||
text: i18n.ts.edit,
|
||||
handler: async (): Promise<void> => {
|
||||
const { canceled, result } = await os.form(clip.name, {
|
||||
const { canceled, result } = await os.form(clip.value.name, {
|
||||
name: {
|
||||
type: 'string',
|
||||
label: i18n.ts.name,
|
||||
default: clip.name,
|
||||
default: clip.value.name,
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
multiline: true,
|
||||
label: i18n.ts.description,
|
||||
default: clip.description,
|
||||
default: clip.value.description,
|
||||
},
|
||||
isPublic: {
|
||||
type: 'boolean',
|
||||
label: i18n.ts.public,
|
||||
default: clip.isPublic,
|
||||
default: clip.value.isPublic,
|
||||
},
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
os.apiWithDialog('clips/update', {
|
||||
clipId: clip.id,
|
||||
clipId: clip.value.id,
|
||||
...result,
|
||||
});
|
||||
|
||||
clipsCache.delete();
|
||||
},
|
||||
}, ...(clip.isPublic ? [{
|
||||
}, ...(clip.value.isPublic ? [{
|
||||
icon: 'ti ti-link',
|
||||
text: i18n.ts.copyUrl,
|
||||
handler: async (): Promise<void> => {
|
||||
copyToClipboard(`${url}/clips/${clip.value.id}`);
|
||||
os.success();
|
||||
},
|
||||
}] : []), ...(clip.value.isPublic && isSupportShare() ? [{
|
||||
icon: 'ti ti-share',
|
||||
text: i18n.ts.share,
|
||||
handler: async (): Promise<void> => {
|
||||
navigator.share({
|
||||
title: clip.name,
|
||||
text: clip.description,
|
||||
url: `${url}/clips/${clip.id}`,
|
||||
title: clip.value.name,
|
||||
text: clip.value.description,
|
||||
url: `${url}/clips/${clip.value.id}`,
|
||||
});
|
||||
},
|
||||
}] : []), {
|
||||
|
|
@ -134,20 +143,20 @@ const headerActions = $computed(() => clip && isOwned ? [{
|
|||
handler: async (): Promise<void> => {
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'warning',
|
||||
text: i18n.t('deleteAreYouSure', { x: clip.name }),
|
||||
text: i18n.t('deleteAreYouSure', { x: clip.value.name }),
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
await os.apiWithDialog('clips/delete', {
|
||||
clipId: clip.id,
|
||||
clipId: clip.value.id,
|
||||
});
|
||||
|
||||
clipsCache.delete();
|
||||
},
|
||||
}] : null);
|
||||
|
||||
definePageMetadata(computed(() => clip ? {
|
||||
title: clip.name,
|
||||
definePageMetadata(computed(() => clip.value ? {
|
||||
title: clip.value.name,
|
||||
icon: 'ti ti-paperclip',
|
||||
} : null));
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ const edit = (emoji) => {
|
|||
}, 'closed');
|
||||
};
|
||||
|
||||
const im = (emoji) => {
|
||||
const importEmoji = (emoji) => {
|
||||
os.apiWithDialog('admin/emoji/copy', {
|
||||
emojiId: emoji.id,
|
||||
});
|
||||
|
|
@ -168,7 +168,7 @@ const remoteMenu = (emoji, ev: MouseEvent) => {
|
|||
}, {
|
||||
text: i18n.ts.import,
|
||||
icon: 'ti ti-plus',
|
||||
action: () => { im(emoji); },
|
||||
action: () => { importEmoji(emoji); },
|
||||
}], ev.currentTarget ?? ev.target);
|
||||
};
|
||||
|
||||
|
|
@ -287,7 +287,7 @@ const delBulk = async () => {
|
|||
emojisPaginationComponent.value.reload();
|
||||
};
|
||||
|
||||
const headerActions = $computed(() => [{
|
||||
const headerActions = computed(() => [{
|
||||
asFullButton: true,
|
||||
icon: 'ti ti-plus',
|
||||
text: i18n.ts.addEmoji,
|
||||
|
|
@ -297,7 +297,7 @@ const headerActions = $computed(() => [{
|
|||
handler: menu,
|
||||
}]);
|
||||
|
||||
const headerTabs = $computed(() => [{
|
||||
const headerTabs = computed(() => [{
|
||||
key: 'local',
|
||||
title: i18n.ts.local,
|
||||
}, {
|
||||
|
|
|
|||
|
|
@ -10,19 +10,19 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import XDrive from '@/components/MkDrive.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
|
||||
let folder = $ref(null);
|
||||
const folder = ref(null);
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata(computed(() => ({
|
||||
title: folder ? folder.name : i18n.ts.drive,
|
||||
title: folder.value ? folder.value.name : i18n.ts.drive,
|
||||
icon: 'ti ti-cloud',
|
||||
hideHeader: true,
|
||||
})));
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch } from 'vue';
|
||||
import { computed, watch, ref } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import MkModalWindow from '@/components/MkModalWindow.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
|
|
@ -110,28 +110,28 @@ const props = defineProps<{
|
|||
emoji?: any,
|
||||
}>();
|
||||
|
||||
let dialog = $ref(null);
|
||||
let name: string = $ref(props.emoji ? props.emoji.name : '');
|
||||
let category: string = $ref(props.emoji ? props.emoji.category : '');
|
||||
let aliases: string = $ref(props.emoji ? props.emoji.aliases.join(' ') : '');
|
||||
let license: string = $ref(props.emoji ? (props.emoji.license ?? '') : '');
|
||||
let isSensitive = $ref(props.emoji ? props.emoji.isSensitive : false);
|
||||
let localOnly = $ref(props.emoji ? props.emoji.localOnly : false);
|
||||
let roleIdsThatCanBeUsedThisEmojiAsReaction = $ref(props.emoji ? props.emoji.roleIdsThatCanBeUsedThisEmojiAsReaction : []);
|
||||
let rolesThatCanBeUsedThisEmojiAsReaction = $ref([]);
|
||||
let roleIdsThatCanNotBeUsedThisEmojiAsReaction = $ref(props.emoji ? props.emoji.roleIdsThatCanNotBeUsedThisEmojiAsReaction : []);
|
||||
let rolesThatCanNotBeUsedThisEmojiAsReaction = $ref([]);
|
||||
let file = $ref<Misskey.entities.DriveFile>();
|
||||
const dialog = ref(null);
|
||||
const name = ref<string>(props.emoji ? props.emoji.name : '');
|
||||
const category = ref<string>(props.emoji ? props.emoji.category : '');
|
||||
const aliases = ref<string>(props.emoji ? props.emoji.aliases.join(' ') : '');
|
||||
const license = ref<string>(props.emoji ? (props.emoji.license ?? '') : '');
|
||||
const isSensitive = ref(props.emoji ? props.emoji.isSensitive : false);
|
||||
const localOnly = ref(props.emoji ? props.emoji.localOnly : false);
|
||||
const roleIdsThatCanBeUsedThisEmojiAsReaction = ref(props.emoji ? props.emoji.roleIdsThatCanBeUsedThisEmojiAsReaction : []);
|
||||
const rolesThatCanBeUsedThisEmojiAsReaction = ref([]);
|
||||
const roleIdsThatCanNotBeUsedThisEmojiAsReaction = ref(props.emoji ? props.emoji.roleIdsThatCanNotBeUsedThisEmojiAsReaction : []);
|
||||
const rolesThatCanNotBeUsedThisEmojiAsReaction = ref([]);
|
||||
const file = ref<Misskey.entities.DriveFile>();
|
||||
|
||||
watch($$(roleIdsThatCanBeUsedThisEmojiAsReaction), async () => {
|
||||
rolesThatCanBeUsedThisEmojiAsReaction = (await Promise.all(roleIdsThatCanBeUsedThisEmojiAsReaction.map((id) => os.api('admin/roles/show', { roleId: id }).catch(() => null)))).filter(x => x != null);
|
||||
watch(roleIdsThatCanBeUsedThisEmojiAsReaction, async () => {
|
||||
rolesThatCanBeUsedThisEmojiAsReaction.value = (await Promise.all(roleIdsThatCanBeUsedThisEmojiAsReaction.value.map((id) => os.api('admin/roles/show', { roleId: id }).catch(() => null)))).filter(x => x != null);
|
||||
}, { immediate: true });
|
||||
|
||||
watch($$(roleIdsThatCanNotBeUsedThisEmojiAsReaction), async () => {
|
||||
rolesThatCanNotBeUsedThisEmojiAsReaction = (await Promise.all(roleIdsThatCanNotBeUsedThisEmojiAsReaction.map((id) => os.api('admin/roles/show', { roleId: id }).catch(() => null)))).filter(x => x != null);
|
||||
watch(roleIdsThatCanNotBeUsedThisEmojiAsReaction, async () => {
|
||||
rolesThatCanNotBeUsedThisEmojiAsReaction.value = (await Promise.all(roleIdsThatCanNotBeUsedThisEmojiAsReaction.value.map((id) => os.api('admin/roles/show', { roleId: id }).catch(() => null)))).filter(x => x != null);
|
||||
}, { immediate: true });
|
||||
|
||||
const imgUrl = computed(() => file ? file.url : props.emoji ? `/emoji/${props.emoji.name}.webp` : null);
|
||||
const imgUrl = computed(() => file.value ? file.value.url : props.emoji ? `/emoji/${props.emoji.name}.webp` : null);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(ev: 'done', v: { deleted?: boolean; updated?: any; created?: any }): void,
|
||||
|
|
@ -139,45 +139,45 @@ const emit = defineEmits<{
|
|||
}>();
|
||||
|
||||
async function changeImage(ev) {
|
||||
file = await selectFile(ev.currentTarget ?? ev.target, null);
|
||||
const candidate = file.name.replace(/\.(.+)$/, '');
|
||||
file.value = await selectFile(ev.currentTarget ?? ev.target, null);
|
||||
const candidate = file.value.name.replace(/\.(.+)$/, '');
|
||||
if (candidate.match(/^[a-z0-9_]+$/)) {
|
||||
name = candidate;
|
||||
name.value = candidate;
|
||||
}
|
||||
}
|
||||
|
||||
async function addRole(type: boolean) {
|
||||
const roles = await os.api('admin/roles/list');
|
||||
const currentRoleIds = type ? rolesThatCanBeUsedThisEmojiAsReaction.map(x => x.id) : rolesThatCanNotBeUsedThisEmojiAsReaction.map(x => x.id);
|
||||
const currentRoleIds = type ? rolesThatCanBeUsedThisEmojiAsReaction.value.map(x => x.id) : rolesThatCanNotBeUsedThisEmojiAsReaction.value.map(x => x.id);
|
||||
|
||||
const { canceled, result: role } = await os.select({
|
||||
items: roles.filter(r => r.isPublic).filter(r => !currentRoleIds.includes(r.id)).map(r => ({ text: r.name, value: r })),
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
if (type) rolesThatCanBeUsedThisEmojiAsReaction.push(role);
|
||||
else rolesThatCanNotBeUsedThisEmojiAsReaction.push(role);
|
||||
if (type) rolesThatCanBeUsedThisEmojiAsReaction.value.push(role);
|
||||
else rolesThatCanNotBeUsedThisEmojiAsReaction.value.push(role);
|
||||
}
|
||||
|
||||
async function removeRole(type: boolean, role, ev) {
|
||||
if (type) rolesThatCanBeUsedThisEmojiAsReaction = rolesThatCanBeUsedThisEmojiAsReaction.filter(x => x.id !== role.id);
|
||||
else rolesThatCanNotBeUsedThisEmojiAsReaction = rolesThatCanNotBeUsedThisEmojiAsReaction.filter(x => x.id !== role.id);
|
||||
if (type) rolesThatCanBeUsedThisEmojiAsReaction.value = rolesThatCanBeUsedThisEmojiAsReaction.value.filter(x => x.id !== role.id);
|
||||
else rolesThatCanNotBeUsedThisEmojiAsReaction.value = rolesThatCanNotBeUsedThisEmojiAsReaction.value.filter(x => x.id !== role.id);
|
||||
}
|
||||
|
||||
async function done() {
|
||||
const params = {
|
||||
name,
|
||||
category: category === '' ? null : category,
|
||||
aliases: aliases.split(' ').filter(x => x !== ''),
|
||||
license: license === '' ? null : license,
|
||||
isSensitive,
|
||||
localOnly,
|
||||
roleIdsThatCanBeUsedThisEmojiAsReaction: rolesThatCanBeUsedThisEmojiAsReaction.map(x => x.id),
|
||||
roleIdsThatCanNotBeUsedThisEmojiAsReaction: rolesThatCanNotBeUsedThisEmojiAsReaction.map(x => x.id),
|
||||
name: name.value,
|
||||
category: category.value === '' ? null : category.value,
|
||||
aliases: aliases.value.split(' ').filter(x => x !== ''),
|
||||
license: license.value === '' ? null : license.value,
|
||||
isSensitive: isSensitive.value,
|
||||
localOnly: localOnly.value,
|
||||
roleIdsThatCanBeUsedThisEmojiAsReaction: rolesThatCanBeUsedThisEmojiAsReaction.value.map(x => x.id),
|
||||
roleIdsThatCanNotBeUsedThisEmojiAsReaction: rolesThatCanNotBeUsedThisEmojiAsReaction.value.map(x => x.id),
|
||||
};
|
||||
|
||||
if (file) {
|
||||
params.fileId = file.id;
|
||||
if (file.value) {
|
||||
params.fileId = file.value.id;
|
||||
}
|
||||
|
||||
if (props.emoji) {
|
||||
|
|
@ -193,7 +193,7 @@ async function done() {
|
|||
},
|
||||
});
|
||||
|
||||
dialog.close();
|
||||
dialog.value.close();
|
||||
} else {
|
||||
const created = await os.apiWithDialog('admin/emoji/add', params);
|
||||
|
||||
|
|
@ -201,14 +201,14 @@ async function done() {
|
|||
created: created,
|
||||
});
|
||||
|
||||
dialog.close();
|
||||
dialog.value.close();
|
||||
}
|
||||
}
|
||||
|
||||
async function del() {
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'warning',
|
||||
text: i18n.t('removeAreYouSure', { x: name }),
|
||||
text: i18n.t('removeAreYouSure', { x: name.value }),
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
|
|
@ -218,7 +218,7 @@ async function del() {
|
|||
emit('done', {
|
||||
deleted: true,
|
||||
});
|
||||
dialog.close();
|
||||
dialog.value.close();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ function menu(ev) {
|
|||
os.apiGet('emoji', { name: props.emoji.name }).then(res => {
|
||||
os.alert({
|
||||
type: 'info',
|
||||
text: `License: ${res.license}`,
|
||||
text: `Name: ${res.name}\nAliases: ${res.aliases.join(' ')}\nCategory: ${res.category}\nisSensitive: ${res.isSensitive}\nlocalOnly: ${res.localOnly}\nLicense: ${res.license}\nURL: ${res.url}`,
|
||||
});
|
||||
});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import MkNotes from '@/components/MkNotes.vue';
|
||||
import MkTab from '@/components/MkTab.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
|
@ -30,5 +31,5 @@ const paginationForPolls = {
|
|||
offsetMode: true,
|
||||
};
|
||||
|
||||
let tab = $ref('notes');
|
||||
const tab = ref('notes');
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -12,14 +12,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { } from 'vue';
|
||||
import { ref } from 'vue';
|
||||
import MkRolePreview from '@/components/MkRolePreview.vue';
|
||||
import * as os from '@/os.js';
|
||||
|
||||
let roles = $ref();
|
||||
const roles = ref();
|
||||
|
||||
os.api('roles/list').then(res => {
|
||||
roles = res.filter(x => x.target === 'manual').sort((a, b) => b.displayOrder - a.displayOrder);
|
||||
roles.value = res.filter(x => x.target === 'manual').sort((a, b) => b.displayOrder - a.displayOrder);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { watch } from 'vue';
|
||||
import { watch, ref, shallowRef, computed } from 'vue';
|
||||
import MkUserList from '@/components/MkUserList.vue';
|
||||
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
||||
import MkTab from '@/components/MkTab.vue';
|
||||
|
|
@ -74,16 +74,16 @@ const props = defineProps<{
|
|||
tag?: string;
|
||||
}>();
|
||||
|
||||
let origin = $ref('local');
|
||||
let tagsEl = $shallowRef<InstanceType<typeof MkFoldableSection>>();
|
||||
let tagsLocal = $ref([]);
|
||||
let tagsRemote = $ref([]);
|
||||
const origin = ref('local');
|
||||
const tagsEl = shallowRef<InstanceType<typeof MkFoldableSection>>();
|
||||
const tagsLocal = ref([]);
|
||||
const tagsRemote = ref([]);
|
||||
|
||||
watch(() => props.tag, () => {
|
||||
if (tagsEl) tagsEl.toggleContent(props.tag == null);
|
||||
if (tagsEl.value) tagsEl.value.toggleContent(props.tag == null);
|
||||
});
|
||||
|
||||
const tagUsers = $computed(() => ({
|
||||
const tagUsers = computed(() => ({
|
||||
endpoint: 'hashtags/users' as const,
|
||||
limit: 30,
|
||||
params: {
|
||||
|
|
@ -127,13 +127,13 @@ os.api('hashtags/list', {
|
|||
attachedToLocalUserOnly: true,
|
||||
limit: 30,
|
||||
}).then(tags => {
|
||||
tagsLocal = tags;
|
||||
tagsLocal.value = tags;
|
||||
});
|
||||
os.api('hashtags/list', {
|
||||
sort: '+attachedRemoteUsers',
|
||||
attachedToRemoteUserOnly: true,
|
||||
limit: 30,
|
||||
}).then(tags => {
|
||||
tagsRemote = tags;
|
||||
tagsRemote.value = tags;
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch } from 'vue';
|
||||
import { computed, watch, ref, shallowRef } from 'vue';
|
||||
import XFeatured from './explore.featured.vue';
|
||||
import XUsers from './explore.users.vue';
|
||||
import XRoles from './explore.roles.vue';
|
||||
|
|
@ -36,16 +36,16 @@ const props = withDefaults(defineProps<{
|
|||
initialTab: 'featured',
|
||||
});
|
||||
|
||||
let tab = $ref(props.initialTab);
|
||||
let tagsEl = $shallowRef<InstanceType<typeof MkFoldableSection>>();
|
||||
const tab = ref(props.initialTab);
|
||||
const tagsEl = shallowRef<InstanceType<typeof MkFoldableSection>>();
|
||||
|
||||
watch(() => props.tag, () => {
|
||||
if (tagsEl) tagsEl.toggleContent(props.tag == null);
|
||||
if (tagsEl.value) tagsEl.value.toggleContent(props.tag == null);
|
||||
});
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => [{
|
||||
const headerTabs = computed(() => [{
|
||||
key: 'featured',
|
||||
icon: 'ti ti-bolt',
|
||||
title: i18n.ts.featured,
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
|
@ -363,80 +363,80 @@ const props = defineProps<{
|
|||
id?: string;
|
||||
}>();
|
||||
|
||||
let flash = $ref(null);
|
||||
let visibility = $ref('public');
|
||||
const flash = ref(null);
|
||||
const visibility = ref('public');
|
||||
|
||||
if (props.id) {
|
||||
flash = await os.api('flash/show', {
|
||||
flash.value = await os.api('flash/show', {
|
||||
flashId: props.id,
|
||||
});
|
||||
}
|
||||
|
||||
let title = $ref(flash?.title ?? 'New Play');
|
||||
let summary = $ref(flash?.summary ?? '');
|
||||
let permissions = $ref(flash?.permissions ?? []);
|
||||
let script = $ref(flash?.script ?? PRESET_DEFAULT);
|
||||
const title = ref(flash.value?.title ?? 'New Play');
|
||||
const summary = ref(flash.value?.summary ?? '');
|
||||
const permissions = ref(flash.value?.permissions ?? []);
|
||||
const script = ref(flash.value?.script ?? PRESET_DEFAULT);
|
||||
|
||||
function selectPreset(ev: MouseEvent) {
|
||||
os.popupMenu([{
|
||||
text: 'Omikuji',
|
||||
action: () => {
|
||||
script = PRESET_OMIKUJI;
|
||||
script.value = PRESET_OMIKUJI;
|
||||
},
|
||||
}, {
|
||||
text: 'Shuffle',
|
||||
action: () => {
|
||||
script = PRESET_SHUFFLE;
|
||||
script.value = PRESET_SHUFFLE;
|
||||
},
|
||||
}, {
|
||||
text: 'Quiz',
|
||||
action: () => {
|
||||
script = PRESET_QUIZ;
|
||||
script.value = PRESET_QUIZ;
|
||||
},
|
||||
}, {
|
||||
text: 'Timeline viewer',
|
||||
action: () => {
|
||||
script = PRESET_TIMELINE;
|
||||
script.value = PRESET_TIMELINE;
|
||||
},
|
||||
}], ev.currentTarget ?? ev.target);
|
||||
}
|
||||
|
||||
async function save() {
|
||||
if (flash) {
|
||||
if (flash.value) {
|
||||
os.apiWithDialog('flash/update', {
|
||||
flashId: props.id,
|
||||
title,
|
||||
summary,
|
||||
permissions,
|
||||
script,
|
||||
visibility,
|
||||
title: title.value,
|
||||
summary: summary.value,
|
||||
permissions: permissions.value,
|
||||
script: script.value,
|
||||
visibility: visibility.value,
|
||||
});
|
||||
} else {
|
||||
const created = await os.apiWithDialog('flash/create', {
|
||||
title,
|
||||
summary,
|
||||
permissions,
|
||||
script,
|
||||
visibility,
|
||||
title: title.value,
|
||||
summary: summary.value,
|
||||
permissions: permissions.value,
|
||||
script: script.value,
|
||||
visibility: visibility.value,
|
||||
});
|
||||
router.push('/play/' + created.id + '/edit');
|
||||
}
|
||||
}
|
||||
|
||||
function show() {
|
||||
if (flash == null) {
|
||||
if (flash.value == null) {
|
||||
os.alert({
|
||||
text: 'Please save',
|
||||
});
|
||||
} else {
|
||||
os.pageWindow(`/play/${flash.id}`);
|
||||
os.pageWindow(`/play/${flash.value.id}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function del() {
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'warning',
|
||||
text: i18n.t('deleteAreYouSure', { x: flash.title }),
|
||||
text: i18n.t('deleteAreYouSure', { x: flash.value.title }),
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
|
|
@ -446,12 +446,12 @@ async function del() {
|
|||
router.push('/play');
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata(computed(() => flash ? {
|
||||
title: i18n.ts._play.edit + ': ' + flash.title,
|
||||
definePageMetadata(computed(() => flash.value ? {
|
||||
title: i18n.ts._play.edit + ': ' + flash.value.title,
|
||||
} : {
|
||||
title: i18n.ts._play.new,
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import MkFlashPreview from '@/components/MkFlashPreview.vue';
|
||||
import MkPagination from '@/components/MkPagination.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
|
|
@ -48,7 +48,7 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
|
|||
|
||||
const router = useRouter();
|
||||
|
||||
let tab = $ref('featured');
|
||||
const tab = ref('featured');
|
||||
|
||||
const featuredFlashsPagination = {
|
||||
endpoint: 'flash/featured' as const,
|
||||
|
|
@ -67,13 +67,13 @@ function create() {
|
|||
router.push('/play/new');
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => [{
|
||||
const headerActions = computed(() => [{
|
||||
icon: 'ti ti-plus',
|
||||
text: i18n.ts.create,
|
||||
handler: create,
|
||||
}]);
|
||||
|
||||
const headerTabs = $computed(() => [{
|
||||
const headerTabs = computed(() => [{
|
||||
key: 'featured',
|
||||
title: i18n.ts._play.featured,
|
||||
icon: 'ti ti-flare',
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<MkButton v-if="flash.isLiked" v-tooltip="i18n.ts.unlike" asLike class="button" rounded primary @click="unlike()"><i class="ti ti-heart"></i><span v-if="flash.likedCount > 0" style="margin-left: 6px;">{{ flash.likedCount }}</span></MkButton>
|
||||
<MkButton v-else v-tooltip="i18n.ts.like" asLike class="button" rounded @click="like()"><i class="ti ti-heart"></i><span v-if="flash.likedCount > 0" style="margin-left: 6px;">{{ flash.likedCount }}</span></MkButton>
|
||||
<MkButton v-tooltip="i18n.ts.shareWithNote" class="button" rounded @click="shareWithNote"><i class="ti ti-repeat ti-fw"></i></MkButton>
|
||||
<MkButton v-tooltip="i18n.ts.share" class="button" rounded @click="share"><i class="ti ti-share ti-fw"></i></MkButton>
|
||||
<MkButton v-tooltip="i18n.ts.copyLink" class="button" rounded @click="copyLink"><i class="ti ti-link ti-fw"></i></MkButton>
|
||||
<MkButton v-if="isSupportShare()" v-tooltip="i18n.ts.share" class="button" rounded @click="share"><i class="ti ti-share ti-fw"></i></MkButton>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else :class="$style.ready">
|
||||
|
|
@ -56,7 +57,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onDeactivated, onUnmounted, Ref, ref, watch } from 'vue';
|
||||
import { computed, onDeactivated, onUnmounted, Ref, ref, watch, shallowRef } from 'vue';
|
||||
import { Interpreter, Parser, values } from '@syuilo/aiscript';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import * as os from '@/os.js';
|
||||
|
|
@ -70,45 +71,52 @@ import MkFolder from '@/components/MkFolder.vue';
|
|||
import MkCode from '@/components/MkCode.vue';
|
||||
import { defaultStore } from '@/store.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { isSupportShare } from '@/scripts/navigator.js';
|
||||
import copyToClipboard from '@/scripts/copy-to-clipboard.js';
|
||||
|
||||
const props = defineProps<{
|
||||
id: string;
|
||||
}>();
|
||||
|
||||
let flash = $ref(null);
|
||||
let error = $ref(null);
|
||||
const flash = ref(null);
|
||||
const error = ref(null);
|
||||
|
||||
function fetchFlash() {
|
||||
flash = null;
|
||||
flash.value = null;
|
||||
os.api('flash/show', {
|
||||
flashId: props.id,
|
||||
}).then(_flash => {
|
||||
flash = _flash;
|
||||
flash.value = _flash;
|
||||
}).catch(err => {
|
||||
error = err;
|
||||
error.value = err;
|
||||
});
|
||||
}
|
||||
|
||||
function copyLink() {
|
||||
copyToClipboard(`${url}/play/${flash.value.id}`);
|
||||
os.success();
|
||||
}
|
||||
|
||||
function share() {
|
||||
navigator.share({
|
||||
title: flash.title,
|
||||
text: flash.summary,
|
||||
url: `${url}/play/${flash.id}`,
|
||||
title: flash.value.title,
|
||||
text: flash.value.summary,
|
||||
url: `${url}/play/${flash.value.id}`,
|
||||
});
|
||||
}
|
||||
|
||||
function shareWithNote() {
|
||||
os.post({
|
||||
initialText: `${flash.title} ${url}/play/${flash.id}`,
|
||||
initialText: `${flash.value.title} ${url}/play/${flash.value.id}`,
|
||||
});
|
||||
}
|
||||
|
||||
function like() {
|
||||
os.apiWithDialog('flash/like', {
|
||||
flashId: flash.id,
|
||||
flashId: flash.value.id,
|
||||
}).then(() => {
|
||||
flash.isLiked = true;
|
||||
flash.likedCount++;
|
||||
flash.value.isLiked = true;
|
||||
flash.value.likedCount++;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -119,10 +127,10 @@ async function unlike() {
|
|||
});
|
||||
if (confirm.canceled) return;
|
||||
os.apiWithDialog('flash/unlike', {
|
||||
flashId: flash.id,
|
||||
flashId: flash.value.id,
|
||||
}).then(() => {
|
||||
flash.isLiked = false;
|
||||
flash.likedCount--;
|
||||
flash.value.isLiked = false;
|
||||
flash.value.likedCount--;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -130,28 +138,28 @@ watch(() => props.id, fetchFlash, { immediate: true });
|
|||
|
||||
const parser = new Parser();
|
||||
|
||||
let started = $ref(false);
|
||||
let aiscript = $shallowRef<Interpreter | null>(null);
|
||||
const started = ref(false);
|
||||
const aiscript = shallowRef<Interpreter | null>(null);
|
||||
const root = ref<AsUiRoot>();
|
||||
const components: Ref<AsUiComponent>[] = $ref([]);
|
||||
const components = ref<Ref<AsUiComponent>[]>([]);
|
||||
|
||||
function start() {
|
||||
started = true;
|
||||
started.value = true;
|
||||
run();
|
||||
}
|
||||
|
||||
async function run() {
|
||||
if (aiscript) aiscript.abort();
|
||||
if (aiscript.value) aiscript.value.abort();
|
||||
|
||||
aiscript = new Interpreter({
|
||||
aiscript.value = new Interpreter({
|
||||
...createAiScriptEnv({
|
||||
storageKey: 'flash:' + flash.id,
|
||||
storageKey: 'flash:' + flash.value.id,
|
||||
}),
|
||||
...registerAsUiLib(components, (_root) => {
|
||||
...registerAsUiLib(components.value, (_root) => {
|
||||
root.value = _root.value;
|
||||
}),
|
||||
THIS_ID: values.STR(flash.id),
|
||||
THIS_URL: values.STR(`${url}/play/${flash.id}`),
|
||||
THIS_ID: values.STR(flash.value.id),
|
||||
THIS_URL: values.STR(`${url}/play/${flash.value.id}`),
|
||||
}, {
|
||||
in: (q) => {
|
||||
return new Promise(ok => {
|
||||
|
|
@ -176,7 +184,7 @@ async function run() {
|
|||
|
||||
let ast;
|
||||
try {
|
||||
ast = parser.parse(flash.script);
|
||||
ast = parser.parse(flash.value.script);
|
||||
} catch (err) {
|
||||
os.alert({
|
||||
type: 'error',
|
||||
|
|
@ -185,7 +193,7 @@ async function run() {
|
|||
return;
|
||||
}
|
||||
try {
|
||||
await aiscript.exec(ast);
|
||||
await aiscript.value.exec(ast);
|
||||
} catch (err) {
|
||||
os.alert({
|
||||
type: 'error',
|
||||
|
|
@ -196,24 +204,24 @@ async function run() {
|
|||
}
|
||||
|
||||
onDeactivated(() => {
|
||||
if (aiscript) aiscript.abort();
|
||||
if (aiscript.value) aiscript.value.abort();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (aiscript) aiscript.abort();
|
||||
if (aiscript.value) aiscript.value.abort();
|
||||
});
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata(computed(() => flash ? {
|
||||
title: flash.title,
|
||||
avatar: flash.user,
|
||||
path: `/play/${flash.id}`,
|
||||
definePageMetadata(computed(() => flash.value ? {
|
||||
title: flash.value.title,
|
||||
avatar: flash.value.user,
|
||||
path: `/play/${flash.value.id}`,
|
||||
share: {
|
||||
title: flash.title,
|
||||
text: flash.summary,
|
||||
title: flash.value.title,
|
||||
text: flash.value.summary,
|
||||
},
|
||||
} : null));
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -65,9 +65,9 @@ function reject(user) {
|
|||
});
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata(computed(() => ({
|
||||
title: i18n.ts.followRequests,
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch } from 'vue';
|
||||
import { computed, watch, ref } from 'vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkTextarea from '@/components/MkTextarea.vue';
|
||||
|
|
@ -56,38 +56,38 @@ const props = defineProps<{
|
|||
postId?: string;
|
||||
}>();
|
||||
|
||||
let init = $ref(null);
|
||||
let files = $ref([]);
|
||||
let description = $ref(null);
|
||||
let title = $ref(null);
|
||||
let isSensitive = $ref(false);
|
||||
const init = ref(null);
|
||||
const files = ref([]);
|
||||
const description = ref(null);
|
||||
const title = ref(null);
|
||||
const isSensitive = ref(false);
|
||||
|
||||
function selectFile(evt) {
|
||||
selectFiles(evt.currentTarget ?? evt.target, null).then(selected => {
|
||||
files = files.concat(selected);
|
||||
files.value = files.value.concat(selected);
|
||||
});
|
||||
}
|
||||
|
||||
function remove(file) {
|
||||
files = files.filter(f => f.id !== file.id);
|
||||
files.value = files.value.filter(f => f.id !== file.id);
|
||||
}
|
||||
|
||||
async function save() {
|
||||
if (props.postId) {
|
||||
await os.apiWithDialog('gallery/posts/update', {
|
||||
postId: props.postId,
|
||||
title: title,
|
||||
description: description,
|
||||
fileIds: files.map(file => file.id),
|
||||
isSensitive: isSensitive,
|
||||
title: title.value,
|
||||
description: description.value,
|
||||
fileIds: files.value.map(file => file.id),
|
||||
isSensitive: isSensitive.value,
|
||||
});
|
||||
router.push(`/gallery/${props.postId}`);
|
||||
} else {
|
||||
const created = await os.apiWithDialog('gallery/posts/create', {
|
||||
title: title,
|
||||
description: description,
|
||||
fileIds: files.map(file => file.id),
|
||||
isSensitive: isSensitive,
|
||||
title: title.value,
|
||||
description: description.value,
|
||||
fileIds: files.value.map(file => file.id),
|
||||
isSensitive: isSensitive.value,
|
||||
});
|
||||
router.push(`/gallery/${created.id}`);
|
||||
}
|
||||
|
|
@ -106,19 +106,19 @@ async function del() {
|
|||
}
|
||||
|
||||
watch(() => props.postId, () => {
|
||||
init = () => props.postId ? os.api('gallery/posts/show', {
|
||||
init.value = () => props.postId ? os.api('gallery/posts/show', {
|
||||
postId: props.postId,
|
||||
}).then(post => {
|
||||
files = post.files;
|
||||
title = post.title;
|
||||
description = post.description;
|
||||
isSensitive = post.isSensitive;
|
||||
files.value = post.files;
|
||||
title.value = post.title;
|
||||
description.value = post.description;
|
||||
isSensitive.value = post.isSensitive;
|
||||
}) : Promise.resolve(null);
|
||||
}, { immediate: true });
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata(computed(() => props.postId ? {
|
||||
title: i18n.ts.edit,
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { watch } from 'vue';
|
||||
import { watch, ref, computed } from 'vue';
|
||||
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
||||
import MkPagination from '@/components/MkPagination.vue';
|
||||
import MkGalleryPostPreview from '@/components/MkGalleryPostPreview.vue';
|
||||
|
|
@ -61,9 +61,9 @@ const props = defineProps<{
|
|||
tag?: string;
|
||||
}>();
|
||||
|
||||
let tab = $ref('explore');
|
||||
let tags = $ref([]);
|
||||
let tagsRef = $ref();
|
||||
const tab = ref('explore');
|
||||
const tags = ref([]);
|
||||
const tagsRef = ref();
|
||||
|
||||
const recentPostsPagination = {
|
||||
endpoint: 'gallery/posts' as const,
|
||||
|
|
@ -82,7 +82,7 @@ const likedPostsPagination = {
|
|||
limit: 5,
|
||||
};
|
||||
|
||||
const tagUsersPagination = $computed(() => ({
|
||||
const tagUsersPagination = computed(() => ({
|
||||
endpoint: 'hashtags/users' as const,
|
||||
limit: 30,
|
||||
params: {
|
||||
|
|
@ -93,10 +93,10 @@ const tagUsersPagination = $computed(() => ({
|
|||
}));
|
||||
|
||||
watch(() => props.tag, () => {
|
||||
if (tagsRef) tagsRef.tags.toggleContent(props.tag == null);
|
||||
if (tagsRef.value) tagsRef.value.tags.toggleContent(props.tag == null);
|
||||
});
|
||||
|
||||
const headerActions = $computed(() => [{
|
||||
const headerActions = computed(() => [{
|
||||
icon: 'ti ti-plus',
|
||||
text: i18n.ts.create,
|
||||
handler: () => {
|
||||
|
|
@ -104,7 +104,7 @@ const headerActions = $computed(() => [{
|
|||
},
|
||||
}]);
|
||||
|
||||
const headerTabs = $computed(() => [{
|
||||
const headerTabs = computed(() => [{
|
||||
key: 'explore',
|
||||
title: i18n.ts.gallery,
|
||||
icon: 'ti ti-icons',
|
||||
|
|
|
|||
|
|
@ -29,7 +29,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<div class="other">
|
||||
<button v-if="$i && $i.id === post.user.id" v-tooltip="i18n.ts.edit" v-click-anime class="_button" @click="edit"><i class="ti ti-pencil ti-fw"></i></button>
|
||||
<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.share" v-click-anime class="_button" @click="share"><i class="ti ti-share 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>
|
||||
</div>
|
||||
</div>
|
||||
<div class="user">
|
||||
|
|
@ -61,7 +62,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch } from 'vue';
|
||||
import { computed, watch, ref } from 'vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import * as os from '@/os.js';
|
||||
import MkContainer from '@/components/MkContainer.vue';
|
||||
|
|
@ -74,6 +75,8 @@ import { i18n } from '@/i18n.js';
|
|||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { isSupportShare } from '@/scripts/navigator.js';
|
||||
import copyToClipboard from '@/scripts/copy-to-clipboard.js';
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
|
|
@ -81,38 +84,43 @@ const props = defineProps<{
|
|||
postId: string;
|
||||
}>();
|
||||
|
||||
let post = $ref(null);
|
||||
let error = $ref(null);
|
||||
const post = ref(null);
|
||||
const error = ref(null);
|
||||
const otherPostsPagination = {
|
||||
endpoint: 'users/gallery/posts' as const,
|
||||
limit: 6,
|
||||
params: computed(() => ({
|
||||
userId: post.user.id,
|
||||
userId: post.value.user.id,
|
||||
})),
|
||||
};
|
||||
|
||||
function fetchPost() {
|
||||
post = null;
|
||||
post.value = null;
|
||||
os.api('gallery/posts/show', {
|
||||
postId: props.postId,
|
||||
}).then(_post => {
|
||||
post = _post;
|
||||
post.value = _post;
|
||||
}).catch(_error => {
|
||||
error = _error;
|
||||
error.value = _error;
|
||||
});
|
||||
}
|
||||
|
||||
function copyLink() {
|
||||
copyToClipboard(`${url}/gallery/${post.value.id}`);
|
||||
os.success();
|
||||
}
|
||||
|
||||
function share() {
|
||||
navigator.share({
|
||||
title: post.title,
|
||||
text: post.description,
|
||||
url: `${url}/gallery/${post.id}`,
|
||||
title: post.value.title,
|
||||
text: post.value.description,
|
||||
url: `${url}/gallery/${post.value.id}`,
|
||||
});
|
||||
}
|
||||
|
||||
function shareWithNote() {
|
||||
os.post({
|
||||
initialText: `${post.title} ${url}/gallery/${post.id}`,
|
||||
initialText: `${post.value.title} ${url}/gallery/${post.value.id}`,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -120,8 +128,8 @@ function like() {
|
|||
os.apiWithDialog('gallery/posts/like', {
|
||||
postId: props.postId,
|
||||
}).then(() => {
|
||||
post.isLiked = true;
|
||||
post.likedCount++;
|
||||
post.value.isLiked = true;
|
||||
post.value.likedCount++;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -134,28 +142,28 @@ async function unlike() {
|
|||
os.apiWithDialog('gallery/posts/unlike', {
|
||||
postId: props.postId,
|
||||
}).then(() => {
|
||||
post.isLiked = false;
|
||||
post.likedCount--;
|
||||
post.value.isLiked = false;
|
||||
post.value.likedCount--;
|
||||
});
|
||||
}
|
||||
|
||||
function edit() {
|
||||
router.push(`/gallery/${post.id}/edit`);
|
||||
router.push(`/gallery/${post.value.id}/edit`);
|
||||
}
|
||||
|
||||
watch(() => props.postId, fetchPost, { immediate: true });
|
||||
|
||||
const headerActions = $computed(() => [{
|
||||
const headerActions = computed(() => [{
|
||||
icon: 'ti ti-pencil',
|
||||
text: i18n.ts.edit,
|
||||
handler: edit,
|
||||
}]);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata(computed(() => post ? {
|
||||
title: post.title,
|
||||
avatar: post.user,
|
||||
definePageMetadata(computed(() => post.value ? {
|
||||
title: post.value.title,
|
||||
avatar: post.value.user,
|
||||
} : null));
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { } from 'vue';
|
||||
import { ref, computed } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import MkChart from '@/components/MkChart.vue';
|
||||
import MkObjectView from '@/components/MkObjectView.vue';
|
||||
|
|
@ -142,14 +142,14 @@ const props = defineProps<{
|
|||
host: string;
|
||||
}>();
|
||||
|
||||
let tab = $ref('overview');
|
||||
let chartSrc = $ref('instance-requests');
|
||||
let meta = $ref<Misskey.entities.AdminInstanceMetadata | null>(null);
|
||||
let instance = $ref<Misskey.entities.Instance | null>(null);
|
||||
let suspended = $ref(false);
|
||||
let isBlocked = $ref(false);
|
||||
let isSilenced = $ref(false);
|
||||
let faviconUrl = $ref<string | null>(null);
|
||||
const tab = ref('overview');
|
||||
const chartSrc = ref('instance-requests');
|
||||
const meta = ref<Misskey.entities.AdminMetaResponse | null>(null);
|
||||
const instance = ref<Misskey.entities.FederationInstance | null>(null);
|
||||
const suspended = ref(false);
|
||||
const isBlocked = ref(false);
|
||||
const isSilenced = ref(false);
|
||||
const faviconUrl = ref<string | null>(null);
|
||||
|
||||
const usersPagination = {
|
||||
endpoint: iAmModerator ? 'admin/show-users' : 'users' as const,
|
||||
|
|
@ -164,47 +164,48 @@ const usersPagination = {
|
|||
|
||||
async function fetch(): Promise<void> {
|
||||
if (iAmAdmin) {
|
||||
meta = await os.api('admin/meta');
|
||||
meta.value = await os.api('admin/meta');
|
||||
}
|
||||
instance = await os.api('federation/show-instance', {
|
||||
instance.value = await os.api('federation/show-instance', {
|
||||
host: props.host,
|
||||
});
|
||||
suspended = instance.isSuspended;
|
||||
isBlocked = instance.isBlocked;
|
||||
isSilenced = instance.isSilenced;
|
||||
faviconUrl = getProxiedImageUrlNullable(instance.faviconUrl, 'preview') ?? getProxiedImageUrlNullable(instance.iconUrl, 'preview');
|
||||
suspended.value = instance.value?.isSuspended ?? false;
|
||||
isBlocked.value = instance.value?.isBlocked ?? false;
|
||||
isSilenced.value = instance.value?.isSilenced ?? false;
|
||||
faviconUrl.value = getProxiedImageUrlNullable(instance.value?.faviconUrl, 'preview') ?? getProxiedImageUrlNullable(instance.value?.iconUrl, 'preview');
|
||||
}
|
||||
|
||||
async function toggleBlock(): Promise<void> {
|
||||
if (!meta) throw new Error('No meta?');
|
||||
if (!instance) throw new Error('No instance?');
|
||||
const { host } = instance;
|
||||
if (!meta.value) throw new Error('No meta?');
|
||||
if (!instance.value) throw new Error('No instance?');
|
||||
const { host } = instance.value;
|
||||
await os.api('admin/update-meta', {
|
||||
blockedHosts: isBlocked ? meta.blockedHosts.concat([host]) : meta.blockedHosts.filter(x => x !== host),
|
||||
blockedHosts: isBlocked.value ? meta.value.blockedHosts.concat([host]) : meta.value.blockedHosts.filter(x => x !== host),
|
||||
});
|
||||
}
|
||||
|
||||
async function toggleSilenced(): Promise<void> {
|
||||
if (!meta) throw new Error('No meta?');
|
||||
if (!instance) throw new Error('No instance?');
|
||||
const { host } = instance;
|
||||
if (!meta.value) throw new Error('No meta?');
|
||||
if (!instance.value) throw new Error('No instance?');
|
||||
const { host } = instance.value;
|
||||
const silencedHosts = meta.value.silencedHosts ?? [];
|
||||
await os.api('admin/update-meta', {
|
||||
silencedHosts: isSilenced ? meta.silencedHosts.concat([host]) : meta.silencedHosts.filter(x => x !== host),
|
||||
silencedHosts: isSilenced.value ? silencedHosts.concat([host]) : silencedHosts.filter(x => x !== host),
|
||||
});
|
||||
}
|
||||
|
||||
async function toggleSuspend(): Promise<void> {
|
||||
if (!instance) throw new Error('No instance?');
|
||||
if (!instance.value) throw new Error('No instance?');
|
||||
await os.api('admin/federation/update-instance', {
|
||||
host: instance.host,
|
||||
isSuspended: suspended,
|
||||
host: instance.value.host,
|
||||
isSuspended: suspended.value,
|
||||
});
|
||||
}
|
||||
|
||||
function refreshMetadata(): void {
|
||||
if (!instance) throw new Error('No instance?');
|
||||
if (!instance.value) throw new Error('No instance?');
|
||||
os.api('admin/federation/refresh-remote-instance-metadata', {
|
||||
host: instance.host,
|
||||
host: instance.value.host,
|
||||
});
|
||||
os.alert({
|
||||
text: 'Refresh requested',
|
||||
|
|
@ -213,7 +214,7 @@ function refreshMetadata(): void {
|
|||
|
||||
fetch();
|
||||
|
||||
const headerActions = $computed(() => [{
|
||||
const headerActions = computed(() => [{
|
||||
text: `https://${props.host}`,
|
||||
icon: 'ti ti-external-link',
|
||||
handler: () => {
|
||||
|
|
@ -221,7 +222,7 @@ const headerActions = $computed(() => [{
|
|||
},
|
||||
}]);
|
||||
|
||||
const headerTabs = $computed(() => [{
|
||||
const headerTabs = computed(() => [{
|
||||
key: 'overview',
|
||||
title: i18n.ts.overview,
|
||||
icon: 'ti ti-info-circle',
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<MkPagination ref="pagingComponent" :pagination="pagination">
|
||||
<template #default="{ items }">
|
||||
<div class="_gaps_s">
|
||||
<MkInviteCode v-for="item in (items as Misskey.entities.Invite[])" :key="item.id" :invite="item" :onDeleted="deleted"/>
|
||||
<MkInviteCode v-for="item in (items as Misskey.entities.InviteCode[])" :key="item.id" :invite="item" :onDeleted="deleted"/>
|
||||
</div>
|
||||
</template>
|
||||
</MkPagination>
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { watch, computed } from 'vue';
|
||||
import { watch, computed, ref } from 'vue';
|
||||
import * as os from '@/os.js';
|
||||
import { userPage } from '@/filters/user.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
|
@ -47,41 +47,41 @@ const props = defineProps<{
|
|||
listId: string;
|
||||
}>();
|
||||
|
||||
let list = $ref(null);
|
||||
let error = $ref();
|
||||
let users = $ref([]);
|
||||
const list = ref(null);
|
||||
const error = ref();
|
||||
const users = ref([]);
|
||||
|
||||
function fetchList(): void {
|
||||
os.api('users/lists/show', {
|
||||
listId: props.listId,
|
||||
forPublic: true,
|
||||
}).then(_list => {
|
||||
list = _list;
|
||||
list.value = _list;
|
||||
os.api('users/show', {
|
||||
userIds: list.userIds,
|
||||
userIds: list.value.userIds,
|
||||
}).then(_users => {
|
||||
users = _users;
|
||||
users.value = _users;
|
||||
});
|
||||
}).catch(err => {
|
||||
error = err;
|
||||
error.value = err;
|
||||
});
|
||||
}
|
||||
|
||||
function like() {
|
||||
os.apiWithDialog('users/lists/favorite', {
|
||||
listId: list.id,
|
||||
listId: list.value.id,
|
||||
}).then(() => {
|
||||
list.isLiked = true;
|
||||
list.likedCount++;
|
||||
list.value.isLiked = true;
|
||||
list.value.likedCount++;
|
||||
});
|
||||
}
|
||||
|
||||
function unlike() {
|
||||
os.apiWithDialog('users/lists/unfavorite', {
|
||||
listId: list.id,
|
||||
listId: list.value.id,
|
||||
}).then(() => {
|
||||
list.isLiked = false;
|
||||
list.likedCount--;
|
||||
list.value.isLiked = false;
|
||||
list.value.likedCount--;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -90,17 +90,17 @@ async function create() {
|
|||
title: i18n.ts.enterListName,
|
||||
});
|
||||
if (canceled) return;
|
||||
await os.apiWithDialog('users/lists/create-from-public', { name: name, listId: list.id });
|
||||
await os.apiWithDialog('users/lists/create-from-public', { name: name, listId: list.value.id });
|
||||
}
|
||||
|
||||
watch(() => props.listId, fetchList, { immediate: true });
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata(computed(() => list ? {
|
||||
title: list.name,
|
||||
definePageMetadata(computed(() => list.value ? {
|
||||
title: list.value.name,
|
||||
icon: 'ti ti-list',
|
||||
} : null));
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { } from 'vue';
|
||||
import { ref, computed } from 'vue';
|
||||
import MkSignin from '@/components/MkSignin.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import * as os from '@/os.js';
|
||||
|
|
@ -61,10 +61,10 @@ const props = defineProps<{
|
|||
|
||||
const _permissions = props.permission ? props.permission.split(',') : [];
|
||||
|
||||
let state = $ref<string | null>(null);
|
||||
const state = ref<string | null>(null);
|
||||
|
||||
async function accept(): Promise<void> {
|
||||
state = 'waiting';
|
||||
state.value = 'waiting';
|
||||
await os.api('miauth/gen-token', {
|
||||
session: props.session,
|
||||
name: props.name,
|
||||
|
|
@ -72,7 +72,7 @@ async function accept(): Promise<void> {
|
|||
permission: _permissions,
|
||||
});
|
||||
|
||||
state = 'accepted';
|
||||
state.value = 'accepted';
|
||||
if (props.callback) {
|
||||
const cbUrl = new URL(props.callback);
|
||||
if (['javascript:', 'file:', 'data:', 'mailto:', 'tel:'].includes(cbUrl.protocol)) throw new Error('invalid url');
|
||||
|
|
@ -82,16 +82,16 @@ async function accept(): Promise<void> {
|
|||
}
|
||||
|
||||
function deny(): void {
|
||||
state = 'denied';
|
||||
state.value = 'denied';
|
||||
}
|
||||
|
||||
function onLogin(res): void {
|
||||
login(res.i);
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: 'MiAuth',
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import XAntenna from './editor.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
|
|
@ -18,7 +19,7 @@ import { antennasCache } from '@/cache.js';
|
|||
|
||||
const router = useRouter();
|
||||
|
||||
let draft = $ref({
|
||||
const draft = ref({
|
||||
name: '',
|
||||
src: 'all',
|
||||
userListId: null,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import XAntenna from './editor.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
|
@ -19,7 +20,7 @@ import { antennasCache } from '@/cache';
|
|||
|
||||
const router = useRouter();
|
||||
|
||||
let antenna: any = $ref(null);
|
||||
const antenna = ref<any>(null);
|
||||
|
||||
const props = defineProps<{
|
||||
antennaId: string
|
||||
|
|
@ -31,7 +32,7 @@ function onAntennaUpdated() {
|
|||
}
|
||||
|
||||
os.api('antennas/show', { antennaId: props.antennaId }).then((antennaResponse) => {
|
||||
antenna = antennaResponse;
|
||||
antenna.value = antennaResponse;
|
||||
});
|
||||
|
||||
definePageMetadata({
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { watch } from 'vue';
|
||||
import { watch, ref } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
|
|
@ -69,38 +69,38 @@ const emit = defineEmits<{
|
|||
(ev: 'deleted'): void,
|
||||
}>();
|
||||
|
||||
let name: string = $ref(props.antenna.name);
|
||||
let src: string = $ref(props.antenna.src);
|
||||
let userListId: any = $ref(props.antenna.userListId);
|
||||
let users: string = $ref(props.antenna.users.join('\n'));
|
||||
let keywords: string = $ref(props.antenna.keywords.map(x => x.join(' ')).join('\n'));
|
||||
let excludeKeywords: string = $ref(props.antenna.excludeKeywords.map(x => x.join(' ')).join('\n'));
|
||||
let caseSensitive: boolean = $ref(props.antenna.caseSensitive);
|
||||
let localOnly: boolean = $ref(props.antenna.localOnly);
|
||||
let withReplies: boolean = $ref(props.antenna.withReplies);
|
||||
let withFile: boolean = $ref(props.antenna.withFile);
|
||||
let notify: boolean = $ref(props.antenna.notify);
|
||||
let userLists: any = $ref(null);
|
||||
const name = ref<string>(props.antenna.name);
|
||||
const src = ref<string>(props.antenna.src);
|
||||
const userListId = ref<any>(props.antenna.userListId);
|
||||
const users = ref<string>(props.antenna.users.join('\n'));
|
||||
const keywords = ref<string>(props.antenna.keywords.map(x => x.join(' ')).join('\n'));
|
||||
const excludeKeywords = ref<string>(props.antenna.excludeKeywords.map(x => x.join(' ')).join('\n'));
|
||||
const caseSensitive = ref<boolean>(props.antenna.caseSensitive);
|
||||
const localOnly = ref<boolean>(props.antenna.localOnly);
|
||||
const withReplies = ref<boolean>(props.antenna.withReplies);
|
||||
const withFile = ref<boolean>(props.antenna.withFile);
|
||||
const notify = ref<boolean>(props.antenna.notify);
|
||||
const userLists = ref<any>(null);
|
||||
|
||||
watch(() => src, async () => {
|
||||
if (src === 'list' && userLists === null) {
|
||||
userLists = await os.api('users/lists/list');
|
||||
watch(() => src.value, async () => {
|
||||
if (src.value === 'list' && userLists.value === null) {
|
||||
userLists.value = await os.api('users/lists/list');
|
||||
}
|
||||
});
|
||||
|
||||
async function saveAntenna() {
|
||||
const antennaData = {
|
||||
name,
|
||||
src,
|
||||
userListId,
|
||||
withReplies,
|
||||
withFile,
|
||||
notify,
|
||||
caseSensitive,
|
||||
localOnly,
|
||||
users: users.trim().split('\n').map(x => x.trim()),
|
||||
keywords: keywords.trim().split('\n').map(x => x.trim().split(' ')),
|
||||
excludeKeywords: excludeKeywords.trim().split('\n').map(x => x.trim().split(' ')),
|
||||
name: name.value,
|
||||
src: src.value,
|
||||
userListId: userListId.value,
|
||||
withReplies: withReplies.value,
|
||||
withFile: withFile.value,
|
||||
notify: notify.value,
|
||||
caseSensitive: caseSensitive.value,
|
||||
localOnly: localOnly.value,
|
||||
users: users.value.trim().split('\n').map(x => x.trim()),
|
||||
keywords: keywords.value.trim().split('\n').map(x => x.trim().split(' ')),
|
||||
excludeKeywords: excludeKeywords.value.trim().split('\n').map(x => x.trim().split(' ')),
|
||||
};
|
||||
|
||||
if (props.antenna.id == null) {
|
||||
|
|
@ -130,9 +130,9 @@ async function deleteAntenna() {
|
|||
|
||||
function addUser() {
|
||||
os.selectUser().then(user => {
|
||||
users = users.trim();
|
||||
users += '\n@' + Misskey.acct.toString(user as any);
|
||||
users = users.trim();
|
||||
users.value = users.value.trim();
|
||||
users.value += '\n@' + Misskey.acct.toString(user as any);
|
||||
users.value = users.value.trim();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -28,14 +28,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onActivated } from 'vue';
|
||||
import { onActivated, computed } from 'vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
import { antennasCache } from '@/cache';
|
||||
import { infoImageUrl } from '@/instance.js';
|
||||
|
||||
const antennas = $computed(() => antennasCache.value.value ?? []);
|
||||
const antennas = computed(() => antennasCache.value.value ?? []);
|
||||
|
||||
function fetch() {
|
||||
antennasCache.fetch();
|
||||
|
|
@ -43,7 +43,7 @@ function fetch() {
|
|||
|
||||
fetch();
|
||||
|
||||
const headerActions = $computed(() => [{
|
||||
const headerActions = computed(() => [{
|
||||
asFullButton: true,
|
||||
icon: 'ti ti-refresh',
|
||||
text: i18n.ts.reload,
|
||||
|
|
@ -53,7 +53,7 @@ const headerActions = $computed(() => [{
|
|||
},
|
||||
}]);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.manageAntennas,
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { watch } from 'vue';
|
||||
import { watch, ref, shallowRef, computed } from 'vue';
|
||||
import MkPagination from '@/components/MkPagination.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkClipPreview from '@/components/MkClipPreview.vue';
|
||||
|
|
@ -41,13 +41,13 @@ const pagination = {
|
|||
limit: 10,
|
||||
};
|
||||
|
||||
let tab = $ref('my');
|
||||
let favorites = $ref();
|
||||
const tab = ref('my');
|
||||
const favorites = ref();
|
||||
|
||||
const pagingComponent = $shallowRef<InstanceType<typeof MkPagination>>();
|
||||
const pagingComponent = shallowRef<InstanceType<typeof MkPagination>>();
|
||||
|
||||
watch($$(tab), async () => {
|
||||
favorites = await os.api('clips/my-favorites');
|
||||
watch(tab, async () => {
|
||||
favorites.value = await os.api('clips/my-favorites');
|
||||
});
|
||||
|
||||
async function create() {
|
||||
|
|
@ -74,20 +74,20 @@ async function create() {
|
|||
|
||||
clipsCache.delete();
|
||||
|
||||
pagingComponent.reload();
|
||||
pagingComponent.value.reload();
|
||||
}
|
||||
|
||||
function onClipCreated() {
|
||||
pagingComponent.reload();
|
||||
pagingComponent.value.reload();
|
||||
}
|
||||
|
||||
function onClipDeleted() {
|
||||
pagingComponent.reload();
|
||||
pagingComponent.value.reload();
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => [{
|
||||
const headerTabs = computed(() => [{
|
||||
key: 'my',
|
||||
title: i18n.ts.myClips,
|
||||
icon: 'ti ti-paperclip',
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onActivated } from 'vue';
|
||||
import { onActivated, computed } from 'vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkAvatars from '@/components/MkAvatars.vue';
|
||||
import * as os from '@/os.js';
|
||||
|
|
@ -39,7 +39,7 @@ import { userListsCache } from '@/cache';
|
|||
import { infoImageUrl } from '@/instance.js';
|
||||
import { $i } from '@/account.js';
|
||||
|
||||
const items = $computed(() => userListsCache.value.value ?? []);
|
||||
const items = computed(() => userListsCache.value.value ?? []);
|
||||
|
||||
function fetch() {
|
||||
userListsCache.fetch();
|
||||
|
|
@ -57,7 +57,7 @@ async function create() {
|
|||
fetch();
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => [{
|
||||
const headerActions = computed(() => [{
|
||||
asFullButton: true,
|
||||
icon: 'ti ti-refresh',
|
||||
text: i18n.ts.reload,
|
||||
|
|
@ -67,7 +67,7 @@ const headerActions = $computed(() => [{
|
|||
},
|
||||
}]);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.manageLists,
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ const props = defineProps<{
|
|||
}>();
|
||||
|
||||
const paginationEl = ref<InstanceType<typeof MkPagination>>();
|
||||
let list = $ref<Misskey.entities.UserList | null>(null);
|
||||
const list = ref<Misskey.entities.UserList | null>(null);
|
||||
const isPublic = ref(false);
|
||||
const name = ref('');
|
||||
const membershipsPagination = {
|
||||
|
|
@ -94,17 +94,17 @@ function fetchList() {
|
|||
os.api('users/lists/show', {
|
||||
listId: props.listId,
|
||||
}).then(_list => {
|
||||
list = _list;
|
||||
name.value = list.name;
|
||||
isPublic.value = list.isPublic;
|
||||
list.value = _list;
|
||||
name.value = list.value.name;
|
||||
isPublic.value = list.value.isPublic;
|
||||
});
|
||||
}
|
||||
|
||||
function addUser() {
|
||||
os.selectUser().then(user => {
|
||||
if (!list) return;
|
||||
if (!list.value) return;
|
||||
os.apiWithDialog('users/lists/push', {
|
||||
listId: list.id,
|
||||
listId: list.value.id,
|
||||
userId: user.id,
|
||||
}).then(() => {
|
||||
paginationEl.value.reload();
|
||||
|
|
@ -118,9 +118,9 @@ async function removeUser(item, ev) {
|
|||
icon: 'ti ti-x',
|
||||
danger: true,
|
||||
action: async () => {
|
||||
if (!list) return;
|
||||
if (!list.value) return;
|
||||
os.api('users/lists/pull', {
|
||||
listId: list.id,
|
||||
listId: list.value.id,
|
||||
userId: item.userId,
|
||||
}).then(() => {
|
||||
paginationEl.value.removeItem(item.id);
|
||||
|
|
@ -135,7 +135,7 @@ async function showMembershipMenu(item, ev) {
|
|||
icon: item.withReplies ? 'ti ti-messages-off' : 'ti ti-messages',
|
||||
action: async () => {
|
||||
os.api('users/lists/update-membership', {
|
||||
listId: list.id,
|
||||
listId: list.value.id,
|
||||
userId: item.userId,
|
||||
withReplies: !item.withReplies,
|
||||
}).then(() => {
|
||||
|
|
@ -149,42 +149,42 @@ async function showMembershipMenu(item, ev) {
|
|||
}
|
||||
|
||||
async function deleteList() {
|
||||
if (!list) return;
|
||||
if (!list.value) return;
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'warning',
|
||||
text: i18n.t('removeAreYouSure', { x: list.name }),
|
||||
text: i18n.t('removeAreYouSure', { x: list.value.name }),
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
await os.apiWithDialog('users/lists/delete', {
|
||||
listId: list.id,
|
||||
listId: list.value.id,
|
||||
});
|
||||
userListsCache.delete();
|
||||
mainRouter.push('/my/lists');
|
||||
}
|
||||
|
||||
async function updateSettings() {
|
||||
if (!list) return;
|
||||
if (!list.value) return;
|
||||
await os.apiWithDialog('users/lists/update', {
|
||||
listId: list.id,
|
||||
listId: list.value.id,
|
||||
name: name.value,
|
||||
isPublic: isPublic.value,
|
||||
});
|
||||
|
||||
userListsCache.delete();
|
||||
|
||||
list.name = name.value;
|
||||
list.isPublic = isPublic.value;
|
||||
list.value.name = name.value;
|
||||
list.value.isPublic = isPublic.value;
|
||||
}
|
||||
|
||||
watch(() => props.listId, fetchList, { immediate: true });
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata(computed(() => list ? {
|
||||
title: list.name,
|
||||
definePageMetadata(computed(() => list.value ? {
|
||||
title: list.value.name,
|
||||
icon: 'ti ti-list',
|
||||
} : null));
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
import { pleaseLogin } from '@/scripts/please-login.js';
|
||||
|
|
@ -26,9 +27,9 @@ if (props.showLoginPopup) {
|
|||
pleaseLogin('/');
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.notFound,
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch } from 'vue';
|
||||
import { computed, watch, ref } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import MkNoteDetailed from '@/components/MkNoteDetailed.vue';
|
||||
import MkNotes from '@/components/MkNotes.vue';
|
||||
|
|
@ -61,18 +61,18 @@ const props = defineProps<{
|
|||
noteId: string;
|
||||
}>();
|
||||
|
||||
let note = $ref<null | Misskey.entities.Note>();
|
||||
let clips = $ref();
|
||||
let showPrev = $ref(false);
|
||||
let showNext = $ref(false);
|
||||
let error = $ref();
|
||||
const note = ref<null | Misskey.entities.Note>();
|
||||
const clips = ref();
|
||||
const showPrev = ref(false);
|
||||
const showNext = ref(false);
|
||||
const error = ref();
|
||||
|
||||
const prevPagination = {
|
||||
endpoint: 'users/notes' as const,
|
||||
limit: 10,
|
||||
params: computed(() => note ? ({
|
||||
userId: note.userId,
|
||||
untilId: note.id,
|
||||
params: computed(() => note.value ? ({
|
||||
userId: note.value.userId,
|
||||
untilId: note.value.id,
|
||||
}) : null),
|
||||
};
|
||||
|
||||
|
|
@ -80,30 +80,30 @@ const nextPagination = {
|
|||
reversed: true,
|
||||
endpoint: 'users/notes' as const,
|
||||
limit: 10,
|
||||
params: computed(() => note ? ({
|
||||
userId: note.userId,
|
||||
sinceId: note.id,
|
||||
params: computed(() => note.value ? ({
|
||||
userId: note.value.userId,
|
||||
sinceId: note.value.id,
|
||||
}) : null),
|
||||
};
|
||||
|
||||
function fetchNote() {
|
||||
showPrev = false;
|
||||
showNext = false;
|
||||
note = null;
|
||||
showPrev.value = false;
|
||||
showNext.value = false;
|
||||
note.value = null;
|
||||
os.api('notes/show', {
|
||||
noteId: props.noteId,
|
||||
}).then(res => {
|
||||
note = res;
|
||||
note.value = res;
|
||||
// 古いノートは被クリップ数をカウントしていないので、2023-10-01以前のものは強制的にnotes/clipsを叩く
|
||||
if (note.clippedCount > 0 || new Date(note.createdAt).getTime() < new Date('2023-10-01').getTime()) {
|
||||
if (note.value.clippedCount > 0 || new Date(note.value.createdAt).getTime() < new Date('2023-10-01').getTime()) {
|
||||
os.api('notes/clips', {
|
||||
noteId: note.id,
|
||||
noteId: note.value.id,
|
||||
}).then((_clips) => {
|
||||
clips = _clips;
|
||||
clips.value = _clips;
|
||||
});
|
||||
}
|
||||
}).catch(err => {
|
||||
error = err;
|
||||
error.value = err;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -111,18 +111,18 @@ watch(() => props.noteId, fetchNote, {
|
|||
immediate: true,
|
||||
});
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata(computed(() => note ? {
|
||||
definePageMetadata(computed(() => note.value ? {
|
||||
title: i18n.ts.note,
|
||||
subtitle: dateString(note.createdAt),
|
||||
avatar: note.user,
|
||||
path: `/notes/${note.id}`,
|
||||
subtitle: dateString(note.value.createdAt),
|
||||
avatar: note.value.user,
|
||||
path: `/notes/${note.value.id}`,
|
||||
share: {
|
||||
title: i18n.t('noteOf', { user: note.user.name }),
|
||||
text: note.text,
|
||||
title: i18n.t('noteOf', { user: note.value.user.name }),
|
||||
text: note.value.text,
|
||||
},
|
||||
} : null));
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import XNotifications from '@/components/MkNotifications.vue';
|
||||
import MkNotes from '@/components/MkNotes.vue';
|
||||
import * as os from '@/os.js';
|
||||
|
|
@ -29,9 +29,9 @@ import { i18n } from '@/i18n.js';
|
|||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
import { notificationTypes } from '@/const.js';
|
||||
|
||||
let tab = $ref('all');
|
||||
let includeTypes = $ref<string[] | null>(null);
|
||||
const excludeTypes = $computed(() => includeTypes ? notificationTypes.filter(t => !includeTypes.includes(t)) : null);
|
||||
const tab = ref('all');
|
||||
const includeTypes = ref<string[] | null>(null);
|
||||
const excludeTypes = computed(() => includeTypes.value ? notificationTypes.filter(t => !includeTypes.value.includes(t)) : null);
|
||||
|
||||
const mentionsPagination = {
|
||||
endpoint: 'notes/mentions' as const,
|
||||
|
|
@ -49,27 +49,27 @@ const directNotesPagination = {
|
|||
function setFilter(ev) {
|
||||
const typeItems = notificationTypes.map(t => ({
|
||||
text: i18n.t(`_notification._types.${t}`),
|
||||
active: includeTypes && includeTypes.includes(t),
|
||||
active: includeTypes.value && includeTypes.value.includes(t),
|
||||
action: () => {
|
||||
includeTypes = [t];
|
||||
includeTypes.value = [t];
|
||||
},
|
||||
}));
|
||||
const items = includeTypes != null ? [{
|
||||
const items = includeTypes.value != null ? [{
|
||||
icon: 'ti ti-x',
|
||||
text: i18n.ts.clear,
|
||||
action: () => {
|
||||
includeTypes = null;
|
||||
includeTypes.value = null;
|
||||
},
|
||||
}, null, ...typeItems] : typeItems;
|
||||
os.popupMenu(items, ev.currentTarget ?? ev.target);
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => [tab === 'all' ? {
|
||||
const headerActions = computed(() => [tab.value === 'all' ? {
|
||||
text: i18n.ts.filter,
|
||||
icon: 'ti ti-filter',
|
||||
highlighted: includeTypes != null,
|
||||
highlighted: includeTypes.value != null,
|
||||
handler: setFilter,
|
||||
} : undefined, tab === 'all' ? {
|
||||
} : undefined, tab.value === 'all' ? {
|
||||
text: i18n.ts.markAllAsRead,
|
||||
icon: 'ti ti-check',
|
||||
handler: () => {
|
||||
|
|
@ -77,7 +77,7 @@ const headerActions = $computed(() => [tab === 'all' ? {
|
|||
},
|
||||
} : undefined].filter(x => x !== undefined));
|
||||
|
||||
const headerTabs = $computed(() => [{
|
||||
const headerTabs = computed(() => [{
|
||||
key: 'all',
|
||||
title: i18n.ts.all,
|
||||
icon: 'ti ti-point',
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<script lang="ts" setup>
|
||||
/* eslint-disable vue/no-mutating-props */
|
||||
import { onMounted } from 'vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import XContainer from '../page-editor.container.vue';
|
||||
import MkDriveFileThumbnail from '@/components/MkDriveFileThumbnail.vue';
|
||||
import * as os from '@/os.js';
|
||||
|
|
@ -35,14 +35,14 @@ const emit = defineEmits<{
|
|||
(ev: 'update:modelValue', value: any): void;
|
||||
}>();
|
||||
|
||||
let file: any = $ref(null);
|
||||
const file = ref<any>(null);
|
||||
|
||||
async function choose() {
|
||||
os.selectDriveFile(false).then((fileResponse) => {
|
||||
file = fileResponse[0];
|
||||
file.value = fileResponse[0];
|
||||
emit('update:modelValue', {
|
||||
...props.modelValue,
|
||||
fileId: file.id,
|
||||
fileId: file.value.id,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -54,7 +54,7 @@ onMounted(async () => {
|
|||
os.api('drive/files/show', {
|
||||
fileId: props.modelValue.fileId,
|
||||
}).then(fileResponse => {
|
||||
file = fileResponse;
|
||||
file.value = fileResponse;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<script lang="ts" setup>
|
||||
/* eslint-disable vue/no-mutating-props */
|
||||
import { watch } from 'vue';
|
||||
import { watch, ref } from 'vue';
|
||||
import XContainer from '../page-editor.container.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
|
|
@ -40,19 +40,19 @@ const emit = defineEmits<{
|
|||
(ev: 'update:modelValue', value: any): void;
|
||||
}>();
|
||||
|
||||
let id: any = $ref(props.modelValue.note);
|
||||
let note: any = $ref(null);
|
||||
const id = ref<any>(props.modelValue.note);
|
||||
const note = ref<any>(null);
|
||||
|
||||
watch($$(id), async () => {
|
||||
if (id && (id.startsWith('http://') || id.startsWith('https://'))) {
|
||||
id = (id.endsWith('/') ? id.slice(0, -1) : id).split('/').pop();
|
||||
watch(id, async () => {
|
||||
if (id.value && (id.value.startsWith('http://') || id.value.startsWith('https://'))) {
|
||||
id.value = (id.value.endsWith('/') ? id.value.slice(0, -1) : id.value).split('/').pop();
|
||||
}
|
||||
|
||||
emit('update:modelValue', {
|
||||
...props.modelValue,
|
||||
note: id,
|
||||
note: id.value,
|
||||
});
|
||||
note = await os.api('notes/show', { noteId: id });
|
||||
note.value = await os.api('notes/show', { noteId: id.value });
|
||||
}, {
|
||||
immediate: true,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<script lang="ts" setup>
|
||||
/* eslint-disable vue/no-mutating-props */
|
||||
import { defineAsyncComponent, inject, onMounted, watch } from 'vue';
|
||||
import { defineAsyncComponent, inject, onMounted, watch, ref } from 'vue';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import XContainer from '../page-editor.container.vue';
|
||||
import * as os from '@/os.js';
|
||||
|
|
@ -42,12 +42,12 @@ const emit = defineEmits<{
|
|||
(ev: 'update:modelValue', value: any): void;
|
||||
}>();
|
||||
|
||||
const children = $ref(deepClone(props.modelValue.children ?? []));
|
||||
const children = ref(deepClone(props.modelValue.children ?? []));
|
||||
|
||||
watch($$(children), () => {
|
||||
watch(children, () => {
|
||||
emit('update:modelValue', {
|
||||
...props.modelValue,
|
||||
children,
|
||||
children: children.value,
|
||||
});
|
||||
}, {
|
||||
deep: true,
|
||||
|
|
@ -75,7 +75,7 @@ async function add() {
|
|||
if (canceled) return;
|
||||
|
||||
const id = uuid();
|
||||
children.push({ id, type });
|
||||
children.value.push({ id, type });
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<script lang="ts" setup>
|
||||
/* eslint-disable vue/no-mutating-props */
|
||||
import { watch } from 'vue';
|
||||
import { watch, ref } from 'vue';
|
||||
import XContainer from '../page-editor.container.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
||||
|
|
@ -28,12 +28,12 @@ const emit = defineEmits<{
|
|||
(ev: 'update:modelValue', value: any): void;
|
||||
}>();
|
||||
|
||||
const text = $ref(props.modelValue.text ?? '');
|
||||
const text = ref(props.modelValue.text ?? '');
|
||||
|
||||
watch($$(text), () => {
|
||||
watch(text, () => {
|
||||
emit('update:modelValue', {
|
||||
...props.modelValue,
|
||||
text,
|
||||
text: text.value,
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, provide, watch } from 'vue';
|
||||
import { computed, provide, watch, ref } from 'vue';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import XBlocks from './page-editor.blocks.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
|
|
@ -82,47 +82,47 @@ const props = defineProps<{
|
|||
initUser?: string;
|
||||
}>();
|
||||
|
||||
let tab = $ref('settings');
|
||||
let author = $ref($i);
|
||||
let readonly = $ref(false);
|
||||
let page = $ref(null);
|
||||
let pageId = $ref(null);
|
||||
let currentName = $ref(null);
|
||||
let title = $ref('');
|
||||
let summary = $ref(null);
|
||||
let name = $ref(Date.now().toString());
|
||||
let eyeCatchingImage = $ref(null);
|
||||
let eyeCatchingImageId = $ref(null);
|
||||
let font = $ref('sans-serif');
|
||||
let content = $ref([]);
|
||||
let alignCenter = $ref(false);
|
||||
let hideTitleWhenPinned = $ref(false);
|
||||
const tab = ref('settings');
|
||||
const author = ref($i);
|
||||
const readonly = ref(false);
|
||||
const page = ref(null);
|
||||
const pageId = ref(null);
|
||||
const currentName = ref(null);
|
||||
const title = ref('');
|
||||
const summary = ref(null);
|
||||
const name = ref(Date.now().toString());
|
||||
const eyeCatchingImage = ref(null);
|
||||
const eyeCatchingImageId = ref(null);
|
||||
const font = ref('sans-serif');
|
||||
const content = ref([]);
|
||||
const alignCenter = ref(false);
|
||||
const hideTitleWhenPinned = ref(false);
|
||||
|
||||
provide('readonly', readonly);
|
||||
provide('readonly', readonly.value);
|
||||
provide('getPageBlockList', getPageBlockList);
|
||||
|
||||
watch($$(eyeCatchingImageId), async () => {
|
||||
if (eyeCatchingImageId == null) {
|
||||
eyeCatchingImage = null;
|
||||
watch(eyeCatchingImageId, async () => {
|
||||
if (eyeCatchingImageId.value == null) {
|
||||
eyeCatchingImage.value = null;
|
||||
} else {
|
||||
eyeCatchingImage = await os.api('drive/files/show', {
|
||||
fileId: eyeCatchingImageId,
|
||||
eyeCatchingImage.value = await os.api('drive/files/show', {
|
||||
fileId: eyeCatchingImageId.value,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function getSaveOptions() {
|
||||
return {
|
||||
title: title.trim(),
|
||||
name: name.trim(),
|
||||
summary: summary,
|
||||
font: font,
|
||||
title: title.value.trim(),
|
||||
name: name.value.trim(),
|
||||
summary: summary.value,
|
||||
font: font.value,
|
||||
script: '',
|
||||
hideTitleWhenPinned: hideTitleWhenPinned,
|
||||
alignCenter: alignCenter,
|
||||
content: content,
|
||||
hideTitleWhenPinned: hideTitleWhenPinned.value,
|
||||
alignCenter: alignCenter.value,
|
||||
content: content.value,
|
||||
variables: [],
|
||||
eyeCatchingImageId: eyeCatchingImageId,
|
||||
eyeCatchingImageId: eyeCatchingImageId.value,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -146,11 +146,11 @@ function save() {
|
|||
}
|
||||
};
|
||||
|
||||
if (pageId) {
|
||||
options.pageId = pageId;
|
||||
if (pageId.value) {
|
||||
options.pageId = pageId.value;
|
||||
os.api('pages/update', options)
|
||||
.then(page => {
|
||||
currentName = name.trim();
|
||||
currentName.value = name.value.trim();
|
||||
os.alert({
|
||||
type: 'success',
|
||||
text: i18n.ts._pages.updated,
|
||||
|
|
@ -159,13 +159,13 @@ function save() {
|
|||
} else {
|
||||
os.api('pages/create', options)
|
||||
.then(created => {
|
||||
pageId = created.id;
|
||||
currentName = name.trim();
|
||||
pageId.value = created.id;
|
||||
currentName.value = name.value.trim();
|
||||
os.alert({
|
||||
type: 'success',
|
||||
text: i18n.ts._pages.created,
|
||||
});
|
||||
mainRouter.push(`/pages/edit/${pageId}`);
|
||||
mainRouter.push(`/pages/edit/${pageId.value}`);
|
||||
}).catch(onError);
|
||||
}
|
||||
}
|
||||
|
|
@ -173,11 +173,11 @@ function save() {
|
|||
function del() {
|
||||
os.confirm({
|
||||
type: 'warning',
|
||||
text: i18n.t('removeAreYouSure', { x: title.trim() }),
|
||||
text: i18n.t('removeAreYouSure', { x: title.value.trim() }),
|
||||
}).then(({ canceled }) => {
|
||||
if (canceled) return;
|
||||
os.api('pages/delete', {
|
||||
pageId: pageId,
|
||||
pageId: pageId.value,
|
||||
}).then(() => {
|
||||
os.alert({
|
||||
type: 'success',
|
||||
|
|
@ -189,16 +189,16 @@ function del() {
|
|||
}
|
||||
|
||||
function duplicate() {
|
||||
title = title + ' - copy';
|
||||
name = name + '-copy';
|
||||
title.value = title.value + ' - copy';
|
||||
name.value = name.value + '-copy';
|
||||
os.api('pages/create', getSaveOptions()).then(created => {
|
||||
pageId = created.id;
|
||||
currentName = name.trim();
|
||||
pageId.value = created.id;
|
||||
currentName.value = name.value.trim();
|
||||
os.alert({
|
||||
type: 'success',
|
||||
text: i18n.ts._pages.created,
|
||||
});
|
||||
mainRouter.push(`/pages/edit/${pageId}`);
|
||||
mainRouter.push(`/pages/edit/${pageId.value}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -211,7 +211,7 @@ async function add() {
|
|||
if (canceled) return;
|
||||
|
||||
const id = uuid();
|
||||
content.push({ id, type });
|
||||
content.value.push({ id, type });
|
||||
}
|
||||
|
||||
function getPageBlockList() {
|
||||
|
|
@ -225,42 +225,42 @@ function getPageBlockList() {
|
|||
|
||||
function setEyeCatchingImage(img) {
|
||||
selectFile(img.currentTarget ?? img.target, null).then(file => {
|
||||
eyeCatchingImageId = file.id;
|
||||
eyeCatchingImageId.value = file.id;
|
||||
});
|
||||
}
|
||||
|
||||
function removeEyeCatchingImage() {
|
||||
eyeCatchingImageId = null;
|
||||
eyeCatchingImageId.value = null;
|
||||
}
|
||||
|
||||
async function init() {
|
||||
if (props.initPageId) {
|
||||
page = await os.api('pages/show', {
|
||||
page.value = await os.api('pages/show', {
|
||||
pageId: props.initPageId,
|
||||
});
|
||||
} else if (props.initPageName && props.initUser) {
|
||||
page = await os.api('pages/show', {
|
||||
page.value = await os.api('pages/show', {
|
||||
name: props.initPageName,
|
||||
username: props.initUser,
|
||||
});
|
||||
readonly = true;
|
||||
readonly.value = true;
|
||||
}
|
||||
|
||||
if (page) {
|
||||
author = page.user;
|
||||
pageId = page.id;
|
||||
title = page.title;
|
||||
name = page.name;
|
||||
currentName = page.name;
|
||||
summary = page.summary;
|
||||
font = page.font;
|
||||
hideTitleWhenPinned = page.hideTitleWhenPinned;
|
||||
alignCenter = page.alignCenter;
|
||||
content = page.content;
|
||||
eyeCatchingImageId = page.eyeCatchingImageId;
|
||||
if (page.value) {
|
||||
author.value = page.value.user;
|
||||
pageId.value = page.value.id;
|
||||
title.value = page.value.title;
|
||||
name.value = page.value.name;
|
||||
currentName.value = page.value.name;
|
||||
summary.value = page.value.summary;
|
||||
font.value = page.value.font;
|
||||
hideTitleWhenPinned.value = page.value.hideTitleWhenPinned;
|
||||
alignCenter.value = page.value.alignCenter;
|
||||
content.value = page.value.content;
|
||||
eyeCatchingImageId.value = page.value.eyeCatchingImageId;
|
||||
} else {
|
||||
const id = uuid();
|
||||
content = [{
|
||||
content.value = [{
|
||||
id,
|
||||
type: 'text',
|
||||
text: 'Hello World!',
|
||||
|
|
@ -270,9 +270,9 @@ async function init() {
|
|||
|
||||
init();
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => [{
|
||||
const headerTabs = computed(() => [{
|
||||
key: 'settings',
|
||||
title: i18n.ts._pages.pageSetting,
|
||||
icon: 'ti ti-settings',
|
||||
|
|
|
|||
|
|
@ -34,7 +34,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</div>
|
||||
<div class="other">
|
||||
<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.share" v-click-anime class="_button" @click="share"><i class="ti ti-share 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>
|
||||
</div>
|
||||
</div>
|
||||
<div class="user">
|
||||
|
|
@ -75,7 +76,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch } from 'vue';
|
||||
import { computed, watch, ref } from 'vue';
|
||||
import XPage from '@/components/page/page.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import * as os from '@/os.js';
|
||||
|
|
@ -90,30 +91,32 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
|
|||
import { pageViewInterruptors, defaultStore } from '@/store.js';
|
||||
import { deepClone } from '@/scripts/clone.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { isSupportShare } from '@/scripts/navigator.js';
|
||||
import copyToClipboard from '@/scripts/copy-to-clipboard.js';
|
||||
|
||||
const props = defineProps<{
|
||||
pageName: string;
|
||||
username: string;
|
||||
}>();
|
||||
|
||||
let page = $ref(null);
|
||||
let error = $ref(null);
|
||||
const page = ref(null);
|
||||
const error = ref(null);
|
||||
const otherPostsPagination = {
|
||||
endpoint: 'users/pages' as const,
|
||||
limit: 6,
|
||||
params: computed(() => ({
|
||||
userId: page.user.id,
|
||||
userId: page.value.user.id,
|
||||
})),
|
||||
};
|
||||
const path = $computed(() => props.username + '/' + props.pageName);
|
||||
const path = computed(() => props.username + '/' + props.pageName);
|
||||
|
||||
function fetchPage() {
|
||||
page = null;
|
||||
page.value = null;
|
||||
os.api('pages/show', {
|
||||
name: props.pageName,
|
||||
username: props.username,
|
||||
}).then(async _page => {
|
||||
page = _page;
|
||||
page.value = _page;
|
||||
|
||||
// plugin
|
||||
if (pageViewInterruptors.length > 0) {
|
||||
|
|
@ -121,33 +124,38 @@ function fetchPage() {
|
|||
for (const interruptor of pageViewInterruptors) {
|
||||
result = await interruptor.handler(result);
|
||||
}
|
||||
page = result;
|
||||
page.value = result;
|
||||
}
|
||||
}).catch(err => {
|
||||
error = err;
|
||||
error.value = err;
|
||||
});
|
||||
}
|
||||
|
||||
function share() {
|
||||
navigator.share({
|
||||
title: page.title ?? page.name,
|
||||
text: page.summary,
|
||||
url: `${url}/@${page.user.username}/pages/${page.name}`,
|
||||
title: page.value.title ?? page.value.name,
|
||||
text: page.value.summary,
|
||||
url: `${url}/@${page.value.user.username}/pages/${page.value.name}`,
|
||||
});
|
||||
}
|
||||
|
||||
function copyLink() {
|
||||
copyToClipboard(`${url}/@${page.value.user.username}/pages/${page.value.name}`);
|
||||
os.success();
|
||||
}
|
||||
|
||||
function shareWithNote() {
|
||||
os.post({
|
||||
initialText: `${page.title || page.name} ${url}/@${page.user.username}/pages/${page.name}`,
|
||||
initialText: `${page.value.title || page.value.name} ${url}/@${page.value.user.username}/pages/${page.value.name}`,
|
||||
});
|
||||
}
|
||||
|
||||
function like() {
|
||||
os.apiWithDialog('pages/like', {
|
||||
pageId: page.id,
|
||||
pageId: page.value.id,
|
||||
}).then(() => {
|
||||
page.isLiked = true;
|
||||
page.likedCount++;
|
||||
page.value.isLiked = true;
|
||||
page.value.likedCount++;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -158,32 +166,32 @@ async function unlike() {
|
|||
});
|
||||
if (confirm.canceled) return;
|
||||
os.apiWithDialog('pages/unlike', {
|
||||
pageId: page.id,
|
||||
pageId: page.value.id,
|
||||
}).then(() => {
|
||||
page.isLiked = false;
|
||||
page.likedCount--;
|
||||
page.value.isLiked = false;
|
||||
page.value.likedCount--;
|
||||
});
|
||||
}
|
||||
|
||||
function pin(pin) {
|
||||
os.apiWithDialog('i/update', {
|
||||
pinnedPageId: pin ? page.id : null,
|
||||
pinnedPageId: pin ? page.value.id : null,
|
||||
});
|
||||
}
|
||||
|
||||
watch(() => path, fetchPage, { immediate: true });
|
||||
watch(() => path.value, fetchPage, { immediate: true });
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata(computed(() => page ? {
|
||||
title: page.title || page.name,
|
||||
avatar: page.user,
|
||||
path: `/@${page.user.username}/pages/${page.name}`,
|
||||
definePageMetadata(computed(() => page.value ? {
|
||||
title: page.value.title || page.value.name,
|
||||
avatar: page.value.user,
|
||||
path: `/@${page.value.user.username}/pages/${page.value.name}`,
|
||||
share: {
|
||||
title: page.title || page.name,
|
||||
text: page.summary,
|
||||
title: page.value.title || page.value.name,
|
||||
text: page.value.summary,
|
||||
},
|
||||
} : null));
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import MkPagePreview from '@/components/MkPagePreview.vue';
|
||||
import MkPagination from '@/components/MkPagination.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
|
|
@ -46,7 +46,7 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
|
|||
|
||||
const router = useRouter();
|
||||
|
||||
let tab = $ref('featured');
|
||||
const tab = ref('featured');
|
||||
|
||||
const featuredPagesPagination = {
|
||||
endpoint: 'pages/featured' as const,
|
||||
|
|
@ -65,13 +65,13 @@ function create() {
|
|||
router.push('/pages/new');
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => [{
|
||||
const headerActions = computed(() => [{
|
||||
icon: 'ti ti-plus',
|
||||
text: i18n.ts.create,
|
||||
handler: create,
|
||||
}]);
|
||||
|
||||
const headerTabs = $computed(() => [{
|
||||
const headerTabs = computed(() => [{
|
||||
key: 'featured',
|
||||
title: i18n.ts._pages.featured,
|
||||
icon: 'ti ti-flare',
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { watch } from 'vue';
|
||||
import { watch, computed, ref } from 'vue';
|
||||
import JSON5 from 'json5';
|
||||
import * as os from '@/os.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
|
@ -49,16 +49,16 @@ const props = defineProps<{
|
|||
domain: string;
|
||||
}>();
|
||||
|
||||
const scope = $computed(() => props.path ? props.path.split('/') : []);
|
||||
const scope = computed(() => props.path ? props.path.split('/') : []);
|
||||
|
||||
let keys = $ref(null);
|
||||
const keys = ref(null);
|
||||
|
||||
function fetchKeys() {
|
||||
os.api('i/registry/keys-with-type', {
|
||||
scope: scope,
|
||||
scope: scope.value,
|
||||
domain: props.domain === '@' ? null : props.domain,
|
||||
}).then(res => {
|
||||
keys = Object.entries(res).sort((a, b) => a[0].localeCompare(b[0]));
|
||||
keys.value = Object.entries(res).sort((a, b) => a[0].localeCompare(b[0]));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -76,7 +76,7 @@ async function createKey() {
|
|||
scope: {
|
||||
type: 'string',
|
||||
label: i18n.ts._registry.scope,
|
||||
default: scope.join('/'),
|
||||
default: scope.value.join('/'),
|
||||
},
|
||||
});
|
||||
if (canceled) return;
|
||||
|
|
@ -91,9 +91,9 @@ async function createKey() {
|
|||
|
||||
watch(() => props.path, fetchKeys, { immediate: true });
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.registry,
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { watch } from 'vue';
|
||||
import { watch, computed, ref } from 'vue';
|
||||
import JSON5 from 'json5';
|
||||
import * as os from '@/os.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
|
@ -61,26 +61,26 @@ const props = defineProps<{
|
|||
domain: string;
|
||||
}>();
|
||||
|
||||
const scope = $computed(() => props.path.split('/').slice(0, -1));
|
||||
const key = $computed(() => props.path.split('/').at(-1));
|
||||
const scope = computed(() => props.path.split('/').slice(0, -1));
|
||||
const key = computed(() => props.path.split('/').at(-1));
|
||||
|
||||
let value = $ref(null);
|
||||
let valueForEditor = $ref(null);
|
||||
const value = ref(null);
|
||||
const valueForEditor = ref(null);
|
||||
|
||||
function fetchValue() {
|
||||
os.api('i/registry/get-detail', {
|
||||
scope,
|
||||
key,
|
||||
scope: scope.value,
|
||||
key: key.value,
|
||||
domain: props.domain === '@' ? null : props.domain,
|
||||
}).then(res => {
|
||||
value = res;
|
||||
valueForEditor = JSON5.stringify(res.value, null, '\t');
|
||||
value.value = res;
|
||||
valueForEditor.value = JSON5.stringify(res.value, null, '\t');
|
||||
});
|
||||
}
|
||||
|
||||
async function save() {
|
||||
try {
|
||||
JSON5.parse(valueForEditor);
|
||||
JSON5.parse(valueForEditor.value);
|
||||
} catch (err) {
|
||||
os.alert({
|
||||
type: 'error',
|
||||
|
|
@ -94,9 +94,9 @@ async function save() {
|
|||
}).then(({ canceled }) => {
|
||||
if (canceled) return;
|
||||
os.apiWithDialog('i/registry/set', {
|
||||
scope,
|
||||
key,
|
||||
value: JSON5.parse(valueForEditor),
|
||||
scope: scope.value,
|
||||
key: key.value,
|
||||
value: JSON5.parse(valueForEditor.value),
|
||||
domain: props.domain === '@' ? null : props.domain,
|
||||
});
|
||||
});
|
||||
|
|
@ -109,8 +109,8 @@ function del() {
|
|||
}).then(({ canceled }) => {
|
||||
if (canceled) return;
|
||||
os.apiWithDialog('i/registry/remove', {
|
||||
scope,
|
||||
key,
|
||||
scope: scope.value,
|
||||
key: key.value,
|
||||
domain: props.domain === '@' ? null : props.domain,
|
||||
});
|
||||
});
|
||||
|
|
@ -118,9 +118,9 @@ function del() {
|
|||
|
||||
watch(() => props.path, fetchValue, { immediate: true });
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.registry,
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import JSON5 from 'json5';
|
||||
import * as os from '@/os.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
|
@ -30,11 +31,11 @@ import FormLink from '@/components/form/link.vue';
|
|||
import FormSection from '@/components/form/section.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
|
||||
let scopesWithDomain = $ref(null);
|
||||
const scopesWithDomain = ref(null);
|
||||
|
||||
function fetchScopes() {
|
||||
os.api('i/registry/scopes-with-domain').then(res => {
|
||||
scopesWithDomain = res;
|
||||
scopesWithDomain.value = res;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -66,9 +67,9 @@ async function createKey() {
|
|||
|
||||
fetchScopes();
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.registry,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent, onMounted } from 'vue';
|
||||
import { defineAsyncComponent, onMounted, ref, computed } from 'vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import * as os from '@/os.js';
|
||||
|
|
@ -32,12 +32,12 @@ const props = defineProps<{
|
|||
token?: string;
|
||||
}>();
|
||||
|
||||
let password = $ref('');
|
||||
const password = ref('');
|
||||
|
||||
async function save() {
|
||||
await os.apiWithDialog('reset-password', {
|
||||
token: props.token,
|
||||
password: password,
|
||||
password: password.value,
|
||||
});
|
||||
mainRouter.push('/');
|
||||
}
|
||||
|
|
@ -49,9 +49,9 @@ onMounted(() => {
|
|||
}
|
||||
});
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.resetPassword,
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch } from 'vue';
|
||||
import { computed, watch, ref } from 'vue';
|
||||
import * as os from '@/os.js';
|
||||
import MkUserList from '@/components/MkUserList.vue';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
|
|
@ -52,29 +52,29 @@ const props = withDefaults(defineProps<{
|
|||
initialTab: 'users',
|
||||
});
|
||||
|
||||
let tab = $ref(props.initialTab);
|
||||
let role = $ref();
|
||||
let error = $ref();
|
||||
let visible = $ref(false);
|
||||
const tab = ref(props.initialTab);
|
||||
const role = ref();
|
||||
const error = ref();
|
||||
const visible = ref(false);
|
||||
|
||||
watch(() => props.role, () => {
|
||||
os.api('roles/show', {
|
||||
roleId: props.role,
|
||||
}).then(res => {
|
||||
role = res;
|
||||
document.title = `${role?.name} | ${instanceName}`;
|
||||
visible = res.isExplorable && res.isPublic;
|
||||
role.value = res;
|
||||
document.title = `${role.value?.name} | ${instanceName}`;
|
||||
visible.value = res.isExplorable && res.isPublic;
|
||||
}).catch((err) => {
|
||||
if (err.code === 'NO_SUCH_ROLE') {
|
||||
error = i18n.ts.noRole;
|
||||
error.value = i18n.ts.noRole;
|
||||
} else {
|
||||
error = i18n.ts.somethingHappened;
|
||||
error.value = i18n.ts.somethingHappened;
|
||||
}
|
||||
document.title = `${error} | ${instanceName}`;
|
||||
document.title = `${error.value} | ${instanceName}`;
|
||||
});
|
||||
}, { immediate: true });
|
||||
|
||||
const users = $computed(() => ({
|
||||
const users = computed(() => ({
|
||||
endpoint: 'roles/users' as const,
|
||||
limit: 30,
|
||||
params: {
|
||||
|
|
@ -82,7 +82,7 @@ const users = $computed(() => ({
|
|||
},
|
||||
}));
|
||||
|
||||
const headerTabs = $computed(() => [{
|
||||
const headerTabs = computed(() => [{
|
||||
key: 'users',
|
||||
icon: 'ti ti-users',
|
||||
title: i18n.ts.users,
|
||||
|
|
@ -93,7 +93,7 @@ const headerTabs = $computed(() => [{
|
|||
}]);
|
||||
|
||||
definePageMetadata(computed(() => ({
|
||||
title: role?.name,
|
||||
title: role.value?.name,
|
||||
icon: 'ti ti-badge',
|
||||
})));
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onDeactivated, onUnmounted, Ref, ref, watch } from 'vue';
|
||||
import { onDeactivated, onUnmounted, Ref, ref, watch, computed } from 'vue';
|
||||
import { Interpreter, Parser, utils } from '@syuilo/aiscript';
|
||||
import MkContainer from '@/components/MkContainer.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
|
|
@ -59,8 +59,8 @@ let aiscript: Interpreter;
|
|||
const code = ref('');
|
||||
const logs = ref<any[]>([]);
|
||||
const root = ref<AsUiRoot>();
|
||||
let components: Ref<AsUiComponent>[] = $ref([]);
|
||||
let uiKey = $ref(0);
|
||||
const components = ref<Ref<AsUiComponent>[]>([]);
|
||||
const uiKey = ref(0);
|
||||
|
||||
const saved = miLocalStorage.getItem('scratchpad');
|
||||
if (saved) {
|
||||
|
|
@ -74,15 +74,15 @@ watch(code, () => {
|
|||
async function run() {
|
||||
if (aiscript) aiscript.abort();
|
||||
root.value = undefined;
|
||||
components = [];
|
||||
uiKey++;
|
||||
components.value = [];
|
||||
uiKey.value++;
|
||||
logs.value = [];
|
||||
aiscript = new Interpreter(({
|
||||
...createAiScriptEnv({
|
||||
storageKey: 'widget',
|
||||
token: $i?.token,
|
||||
}),
|
||||
...registerAsUiLib(components, (_root) => {
|
||||
...registerAsUiLib(components.value, (_root) => {
|
||||
root.value = _root.value;
|
||||
}),
|
||||
}), {
|
||||
|
|
@ -160,9 +160,9 @@ onUnmounted(() => {
|
|||
if (aiscript) aiscript.abort();
|
||||
});
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.scratchpad,
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted } from 'vue';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import MkNotes from '@/components/MkNotes.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkRadios from '@/components/MkRadios.vue';
|
||||
|
|
@ -59,21 +59,21 @@ import MkFolder from '@/components/MkFolder.vue';
|
|||
|
||||
const router = useRouter();
|
||||
|
||||
let key = $ref(0);
|
||||
let searchQuery = $ref('');
|
||||
let searchOrigin = $ref('combined');
|
||||
let notePagination = $ref();
|
||||
let user = $ref(null);
|
||||
let isLocalOnly = $ref(false);
|
||||
const key = ref(0);
|
||||
const searchQuery = ref('');
|
||||
const searchOrigin = ref('combined');
|
||||
const notePagination = ref();
|
||||
const user = ref(null);
|
||||
const isLocalOnly = ref(false);
|
||||
|
||||
function selectUser() {
|
||||
os.selectUser().then(_user => {
|
||||
user = _user;
|
||||
user.value = _user;
|
||||
});
|
||||
}
|
||||
|
||||
async function search() {
|
||||
const query = searchQuery.toString().trim();
|
||||
const query = searchQuery.value.toString().trim();
|
||||
|
||||
if (query == null || query === '') return;
|
||||
|
||||
|
|
@ -95,17 +95,17 @@ async function search() {
|
|||
return;
|
||||
}
|
||||
|
||||
notePagination = {
|
||||
notePagination.value = {
|
||||
endpoint: 'notes/search',
|
||||
limit: 10,
|
||||
params: {
|
||||
query: searchQuery,
|
||||
userId: user ? user.id : null,
|
||||
query: searchQuery.value,
|
||||
userId: user.value ? user.value.id : null,
|
||||
},
|
||||
};
|
||||
|
||||
if (isLocalOnly) notePagination.params.host = '.';
|
||||
if (isLocalOnly.value) notePagination.value.params.host = '.';
|
||||
|
||||
key++;
|
||||
key.value++;
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, defineAsyncComponent, onMounted } from 'vue';
|
||||
import { computed, defineAsyncComponent, onMounted, ref } from 'vue';
|
||||
import MkUserList from '@/components/MkUserList.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkRadios from '@/components/MkRadios.vue';
|
||||
|
|
@ -40,13 +40,13 @@ import { useRouter } from '@/router.js';
|
|||
|
||||
const router = useRouter();
|
||||
|
||||
let key = $ref('');
|
||||
let searchQuery = $ref('');
|
||||
let searchOrigin = $ref('combined');
|
||||
let userPagination = $ref();
|
||||
const key = ref('');
|
||||
const searchQuery = ref('');
|
||||
const searchOrigin = ref('combined');
|
||||
const userPagination = ref();
|
||||
|
||||
async function search() {
|
||||
const query = searchQuery.toString().trim();
|
||||
const query = searchQuery.value.toString().trim();
|
||||
|
||||
if (query == null || query === '') return;
|
||||
|
||||
|
|
@ -68,15 +68,15 @@ async function search() {
|
|||
return;
|
||||
}
|
||||
|
||||
userPagination = {
|
||||
userPagination.value = {
|
||||
endpoint: 'users/search',
|
||||
limit: 10,
|
||||
params: {
|
||||
query: query,
|
||||
origin: searchOrigin,
|
||||
origin: searchOrigin.value,
|
||||
},
|
||||
};
|
||||
|
||||
key = query;
|
||||
key.value = query;
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue