Merge tag '2023.12.0-beta.3' into merge-upstream

This commit is contained in:
riku6460 2023-12-10 08:58:57 +09:00
commit e77ddfce91
No known key found for this signature in database
GPG key ID: 27414FA27DB94CF6
423 changed files with 42868 additions and 10814 deletions

View file

@ -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,

View file

@ -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,

View file

@ -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>

View file

@ -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;

View file

@ -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,
}, {

View file

@ -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>

View file

@ -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>

View file

@ -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';
}
});
}, {

View file

@ -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,
}, {

View file

@ -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[]>([]);
// ISOTZUTCTZ
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,

View file

@ -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,

View file

@ -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();
});

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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: {

View file

@ -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',

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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 () => {

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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(() => {

View file

@ -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>

View file

@ -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, {

View file

@ -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,

View file

@ -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,

View file

@ -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(() => {

View file

@ -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',
}, {

View file

@ -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,

View file

@ -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,

View file

@ -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>

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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',

View file

@ -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>

View file

@ -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',

View file

@ -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;
});

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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>

View file

@ -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',

View file

@ -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>

View file

@ -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,
}, {

View file

@ -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,
})));

View file

@ -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>

View file

@ -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}`,
});
});
},

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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,

View file

@ -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,
}));

View file

@ -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',

View file

@ -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>

View file

@ -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,

View file

@ -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,

View file

@ -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',

View file

@ -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>

View file

@ -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',

View file

@ -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>

View file

@ -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>

View file

@ -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',

View file

@ -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,

View file

@ -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({

View file

@ -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>

View file

@ -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,

View file

@ -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',

View file

@ -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,

View file

@ -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>

View file

@ -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,

View file

@ -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-01notes/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>

View file

@ -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',

View file

@ -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;
});
}
});

View file

@ -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,
});

View file

@ -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(() => {

View file

@ -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>

View file

@ -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',

View file

@ -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>

View file

@ -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',

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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>

View file

@ -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,

View file

@ -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>

View file

@ -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