mirror of
https://github.com/paricafe/misskey.git
synced 2025-03-23 11:39:25 -05:00
enhance(frontend): improve accounts management
This commit is contained in:
parent
44073736de
commit
8c9ec5827f
137 changed files with 640 additions and 622 deletions
packages/frontend/src
account.tsaccounts.ts
aiscript
boot
components
MkAnnouncementDialog.vueMkAuthConfirm.vueMkClipPreview.vueMkCropperDialog.vueMkDrive.file.vueMkEmojiPicker.vueMkFollowButton.vueMkInstanceStats.vueMkMediaAudio.vueMkMediaImage.vueMkMediaVideo.vueMkMention.vueMkNote.vueMkNoteDetailed.vueMkNoteSub.vueMkNotification.vueMkPasswordDialog.vueMkPostForm.vueMkPreview.vueMkPushNotificationAllowButton.vueMkReactionsViewer.reaction.vueMkSignin.vueMkSignupDialog.form.vueMkTimeline.vueMkTokenGenerateWindow.vueMkTutorialDialog.Note.vueMkTutorialDialog.Sensitive.vueMkUserInfo.vueMkUserPopup.vueMkUserSelectDialog.vueMkUserSetupDialog.Profile.vue
i.tslocal-storage.tsnavbar.tsglobal
pages
about-misskey.vueabout.emojis.vueachievements.vueadmin-file.vueadmin-user.vueannouncement.vueannouncements.vueauth.vueavatar-decoration-edit-dialog.vueavatar-decorations.vuechannel.vueclip.vuedrop-and-fusion.game.vueemojis.emoji.vue
pizzax.tspreferences.tsflash
follow-requests.vuegallery
instance-info.vueinvite.vuemy-lists
note.vuepage-editor
page.vuereversi
scratchpad.vuesearch.note.vuesettings
2fa.qrdialog.vue2fa.vueaccount-data.vueaccounts.vueavatar-decoration.decoration.vueavatar-decoration.dialog.vueavatar-decoration.vuedrive.vueemail.vueindex.vuemigration.vuemute-block.instance-mute.vuemute-block.vuenotifications.vueother.vueprivacy.vueprofile.vue
signup-complete.vuetag.vuetheme-editor.vuetimeline.vueuser
welcome.setup.vuepreferences
|
@ -1,390 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { defineAsyncComponent, reactive, ref } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { apiUrl } from '@@/js/config.js';
|
||||
import type { MenuItem, MenuButton } from '@/types/menu.js';
|
||||
import { defaultMemoryStorage } from '@/memory-storage';
|
||||
import { showSuspendedDialog } from '@/utility/show-suspended-dialog.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { miLocalStorage } from '@/local-storage.js';
|
||||
import { del, get, set } from '@/utility/idb-proxy.js';
|
||||
import { waiting, popup, popupMenu, success, alert } from '@/os.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { unisonReload, reloadChannel } from '@/utility/unison-reload.js';
|
||||
|
||||
// TODO: 他のタブと永続化されたstateを同期
|
||||
// TODO: accountsはpreferences管理にする(tokenは別管理)
|
||||
|
||||
type Account = Misskey.entities.MeDetailed & { token: string };
|
||||
|
||||
const accountData = miLocalStorage.getItem('account');
|
||||
|
||||
// TODO: 外部からはreadonlyに
|
||||
export const $i = accountData ? reactive(JSON.parse(accountData) as Account) : null;
|
||||
|
||||
export const iAmModerator = $i != null && ($i.isAdmin === true || $i.isModerator === true);
|
||||
export const iAmAdmin = $i != null && $i.isAdmin;
|
||||
|
||||
export function signinRequired() {
|
||||
if ($i == null) throw new Error('signin required');
|
||||
return $i;
|
||||
}
|
||||
|
||||
export let notesCount = $i == null ? 0 : $i.notesCount;
|
||||
export function incNotesCount() {
|
||||
notesCount++;
|
||||
}
|
||||
|
||||
export async function signout() {
|
||||
if (!$i) return;
|
||||
|
||||
defaultMemoryStorage.clear();
|
||||
|
||||
waiting();
|
||||
document.cookie.split(';').forEach((cookie) => {
|
||||
const cookieName = cookie.split('=')[0].trim();
|
||||
if (cookieName === 'token') {
|
||||
document.cookie = `${cookieName}=; max-age=0; path=/`;
|
||||
}
|
||||
});
|
||||
miLocalStorage.removeItem('account');
|
||||
await removeAccount($i.id);
|
||||
const accounts = await getAccounts();
|
||||
|
||||
//#region Remove service worker registration
|
||||
try {
|
||||
if (navigator.serviceWorker.controller) {
|
||||
const registration = await navigator.serviceWorker.ready;
|
||||
const push = await registration.pushManager.getSubscription();
|
||||
if (push) {
|
||||
await window.fetch(`${apiUrl}/sw/unregister`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
i: $i.token,
|
||||
endpoint: push.endpoint,
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (accounts.length === 0) {
|
||||
await navigator.serviceWorker.getRegistrations()
|
||||
.then(registrations => {
|
||||
return Promise.all(registrations.map(registration => registration.unregister()));
|
||||
});
|
||||
}
|
||||
} catch (err) {}
|
||||
//#endregion
|
||||
|
||||
if (accounts.length > 0) login(accounts[0].token);
|
||||
else unisonReload('/');
|
||||
}
|
||||
|
||||
export async function getAccounts(): Promise<{ id: Account['id'], token: Account['token'] }[]> {
|
||||
return (await get('accounts')) || [];
|
||||
}
|
||||
|
||||
export async function addAccount(id: Account['id'], token: Account['token']) {
|
||||
const accounts = await getAccounts();
|
||||
if (!accounts.some(x => x.id === id)) {
|
||||
await set('accounts', accounts.concat([{ id, token }]));
|
||||
}
|
||||
}
|
||||
|
||||
export async function removeAccount(idOrToken: Account['id']) {
|
||||
const accounts = await getAccounts();
|
||||
const i = accounts.findIndex(x => x.id === idOrToken || x.token === idOrToken);
|
||||
if (i !== -1) accounts.splice(i, 1);
|
||||
|
||||
if (accounts.length > 0) {
|
||||
await set('accounts', accounts);
|
||||
} else {
|
||||
await del('accounts');
|
||||
}
|
||||
}
|
||||
|
||||
function fetchAccount(token: string, id?: string, forceShowDialog?: boolean): Promise<Account> {
|
||||
document.cookie = 'token=; path=/; max-age=0';
|
||||
document.cookie = `token=${token}; path=/queue; max-age=86400; SameSite=Strict; Secure`; // bull dashboardの認証とかで使う
|
||||
|
||||
return new Promise((done, fail) => {
|
||||
window.fetch(`${apiUrl}/i`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
i: token,
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
.then(res => new Promise<Account | { error: Record<string, any> }>((done2, fail2) => {
|
||||
if (res.status >= 500 && res.status < 600) {
|
||||
// サーバーエラー(5xx)の場合をrejectとする
|
||||
// (認証エラーなど4xxはresolve)
|
||||
return fail2(res);
|
||||
}
|
||||
res.json().then(done2, fail2);
|
||||
}))
|
||||
.then(async res => {
|
||||
if ('error' in res) {
|
||||
if (res.error.id === 'a8c724b3-6e9c-4b46-b1a8-bc3ed6258370') {
|
||||
// SUSPENDED
|
||||
if (forceShowDialog || $i && (token === $i.token || id === $i.id)) {
|
||||
await showSuspendedDialog();
|
||||
}
|
||||
} else if (res.error.id === 'e5b3b9f0-2b8f-4b9f-9c1f-8c5c1b2e1b1a') {
|
||||
// USER_IS_DELETED
|
||||
// アカウントが削除されている
|
||||
if (forceShowDialog || $i && (token === $i.token || id === $i.id)) {
|
||||
await alert({
|
||||
type: 'error',
|
||||
title: i18n.ts.accountDeleted,
|
||||
text: i18n.ts.accountDeletedDescription,
|
||||
});
|
||||
}
|
||||
} else if (res.error.id === 'b0a7f5f8-dc2f-4171-b91f-de88ad238e14') {
|
||||
// AUTHENTICATION_FAILED
|
||||
// トークンが無効化されていたりアカウントが削除されたりしている
|
||||
if (forceShowDialog || $i && (token === $i.token || id === $i.id)) {
|
||||
await alert({
|
||||
type: 'error',
|
||||
title: i18n.ts.tokenRevoked,
|
||||
text: i18n.ts.tokenRevokedDescription,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
await alert({
|
||||
type: 'error',
|
||||
title: i18n.ts.failedToFetchAccountInformation,
|
||||
text: JSON.stringify(res.error),
|
||||
});
|
||||
}
|
||||
|
||||
// rejectかつ理由がtrueの場合、削除対象であることを示す
|
||||
fail(true);
|
||||
} else {
|
||||
(res as Account).token = token;
|
||||
done(res as Account);
|
||||
}
|
||||
})
|
||||
.catch(fail);
|
||||
});
|
||||
}
|
||||
|
||||
export function updateAccount(accountData: Account) {
|
||||
if (!$i) return;
|
||||
for (const key of Object.keys($i)) {
|
||||
delete $i[key];
|
||||
}
|
||||
for (const [key, value] of Object.entries(accountData)) {
|
||||
$i[key] = value;
|
||||
}
|
||||
miLocalStorage.setItem('account', JSON.stringify($i));
|
||||
}
|
||||
|
||||
export function updateAccountPartial(accountData: Partial<Account>) {
|
||||
if (!$i) return;
|
||||
for (const [key, value] of Object.entries(accountData)) {
|
||||
$i[key] = value;
|
||||
}
|
||||
miLocalStorage.setItem('account', JSON.stringify($i));
|
||||
}
|
||||
|
||||
export async function refreshAccount() {
|
||||
if (!$i) return;
|
||||
return fetchAccount($i.token, $i.id)
|
||||
.then(updateAccount, reason => {
|
||||
if (reason === true) return signout();
|
||||
return;
|
||||
});
|
||||
}
|
||||
|
||||
export async function login(token: Account['token'], redirect?: string) {
|
||||
const showing = ref(true);
|
||||
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkWaitingDialog.vue')), {
|
||||
success: false,
|
||||
showing: showing,
|
||||
}, {
|
||||
closed: () => dispose(),
|
||||
});
|
||||
if (_DEV_) console.log('logging as token ', token);
|
||||
const me = await fetchAccount(token, undefined, true)
|
||||
.catch(reason => {
|
||||
if (reason === true) {
|
||||
// 削除対象の場合
|
||||
removeAccount(token);
|
||||
}
|
||||
|
||||
showing.value = false;
|
||||
throw reason;
|
||||
});
|
||||
miLocalStorage.setItem('account', JSON.stringify(me));
|
||||
await addAccount(me.id, token);
|
||||
|
||||
if (redirect) {
|
||||
// 他のタブは再読み込みするだけ
|
||||
reloadChannel.postMessage(null);
|
||||
// このページはredirectで指定された先に移動
|
||||
location.href = redirect;
|
||||
return;
|
||||
}
|
||||
|
||||
unisonReload();
|
||||
}
|
||||
|
||||
export async function openAccountMenu(opts: {
|
||||
includeCurrentAccount?: boolean;
|
||||
withExtraOperation: boolean;
|
||||
active?: Misskey.entities.UserDetailed['id'];
|
||||
onChoose?: (account: Misskey.entities.UserDetailed) => void;
|
||||
}, ev: MouseEvent) {
|
||||
if (!$i) return;
|
||||
|
||||
async function switchAccount(account: Misskey.entities.UserDetailed) {
|
||||
const storedAccounts = await getAccounts();
|
||||
const found = storedAccounts.find(x => x.id === account.id);
|
||||
if (found == null) return;
|
||||
switchAccountWithToken(found.token);
|
||||
}
|
||||
|
||||
function switchAccountWithToken(token: string) {
|
||||
login(token);
|
||||
}
|
||||
|
||||
const storedAccounts = await getAccounts().then(accounts => accounts.filter(x => x.id !== $i.id));
|
||||
const accountsPromise = misskeyApi('users/show', { userIds: storedAccounts.map(x => x.id) });
|
||||
|
||||
function createItem(account: Misskey.entities.UserDetailed) {
|
||||
return {
|
||||
type: 'user' as const,
|
||||
user: account,
|
||||
active: opts.active != null ? opts.active === account.id : false,
|
||||
action: () => {
|
||||
if (opts.onChoose) {
|
||||
opts.onChoose(account);
|
||||
} else {
|
||||
switchAccount(account);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const accountItemPromises = storedAccounts.map(a => new Promise<ReturnType<typeof createItem> | MenuButton>(res => {
|
||||
accountsPromise.then(accounts => {
|
||||
const account = accounts.find(x => x.id === a.id);
|
||||
if (account == null) return res({
|
||||
type: 'button' as const,
|
||||
text: a.id,
|
||||
action: () => {
|
||||
switchAccountWithToken(a.token);
|
||||
},
|
||||
});
|
||||
|
||||
res(createItem(account));
|
||||
});
|
||||
}));
|
||||
|
||||
const menuItems: MenuItem[] = [];
|
||||
|
||||
if (opts.withExtraOperation) {
|
||||
menuItems.push({
|
||||
type: 'link',
|
||||
text: i18n.ts.profile,
|
||||
to: `/@${$i.username}`,
|
||||
avatar: $i,
|
||||
}, {
|
||||
type: 'divider',
|
||||
});
|
||||
|
||||
if (opts.includeCurrentAccount) {
|
||||
menuItems.push(createItem($i));
|
||||
}
|
||||
|
||||
menuItems.push(...accountItemPromises);
|
||||
|
||||
menuItems.push({
|
||||
type: 'parent',
|
||||
icon: 'ti ti-plus',
|
||||
text: i18n.ts.addAccount,
|
||||
children: [{
|
||||
text: i18n.ts.existingAccount,
|
||||
action: () => {
|
||||
getAccountWithSigninDialog().then(res => {
|
||||
if (res != null) {
|
||||
success();
|
||||
}
|
||||
});
|
||||
},
|
||||
}, {
|
||||
text: i18n.ts.createAccount,
|
||||
action: () => {
|
||||
getAccountWithSignupDialog().then(res => {
|
||||
if (res != null) {
|
||||
switchAccountWithToken(res.token);
|
||||
}
|
||||
});
|
||||
},
|
||||
}],
|
||||
}, {
|
||||
type: 'link',
|
||||
icon: 'ti ti-users',
|
||||
text: i18n.ts.manageAccounts,
|
||||
to: '/settings/accounts',
|
||||
});
|
||||
} else {
|
||||
if (opts.includeCurrentAccount) {
|
||||
menuItems.push(createItem($i));
|
||||
}
|
||||
|
||||
menuItems.push(...accountItemPromises);
|
||||
}
|
||||
|
||||
popupMenu(menuItems, ev.currentTarget ?? ev.target, {
|
||||
align: 'left',
|
||||
});
|
||||
}
|
||||
|
||||
export function getAccountWithSigninDialog(): Promise<{ id: string, token: string } | null> {
|
||||
return new Promise((resolve) => {
|
||||
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), {}, {
|
||||
done: async (res: Misskey.entities.SigninFlowResponse & { finished: true }) => {
|
||||
await addAccount(res.id, res.i);
|
||||
resolve({ id: res.id, token: res.i });
|
||||
},
|
||||
cancelled: () => {
|
||||
resolve(null);
|
||||
},
|
||||
closed: () => {
|
||||
dispose();
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function getAccountWithSignupDialog(): Promise<{ id: string, token: string } | null> {
|
||||
return new Promise((resolve) => {
|
||||
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSignupDialog.vue')), {}, {
|
||||
done: async (res: Misskey.entities.SignupResponse) => {
|
||||
await addAccount(res.id, res.token);
|
||||
resolve({ id: res.id, token: res.token });
|
||||
},
|
||||
cancelled: () => {
|
||||
resolve(null);
|
||||
},
|
||||
closed: () => {
|
||||
dispose();
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (_DEV_) {
|
||||
(window as any).$i = $i;
|
||||
}
|
341
packages/frontend/src/accounts.ts
Normal file
341
packages/frontend/src/accounts.ts
Normal file
|
@ -0,0 +1,341 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { defineAsyncComponent, ref } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { apiUrl, host } from '@@/js/config.js';
|
||||
import type { MenuItem } from '@/types/menu.js';
|
||||
import { showSuspendedDialog } from '@/utility/show-suspended-dialog.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { miLocalStorage } from '@/local-storage.js';
|
||||
import { waiting, popup, popupMenu, success, alert } from '@/os.js';
|
||||
import { unisonReload, reloadChannel } from '@/utility/unison-reload.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import { store } from '@/store.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { signout } from '@/signout.js';
|
||||
|
||||
// TODO: 他のタブと永続化されたstateを同期
|
||||
|
||||
type AccountWithToken = Misskey.entities.MeDetailed & { token: string };
|
||||
|
||||
export async function getAccounts(): Promise<{
|
||||
host: string;
|
||||
user: Misskey.entities.User;
|
||||
token: string | null;
|
||||
}[]> {
|
||||
const tokens = store.s.accountTokens;
|
||||
const accounts = prefer.s.accounts;
|
||||
return accounts.map(([host, user]) => ({
|
||||
host,
|
||||
user,
|
||||
token: tokens[host + '/' + user.id] ?? null,
|
||||
}));
|
||||
}
|
||||
|
||||
async function addAccount(host: string, user: Misskey.entities.User, token: AccountWithToken['token']) {
|
||||
if (!prefer.s.accounts.some(x => x[0] === host && x[1].id === user.id)) {
|
||||
store.set('accountTokens', { ...store.s.accountTokens, [host + '/' + user.id]: token });
|
||||
prefer.commit('accounts', [...prefer.s.accounts, [host, user]]);
|
||||
}
|
||||
}
|
||||
|
||||
export async function removeAccount(host: string, id: AccountWithToken['id']) {
|
||||
const tokens = JSON.parse(JSON.stringify(store.s.accountTokens));
|
||||
delete tokens[host + '/' + id];
|
||||
store.set('accountTokens', tokens);
|
||||
prefer.commit('accounts', prefer.s.accounts.filter(x => x[0] !== host || x[1].id !== id));
|
||||
}
|
||||
|
||||
const isAccountDeleted = Symbol('isAccountDeleted');
|
||||
|
||||
function fetchAccount(token: string, id?: string, forceShowDialog?: boolean): Promise<Misskey.entities.MeDetailed> {
|
||||
return new Promise((done, fail) => {
|
||||
window.fetch(`${apiUrl}/i`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
i: token,
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
.then(res => new Promise<Misskey.entities.MeDetailed | { error: Record<string, any> }>((done2, fail2) => {
|
||||
if (res.status >= 500 && res.status < 600) {
|
||||
// サーバーエラー(5xx)の場合をrejectとする
|
||||
// (認証エラーなど4xxはresolve)
|
||||
return fail2(res);
|
||||
}
|
||||
res.json().then(done2, fail2);
|
||||
}))
|
||||
.then(async res => {
|
||||
if ('error' in res) {
|
||||
if (res.error.id === 'a8c724b3-6e9c-4b46-b1a8-bc3ed6258370') {
|
||||
// SUSPENDED
|
||||
if (forceShowDialog || $i && (token === $i.token || id === $i.id)) {
|
||||
await showSuspendedDialog();
|
||||
}
|
||||
} else if (res.error.id === 'e5b3b9f0-2b8f-4b9f-9c1f-8c5c1b2e1b1a') {
|
||||
// USER_IS_DELETED
|
||||
// アカウントが削除されている
|
||||
if (forceShowDialog || $i && (token === $i.token || id === $i.id)) {
|
||||
await alert({
|
||||
type: 'error',
|
||||
title: i18n.ts.accountDeleted,
|
||||
text: i18n.ts.accountDeletedDescription,
|
||||
});
|
||||
}
|
||||
} else if (res.error.id === 'b0a7f5f8-dc2f-4171-b91f-de88ad238e14') {
|
||||
// AUTHENTICATION_FAILED
|
||||
// トークンが無効化されていたりアカウントが削除されたりしている
|
||||
if (forceShowDialog || $i && (token === $i.token || id === $i.id)) {
|
||||
await alert({
|
||||
type: 'error',
|
||||
title: i18n.ts.tokenRevoked,
|
||||
text: i18n.ts.tokenRevokedDescription,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
await alert({
|
||||
type: 'error',
|
||||
title: i18n.ts.failedToFetchAccountInformation,
|
||||
text: JSON.stringify(res.error),
|
||||
});
|
||||
}
|
||||
|
||||
fail(isAccountDeleted);
|
||||
} else {
|
||||
done(res);
|
||||
}
|
||||
})
|
||||
.catch(fail);
|
||||
});
|
||||
}
|
||||
|
||||
export function updateCurrentAccount(accountData: Misskey.entities.MeDetailed) {
|
||||
if (!$i) return;
|
||||
const token = $i.token;
|
||||
for (const key of Object.keys($i)) {
|
||||
delete $i[key];
|
||||
}
|
||||
for (const [key, value] of Object.entries(accountData)) {
|
||||
$i[key] = value;
|
||||
}
|
||||
prefer.commit('accounts', prefer.s.accounts.map(([host, user]) => {
|
||||
// TODO: $iのホストも比較したいけど通常null
|
||||
if (user.id === $i.id) {
|
||||
return [host, $i];
|
||||
} else {
|
||||
return [host, user];
|
||||
}
|
||||
}));
|
||||
$i.token = token;
|
||||
miLocalStorage.setItem('account', JSON.stringify($i));
|
||||
}
|
||||
|
||||
export function updateCurrentAccountPartial(accountData: Partial<Misskey.entities.MeDetailed>) {
|
||||
if (!$i) return;
|
||||
for (const [key, value] of Object.entries(accountData)) {
|
||||
$i[key] = value;
|
||||
}
|
||||
prefer.commit('accounts', prefer.s.accounts.map(([host, user]) => {
|
||||
// TODO: $iのホストも比較したいけど通常null
|
||||
if (user.id === $i.id) {
|
||||
const newUser = JSON.parse(JSON.stringify($i));
|
||||
for (const [key, value] of Object.entries(accountData)) {
|
||||
newUser[key] = value;
|
||||
}
|
||||
return [host, newUser];
|
||||
}
|
||||
return [host, user];
|
||||
}));
|
||||
miLocalStorage.setItem('account', JSON.stringify($i));
|
||||
}
|
||||
|
||||
export async function refreshCurrentAccount() {
|
||||
if (!$i) return;
|
||||
return fetchAccount($i.token, $i.id).then(updateCurrentAccount).catch(reason => {
|
||||
if (reason === isAccountDeleted) {
|
||||
removeAccount(host, $i.id);
|
||||
if (Object.keys(store.s.accountTokens).length > 0) {
|
||||
login(Object.values(store.s.accountTokens)[0]);
|
||||
} else {
|
||||
signout();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function login(token: AccountWithToken['token'], redirect?: string) {
|
||||
const showing = ref(true);
|
||||
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkWaitingDialog.vue')), {
|
||||
success: false,
|
||||
showing: showing,
|
||||
}, {
|
||||
closed: () => dispose(),
|
||||
});
|
||||
|
||||
const me = await fetchAccount(token, undefined, true).catch(reason => {
|
||||
showing.value = false;
|
||||
throw reason;
|
||||
});
|
||||
|
||||
miLocalStorage.setItem('account', JSON.stringify({
|
||||
...me,
|
||||
token,
|
||||
}));
|
||||
|
||||
await addAccount(host, me, token);
|
||||
|
||||
if (redirect) {
|
||||
// 他のタブは再読み込みするだけ
|
||||
reloadChannel.postMessage(null);
|
||||
// このページはredirectで指定された先に移動
|
||||
location.href = redirect;
|
||||
return;
|
||||
}
|
||||
|
||||
unisonReload();
|
||||
}
|
||||
|
||||
export async function switchAccount(host: string, id: string) {
|
||||
const token = store.s.accountTokens[host + '/' + id];
|
||||
if (token) {
|
||||
login(token);
|
||||
} else {
|
||||
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), {}, {
|
||||
done: async (res: Misskey.entities.SigninFlowResponse & { finished: true }) => {
|
||||
store.set('accountTokens', { ...store.s.accountTokens, [host + '/' + res.id]: res.i });
|
||||
login(res.i);
|
||||
},
|
||||
closed: () => {
|
||||
dispose();
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function openAccountMenu(opts: {
|
||||
includeCurrentAccount?: boolean;
|
||||
withExtraOperation: boolean;
|
||||
active?: Misskey.entities.User['id'];
|
||||
onChoose?: (account: Misskey.entities.User) => void;
|
||||
}, ev: MouseEvent) {
|
||||
if (!$i) return;
|
||||
|
||||
function createItem(host: string, account: Misskey.entities.User): MenuItem {
|
||||
return {
|
||||
type: 'user' as const,
|
||||
user: account,
|
||||
active: opts.active != null ? opts.active === account.id : false,
|
||||
action: async () => {
|
||||
if (opts.onChoose) {
|
||||
opts.onChoose(account);
|
||||
} else {
|
||||
switchAccount(host, account.id);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const menuItems: MenuItem[] = [];
|
||||
|
||||
// TODO: $iのホストも比較したいけど通常null
|
||||
const accountItems = (await getAccounts().then(accounts => accounts.filter(x => x.user.id !== $i.id))).map(a => createItem(a.host, a.user));
|
||||
|
||||
if (opts.withExtraOperation) {
|
||||
menuItems.push({
|
||||
type: 'link',
|
||||
text: i18n.ts.profile,
|
||||
to: `/@${$i.username}`,
|
||||
avatar: $i,
|
||||
}, {
|
||||
type: 'divider',
|
||||
});
|
||||
|
||||
if (opts.includeCurrentAccount) {
|
||||
menuItems.push(createItem(host, $i));
|
||||
}
|
||||
|
||||
menuItems.push(...accountItems);
|
||||
|
||||
menuItems.push({
|
||||
type: 'parent',
|
||||
icon: 'ti ti-plus',
|
||||
text: i18n.ts.addAccount,
|
||||
children: [{
|
||||
text: i18n.ts.existingAccount,
|
||||
action: () => {
|
||||
getAccountWithSigninDialog().then(res => {
|
||||
if (res != null) {
|
||||
success();
|
||||
}
|
||||
});
|
||||
},
|
||||
}, {
|
||||
text: i18n.ts.createAccount,
|
||||
action: () => {
|
||||
getAccountWithSignupDialog().then(res => {
|
||||
if (res != null) {
|
||||
switchAccount(host, res.id);
|
||||
}
|
||||
});
|
||||
},
|
||||
}],
|
||||
}, {
|
||||
type: 'link',
|
||||
icon: 'ti ti-users',
|
||||
text: i18n.ts.manageAccounts,
|
||||
to: '/settings/accounts',
|
||||
});
|
||||
} else {
|
||||
if (opts.includeCurrentAccount) {
|
||||
menuItems.push(createItem(host, $i));
|
||||
}
|
||||
|
||||
menuItems.push(...accountItems);
|
||||
}
|
||||
|
||||
popupMenu(menuItems, ev.currentTarget ?? ev.target, {
|
||||
align: 'left',
|
||||
});
|
||||
}
|
||||
|
||||
export function getAccountWithSigninDialog(): Promise<{ id: string, token: string } | null> {
|
||||
return new Promise((resolve) => {
|
||||
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), {}, {
|
||||
done: async (res: Misskey.entities.SigninFlowResponse & { finished: true }) => {
|
||||
const user = await fetchAccount(res.i, res.id, true);
|
||||
await addAccount(host, user, res.i);
|
||||
resolve({ id: res.id, token: res.i });
|
||||
},
|
||||
cancelled: () => {
|
||||
resolve(null);
|
||||
},
|
||||
closed: () => {
|
||||
dispose();
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function getAccountWithSignupDialog(): Promise<{ id: string, token: string } | null> {
|
||||
return new Promise((resolve) => {
|
||||
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSignupDialog.vue')), {}, {
|
||||
done: async (res: Misskey.entities.SignupResponse) => {
|
||||
const user = JSON.parse(JSON.stringify(res));
|
||||
delete user.token;
|
||||
await addAccount(host, user, res.token);
|
||||
resolve({ id: res.id, token: res.token });
|
||||
},
|
||||
cancelled: () => {
|
||||
resolve(null);
|
||||
},
|
||||
closed: () => {
|
||||
dispose();
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
|
@ -9,7 +9,7 @@ import { url, lang } from '@@/js/config.js';
|
|||
import { assertStringAndIsIn } from './common.js';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { miLocalStorage } from '@/local-storage.js';
|
||||
import { customEmojis } from '@/custom-emojis.js';
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ import components from '@/components/index.js';
|
|||
import { applyTheme } from '@/theme.js';
|
||||
import { isDeviceDarkmode } from '@/utility/is-device-darkmode.js';
|
||||
import { updateI18n, i18n } from '@/i18n.js';
|
||||
import { $i, refreshAccount, login } from '@/account.js';
|
||||
import { refreshCurrentAccount, login } from '@/accounts.js';
|
||||
import { store } from '@/store.js';
|
||||
import { fetchInstance, instance } from '@/instance.js';
|
||||
import { deviceKind, updateDeviceKind } from '@/utility/device-kind.js';
|
||||
|
@ -29,6 +29,7 @@ import { fetchCustomEmojis } from '@/custom-emojis.js';
|
|||
import { setupRouter } from '@/router/main.js';
|
||||
import { createMainRouter } from '@/router/definition.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import { $i } from '@/i.js';
|
||||
|
||||
export async function common(createVue: () => App<Element>) {
|
||||
console.info(`Misskey v${version}`);
|
||||
|
@ -38,11 +39,6 @@ export async function common(createVue: () => App<Element>) {
|
|||
|
||||
console.info(`vue ${vueVersion}`);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(window as any).$i = $i;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(window as any).$store = store;
|
||||
|
||||
window.addEventListener('error', event => {
|
||||
console.error(event);
|
||||
/*
|
||||
|
@ -244,7 +240,7 @@ export async function common(createVue: () => App<Element>) {
|
|||
console.log('account cache found. refreshing...');
|
||||
}
|
||||
|
||||
refreshAccount();
|
||||
refreshCurrentAccount();
|
||||
}
|
||||
//#endregion
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ import { i18n } from '@/i18n.js';
|
|||
import { alert, confirm, popup, post, toast } from '@/os.js';
|
||||
import { useStream } from '@/stream.js';
|
||||
import * as sound from '@/utility/sound.js';
|
||||
import { $i, signout, updateAccountPartial } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { instance } from '@/instance.js';
|
||||
import { ColdDeviceStorage, store } from '@/store.js';
|
||||
import { reactionPicker } from '@/utility/reaction-picker.js';
|
||||
|
@ -32,6 +32,8 @@ import { misskeyApi } from '@/utility/misskey-api.js';
|
|||
import { deckStore } from '@/ui/deck/deck-store.js';
|
||||
import { launchPlugins } from '@/plugin.js';
|
||||
import { unisonReload } from '@/utility/unison-reload.js';
|
||||
import { updateCurrentAccountPartial } from '@/accounts.js';
|
||||
import { signout } from '@/signout.js';
|
||||
|
||||
export async function mainBoot() {
|
||||
const { isClientUpdated, lastVersion } = await common(() => {
|
||||
|
@ -480,11 +482,11 @@ export async function mainBoot() {
|
|||
|
||||
// 自分の情報が更新されたとき
|
||||
main.on('meUpdated', i => {
|
||||
updateAccountPartial(i);
|
||||
updateCurrentAccountPartial(i);
|
||||
});
|
||||
|
||||
main.on('readAllNotifications', () => {
|
||||
updateAccountPartial({
|
||||
updateCurrentAccountPartial({
|
||||
hasUnreadNotification: false,
|
||||
unreadNotificationsCount: 0,
|
||||
});
|
||||
|
@ -492,39 +494,39 @@ export async function mainBoot() {
|
|||
|
||||
main.on('unreadNotification', () => {
|
||||
const unreadNotificationsCount = ($i?.unreadNotificationsCount ?? 0) + 1;
|
||||
updateAccountPartial({
|
||||
updateCurrentAccountPartial({
|
||||
hasUnreadNotification: true,
|
||||
unreadNotificationsCount,
|
||||
});
|
||||
});
|
||||
|
||||
main.on('unreadMention', () => {
|
||||
updateAccountPartial({ hasUnreadMentions: true });
|
||||
updateCurrentAccountPartial({ hasUnreadMentions: true });
|
||||
});
|
||||
|
||||
main.on('readAllUnreadMentions', () => {
|
||||
updateAccountPartial({ hasUnreadMentions: false });
|
||||
updateCurrentAccountPartial({ hasUnreadMentions: false });
|
||||
});
|
||||
|
||||
main.on('unreadSpecifiedNote', () => {
|
||||
updateAccountPartial({ hasUnreadSpecifiedNotes: true });
|
||||
updateCurrentAccountPartial({ hasUnreadSpecifiedNotes: true });
|
||||
});
|
||||
|
||||
main.on('readAllUnreadSpecifiedNotes', () => {
|
||||
updateAccountPartial({ hasUnreadSpecifiedNotes: false });
|
||||
updateCurrentAccountPartial({ hasUnreadSpecifiedNotes: false });
|
||||
});
|
||||
|
||||
main.on('readAllAntennas', () => {
|
||||
updateAccountPartial({ hasUnreadAntenna: false });
|
||||
updateCurrentAccountPartial({ hasUnreadAntenna: false });
|
||||
});
|
||||
|
||||
main.on('unreadAntenna', () => {
|
||||
updateAccountPartial({ hasUnreadAntenna: true });
|
||||
updateCurrentAccountPartial({ hasUnreadAntenna: true });
|
||||
sound.playMisskeySfx('antenna');
|
||||
});
|
||||
|
||||
main.on('readAllAnnouncements', () => {
|
||||
updateAccountPartial({ hasUnreadAnnouncement: false });
|
||||
updateCurrentAccountPartial({ hasUnreadAnnouncement: false });
|
||||
});
|
||||
|
||||
// 個人宛てお知らせが発行されたとき
|
||||
|
|
|
@ -29,7 +29,8 @@ import { misskeyApi } from '@/utility/misskey-api.js';
|
|||
import MkModal from '@/components/MkModal.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { $i, updateAccountPartial } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { updateCurrentAccountPartial } from '@/accounts.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
announcement: Misskey.entities.Announcement;
|
||||
|
@ -51,7 +52,7 @@ async function ok() {
|
|||
|
||||
modal.value?.close();
|
||||
misskeyApi('i/read-announcement', { announcementId: props.announcement.id });
|
||||
updateAccountPartial({
|
||||
updateCurrentAccountPartial({
|
||||
unreadAnnouncements: $i!.unreadAnnouncements.filter(a => a.id !== props.announcement.id),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -117,10 +117,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
|
||||
import { $i, getAccounts, getAccountWithSigninDialog, getAccountWithSignupDialog } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { getAccounts, getAccountWithSigninDialog, getAccountWithSignupDialog } from '@/accounts.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import * as os from '@/os.js';
|
||||
import { getProxiedImageUrl } from '@/utility/media-proxy.js';
|
||||
|
@ -158,7 +157,7 @@ async function init() {
|
|||
|
||||
const accounts = await getAccounts();
|
||||
|
||||
const accountIdsToFetch = accounts.map(a => a.id).filter(id => !users.value.has(id));
|
||||
const accountIdsToFetch = accounts.map(a => a.user.id).filter(id => !users.value.has(id));
|
||||
|
||||
if (accountIdsToFetch.length > 0) {
|
||||
const usersRes = await misskeyApi('users/show', {
|
||||
|
@ -170,7 +169,7 @@ async function init() {
|
|||
|
||||
users.value.set(user.id, {
|
||||
...user,
|
||||
token: accounts.find(a => a.id === user.id)!.token,
|
||||
token: accounts.find(a => a.user.id === user.id)!.token,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
import * as Misskey from 'misskey-js';
|
||||
import { computed } from 'vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import number from '@/filters/number.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
|
|
|
@ -38,7 +38,7 @@ import tinycolor from 'tinycolor2';
|
|||
import { apiUrl } from '@@/js/config.js';
|
||||
import MkModalWindow from '@/components/MkModalWindow.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { getProxiedImageUrl } from '@/utility/media-proxy.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
|
|
|
@ -44,7 +44,7 @@ import MkDriveFileThumbnail from '@/components/MkDriveFileThumbnail.vue';
|
|||
import bytes from '@/filters/bytes.js';
|
||||
import * as os from '@/os.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { getDriveFileMenu } from '@/utility/get-drive-file-menu.js';
|
||||
import { deviceKind } from '@/utility/device-kind.js';
|
||||
import { useRouter } from '@/router/supplier.js';
|
||||
|
|
|
@ -136,7 +136,7 @@ import { deviceKind } from '@/utility/device-kind.js';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import { store } from '@/store.js';
|
||||
import { customEmojiCategories, customEmojis, customEmojisMap } from '@/custom-emojis.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { checkReactionPermissions } from '@/utility/check-reaction-permissions.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ import { useStream } from '@/stream.js';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import { claimAchievement } from '@/utility/achievements.js';
|
||||
import { pleaseLogin } from '@/utility/please-login.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
|
|
|
@ -89,7 +89,7 @@ import { Chart } from 'chart.js';
|
|||
import MkSelect from '@/components/MkSelect.vue';
|
||||
import MkChart from '@/components/MkChart.vue';
|
||||
import { useChartTooltip } from '@/use/use-chart-tooltip.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApiGet } from '@/utility/misskey-api.js';
|
||||
import { instance } from '@/instance.js';
|
||||
|
|
|
@ -98,7 +98,7 @@ import * as os from '@/os.js';
|
|||
import bytes from '@/filters/bytes.js';
|
||||
import { hms } from '@/filters/hms.js';
|
||||
import MkMediaRange from '@/components/MkMediaRange.vue';
|
||||
import { $i, iAmModerator } from '@/account.js';
|
||||
import { $i, iAmModerator } from '@/i.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
|
||||
const props = defineProps<{
|
||||
|
|
|
@ -60,7 +60,7 @@ import bytes from '@/filters/bytes.js';
|
|||
import ImgWithBlurhash from '@/components/MkImgWithBlurhash.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import * as os from '@/os.js';
|
||||
import { $i, iAmModerator } from '@/account.js';
|
||||
import { $i, iAmModerator } from '@/i.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
|
|
|
@ -121,7 +121,7 @@ import * as os from '@/os.js';
|
|||
import { exitFullscreen, requestFullscreen } from '@/utility/fullscreen.js';
|
||||
import hasAudio from '@/utility/media-has-audio.js';
|
||||
import MkMediaRange from '@/components/MkMediaRange.vue';
|
||||
import { $i, iAmModerator } from '@/account.js';
|
||||
import { $i, iAmModerator } from '@/i.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
|
||||
const props = defineProps<{
|
||||
|
|
|
@ -18,7 +18,7 @@ import { toUnicode } from 'punycode.js';
|
|||
import { computed } from 'vue';
|
||||
import { host as localHost } from '@@/js/config.js';
|
||||
import type { MkABehavior } from '@/components/global/MkA.vue';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { getStaticImageUrl } from '@/utility/media-proxy.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
|
||||
|
|
|
@ -208,7 +208,7 @@ import * as sound from '@/utility/sound.js';
|
|||
import { misskeyApi, misskeyApiGet } from '@/utility/misskey-api.js';
|
||||
import { reactionPicker } from '@/utility/reaction-picker.js';
|
||||
import { extractUrlFromMfm } from '@/utility/extract-url-from-mfm.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { getAbuseNoteMenu, getCopyNoteLinkMenu, getNoteClipMenu, getNoteMenu, getRenoteMenu } from '@/utility/get-note-menu.js';
|
||||
import { useNoteCapture } from '@/use/use-note-capture.js';
|
||||
|
|
|
@ -238,7 +238,7 @@ import { misskeyApi, misskeyApiGet } from '@/utility/misskey-api.js';
|
|||
import * as sound from '@/utility/sound.js';
|
||||
import { reactionPicker } from '@/utility/reaction-picker.js';
|
||||
import { extractUrlFromMfm } from '@/utility/extract-url-from-mfm.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { getNoteClipMenu, getNoteMenu, getRenoteMenu } from '@/utility/get-note-menu.js';
|
||||
import { useNoteCapture } from '@/use/use-note-capture.js';
|
||||
|
|
|
@ -48,7 +48,7 @@ import MkCwButton from '@/components/MkCwButton.vue';
|
|||
import { notePage } from '@/filters/note.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { userPage } from '@/filters/user.js';
|
||||
import { checkWordMute } from '@/utility/check-word-mute.js';
|
||||
|
||||
|
|
|
@ -169,7 +169,7 @@ import { notePage } from '@/filters/note.js';
|
|||
import { userPage } from '@/filters/user.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { signinRequired } from '@/account.js';
|
||||
import { signinRequired } from '@/i.js';
|
||||
import { infoImageUrl } from '@/instance.js';
|
||||
|
||||
const $i = signinRequired();
|
||||
|
|
|
@ -44,7 +44,7 @@ import MkInput from '@/components/MkInput.vue';
|
|||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkModalWindow from '@/components/MkModalWindow.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { signinRequired } from '@/account.js';
|
||||
import { signinRequired } from '@/i.js';
|
||||
|
||||
const $i = signinRequired();
|
||||
|
||||
|
|
|
@ -127,7 +127,8 @@ import { store } from '@/store.js';
|
|||
import MkInfo from '@/components/MkInfo.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { instance } from '@/instance.js';
|
||||
import { signinRequired, notesCount, incNotesCount, getAccounts, openAccountMenu as openAccountMenu_ } from '@/account.js';
|
||||
import { signinRequired, notesCount, incNotesCount } from '@/i.js';
|
||||
import { getAccounts, openAccountMenu as openAccountMenu_ } from '@/accounts.js';
|
||||
import { uploadFile } from '@/utility/upload.js';
|
||||
import { deepClone } from '@/utility/clone.js';
|
||||
import MkRippleEffect from '@/components/MkRippleEffect.vue';
|
||||
|
@ -837,7 +838,7 @@ async function post(ev?: MouseEvent) {
|
|||
|
||||
if (postAccount.value) {
|
||||
const storedAccounts = await getAccounts();
|
||||
token = storedAccounts.find(x => x.id === postAccount.value?.id)?.token;
|
||||
token = storedAccounts.find(x => x.user.id === postAccount.value?.id)?.token;
|
||||
}
|
||||
|
||||
posting.value = true;
|
||||
|
|
|
@ -43,7 +43,7 @@ import MkTextarea from '@/components/MkTextarea.vue';
|
|||
import MkRadio from '@/components/MkRadio.vue';
|
||||
import * as os from '@/os.js';
|
||||
import * as config from '@@/js/config.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
|
||||
const text = ref('');
|
||||
const flag = ref(true);
|
||||
|
|
|
@ -42,12 +42,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { $i, getAccounts } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import { instance } from '@/instance.js';
|
||||
import { apiWithDialog, promiseDialog } from '@/os.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { getAccounts } from '@/accounts.js';
|
||||
|
||||
defineProps<{
|
||||
primary?: boolean;
|
||||
|
|
|
@ -27,7 +27,7 @@ import MkReactionIcon from '@/components/MkReactionIcon.vue';
|
|||
import * as os from '@/os.js';
|
||||
import { misskeyApi, misskeyApiGet } from '@/utility/misskey-api.js';
|
||||
import { useTooltip } from '@/use/use-tooltip.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import MkReactionEffect from '@/components/MkReactionEffect.vue';
|
||||
import { claimAchievement } from '@/utility/achievements.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
|
|
@ -67,20 +67,19 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
import { nextTick, onBeforeUnmount, ref, shallowRef, useTemplateRef } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { supported as webAuthnSupported, parseRequestOptionsFromJSON } from '@github/webauthn-json/browser-ponyfill';
|
||||
|
||||
import type { AuthenticationPublicKeyCredential } from '@github/webauthn-json/browser-ponyfill';
|
||||
import type { OpenOnRemoteOptions } from '@/utility/please-login.js';
|
||||
import type { PwResponse } from '@/components/MkSignin.password.vue';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { showSuspendedDialog } from '@/utility/show-suspended-dialog.js';
|
||||
import { login } from '@/account.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import * as os from '@/os.js';
|
||||
|
||||
import XInput from '@/components/MkSignin.input.vue';
|
||||
import XPassword from '@/components/MkSignin.password.vue';
|
||||
import type { PwResponse } from '@/components/MkSignin.password.vue';
|
||||
import XTotp from '@/components/MkSignin.totp.vue';
|
||||
import XPasskey from '@/components/MkSignin.passkey.vue';
|
||||
import { login } from '@/accounts.js';
|
||||
|
||||
const emit = defineEmits<{
|
||||
(ev: 'login', v: Misskey.entities.SigninFlowResponse & { finished: true }): void;
|
||||
|
|
|
@ -85,13 +85,13 @@ import * as Misskey from 'misskey-js';
|
|||
import * as config from '@@/js/config.js';
|
||||
import MkButton from './MkButton.vue';
|
||||
import MkInput from './MkInput.vue';
|
||||
import MkCaptcha from '@/components/MkCaptcha.vue';
|
||||
import type { Captcha } from '@/components/MkCaptcha.vue';
|
||||
import MkCaptcha from '@/components/MkCaptcha.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { login } from '@/account.js';
|
||||
import { instance } from '@/instance.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { login } from '@/accounts.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
autoSet?: boolean;
|
||||
|
|
|
@ -25,7 +25,7 @@ import MkNotes from '@/components/MkNotes.vue';
|
|||
import MkPullToRefresh from '@/components/MkPullToRefresh.vue';
|
||||
import { useStream } from '@/stream.js';
|
||||
import * as sound from '@/utility/sound.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { instance } from '@/instance.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ import MkButton from './MkButton.vue';
|
|||
import MkInfo from './MkInfo.vue';
|
||||
import MkModalWindow from '@/components/MkModalWindow.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { iAmAdmin } from '@/account.js';
|
||||
import { iAmAdmin } from '@/i.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
title?: string | null;
|
||||
|
|
|
@ -27,7 +27,7 @@ import * as Misskey from 'misskey-js';
|
|||
import { ref, reactive } from 'vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { globalEvents } from '@/events.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import MkNote from '@/components/MkNote.vue';
|
||||
|
||||
const props = defineProps<{
|
||||
|
|
|
@ -31,7 +31,7 @@ import MkPostForm from '@/components/MkPostForm.vue';
|
|||
import MkFolder from '@/components/MkFolder.vue';
|
||||
import MkInfo from '@/components/MkInfo.vue';
|
||||
import MkNote from '@/components/MkNote.vue';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
|
||||
const emit = defineEmits<{
|
||||
(ev: 'succeeded'): void;
|
||||
|
|
|
@ -39,7 +39,7 @@ import MkFollowButton from '@/components/MkFollowButton.vue';
|
|||
import number from '@/filters/number.js';
|
||||
import { userPage } from '@/filters/user.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { isFollowingVisibleForMe, isFollowersVisibleForMe } from '@/utility/isFfVisibleForMe.js';
|
||||
import { getStaticImageUrl } from '@/utility/media-proxy.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
|
|
|
@ -65,7 +65,7 @@ import { getUserMenu } from '@/utility/get-user-menu.js';
|
|||
import number from '@/filters/number.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { isFollowingVisibleForMe, isFollowersVisibleForMe } from '@/utility/isFfVisibleForMe.js';
|
||||
import { getStaticImageUrl } from '@/utility/media-proxy.js';
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ import MkModalWindow from '@/components/MkModalWindow.vue';
|
|||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { store } from '@/store.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { instance } from '@/instance.js';
|
||||
|
||||
const emit = defineEmits<{
|
||||
|
|
|
@ -39,7 +39,7 @@ import FormSlot from '@/components/form/slot.vue';
|
|||
import MkInfo from '@/components/MkInfo.vue';
|
||||
import { chooseFileFromPc } from '@/utility/select-file.js';
|
||||
import * as os from '@/os.js';
|
||||
import { signinRequired } from '@/account.js';
|
||||
import { signinRequired } from '@/i.js';
|
||||
|
||||
const $i = signinRequired();
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ import { instance } from '@/instance.js';
|
|||
import MkButton from '@/components/MkButton.vue';
|
||||
import { store } from '@/store.js';
|
||||
import * as os from '@/os.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
|
||||
type Ad = (typeof instance)['ads'][number];
|
||||
|
|
|
@ -35,7 +35,7 @@ import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
|||
import * as sound from '@/utility/sound.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import MkCustomEmojiDetailedDialog from '@/components/MkCustomEmojiDetailedDialog.vue';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
|
||||
const props = defineProps<{
|
||||
|
|
|
@ -50,7 +50,8 @@ import type { PageHeaderItem } from '@/types/page-header.js';
|
|||
import type { PageMetadata } from '@/page.js';
|
||||
import { globalEvents } from '@/events.js';
|
||||
import { injectReactiveMetadata } from '@/page.js';
|
||||
import { $i, openAccountMenu as openAccountMenu_ } from '@/account.js';
|
||||
import { openAccountMenu as openAccountMenu_ } from '@/accounts.js';
|
||||
import { $i } from '@/i.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
overridePageMetadata?: PageMetadata;
|
||||
|
|
34
packages/frontend/src/i.ts
Normal file
34
packages/frontend/src/i.ts
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { reactive } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { miLocalStorage } from '@/local-storage.js';
|
||||
|
||||
// TODO: 他のタブと永続化されたstateを同期
|
||||
|
||||
type AccountWithToken = Misskey.entities.MeDetailed & { token: string };
|
||||
|
||||
const accountData = miLocalStorage.getItem('account');
|
||||
|
||||
// TODO: 外部からはreadonlyに
|
||||
export const $i = accountData ? reactive(JSON.parse(accountData) as AccountWithToken) : null;
|
||||
|
||||
export const iAmModerator = $i != null && ($i.isAdmin === true || $i.isModerator === true);
|
||||
export const iAmAdmin = $i != null && $i.isAdmin;
|
||||
|
||||
export function signinRequired() {
|
||||
if ($i == null) throw new Error('signin required');
|
||||
return $i;
|
||||
}
|
||||
|
||||
export let notesCount = $i == null ? 0 : $i.notesCount;
|
||||
export function incNotesCount() {
|
||||
notesCount++;
|
||||
}
|
||||
|
||||
if (_DEV_) {
|
||||
(window as any).$i = $i;
|
||||
}
|
|
@ -9,7 +9,6 @@ export type Keys = (
|
|||
'instance' |
|
||||
'instanceCachedAt' |
|
||||
'account' |
|
||||
'accounts' |
|
||||
'latestDonationInfoShownAt' |
|
||||
'neverShowDonationInfo' |
|
||||
'neverShowLocalOnlyInfo' |
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import { computed, reactive } from 'vue';
|
||||
import { clearCache } from './utility/clear-cache.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { miLocalStorage } from '@/local-storage.js';
|
||||
import { openInstanceMenu, openToolsMenu } from '@/ui/_common_/common.js';
|
||||
import { lookup } from '@/utility/lookup.js';
|
||||
|
|
|
@ -146,7 +146,7 @@ import { instance } from '@/instance.js';
|
|||
import * as os from '@/os.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { claimAchievement, claimedAchievements } from '@/utility/achievements.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
|
||||
const patronsWithIcon = [{
|
||||
|
|
|
@ -44,7 +44,7 @@ import MkInput from '@/components/MkInput.vue';
|
|||
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
||||
import { customEmojis, customEmojiCategories, getCustomEmojiTags } from '@/custom-emojis.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
|
||||
const customEmojiTags = getCustomEmojiTags();
|
||||
const q = ref('');
|
||||
|
|
|
@ -17,7 +17,7 @@ import { onActivated, onDeactivated, onMounted, onUnmounted } from 'vue';
|
|||
import MkAchievements from '@/components/MkAchievements.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { claimAchievement } from '@/utility/achievements.js';
|
||||
|
||||
let timer: number | null;
|
||||
|
|
|
@ -86,7 +86,7 @@ import * as os from '@/os.js';
|
|||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { iAmAdmin, iAmModerator } from '@/account.js';
|
||||
import { iAmAdmin, iAmModerator } from '@/i.js';
|
||||
|
||||
const tab = ref('overview');
|
||||
const file = ref<Misskey.entities.DriveFile | null>(null);
|
||||
|
|
|
@ -233,7 +233,7 @@ import { misskeyApi } from '@/utility/misskey-api.js';
|
|||
import { acct } from '@/filters/user.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { iAmAdmin, $i, iAmModerator } from '@/account.js';
|
||||
import { iAmAdmin, $i, iAmModerator } from '@/i.js';
|
||||
import MkRolePreview from '@/components/MkRolePreview.vue';
|
||||
import MkPagination from '@/components/MkPagination.vue';
|
||||
|
||||
|
|
|
@ -55,8 +55,9 @@ import * as os from '@/os.js';
|
|||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { $i, updateAccountPartial } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import { updateCurrentAccountPartial } from '@/accounts.js';
|
||||
|
||||
const props = defineProps<{
|
||||
announcementId: string;
|
||||
|
@ -90,7 +91,7 @@ async function read(target: Misskey.entities.Announcement): Promise<void> {
|
|||
target.isRead = true;
|
||||
await misskeyApi('i/read-announcement', { announcementId: target.id });
|
||||
if ($i) {
|
||||
updateAccountPartial({
|
||||
updateCurrentAccountPartial({
|
||||
unreadAnnouncements: $i.unreadAnnouncements.filter((a: { id: string; }) => a.id !== target.id),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -56,7 +56,8 @@ import * as os from '@/os.js';
|
|||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { $i, updateAccountPartial } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { updateCurrentAccountPartial } from '@/accounts.js';
|
||||
|
||||
const paginationCurrent = {
|
||||
endpoint: 'announcements' as const,
|
||||
|
@ -94,7 +95,7 @@ async function read(target) {
|
|||
return a;
|
||||
});
|
||||
misskeyApi('i/read-announcement', { announcementId: target.id });
|
||||
updateAccountPartial({
|
||||
updateCurrentAccountPartial({
|
||||
unreadAnnouncements: $i!.unreadAnnouncements.filter(a => a.id !== target.id),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -47,9 +47,10 @@ import * as Misskey from 'misskey-js';
|
|||
import XForm from './auth.form.vue';
|
||||
import MkSignin from '@/components/MkSignin.vue';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { $i, login } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { login } from '@/accounts.js';
|
||||
|
||||
const props = defineProps<{
|
||||
token: string;
|
||||
|
|
|
@ -73,7 +73,7 @@ import { i18n } from '@/i18n.js';
|
|||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import MkRolePreview from '@/components/MkRolePreview.vue';
|
||||
import MkTextarea from '@/components/MkTextarea.vue';
|
||||
import { signinRequired } from '@/account.js';
|
||||
import { signinRequired } from '@/i.js';
|
||||
|
||||
const $i = signinRequired();
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<script lang="ts" setup>
|
||||
import { ref, computed, defineAsyncComponent } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { signinRequired } from '@/account.js';
|
||||
import { signinRequired } from '@/i.js';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
|
|
@ -82,7 +82,7 @@ import MkTimeline from '@/components/MkTimeline.vue';
|
|||
import XChannelFollowButton from '@/components/MkChannelFollowButton.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { $i, iAmModerator } from '@/account.js';
|
||||
import { $i, iAmModerator } from '@/i.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { deviceKind } from '@/utility/device-kind.js';
|
||||
|
|
|
@ -36,7 +36,7 @@ import * as Misskey from 'misskey-js';
|
|||
import { url } from '@@/js/config.js';
|
||||
import type { MenuItem } from '@/types/menu.js';
|
||||
import MkNotes from '@/components/MkNotes.vue';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
|
|
|
@ -208,7 +208,7 @@ import { claimAchievement } from '@/utility/achievements.js';
|
|||
import { store } from '@/store.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import * as sound from '@/utility/sound.js';
|
||||
import MkRange from '@/components/MkRange.vue';
|
||||
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
||||
|
|
|
@ -22,7 +22,7 @@ import { misskeyApiGet } from '@/utility/misskey-api.js';
|
|||
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import MkCustomEmojiDetailedDialog from '@/components/MkCustomEmojiDetailedDialog.vue';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
|
||||
const props = defineProps<{
|
||||
emoji: Misskey.entities.EmojiSimple;
|
||||
|
|
|
@ -80,7 +80,7 @@ import { aiScriptReadline, createAiScriptEnv } from '@/aiscript/api.js';
|
|||
import MkFolder from '@/components/MkFolder.vue';
|
||||
import MkCode from '@/components/MkCode.vue';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { isSupportShare } from '@/utility/navigator.js';
|
||||
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
||||
import { pleaseLogin } from '@/utility/please-login.js';
|
||||
|
|
|
@ -54,7 +54,7 @@ import * as os from '@/os.js';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { infoImageUrl } from '@/instance.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
||||
|
||||
const paginationComponent = shallowRef<InstanceType<typeof MkPagination>>();
|
||||
|
|
|
@ -77,7 +77,7 @@ import MkFollowButton from '@/components/MkFollowButton.vue';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { isSupportShare } from '@/utility/navigator.js';
|
||||
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
||||
import { useRouter } from '@/router/supplier.js';
|
||||
|
|
|
@ -148,7 +148,7 @@ import MkSwitch from '@/components/MkSwitch.vue';
|
|||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import number from '@/filters/number.js';
|
||||
import { iAmModerator, iAmAdmin } from '@/account.js';
|
||||
import { iAmModerator, iAmAdmin } from '@/i.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||
|
|
|
@ -45,7 +45,7 @@ import type { Paging } from '@/components/MkPagination.vue';
|
|||
import MkInviteCode from '@/components/MkInviteCode.vue';
|
||||
import { definePage } from '@/page.js';
|
||||
import { serverErrorImageUrl, instance } from '@/instance.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
|
||||
const pagingComponent = shallowRef<InstanceType<typeof MkPagination>>();
|
||||
const currentInviteLimit = ref<null | number>(null);
|
||||
|
|
|
@ -37,7 +37,7 @@ import { i18n } from '@/i18n.js';
|
|||
import { definePage } from '@/page.js';
|
||||
import { userListsCache } from '@/cache.js';
|
||||
import { infoImageUrl } from '@/instance.js';
|
||||
import { signinRequired } from '@/account.js';
|
||||
import { signinRequired } from '@/i.js';
|
||||
|
||||
const $i = signinRequired();
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ import MkSwitch from '@/components/MkSwitch.vue';
|
|||
import MkFolder from '@/components/MkFolder.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import { userListsCache } from '@/cache.js';
|
||||
import { signinRequired } from '@/account.js';
|
||||
import { signinRequired } from '@/i.js';
|
||||
import MkPagination from '@/components/MkPagination.vue';
|
||||
import { mainRouter } from '@/router/main.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
|
|
|
@ -65,7 +65,7 @@ import { prefer } from '@/preferences.js';
|
|||
import { pleaseLogin } from '@/utility/please-login.js';
|
||||
import { getAppearNote } from '@/utility/get-appear-note.js';
|
||||
import { serverContext, assertServerContext } from '@/server-context.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
|
||||
// contextは非ログイン状態の情報しかないためログイン時は利用できない
|
||||
const CTX_NOTE = !$i && assertServerContext(serverContext, 'note') ? serverContext.note : null;
|
||||
|
|
|
@ -75,7 +75,7 @@ import { misskeyApi } from '@/utility/misskey-api.js';
|
|||
import { selectFile } from '@/utility/select-file.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { mainRouter } from '@/router/main.js';
|
||||
import { getPageBlockList } from '@/pages/page-editor/common.js';
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ import MkPagePreview from '@/components/MkPagePreview.vue';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { deepClone } from '@/utility/clone.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { isSupportShare } from '@/utility/navigator.js';
|
||||
import { instance } from '@/instance.js';
|
||||
import { getStaticImageUrl } from '@/utility/media-proxy.js';
|
||||
|
|
|
@ -150,7 +150,7 @@ import MkFolder from '@/components/MkFolder.vue';
|
|||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import { deepClone } from '@/utility/clone.js';
|
||||
import { useInterval } from '@@/js/use-interval.js';
|
||||
import { signinRequired } from '@/account.js';
|
||||
import { signinRequired } from '@/i.js';
|
||||
import { url } from '@@/js/config.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
|
|
|
@ -114,7 +114,7 @@ import { computed, watch, ref, onMounted, shallowRef, onUnmounted } from 'vue';
|
|||
import * as Misskey from 'misskey-js';
|
||||
import * as Reversi from 'misskey-reversi';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { signinRequired } from '@/account.js';
|
||||
import { signinRequired } from '@/i.js';
|
||||
import { deepClone } from '@/utility/clone.js';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkRadios from '@/components/MkRadios.vue';
|
||||
|
|
|
@ -17,7 +17,7 @@ import GameBoard from './game.board.vue';
|
|||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { useStream } from '@/stream.js';
|
||||
import { signinRequired } from '@/account.js';
|
||||
import { signinRequired } from '@/i.js';
|
||||
import { useRouter } from '@/router/supplier.js';
|
||||
import * as os from '@/os.js';
|
||||
import { url } from '@@/js/config.js';
|
||||
|
|
|
@ -113,7 +113,7 @@ import { useStream } from '@/stream.js';
|
|||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkFolder from '@/components/MkFolder.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import MkPagination from '@/components/MkPagination.vue';
|
||||
import { useRouter } from '@/router/supplier.js';
|
||||
import * as os from '@/os.js';
|
||||
|
|
|
@ -66,7 +66,7 @@ import MkTextarea from '@/components/MkTextarea.vue';
|
|||
import MkCodeEditor from '@/components/MkCodeEditor.vue';
|
||||
import { aiScriptReadline, createAiScriptEnv } from '@/aiscript/api.js';
|
||||
import * as os from '@/os.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { registerAsUiLib } from '@/aiscript/ui.js';
|
||||
|
|
|
@ -114,7 +114,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
import { computed, ref, shallowRef, toRef } from 'vue';
|
||||
import type * as Misskey from 'misskey-js';
|
||||
import type { Paging } from '@/components/MkPagination.vue';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { host as localHost } from '@@/js/config.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { instance } from '@/instance.js';
|
||||
|
|
|
@ -117,7 +117,7 @@ import MkFolder from '@/components/MkFolder.vue';
|
|||
import MkInfo from '@/components/MkInfo.vue';
|
||||
import MkLink from '@/components/MkLink.vue';
|
||||
import { confetti } from '@/utility/confetti.js';
|
||||
import { signinRequired } from '@/account.js';
|
||||
import { signinRequired } from '@/i.js';
|
||||
|
||||
const $i = signinRequired();
|
||||
|
||||
|
|
|
@ -92,8 +92,9 @@ import FormSection from '@/components/form/section.vue';
|
|||
import MkFolder from '@/components/MkFolder.vue';
|
||||
import MkLink from '@/components/MkLink.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { signinRequired, updateAccountPartial } from '@/account.js';
|
||||
import { signinRequired } from '@/i.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { updateCurrentAccountPartial } from '@/accounts.js';
|
||||
|
||||
const $i = signinRequired();
|
||||
|
||||
|
@ -131,7 +132,7 @@ async function unregisterTOTP(): Promise<void> {
|
|||
password: auth.result.password,
|
||||
token: auth.result.token,
|
||||
}).then(res => {
|
||||
updateAccountPartial({
|
||||
updateCurrentAccountPartial({
|
||||
twoFactorEnabled: false,
|
||||
});
|
||||
}).catch(error => {
|
||||
|
|
|
@ -167,7 +167,7 @@ import { misskeyApi } from '@/utility/misskey-api.js';
|
|||
import { selectFile } from '@/utility/select-file.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import MkFeatureBanner from '@/components/MkFeatureBanner.vue';
|
||||
import { prefer } from '@/preferences.js';
|
||||
|
||||
|
|
|
@ -4,80 +4,51 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
-->
|
||||
|
||||
<template>
|
||||
<div class="">
|
||||
<FormSuspense :p="init">
|
||||
<div class="_gaps">
|
||||
<div class="_buttons">
|
||||
<MkButton primary @click="addAccount"><i class="ti ti-plus"></i> {{ i18n.ts.addAccount }}</MkButton>
|
||||
<MkButton @click="init"><i class="ti ti-refresh"></i> {{ i18n.ts.reloadAccountsList }}</MkButton>
|
||||
</div>
|
||||
|
||||
<template v-for="[id, user] in accounts">
|
||||
<MkUserCardMini v-if="user != null" :key="user.id" :user="user" :class="$style.user" @click.prevent="menu(user, $event)"/>
|
||||
<button v-else v-panel class="_button" :class="$style.unknownUser" @click="menu(id, $event)">
|
||||
<div :class="$style.unknownUserAvatarMock"><i class="ti ti-user-question"></i></div>
|
||||
<div>
|
||||
<div :class="$style.unknownUserTitle">{{ i18n.ts.unknown }}</div>
|
||||
<div :class="$style.unknownUserSub">ID: <span class="_monospace">{{ id }}</span></div>
|
||||
</div>
|
||||
</button>
|
||||
</template>
|
||||
<SearchMarker path="/settings/accounts" :label="i18n.ts.accounts" :keywords="['accounts']" icon="ti ti-users">
|
||||
<div class="_gaps">
|
||||
<div class="_buttons">
|
||||
<MkButton primary @click="addAccount"><i class="ti ti-plus"></i> {{ i18n.ts.addAccount }}</MkButton>
|
||||
<!--<MkButton @click="refreshAllAccounts"><i class="ti ti-refresh"></i></MkButton>-->
|
||||
</div>
|
||||
</FormSuspense>
|
||||
</div>
|
||||
|
||||
<MkUserCardMini v-for="x in accounts" :key="x[0] + x[1].id" :user="x[1]" :class="$style.user" @click.prevent="menu(x[0], x[1], $event)"/>
|
||||
</div>
|
||||
</SearchMarker>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import FormSuspense from '@/components/form/suspense.vue';
|
||||
import type { MenuItem } from '@/types/menu.js';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { getAccounts, removeAccount as _removeAccount, login, $i, getAccountWithSigninDialog, getAccountWithSignupDialog } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { switchAccount, removeAccount, login, getAccountWithSigninDialog, getAccountWithSignupDialog } from '@/accounts.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||
import type { MenuItem } from '@/types/menu.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
|
||||
const storedAccounts = ref<{ id: string, token: string }[] | null>(null);
|
||||
const accounts = ref(new Map<string, Misskey.entities.UserDetailed | null>());
|
||||
const accounts = prefer.r.accounts;
|
||||
|
||||
const init = async () => {
|
||||
getAccounts().then(accounts => {
|
||||
storedAccounts.value = accounts.filter(x => x.id !== $i!.id);
|
||||
function refreshAllAccounts() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
return misskeyApi('users/show', {
|
||||
userIds: storedAccounts.value.map(x => x.id),
|
||||
});
|
||||
}).then(response => {
|
||||
if (storedAccounts.value == null) return;
|
||||
accounts.value = new Map(storedAccounts.value.map(x => [x.id, response.find((y: Misskey.entities.UserDetailed) => y.id === x.id) ?? null]));
|
||||
});
|
||||
};
|
||||
|
||||
function menu(account: Misskey.entities.UserDetailed | string, ev: MouseEvent) {
|
||||
function menu(host: string, account: Misskey.entities.UserDetailed, ev: MouseEvent) {
|
||||
let menu: MenuItem[];
|
||||
|
||||
if (typeof account === 'string') {
|
||||
menu = [{
|
||||
text: i18n.ts.logout,
|
||||
icon: 'ti ti-trash',
|
||||
danger: true,
|
||||
action: () => removeAccount(account),
|
||||
}];
|
||||
} else {
|
||||
menu = [{
|
||||
text: i18n.ts.switch,
|
||||
icon: 'ti ti-switch-horizontal',
|
||||
action: () => switchAccount(account.id),
|
||||
}, {
|
||||
text: i18n.ts.logout,
|
||||
icon: 'ti ti-trash',
|
||||
danger: true,
|
||||
action: () => removeAccount(account.id),
|
||||
}];
|
||||
}
|
||||
menu = [{
|
||||
text: i18n.ts.switch,
|
||||
icon: 'ti ti-switch-horizontal',
|
||||
action: () => switchAccount(host, account.id),
|
||||
}, {
|
||||
text: i18n.ts.logout,
|
||||
icon: 'ti ti-trash',
|
||||
danger: true,
|
||||
action: () => removeAccount(host, account.id),
|
||||
}];
|
||||
|
||||
os.popupMenu(menu, ev.currentTarget ?? ev.target);
|
||||
}
|
||||
|
@ -92,16 +63,10 @@ function addAccount(ev: MouseEvent) {
|
|||
}], ev.currentTarget ?? ev.target);
|
||||
}
|
||||
|
||||
async function removeAccount(id: string) {
|
||||
await _removeAccount(id);
|
||||
accounts.value.delete(id);
|
||||
}
|
||||
|
||||
function addExistingAccount() {
|
||||
getAccountWithSigninDialog().then((res) => {
|
||||
if (res != null) {
|
||||
os.success();
|
||||
init();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -109,21 +74,11 @@ function addExistingAccount() {
|
|||
function createAccount() {
|
||||
getAccountWithSignupDialog().then((res) => {
|
||||
if (res != null) {
|
||||
switchAccountWithToken(res.token);
|
||||
login(res.token);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function switchAccount(id: string) {
|
||||
const fetchedAccounts = await getAccounts();
|
||||
const token = fetchedAccounts.find(x => x.id === id)!.token;
|
||||
switchAccountWithToken(token);
|
||||
}
|
||||
|
||||
function switchAccountWithToken(token: string) {
|
||||
login(token);
|
||||
}
|
||||
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = computed(() => []);
|
||||
|
|
|
@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { signinRequired } from '@/account.js';
|
||||
import { signinRequired } from '@/i.js';
|
||||
|
||||
const $i = signinRequired();
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ import MkModalWindow from '@/components/MkModalWindow.vue';
|
|||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import MkRange from '@/components/MkRange.vue';
|
||||
import { signinRequired } from '@/account.js';
|
||||
import { signinRequired } from '@/i.js';
|
||||
|
||||
const $i = signinRequired();
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ import MkButton from '@/components/MkButton.vue';
|
|||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { signinRequired } from '@/account.js';
|
||||
import { signinRequired } from '@/i.js';
|
||||
import MkInfo from '@/components/MkInfo.vue';
|
||||
import { definePage } from '@/page.js';
|
||||
|
||||
|
|
|
@ -104,7 +104,7 @@ import bytes from '@/filters/bytes.js';
|
|||
import MkChart from '@/components/MkChart.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { signinRequired } from '@/account.js';
|
||||
import { signinRequired } from '@/i.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import MkPreferenceContainer from '@/components/MkPreferenceContainer.vue';
|
||||
import MkFeatureBanner from '@/components/MkFeatureBanner.vue';
|
||||
|
|
|
@ -67,7 +67,7 @@ import MkSwitch from '@/components/MkSwitch.vue';
|
|||
import MkDisableSection from '@/components/MkDisableSection.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { signinRequired } from '@/account.js';
|
||||
import { signinRequired } from '@/i.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { instance } from '@/instance.js';
|
||||
|
|
|
@ -38,7 +38,7 @@ import type { SuperMenuDef } from '@/components/MkSuperMenu.vue';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import MkInfo from '@/components/MkInfo.vue';
|
||||
import MkSuperMenu from '@/components/MkSuperMenu.vue';
|
||||
import { signout, $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { clearCache } from '@/utility/clear-cache.js';
|
||||
import { instance } from '@/instance.js';
|
||||
import { definePage, provideMetadataReceiver, provideReactiveMetadata } from '@/page.js';
|
||||
|
@ -47,6 +47,7 @@ import { useRouter } from '@/router/supplier.js';
|
|||
import { searchIndexes } from '@/utility/autogen/settings-search-index.js';
|
||||
import { enableAutoBackup, getPreferencesProfileMenu } from '@/preferences/utility.js';
|
||||
import { store } from '@/store.js';
|
||||
import { signout } from '@/signout.js';
|
||||
|
||||
const SETTING_INDEX = searchIndexes; // TODO: lazy load
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ import MkUserInfo from '@/components/MkUserInfo.vue';
|
|||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { signinRequired } from '@/account.js';
|
||||
import { signinRequired } from '@/i.js';
|
||||
import { unisonReload } from '@/utility/unison-reload.js';
|
||||
|
||||
const $i = signinRequired();
|
||||
|
|
|
@ -19,7 +19,7 @@ import { ref, watch } from 'vue';
|
|||
import MkTextarea from '@/components/MkTextarea.vue';
|
||||
import MkInfo from '@/components/MkInfo.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import { signinRequired } from '@/account.js';
|
||||
import { signinRequired } from '@/i.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
||||
|
|
|
@ -188,7 +188,7 @@ import { definePage } from '@/page.js';
|
|||
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { instance, infoImageUrl } from '@/instance.js';
|
||||
import { signinRequired } from '@/account.js';
|
||||
import { signinRequired } from '@/i.js';
|
||||
import MkInfo from '@/components/MkInfo.vue';
|
||||
import MkFolder from '@/components/MkFolder.vue';
|
||||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
|
|
|
@ -75,7 +75,7 @@ import FormSection from '@/components/form/section.vue';
|
|||
import MkFolder from '@/components/MkFolder.vue';
|
||||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { signinRequired } from '@/account.js';
|
||||
import { signinRequired } from '@/i.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
|
|
|
@ -127,13 +127,14 @@ import MkKeyValue from '@/components/MkKeyValue.vue';
|
|||
import MkButton from '@/components/MkButton.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { signout, signinRequired } from '@/account.js';
|
||||
import { signinRequired } from '@/i.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { reloadAsk } from '@/utility/reload-ask.js';
|
||||
import FormSection from '@/components/form/section.vue';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import MkRolePreview from '@/components/MkRolePreview.vue';
|
||||
import { signout } from '@/signout.js';
|
||||
|
||||
const $i = signinRequired();
|
||||
|
||||
|
|
|
@ -185,7 +185,7 @@ import MkFolder from '@/components/MkFolder.vue';
|
|||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { instance } from '@/instance.js';
|
||||
import { signinRequired } from '@/account.js';
|
||||
import { signinRequired } from '@/i.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import FormSlot from '@/components/form/slot.vue';
|
||||
import { formatDateTimeString } from '@/utility/format-time-string.js';
|
||||
|
|
|
@ -164,7 +164,7 @@ import FormSlot from '@/components/form/slot.vue';
|
|||
import { selectFile } from '@/utility/select-file.js';
|
||||
import * as os from '@/os.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { signinRequired } from '@/account.js';
|
||||
import { signinRequired } from '@/i.js';
|
||||
import { langmap } from '@/utility/langmap.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { claimAchievement } from '@/utility/achievements.js';
|
||||
|
|
|
@ -28,10 +28,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
import { ref } from 'vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkAnimBg from '@/components/MkAnimBg.vue';
|
||||
import { login } from '@/account.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { login } from '@/accounts.js';
|
||||
|
||||
const submitting = ref(false);
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ import MkNotes from '@/components/MkNotes.vue';
|
|||
import MkButton from '@/components/MkButton.vue';
|
||||
import { definePage } from '@/page.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { store } from '@/store.js';
|
||||
import * as os from '@/os.js';
|
||||
import { genEmbedCode } from '@/utility/get-embed-code.js';
|
||||
|
|
|
@ -86,7 +86,7 @@ import MkButton from '@/components/MkButton.vue';
|
|||
import MkCodeEditor from '@/components/MkCodeEditor.vue';
|
||||
import MkTextarea from '@/components/MkTextarea.vue';
|
||||
import MkFolder from '@/components/MkFolder.vue';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { applyTheme } from '@/theme.js';
|
||||
import * as os from '@/os.js';
|
||||
import { store } from '@/store.js';
|
||||
|
|
|
@ -48,7 +48,7 @@ import * as os from '@/os.js';
|
|||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { store } from '@/store.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { antennasCache, userListsCache, favoritedChannelsCache } from '@/cache.js';
|
||||
import { deviceKind } from '@/utility/device-kind.js';
|
||||
|
|
|
@ -14,7 +14,7 @@ import { onActivated, onDeactivated, onMounted, onUnmounted } from 'vue';
|
|||
import * as Misskey from 'misskey-js';
|
||||
import MkAchievements from '@/components/MkAchievements.vue';
|
||||
import { claimAchievement } from '@/utility/achievements.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
|
||||
const props = defineProps<{
|
||||
user: Misskey.entities.User;
|
||||
|
|
|
@ -176,7 +176,7 @@ import number from '@/filters/number.js';
|
|||
import { userPage } from '@/filters/user.js';
|
||||
import * as os from '@/os.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { $i, iAmModerator } from '@/account.js';
|
||||
import { $i, iAmModerator } from '@/i.js';
|
||||
import { dateString } from '@/filters/date.js';
|
||||
import { confetti } from '@/utility/confetti.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
|
|
|
@ -38,7 +38,7 @@ import { acct as getAcct } from '@/filters/user.js';
|
|||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
||||
import { serverContext, assertServerContext } from '@/server-context.js';
|
||||
|
||||
|
|
|
@ -45,9 +45,9 @@ import MkButton from '@/components/MkButton.vue';
|
|||
import MkInput from '@/components/MkInput.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { login } from '@/account.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import MkAnimBg from '@/components/MkAnimBg.vue';
|
||||
import { login } from '@/accounts.js';
|
||||
|
||||
const username = ref('');
|
||||
const password = ref('');
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import { onUnmounted, ref, watch } from 'vue';
|
||||
import { BroadcastChannel } from 'broadcast-channel';
|
||||
import type { Ref } from 'vue';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { get, set } from '@/utility/idb-proxy.js';
|
||||
import { store } from '@/store.js';
|
||||
|
|
|
@ -9,7 +9,7 @@ import { cloudBackup } from '@/preferences/utility.js';
|
|||
import { miLocalStorage } from '@/local-storage.js';
|
||||
import { isSameScope, PreferencesManager } from '@/preferences/manager.js';
|
||||
import { store } from '@/store.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
|
||||
const TAB_ID = uuid();
|
||||
|
|
|
@ -32,6 +32,10 @@ export type SoundStore = {
|
|||
// NOTE: デフォルト値は他の設定の状態に依存してはならない(依存していた場合、ユーザーがその設定項目単体で「初期値にリセット」した場合不具合の原因になる)
|
||||
|
||||
export const PREF_DEF = {
|
||||
accounts: {
|
||||
default: [] as [host: string, user: Misskey.entities.User][],
|
||||
},
|
||||
|
||||
pinnedUserLists: {
|
||||
accountDependent: true,
|
||||
default: [] as Misskey.entities.UserList[],
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue