Frontend: Removed the update check
This commit is contained in:
parent
39f9ecd8d3
commit
40c471ff56
|
@ -2034,10 +2034,6 @@ export type Endpoints = {
|
||||||
req: NoParams;
|
req: NoParams;
|
||||||
res: ServerInfo;
|
res: ServerInfo;
|
||||||
};
|
};
|
||||||
"latest-version": {
|
|
||||||
req: NoParams;
|
|
||||||
res: TODO;
|
|
||||||
};
|
|
||||||
"sw/register": {
|
"sw/register": {
|
||||||
req: TODO;
|
req: TODO;
|
||||||
res: TODO;
|
res: TODO;
|
||||||
|
|
|
@ -1698,10 +1698,6 @@ export declare type Endpoints = {
|
||||||
req: NoParams;
|
req: NoParams;
|
||||||
res: ServerInfo;
|
res: ServerInfo;
|
||||||
};
|
};
|
||||||
"latest-version": {
|
|
||||||
req: NoParams;
|
|
||||||
res: TODO;
|
|
||||||
};
|
|
||||||
"sw/register": {
|
"sw/register": {
|
||||||
req: TODO;
|
req: TODO;
|
||||||
res: TODO;
|
res: TODO;
|
||||||
|
|
|
@ -5,7 +5,6 @@ import {
|
||||||
App,
|
App,
|
||||||
AuthSession,
|
AuthSession,
|
||||||
Blocking,
|
Blocking,
|
||||||
Channel,
|
|
||||||
Clip,
|
Clip,
|
||||||
DateString,
|
DateString,
|
||||||
DetailedInstanceMetadata,
|
DetailedInstanceMetadata,
|
||||||
|
@ -17,24 +16,23 @@ import {
|
||||||
FollowRequest,
|
FollowRequest,
|
||||||
GalleryPost,
|
GalleryPost,
|
||||||
Instance,
|
Instance,
|
||||||
InstanceMetadata,
|
|
||||||
LiteInstanceMetadata,
|
LiteInstanceMetadata,
|
||||||
MeDetailed,
|
MeDetailed,
|
||||||
|
MessagingMessage,
|
||||||
Note,
|
Note,
|
||||||
NoteFavorite,
|
NoteFavorite,
|
||||||
|
NoteReaction,
|
||||||
|
Notification,
|
||||||
OriginType,
|
OriginType,
|
||||||
Page,
|
Page,
|
||||||
ServerInfo,
|
ServerInfo,
|
||||||
|
Signin,
|
||||||
Stats,
|
Stats,
|
||||||
User,
|
User,
|
||||||
UserDetailed,
|
UserDetailed,
|
||||||
UserGroup,
|
UserGroup,
|
||||||
UserList,
|
UserList,
|
||||||
UserSorting,
|
UserSorting,
|
||||||
Notification,
|
|
||||||
NoteReaction,
|
|
||||||
Signin,
|
|
||||||
MessagingMessage,
|
|
||||||
} from "./entities";
|
} from "./entities";
|
||||||
|
|
||||||
type TODO = Record<string, any> | null;
|
type TODO = Record<string, any> | null;
|
||||||
|
@ -758,10 +756,7 @@ export type Endpoints = {
|
||||||
$cases: [
|
$cases: [
|
||||||
[{ detail: true }, DetailedInstanceMetadata],
|
[{ detail: true }, DetailedInstanceMetadata],
|
||||||
[{ detail: false }, LiteInstanceMetadata],
|
[{ detail: false }, LiteInstanceMetadata],
|
||||||
[
|
[{ detail: boolean }, LiteInstanceMetadata | DetailedInstanceMetadata]
|
||||||
{ detail: boolean },
|
|
||||||
LiteInstanceMetadata | DetailedInstanceMetadata,
|
|
||||||
],
|
|
||||||
];
|
];
|
||||||
$default: LiteInstanceMetadata;
|
$default: LiteInstanceMetadata;
|
||||||
};
|
};
|
||||||
|
@ -977,9 +972,6 @@ export type Endpoints = {
|
||||||
// server-info
|
// server-info
|
||||||
"server-info": { req: NoParams; res: ServerInfo };
|
"server-info": { req: NoParams; res: ServerInfo };
|
||||||
|
|
||||||
// ck specific
|
|
||||||
"latest-version": { req: NoParams; res: TODO };
|
|
||||||
|
|
||||||
// sw
|
// sw
|
||||||
"sw/register": { req: TODO; res: TODO };
|
"sw/register": { req: TODO; res: TODO };
|
||||||
|
|
||||||
|
|
|
@ -38,15 +38,6 @@
|
||||||
i18n.ts.configure
|
i18n.ts.configure
|
||||||
}}</MkA></MkInfo
|
}}</MkA></MkInfo
|
||||||
>
|
>
|
||||||
<MkInfo v-if="updateAvailable" warn class="info"
|
|
||||||
>{{ i18n.ts.updateAvailable }}
|
|
||||||
<a
|
|
||||||
href="https://codeberg.org/calckey/calckey/releases"
|
|
||||||
target="_bank"
|
|
||||||
class="_link"
|
|
||||||
>{{ i18n.ts.check }}</a
|
|
||||||
></MkInfo
|
|
||||||
>
|
|
||||||
|
|
||||||
<MkSuperMenu :def="menuDef" :grid="narrow"></MkSuperMenu>
|
<MkSuperMenu :def="menuDef" :grid="narrow"></MkSuperMenu>
|
||||||
</div>
|
</div>
|
||||||
|
@ -59,35 +50,21 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {
|
import { onActivated, onMounted, onUnmounted, provide, ref, watch } from "vue";
|
||||||
defineAsyncComponent,
|
|
||||||
inject,
|
|
||||||
nextTick,
|
|
||||||
onMounted,
|
|
||||||
onUnmounted,
|
|
||||||
onActivated,
|
|
||||||
provide,
|
|
||||||
watch,
|
|
||||||
ref,
|
|
||||||
} from "vue";
|
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
import MkSuperMenu from "@/components/MkSuperMenu.vue";
|
import MkSuperMenu from "@/components/MkSuperMenu.vue";
|
||||||
import MkInfo from "@/components/MkInfo.vue";
|
import MkInfo from "@/components/MkInfo.vue";
|
||||||
import { scroll } from "@/scripts/scroll";
|
|
||||||
import { instance } from "@/instance";
|
import { instance } from "@/instance";
|
||||||
import { version } from "@/config";
|
|
||||||
import { $i } from "@/account";
|
import { $i } from "@/account";
|
||||||
import * as os from "@/os";
|
import * as os from "@/os";
|
||||||
import { lookupUser } from "@/scripts/lookup-user";
|
import { lookupUser } from "@/scripts/lookup-user";
|
||||||
import { lookupFile } from "@/scripts/lookup-file";
|
import { lookupFile } from "@/scripts/lookup-file";
|
||||||
import { lookupInstance } from "@/scripts/lookup-instance";
|
import { lookupInstance } from "@/scripts/lookup-instance";
|
||||||
import { indexPosts } from "@/scripts/index-posts";
|
import { indexPosts } from "@/scripts/index-posts";
|
||||||
import { defaultStore } from "@/store";
|
|
||||||
import { useRouter } from "@/router";
|
import { useRouter } from "@/router";
|
||||||
import {
|
import {
|
||||||
definePageMetadata,
|
definePageMetadata,
|
||||||
provideMetadataReceiver,
|
provideMetadataReceiver,
|
||||||
setPageMetadata,
|
|
||||||
} from "@/scripts/page-metadata";
|
} from "@/scripts/page-metadata";
|
||||||
|
|
||||||
const isEmpty = (x: string | null) => x == null || x === "";
|
const isEmpty = (x: string | null) => x == null || x === "";
|
||||||
|
@ -115,7 +92,6 @@ let noBotProtection =
|
||||||
!instance.enableRecaptcha;
|
!instance.enableRecaptcha;
|
||||||
let noEmailServer = !instance.enableEmail;
|
let noEmailServer = !instance.enableEmail;
|
||||||
let thereIsUnresolvedAbuseReport = $ref(false);
|
let thereIsUnresolvedAbuseReport = $ref(false);
|
||||||
let updateAvailable = $ref(false);
|
|
||||||
let currentPage = $computed(() => router.currentRef.value.child);
|
let currentPage = $computed(() => router.currentRef.value.child);
|
||||||
|
|
||||||
os.api("admin/abuse-user-reports", {
|
os.api("admin/abuse-user-reports", {
|
||||||
|
@ -125,16 +101,6 @@ os.api("admin/abuse-user-reports", {
|
||||||
if (reports?.length > 0) thereIsUnresolvedAbuseReport = true;
|
if (reports?.length > 0) thereIsUnresolvedAbuseReport = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (defaultStore.state.showAdminUpdates) {
|
|
||||||
os.api("latest-version").then((res) => {
|
|
||||||
const cleanRes = parseInt(res?.tag_name.replace(/[^0-9]/g, ""));
|
|
||||||
const cleanVersion = parseInt(version.replace(/[^0-9]/g, ""));
|
|
||||||
if (cleanRes > cleanVersion) {
|
|
||||||
updateAvailable = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const NARROW_THRESHOLD = 600;
|
const NARROW_THRESHOLD = 600;
|
||||||
const ro = new ResizeObserver((entries, observer) => {
|
const ro = new ResizeObserver((entries, observer) => {
|
||||||
if (entries.length === 0) return;
|
if (entries.length === 0) return;
|
||||||
|
@ -247,15 +213,13 @@ const menuDef = $computed(() => [
|
||||||
icon: "ph-envelope-simple-open ph-bold ph-lg",
|
icon: "ph-envelope-simple-open ph-bold ph-lg",
|
||||||
text: i18n.ts.emailServer,
|
text: i18n.ts.emailServer,
|
||||||
to: "/admin/email-settings",
|
to: "/admin/email-settings",
|
||||||
active:
|
active: currentPage?.route.name === "email-settings",
|
||||||
currentPage?.route.name === "email-settings",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "ph-cloud ph-bold ph-lg",
|
icon: "ph-cloud ph-bold ph-lg",
|
||||||
text: i18n.ts.objectStorage,
|
text: i18n.ts.objectStorage,
|
||||||
to: "/admin/object-storage",
|
to: "/admin/object-storage",
|
||||||
active:
|
active: currentPage?.route.name === "object-storage",
|
||||||
currentPage?.route.name === "object-storage",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "ph-lock ph-bold ph-lg",
|
icon: "ph-lock ph-bold ph-lg",
|
||||||
|
@ -279,8 +243,7 @@ const menuDef = $computed(() => [
|
||||||
icon: "ph-prohibit ph-bold ph-lg",
|
icon: "ph-prohibit ph-bold ph-lg",
|
||||||
text: i18n.ts.instanceBlocking,
|
text: i18n.ts.instanceBlocking,
|
||||||
to: "/admin/instance-block",
|
to: "/admin/instance-block",
|
||||||
active:
|
active: currentPage?.route.name === "instance-block",
|
||||||
currentPage?.route.name === "instance-block",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "ph-hash ph-bold ph-lg",
|
icon: "ph-hash ph-bold ph-lg",
|
||||||
|
|
|
@ -187,12 +187,6 @@
|
||||||
<FormSwitch v-model="showFixedPostForm" class="_formBlock">{{
|
<FormSwitch v-model="showFixedPostForm" class="_formBlock">{{
|
||||||
i18n.ts.showFixedPostForm
|
i18n.ts.showFixedPostForm
|
||||||
}}</FormSwitch>
|
}}</FormSwitch>
|
||||||
<FormSwitch
|
|
||||||
v-if="$i?.isAdmin"
|
|
||||||
v-model="showAdminUpdates"
|
|
||||||
class="_formBlock"
|
|
||||||
>{{ i18n.ts.showAdminUpdates }}</FormSwitch
|
|
||||||
>
|
|
||||||
<FormSelect v-model="instanceTicker" class="_formBlock">
|
<FormSelect v-model="instanceTicker" class="_formBlock">
|
||||||
<template #label>{{ i18n.ts.instanceTicker }}</template>
|
<template #label>{{ i18n.ts.instanceTicker }}</template>
|
||||||
<option value="none">{{ i18n.ts._instanceTicker.none }}</option>
|
<option value="none">{{ i18n.ts._instanceTicker.none }}</option>
|
||||||
|
@ -238,8 +232,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { reactive, computed, ref, watch } from "vue";
|
import { computed, ref, watch } from "vue";
|
||||||
import { $i } from "@/account";
|
|
||||||
import FormSwitch from "@/components/form/switch.vue";
|
import FormSwitch from "@/components/form/switch.vue";
|
||||||
import FormSelect from "@/components/form/select.vue";
|
import FormSelect from "@/components/form/select.vue";
|
||||||
import FormRadios from "@/components/form/radios.vue";
|
import FormRadios from "@/components/form/radios.vue";
|
||||||
|
@ -339,9 +332,6 @@ const showUpdates = computed(defaultStore.makeGetterSetter("showUpdates"));
|
||||||
const swipeOnDesktop = computed(
|
const swipeOnDesktop = computed(
|
||||||
defaultStore.makeGetterSetter("swipeOnDesktop")
|
defaultStore.makeGetterSetter("swipeOnDesktop")
|
||||||
);
|
);
|
||||||
const showAdminUpdates = computed(
|
|
||||||
defaultStore.makeGetterSetter("showAdminUpdates")
|
|
||||||
);
|
|
||||||
const showTimelineReplies = computed(
|
const showTimelineReplies = computed(
|
||||||
defaultStore.makeGetterSetter("showTimelineReplies")
|
defaultStore.makeGetterSetter("showTimelineReplies")
|
||||||
);
|
);
|
||||||
|
@ -381,7 +371,6 @@ watch(
|
||||||
showUpdates,
|
showUpdates,
|
||||||
swipeOnDesktop,
|
swipeOnDesktop,
|
||||||
seperateRenoteQuote,
|
seperateRenoteQuote,
|
||||||
showAdminUpdates,
|
|
||||||
advancedMfm,
|
advancedMfm,
|
||||||
autoplayMfm,
|
autoplayMfm,
|
||||||
expandOnNoteClick,
|
expandOnNoteClick,
|
||||||
|
|
|
@ -67,8 +67,9 @@ import { unisonReload } from "@/scripts/unison-reload";
|
||||||
import { stream } from "@/stream";
|
import { stream } from "@/stream";
|
||||||
import { $i } from "@/account";
|
import { $i } from "@/account";
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
import { version, host } from "@/config";
|
import { host, version } from "@/config";
|
||||||
import { definePageMetadata } from "@/scripts/page-metadata";
|
import { definePageMetadata } from "@/scripts/page-metadata";
|
||||||
|
|
||||||
const { t, ts } = i18n;
|
const { t, ts } = i18n;
|
||||||
|
|
||||||
useCssModule();
|
useCssModule();
|
||||||
|
@ -111,7 +112,6 @@ const defaultStoreSaveKeys: (keyof (typeof defaultStore)["state"])[] = [
|
||||||
"numberOfPageCache",
|
"numberOfPageCache",
|
||||||
"showUpdates",
|
"showUpdates",
|
||||||
"swipeOnDesktop",
|
"swipeOnDesktop",
|
||||||
"showAdminUpdates",
|
|
||||||
"enableCustomKaTeXMacro",
|
"enableCustomKaTeXMacro",
|
||||||
"enableEmojiReactions",
|
"enableEmojiReactions",
|
||||||
"showEmojisInReactionNotifications",
|
"showEmojisInReactionNotifications",
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
import { markRaw, ref } from "vue";
|
import { markRaw, ref } from "vue";
|
||||||
import { Storage } from "./pizzax";
|
import { Storage } from "./pizzax";
|
||||||
import { Theme } from "./scripts/theme";
|
/**
|
||||||
|
* 常にメモリにロードしておく必要がないような設定情報を保管するストレージ(非リアクティブ)
|
||||||
|
*/
|
||||||
|
import lightTheme from "@/themes/l-rosepinedawn.json5";
|
||||||
|
import darkTheme from "@/themes/d-rosepine.json5";
|
||||||
|
|
||||||
export const postFormActions = [];
|
export const postFormActions = [];
|
||||||
export const userActions = [];
|
export const userActions = [];
|
||||||
|
@ -312,10 +316,6 @@ export const defaultStore = markRaw(
|
||||||
where: "device",
|
where: "device",
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
showAdminUpdates: {
|
|
||||||
where: "account",
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
woozyMode: {
|
woozyMode: {
|
||||||
where: "device",
|
where: "device",
|
||||||
default: false,
|
default: false,
|
||||||
|
@ -336,7 +336,7 @@ export const defaultStore = markRaw(
|
||||||
where: "device",
|
where: "device",
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
}),
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: 他のタブと永続化されたstateを同期
|
// TODO: 他のタブと永続化されたstateを同期
|
||||||
|
@ -352,12 +352,6 @@ type Plugin = {
|
||||||
ast: any[];
|
ast: any[];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* 常にメモリにロードしておく必要がないような設定情報を保管するストレージ(非リアクティブ)
|
|
||||||
*/
|
|
||||||
import lightTheme from "@/themes/l-rosepinedawn.json5";
|
|
||||||
import darkTheme from "@/themes/d-rosepine.json5";
|
|
||||||
|
|
||||||
export class ColdDeviceStorage {
|
export class ColdDeviceStorage {
|
||||||
public static default = {
|
public static default = {
|
||||||
lightTheme,
|
lightTheme,
|
||||||
|
@ -378,8 +372,8 @@ export class ColdDeviceStorage {
|
||||||
public static watchers = [];
|
public static watchers = [];
|
||||||
|
|
||||||
public static get<T extends keyof typeof ColdDeviceStorage.default>(
|
public static get<T extends keyof typeof ColdDeviceStorage.default>(
|
||||||
key: T,
|
key: T
|
||||||
): typeof ColdDeviceStorage.default[T] {
|
): (typeof ColdDeviceStorage.default)[T] {
|
||||||
// TODO: indexedDBにする
|
// TODO: indexedDBにする
|
||||||
// ただしその際はnullチェックではなくキー存在チェックにしないとダメ
|
// ただしその際はnullチェックではなくキー存在チェックにしないとダメ
|
||||||
// (indexedDBはnullを保存できるため、ユーザーが意図してnullを格納した可能性がある)
|
// (indexedDBはnullを保存できるため、ユーザーが意図してnullを格納した可能性がある)
|
||||||
|
@ -393,7 +387,7 @@ export class ColdDeviceStorage {
|
||||||
|
|
||||||
public static set<T extends keyof typeof ColdDeviceStorage.default>(
|
public static set<T extends keyof typeof ColdDeviceStorage.default>(
|
||||||
key: T,
|
key: T,
|
||||||
value: typeof ColdDeviceStorage.default[T],
|
value: (typeof ColdDeviceStorage.default)[T]
|
||||||
): void {
|
): void {
|
||||||
// 呼び出し側のバグ等で undefined が来ることがある
|
// 呼び出し側のバグ等で undefined が来ることがある
|
||||||
// undefined を文字列として localStorage に入れると参照する際の JSON.parse でコケて不具合の元になるため無視
|
// undefined を文字列として localStorage に入れると参照する際の JSON.parse でコケて不具合の元になるため無視
|
||||||
|
@ -414,7 +408,9 @@ export class ColdDeviceStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: VueのcustomRef使うと良い感じになるかも
|
// TODO: VueのcustomRef使うと良い感じになるかも
|
||||||
public static ref<T extends keyof typeof ColdDeviceStorage.default>(key: T) {
|
public static ref<T extends keyof typeof ColdDeviceStorage.default>(
|
||||||
|
key: T
|
||||||
|
) {
|
||||||
const v = ColdDeviceStorage.get(key);
|
const v = ColdDeviceStorage.get(key);
|
||||||
const r = ref(v);
|
const r = ref(v);
|
||||||
// TODO: このままではwatcherがリークするので開放する方法を考える
|
// TODO: このままではwatcherがリークするので開放する方法を考える
|
||||||
|
@ -429,7 +425,7 @@ export class ColdDeviceStorage {
|
||||||
* 主にvue場で設定コントロールのmodelとして使う用
|
* 主にvue場で設定コントロールのmodelとして使う用
|
||||||
*/
|
*/
|
||||||
public static makeGetterSetter<
|
public static makeGetterSetter<
|
||||||
K extends keyof typeof ColdDeviceStorage.default,
|
K extends keyof typeof ColdDeviceStorage.default
|
||||||
>(key: K) {
|
>(key: K) {
|
||||||
// TODO: VueのcustomRef使うと良い感じになるかも
|
// TODO: VueのcustomRef使うと良い感じになるかも
|
||||||
const valueRef = ColdDeviceStorage.ref(key);
|
const valueRef = ColdDeviceStorage.ref(key);
|
||||||
|
|
|
@ -84,8 +84,7 @@
|
||||||
thereIsUnresolvedAbuseReport ||
|
thereIsUnresolvedAbuseReport ||
|
||||||
noMaintainerInformation ||
|
noMaintainerInformation ||
|
||||||
noBotProtection ||
|
noBotProtection ||
|
||||||
noEmailServer ||
|
noEmailServer
|
||||||
updateAvailable
|
|
||||||
"
|
"
|
||||||
class="indicator"
|
class="indicator"
|
||||||
></span
|
></span
|
||||||
|
@ -154,7 +153,6 @@ import { openHelpMenu_ } from "@/scripts/helpMenu";
|
||||||
import { defaultStore } from "@/store";
|
import { defaultStore } from "@/store";
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
import { instance } from "@/instance";
|
import { instance } from "@/instance";
|
||||||
import { version } from "@/config";
|
|
||||||
|
|
||||||
const isEmpty = (x: string | null) => x == null || x === "";
|
const isEmpty = (x: string | null) => x == null || x === "";
|
||||||
|
|
||||||
|
@ -191,7 +189,6 @@ let noBotProtection =
|
||||||
!instance.enableRecaptcha;
|
!instance.enableRecaptcha;
|
||||||
let noEmailServer = !instance.enableEmail;
|
let noEmailServer = !instance.enableEmail;
|
||||||
let thereIsUnresolvedAbuseReport = $ref(false);
|
let thereIsUnresolvedAbuseReport = $ref(false);
|
||||||
let updateAvailable = $ref(false);
|
|
||||||
|
|
||||||
if ($i?.isAdmin) {
|
if ($i?.isAdmin) {
|
||||||
os.api("admin/abuse-user-reports", {
|
os.api("admin/abuse-user-reports", {
|
||||||
|
@ -202,16 +199,6 @@ if ($i?.isAdmin) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defaultStore.state.showAdminUpdates) {
|
|
||||||
os.api("latest-version").then((res) => {
|
|
||||||
const cleanRes = parseInt(res?.tag_name.replace(/[^0-9]/g, ""));
|
|
||||||
const cleanVersion = parseInt(version.replace(/[^0-9]/g, ""));
|
|
||||||
if (cleanRes > cleanVersion) {
|
|
||||||
updateAvailable = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function openAccountMenu(ev: MouseEvent) {
|
function openAccountMenu(ev: MouseEvent) {
|
||||||
openAccountMenu_(
|
openAccountMenu_(
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue