feat: ✨ Toggle showing calckey updates as admin
This commit is contained in:
parent
07c6472ba6
commit
7559a0d81a
8 changed files with 54 additions and 13 deletions
|
@ -917,6 +917,7 @@ splash: "Splash Screen"
|
||||||
updateAvailable: "There might be an update available!"
|
updateAvailable: "There might be an update available!"
|
||||||
swipeOnDesktop: "Allow mobile-style swiping on desktop"
|
swipeOnDesktop: "Allow mobile-style swiping on desktop"
|
||||||
logoImageUrl: "Logo image URL"
|
logoImageUrl: "Logo image URL"
|
||||||
|
showAdminUpdates: "Indicate a new Calckey version is avaliable (admin only)"
|
||||||
|
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "Reduces the effort of server moderation through automatically recognizing NSFW media via Machine Learning. This will slightly increase the load on the server."
|
description: "Reduces the effort of server moderation through automatically recognizing NSFW media via Machine Learning. This will slightly increase the load on the server."
|
||||||
|
|
|
@ -905,18 +905,19 @@ shuffle: "シャッフル"
|
||||||
account: "アカウント"
|
account: "アカウント"
|
||||||
move: "移動"
|
move: "移動"
|
||||||
adminCustomCssWarn: "この設定は、それが何をするものであるかを知っている場合のみ使用してください。不適切な値を入力すると、クライアントが正常に動作しなくなる可能性があります。ユーザー設定でCSSをテストし、正しく動作することを確認してください。"
|
adminCustomCssWarn: "この設定は、それが何をするものであるかを知っている場合のみ使用してください。不適切な値を入力すると、クライアントが正常に動作しなくなる可能性があります。ユーザー設定でCSSをテストし、正しく動作することを確認してください。"
|
||||||
customMOTD: "カスタムMOTD(スプラッシュスクリーンメッセージ)"
|
customMOTD: "カスタムMOTD(スプラッシュスクリーンメッセージ)"
|
||||||
customMOTDDescription: "ユーザがページをロード/リロードするたびにランダムに表示される、改行で区切られたMOTD(スプラッシュスクリーン)用のカスタムメッセージ"
|
customMOTDDescription: "ユーザがページをロード/リロードするたびにランダムに表示される、改行で区切られたMOTD(スプラッシュスクリーン)用のカスタムメッセージ"
|
||||||
customSplashIcons: "カスタムスプラッシュスクリーンアイコン"
|
customSplashIcons: "カスタムスプラッシュスクリーンアイコン"
|
||||||
customSplashIconsDescription: "ユーザがページをロード/リロードするたびにランダムに表示される、改行で区切られたカスタムスプラッシュスクリーンアイコンの URL。画像は静的なURLで、できればすべて192x192にリサイズしてください。"
|
customSplashIconsDescription: "ユーザがページをロード/リロードするたびにランダムに表示される、改行で区切られたカスタムスプラッシュスクリーンアイコンの URL。画像は静的なURLで、できればすべて192x192にリサイズしてください。"
|
||||||
showUpdates: "Calckeyの更新時にポップアップを表示する"
|
showUpdates: "Calckeyの更新時にポップアップを表示する"
|
||||||
recommendedInstances: "推奨インスタンス"
|
recommendedInstances: "推奨インスタンス"
|
||||||
recommendedInstancesDescription: "推奨タイムラインに表示するために改行で区切られた推奨インスタンス。`https://`を追加しないでください。ドメインのみを追加してください。"
|
recommendedInstancesDescription: "推奨タイムラインに表示するために改行で区切られた推奨インスタンス。`https://`を追加しないでください。ドメインのみを追加してください。"
|
||||||
caption: "自動キャプション"
|
caption: "自動キャプション"
|
||||||
splash: "スプラッシュスクリーン"
|
splash: "スプラッシュスクリーン"
|
||||||
updateAvailable: "アップデートがありますよ"
|
updateAvailable: "アップデートがありますよ"
|
||||||
swipeOnDesktop: "デスクトップでモバイルスタイルのスワイプを可能にする"
|
swipeOnDesktop: "デスクトップでモバイルスタイルのスワイプを可能にする"
|
||||||
logoImageUrl: "ロゴのURL"
|
logoImageUrl: "ロゴのURL"
|
||||||
|
showAdminUpdates: "新しいCalckeyのバージョンが利用可能であることを示す(管理者のみ)"
|
||||||
|
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "機械学習を使って自動でセンシティブなメディアを検出し、モデレーションに役立てることができます。サーバーの負荷が少し増えます。"
|
description: "機械学習を使って自動でセンシティブなメディアを検出し、モデレーションに役立てることができます。サーバーの負荷が少し増えます。"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "calckey",
|
"name": "calckey",
|
||||||
"version": "12.119.0-calc.4.1",
|
"version": "12.119.0-calc.4.2",
|
||||||
"codename": "aqua",
|
"codename": "aqua",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
@ -33,6 +33,7 @@ import { instance } from '@/instance';
|
||||||
import { version } from '@/config';
|
import { version } from '@/config';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import { lookupUser } from '@/scripts/lookup-user';
|
import { lookupUser } from '@/scripts/lookup-user';
|
||||||
|
import { defaultStore } from '@/store';
|
||||||
import { useRouter } from '@/router';
|
import { useRouter } from '@/router';
|
||||||
import { definePageMetadata, provideMetadataReceiver, setPageMetadata } from '@/scripts/page-metadata';
|
import { definePageMetadata, provideMetadataReceiver, setPageMetadata } from '@/scripts/page-metadata';
|
||||||
|
|
||||||
|
@ -68,13 +69,15 @@ os.api('admin/abuse-user-reports', {
|
||||||
if (reports?.length > 0) thereIsUnresolvedAbuseReport = true;
|
if (reports?.length > 0) thereIsUnresolvedAbuseReport = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
os.api('latest-version').then(res => {
|
if (defaultStore.state.showAdminUpdates) {
|
||||||
const cleanRes = res?.tag_name.replace(/[^0-9]/g, '');
|
os.api('latest-version').then(res => {
|
||||||
const cleanVersion = version.replace(/[^0-9]/g, '');
|
const cleanRes = res?.tag_name.replace(/[^0-9]/g, '');
|
||||||
if (cleanRes !== cleanVersion) {
|
const cleanVersion = version.replace(/[^0-9]/g, '');
|
||||||
updateAvailable = true;
|
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) => {
|
||||||
|
|
|
@ -59,6 +59,7 @@
|
||||||
</FormSwitch>
|
</FormSwitch>
|
||||||
<FormSwitch v-model="disableDrawer" class="_formBlock">{{ i18n.ts.disableDrawer }}</FormSwitch>
|
<FormSwitch v-model="disableDrawer" class="_formBlock">{{ i18n.ts.disableDrawer }}</FormSwitch>
|
||||||
<FormSwitch v-model="showUpdates" class="_formBlock">{{ i18n.ts.showUpdates }}</FormSwitch>
|
<FormSwitch v-model="showUpdates" class="_formBlock">{{ i18n.ts.showUpdates }}</FormSwitch>
|
||||||
|
<FormSwitch v-if="$i?.isAdmin" v-model="showAdminUpdates" class="_formBlock">{{ i18n.ts.showAdminUpdates }}</FormSwitch>
|
||||||
|
|
||||||
<FormRadios v-model="fontSize" class="_formBlock">
|
<FormRadios v-model="fontSize" class="_formBlock">
|
||||||
<template #label>{{ i18n.ts.fontSize }}</template>
|
<template #label>{{ i18n.ts.fontSize }}</template>
|
||||||
|
@ -96,6 +97,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { 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';
|
||||||
|
@ -149,6 +151,7 @@ const seperateRenoteQuote = computed(defaultStore.makeGetterSetter('seperateReno
|
||||||
const squareAvatars = computed(defaultStore.makeGetterSetter('squareAvatars'));
|
const squareAvatars = computed(defaultStore.makeGetterSetter('squareAvatars'));
|
||||||
const showUpdates = computed(defaultStore.makeGetterSetter('showUpdates'));
|
const showUpdates = computed(defaultStore.makeGetterSetter('showUpdates'));
|
||||||
const swipeOnDesktop = computed(defaultStore.makeGetterSetter('swipeOnDesktop'));
|
const swipeOnDesktop = computed(defaultStore.makeGetterSetter('swipeOnDesktop'));
|
||||||
|
const showAdminUpdates = computed(defaultStore.makeGetterSetter('showAdminUpdates'));
|
||||||
|
|
||||||
watch(lang, () => {
|
watch(lang, () => {
|
||||||
localStorage.setItem('lang', lang.value as string);
|
localStorage.setItem('lang', lang.value as string);
|
||||||
|
@ -184,6 +187,7 @@ watch([
|
||||||
showUpdates,
|
showUpdates,
|
||||||
swipeOnDesktop,
|
swipeOnDesktop,
|
||||||
seperateRenoteQuote,
|
seperateRenoteQuote,
|
||||||
|
showAdminUpdates,
|
||||||
], async () => {
|
], async () => {
|
||||||
await reloadAsk();
|
await reloadAsk();
|
||||||
});
|
});
|
||||||
|
|
|
@ -85,6 +85,7 @@ const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [
|
||||||
'numberOfPageCache',
|
'numberOfPageCache',
|
||||||
'showUpdates',
|
'showUpdates',
|
||||||
'swipeOnDesktop',
|
'swipeOnDesktop',
|
||||||
|
'showAdminUpdates',
|
||||||
];
|
];
|
||||||
const coldDeviceStorageSaveKeys: (keyof typeof ColdDeviceStorage.default)[] = [
|
const coldDeviceStorageSaveKeys: (keyof typeof ColdDeviceStorage.default)[] = [
|
||||||
'lightTheme',
|
'lightTheme',
|
||||||
|
|
|
@ -263,6 +263,10 @@ export const defaultStore = markRaw(new Storage('base', {
|
||||||
where: 'device',
|
where: 'device',
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
showAdminUpdates: {
|
||||||
|
where: 'account',
|
||||||
|
default: false,
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// TODO: 他のタブと永続化されたstateを同期
|
// TODO: 他のタブと永続化されたstateを同期
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
</template>
|
</template>
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
<MkA v-if="$i.isAdmin || $i.isModerator" v-click-anime v-tooltip.noDelay.right="i18n.ts.controlPanel" class="item" active-class="active" to="/admin">
|
<MkA v-if="$i.isAdmin || $i.isModerator" v-click-anime v-tooltip.noDelay.right="i18n.ts.controlPanel" class="item" active-class="active" to="/admin">
|
||||||
<i class="icon fas fa-door-open fa-fw"></i><span class="text">{{ i18n.ts.controlPanel }}</span>
|
<span v-if="thereIsUnresolvedAbuseReport || noMaintainerInformation || noBotProtection || noEmailServer || updateAvailable" class="indicator"></span><i class="icon fas fa-door-open fa-fw"></i><span class="text">{{ i18n.ts.controlPanel }}</span>
|
||||||
</MkA>
|
</MkA>
|
||||||
<button v-click-anime class="item _button" @click="more">
|
<button v-click-anime class="item _button" @click="more">
|
||||||
<i class="icon fa fa-ellipsis-h fa-fw"></i><span class="text">{{ i18n.ts.more }}</span>
|
<i class="icon fa fa-ellipsis-h fa-fw"></i><span class="text">{{ i18n.ts.more }}</span>
|
||||||
|
@ -63,7 +63,9 @@ import { $i, openAccountMenu as openAccountMenu_ } from '@/account';
|
||||||
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 { host } from '@/config';
|
import { host, version } from '@/config';
|
||||||
|
|
||||||
|
const isEmpty = (x: string | null) => x == null || x === '';
|
||||||
|
|
||||||
const iconOnly = ref(false);
|
const iconOnly = ref(false);
|
||||||
|
|
||||||
|
@ -88,6 +90,31 @@ watch(defaultStore.reactiveState.menuDisplay, () => {
|
||||||
calcViewState();
|
calcViewState();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let noMaintainerInformation = isEmpty(instance.maintainerName) || isEmpty(instance.maintainerEmail);
|
||||||
|
let noBotProtection = !instance.disableRegistration && !instance.enableHcaptcha && !instance.enableRecaptcha;
|
||||||
|
let noEmailServer = !instance.enableEmail;
|
||||||
|
let thereIsUnresolvedAbuseReport = $ref(false);
|
||||||
|
let updateAvailable = $ref(false);
|
||||||
|
|
||||||
|
if ($i?.isAdmin) {
|
||||||
|
os.api('admin/abuse-user-reports', {
|
||||||
|
state: 'unresolved',
|
||||||
|
limit: 1,
|
||||||
|
}).then(reports => {
|
||||||
|
if (reports?.length > 0) thereIsUnresolvedAbuseReport = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defaultStore.state.showAdminUpdates) {
|
||||||
|
os.api('latest-version').then(res => {
|
||||||
|
const cleanRes = res?.tag_name.replace(/[^0-9]/g, '');
|
||||||
|
const cleanVersion = version.replace(/[^0-9]/g, '');
|
||||||
|
if (cleanRes !== cleanVersion) {
|
||||||
|
updateAvailable = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function openAccountMenu(ev: MouseEvent) {
|
function openAccountMenu(ev: MouseEvent) {
|
||||||
openAccountMenu_({
|
openAccountMenu_({
|
||||||
withExtraOperation: true,
|
withExtraOperation: true,
|
||||||
|
|
Loading…
Reference in a new issue