feat: クライアントのアップデートがある場合の通知
This commit is contained in:
parent
9e32d84a2e
commit
e8d249f62b
|
@ -35,6 +35,7 @@ Misskey의 전체 변경 사항을 확인하려면, [CHANGELOG.md#2023xx](CHANGE
|
|||
- 마우스를 움직이거나 화면을 터치하고 있으면 이미지를 재생
|
||||
- 일정 시간이 경과하면 이미지 재생을 중지
|
||||
- Feat: 미디어가 포함된 모든 노트를 접을 수 있음
|
||||
- Feat: 클라이언트 업데이트가 있으면 알림
|
||||
- Fix: 로그인하지 않은 상태에서 노트 상세 페이지의 노트 작성 폼을 조작할 수 있음
|
||||
|
||||
### Server
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
---
|
||||
_lang_: "English"
|
||||
youAreRunningBetaClient: "Unreleased version of CherryPick in use!"
|
||||
cherrypickUpdate: "CherryPick Update"
|
||||
allMediaNoteCollapse: "Collapse all media notes"
|
||||
showingAnimatedImagesDescription: "When set to \"Animate on interaction\", the image will play when you hover over it or touch it."
|
||||
showFixedPostFormInReplies: "Show posting form in replies"
|
||||
|
|
2
locales/index.d.ts
vendored
2
locales/index.d.ts
vendored
|
@ -3,6 +3,8 @@
|
|||
// Do not edit this file directly.
|
||||
export interface Locale {
|
||||
"_lang_": string;
|
||||
"youAreRunningBetaClient": string;
|
||||
"cherrypickUpdate": string;
|
||||
"allMediaNoteCollapse": string;
|
||||
"showingAnimatedImagesDescription": string;
|
||||
"showFixedPostFormInReplies": string;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
_lang_: "日本語"
|
||||
|
||||
youAreRunningBetaClient: "未発売バージョンのCherryPickを利用しています!"
|
||||
cherrypickUpdate: "CherryPickアップデート"
|
||||
allMediaNoteCollapse: "すべてのメディアノートを省略して表示"
|
||||
showingAnimatedImagesDescription: "「インタラクト時に再生」に設定すると、画像の上にマウスを置いたり、画像をタッチすると再生されます。"
|
||||
showFixedPostFormInReplies: "返信に投稿フォームを表示する"
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
---
|
||||
_lang_: "한국어"
|
||||
youAreRunningBetaClient: "아직 출시되지 않은 버전의 CherryPick를 이용하고 있어요!"
|
||||
cherrypickUpdate: "CherryPick 업데이트"
|
||||
allMediaNoteCollapse: "모든 미디어 노트 간략화하기"
|
||||
showingAnimatedImagesDescription: "'건드리면 움직임'으로 설정하면 이미지 위에 마우스를 올리거나 이미지를 터치하면 움직여요."
|
||||
showFixedPostFormInReplies: "답글에 글 작성란 표시"
|
||||
|
|
|
@ -16,6 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<MkInfo v-if="noMaintainerInformation" warn class="info">{{ i18n.ts.noMaintainerInformationWarning }} <MkA to="/admin/settings" class="_link">{{ i18n.ts.configure }}</MkA></MkInfo>
|
||||
<MkInfo v-if="noBotProtection" warn class="info">{{ i18n.ts.noBotProtectionWarning }} <MkA to="/admin/security" class="_link">{{ i18n.ts.configure }}</MkA></MkInfo>
|
||||
<MkInfo v-if="noEmailServer" warn class="info">{{ i18n.ts.noEmailServerWarning }} <MkA to="/admin/email-settings" class="_link">{{ i18n.ts.configure }}</MkA></MkInfo>
|
||||
<MkInfo v-if="updateAvailable" warn class="info">{{ i18n.ts.newVersionOfClientAvailable }} <MkA to="/admin/update" class="_link">{{ i18n.ts.configure }}</MkA></MkInfo>
|
||||
|
||||
<MkSuperMenu :def="menuDef" :grid="narrow"></MkSuperMenu>
|
||||
</div>
|
||||
|
@ -37,6 +38,7 @@ import * as os from '@/os.js';
|
|||
import { lookupUser } from '@/scripts/lookup-user.js';
|
||||
import { useRouter } from '@/router.js';
|
||||
import { definePageMetadata, provideMetadataReceiver } from '@/scripts/page-metadata.js';
|
||||
import { version } from '@/config.js';
|
||||
|
||||
const isEmpty = (x: string | null) => x == null || x === '';
|
||||
|
||||
|
@ -61,6 +63,8 @@ let noBotProtection = !instance.disableRegistration && !instance.enableHcaptcha
|
|||
let noEmailServer = !instance.enableEmail;
|
||||
let thereIsUnresolvedAbuseReport = $ref(false);
|
||||
let currentPage = $computed(() => router.currentRef.value.child);
|
||||
let updateAvailable = $ref(false);
|
||||
let releasesCherryPick = $ref(null);
|
||||
|
||||
os.api('admin/abuse-user-reports', {
|
||||
state: 'unresolved',
|
||||
|
@ -69,6 +73,14 @@ os.api('admin/abuse-user-reports', {
|
|||
if (reports.length > 0) thereIsUnresolvedAbuseReport = true;
|
||||
});
|
||||
|
||||
fetch('https://api.github.com/repos/kokonect-link/cherrypick/releases', {
|
||||
method: 'GET',
|
||||
}).then(res => res.json())
|
||||
.then(res => {
|
||||
releasesCherryPick = res;
|
||||
if (version < releasesCherryPick[0].tag_name) updateAvailable = true;
|
||||
});
|
||||
|
||||
const NARROW_THRESHOLD = 600;
|
||||
const ro = new ResizeObserver((entries, observer) => {
|
||||
if (entries.length === 0) return;
|
||||
|
|
|
@ -9,6 +9,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="32">
|
||||
<FormSuspense :p="init">
|
||||
<div class="_gaps">
|
||||
<FormLink to="/admin/update"><template #icon><i class="ti ti-refresh"></i></template>{{ i18n.ts.cherrypickUpdate }}</FormLink>
|
||||
|
||||
<div class="_panel" style="padding: 16px;">
|
||||
<MkSwitch v-model="enableServerMachineStats">
|
||||
<template #label>{{ i18n.ts.enableServerMachineStats }}</template>
|
||||
|
@ -57,6 +59,7 @@ import { fetchInstance } from '@/instance.js';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import FormLink from '@/components/form/link.vue';
|
||||
|
||||
let enableServerMachineStats: boolean = $ref(false);
|
||||
let enableIdenticonGeneration: boolean = $ref(false);
|
||||
|
|
122
packages/frontend/src/pages/admin/update.vue
Normal file
122
packages/frontend/src/pages/admin/update.vue
Normal file
|
@ -0,0 +1,122 @@
|
|||
<!--
|
||||
SPDX-FileCopyrightText: syuilo and noridev and other misskey, cherrypick contributors
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<template>
|
||||
<MkStickyContainer>
|
||||
<template #header><XHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
||||
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="32">
|
||||
<div class="_gaps_m">
|
||||
<template v-if="meta">
|
||||
<FormInfo v-if="version > releasesCherryPick[0].tag_name">{{ i18n.ts.youAreRunningBetaClient }}</FormInfo>
|
||||
<FormInfo v-else-if="version === (meta.version && releasesCherryPick[0].tag_name)">{{ i18n.ts.youAreRunningUpToDateClient }}</FormInfo>
|
||||
<FormInfo v-else warn>{{ i18n.ts.newVersionOfClientAvailable }}</FormInfo>
|
||||
</template>
|
||||
|
||||
<FormSection first>
|
||||
<template #label>{{ instanceName }}</template>
|
||||
<MkKeyValue @click="whatIsNewCherryPick">
|
||||
<template #key>{{ i18n.ts.currentVersion }} <i class="ti ti-external-link"></i></template>
|
||||
<template #value>{{ version }}</template>
|
||||
</MkKeyValue>
|
||||
<MkKeyValue style="margin-top: 10px;" @click="whatIsNewLatestCherryPick">
|
||||
<template #key>{{ i18n.ts.latestVersion }} <i class="ti ti-external-link"></i></template>
|
||||
<template v-if="releasesCherryPick" #value>{{ releasesCherryPick[0].tag_name }}</template>
|
||||
<template v-else #value><MkEllipsis/></template>
|
||||
</MkKeyValue>
|
||||
</FormSection>
|
||||
|
||||
<FormSection @click="whatIsNewLatestCherryPick">
|
||||
<template #label>CherryPick <i class="ti ti-external-link"></i></template>
|
||||
<MkKeyValue>
|
||||
<template #key>{{ i18n.ts.latestVersion }}</template>
|
||||
<template v-if="releasesCherryPick" #value>{{ releasesCherryPick[0].tag_name }}</template>
|
||||
<template v-else #value><MkEllipsis/></template>
|
||||
</MkKeyValue>
|
||||
<MkKeyValue style="margin: 8px 0 0; color: var(--fgTransparentWeak); font-size: 0.85em;">
|
||||
<template v-if="releasesCherryPick" #value><MkTime :time="releasesCherryPick[0].published_at" mode="detail"/></template>
|
||||
<template v-else #value><MkEllipsis/></template>
|
||||
</MkKeyValue>
|
||||
</FormSection>
|
||||
|
||||
<FormSection @click="whatIsNewLatestMisskey">
|
||||
<template #label>Misskey <i class="ti ti-external-link"></i></template>
|
||||
<MkKeyValue>
|
||||
<template #key>{{ i18n.ts.latestVersion }}</template>
|
||||
<template v-if="releasesMisskey" #value>{{ releasesMisskey[0].tag_name }}</template>
|
||||
<template v-else #value><MkEllipsis/></template>
|
||||
</MkKeyValue>
|
||||
<MkKeyValue style="margin: 8px 0 0; color: var(--fgTransparentWeak); font-size: 0.85em;">
|
||||
<template v-if="releasesMisskey" #value><MkTime :time="releasesMisskey[0].published_at" mode="detail"/></template>
|
||||
<template v-else #value><MkEllipsis/></template>
|
||||
</MkKeyValue>
|
||||
</FormSection>
|
||||
</div>
|
||||
</MkSpacer>
|
||||
</MkStickyContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted } from 'vue';
|
||||
import * as Misskey from 'cherrypick-js';
|
||||
import * as os from '@/os.js';
|
||||
import FormInfo from '@/components/MkInfo.vue';
|
||||
import FormSection from '@/components/form/section.vue';
|
||||
import MkKeyValue from '@/components/MkKeyValue.vue';
|
||||
import { version, instanceName, basedMisskeyVersion } from '@/config.js';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import XHeader from '@/pages/admin/_header_.vue';
|
||||
|
||||
let meta = $ref<Misskey.entities.LiteInstanceMetadata | null>(null);
|
||||
let releasesCherryPick = $ref(null);
|
||||
let releasesMisskey = $ref(null);
|
||||
|
||||
onMounted(() => {
|
||||
os.api('meta', {
|
||||
detail: false,
|
||||
}).then(res => {
|
||||
meta = res;
|
||||
});
|
||||
|
||||
fetch('https://api.github.com/repos/kokonect-link/cherrypick/releases', {
|
||||
method: 'GET',
|
||||
}).then(res => res.json())
|
||||
.then(res => {
|
||||
releasesCherryPick = res;
|
||||
});
|
||||
|
||||
fetch('https://api.github.com/repos/misskey-dev/misskey/releases', {
|
||||
method: 'GET',
|
||||
}).then(res => res.json())
|
||||
.then(res => {
|
||||
releasesMisskey = res;
|
||||
});
|
||||
});
|
||||
|
||||
const whatIsNewCherryPick = () => {
|
||||
window.open(`https://github.com/kokonect-link/cherrypick/blob/develop/CHANGELOG_CHERRYPICK.md#${version.replace(/\./g, '')}`, '_blank');
|
||||
};
|
||||
|
||||
const whatIsNewLatestCherryPick = () => {
|
||||
window.open(`https://github.com/kokonect-link/cherrypick/blob/develop/CHANGELOG_CHERRYPICK.md#${releasesCherryPick[0].tag_name.replace(/\./g, '')}`, '_blank');
|
||||
};
|
||||
|
||||
const whatIsNewMisskey = () => {
|
||||
window.open(`https://misskey-hub.net/docs/releases.html#_${basedMisskeyVersion.replace(/\./g, '-')}`, '_blank');
|
||||
};
|
||||
|
||||
const whatIsNewLatestMisskey = () => {
|
||||
window.open(`https://misskey-hub.net/docs/releases.html#_${releasesMisskey[0].tag_name.replace(/\./g, '-')}`, '_blank');
|
||||
};
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.cherrypickUpdate,
|
||||
icon: 'ti ti-refresh',
|
||||
});
|
||||
</script>
|
|
@ -459,6 +459,10 @@ export const routes = [{
|
|||
path: '/invites',
|
||||
name: 'invites',
|
||||
component: page(() => import('./pages/admin/invites.vue')),
|
||||
}, {
|
||||
path: '/update',
|
||||
name: 'update',
|
||||
component: page(() => import('./pages/admin/update.vue')),
|
||||
}, {
|
||||
path: '/',
|
||||
component: page(() => import('./pages/_empty_.vue')),
|
||||
|
|
|
@ -57,6 +57,7 @@ import { $i, openAccountMenu as openAccountMenu_ } from '@/account.js';
|
|||
import { defaultStore } from '@/store.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { instance } from '@/instance.js';
|
||||
import { version } from '@/config.js';
|
||||
|
||||
const menu = toRef(defaultStore.state, 'menu');
|
||||
const otherMenuItemIndicated = computed(() => {
|
||||
|
@ -67,6 +68,7 @@ const otherMenuItemIndicated = computed(() => {
|
|||
return false;
|
||||
});
|
||||
let controlPanelIndicated = $ref(false);
|
||||
let releasesCherryPick = $ref(null);
|
||||
|
||||
os.api('admin/abuse-user-reports', {
|
||||
state: 'unresolved',
|
||||
|
@ -75,6 +77,14 @@ os.api('admin/abuse-user-reports', {
|
|||
if (reports.length > 0) controlPanelIndicated = true;
|
||||
});
|
||||
|
||||
fetch('https://api.github.com/repos/kokonect-link/cherrypick/releases', {
|
||||
method: 'GET',
|
||||
}).then(res => res.json())
|
||||
.then(res => {
|
||||
releasesCherryPick = res;
|
||||
if (version < releasesCherryPick[0].tag_name) controlPanelIndicated = true;
|
||||
});
|
||||
|
||||
function openAccountMenu(ev: MouseEvent) {
|
||||
openAccountMenu_({
|
||||
withExtraOperation: true,
|
||||
|
|
|
@ -69,6 +69,7 @@ import { $i, openAccountMenu as openAccountMenu_ } from '@/account.js';
|
|||
import { defaultStore } from '@/store.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { instance } from '@/instance.js';
|
||||
import { version } from '@/config.js';
|
||||
|
||||
const iconOnly = ref(false);
|
||||
|
||||
|
@ -81,6 +82,7 @@ const otherMenuItemIndicated = computed(() => {
|
|||
return false;
|
||||
});
|
||||
let controlPanelIndicated = $ref(false);
|
||||
let releasesCherryPick = $ref(null);
|
||||
|
||||
os.api('admin/abuse-user-reports', {
|
||||
state: 'unresolved',
|
||||
|
@ -89,6 +91,14 @@ os.api('admin/abuse-user-reports', {
|
|||
if (reports.length > 0) controlPanelIndicated = true;
|
||||
});
|
||||
|
||||
fetch('https://api.github.com/repos/kokonect-link/cherrypick/releases', {
|
||||
method: 'GET',
|
||||
}).then(res => res.json())
|
||||
.then(res => {
|
||||
releasesCherryPick = res;
|
||||
if (version < releasesCherryPick[0].tag_name) controlPanelIndicated = true;
|
||||
});
|
||||
|
||||
const calcViewState = () => {
|
||||
iconOnly.value = (window.innerWidth <= 1279) || (defaultStore.state.menuDisplay === 'sideIcon');
|
||||
};
|
||||
|
|
|
@ -60,6 +60,7 @@ import MkButton from '@/components/MkButton.vue';
|
|||
import { defaultStore } from '@/store.js';
|
||||
import { instance } from '@/instance.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { version } from '@/config.js';
|
||||
|
||||
const WINDOW_THRESHOLD = 1400;
|
||||
|
||||
|
@ -78,6 +79,7 @@ let el = $shallowRef<HTMLElement>();
|
|||
let iconOnly = $ref(false);
|
||||
let settingsWindowed = $ref(false);
|
||||
let controlPanelIndicated = $ref(false);
|
||||
let releasesCherryPick = $ref(null);
|
||||
|
||||
os.api('admin/abuse-user-reports', {
|
||||
state: 'unresolved',
|
||||
|
@ -86,6 +88,14 @@ os.api('admin/abuse-user-reports', {
|
|||
if (reports.length > 0) controlPanelIndicated = true;
|
||||
});
|
||||
|
||||
fetch('https://api.github.com/repos/kokonect-link/cherrypick/releases', {
|
||||
method: 'GET',
|
||||
}).then(res => res.json())
|
||||
.then(res => {
|
||||
releasesCherryPick = res;
|
||||
if (version < releasesCherryPick[0].tag_name) controlPanelIndicated = true;
|
||||
});
|
||||
|
||||
function calcViewState() {
|
||||
iconOnly = (window.innerWidth <= WINDOW_THRESHOLD) || (menuDisplay.value === 'sideIcon');
|
||||
settingsWindowed = (window.innerWidth > WINDOW_THRESHOLD);
|
||||
|
|
|
@ -61,6 +61,7 @@ import { defaultStore } from '@/store.js';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import { instance } from '@/instance.js';
|
||||
import { mainRouter } from '@/router.js';
|
||||
import { version } from '@/config.js';
|
||||
|
||||
const menu = toRef(defaultStore.state, 'menu');
|
||||
const otherMenuItemIndicated = computed(() => {
|
||||
|
@ -71,6 +72,7 @@ const otherMenuItemIndicated = computed(() => {
|
|||
return false;
|
||||
});
|
||||
let controlPanelIndicated = $ref(false);
|
||||
let releasesCherryPick = $ref(null);
|
||||
|
||||
os.api('admin/abuse-user-reports', {
|
||||
state: 'unresolved',
|
||||
|
@ -79,6 +81,14 @@ os.api('admin/abuse-user-reports', {
|
|||
if (reports.length > 0) controlPanelIndicated = true;
|
||||
});
|
||||
|
||||
fetch('https://api.github.com/repos/kokonect-link/cherrypick/releases', {
|
||||
method: 'GET',
|
||||
}).then(res => res.json())
|
||||
.then(res => {
|
||||
releasesCherryPick = res;
|
||||
if (version < releasesCherryPick[0].tag_name) controlPanelIndicated = true;
|
||||
});
|
||||
|
||||
function openAccountMenu(ev: MouseEvent) {
|
||||
openAccountMenu_({
|
||||
withExtraOperation: true,
|
||||
|
|
|
@ -76,6 +76,7 @@ import { defaultStore } from '@/store.js';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import { instance } from '@/instance.js';
|
||||
import { mainRouter } from '@/router.js';
|
||||
import { version } from '@/config.js';
|
||||
|
||||
const iconOnly = ref(false);
|
||||
|
||||
|
@ -88,6 +89,7 @@ const otherMenuItemIndicated = computed(() => {
|
|||
return false;
|
||||
});
|
||||
let controlPanelIndicated = $ref(false);
|
||||
let releasesCherryPick = $ref(null);
|
||||
|
||||
os.api('admin/abuse-user-reports', {
|
||||
state: 'unresolved',
|
||||
|
@ -96,6 +98,14 @@ os.api('admin/abuse-user-reports', {
|
|||
if (reports.length > 0) controlPanelIndicated = true;
|
||||
});
|
||||
|
||||
fetch('https://api.github.com/repos/kokonect-link/cherrypick/releases', {
|
||||
method: 'GET',
|
||||
}).then(res => res.json())
|
||||
.then(res => {
|
||||
releasesCherryPick = res;
|
||||
if (version < releasesCherryPick[0].tag_name) controlPanelIndicated = true;
|
||||
});
|
||||
|
||||
const calcViewState = () => {
|
||||
iconOnly.value = (window.innerWidth <= 1279) || (defaultStore.state.menuDisplay === 'sideIcon');
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue