Merge branch 'develop' into no-websocket

This commit is contained in:
syuilo 2025-05-06 20:58:18 +09:00
commit 0f5531bf14
9 changed files with 91 additions and 16 deletions

View File

@ -10,6 +10,7 @@
- Feat: マウスでもタイムラインを引っ張って更新できるように - Feat: マウスでもタイムラインを引っ張って更新できるように
- アクセシビリティ設定からオフにすることもできます - アクセシビリティ設定からオフにすることもできます
- Enhance: タイムラインのパフォーマンスを向上 - Enhance: タイムラインのパフォーマンスを向上
- Enhance: バックアップされた設定のプロファイルを削除できるように
- Fix: 一部のブラウザでアコーディオンメニューのアニメーションが動作しない問題を修正 - Fix: 一部のブラウザでアコーディオンメニューのアニメーションが動作しない問題を修正
- Fix: ダイアログのお知らせが画面からはみ出ることがある問題を修正 - Fix: ダイアログのお知らせが画面からはみ出ることがある問題を修正
- Fix: ユーザーポップアップでエラーが生じてもインジケーターが表示され続けてしまう問題を修正 - Fix: ユーザーポップアップでエラーが生じてもインジケーターが表示され続けてしまう問題を修正

4
locales/index.d.ts vendored
View File

@ -5769,6 +5769,10 @@ export interface Locale extends ILocale {
* : PC * : PC
*/ */
"profileNameDescription2": string; "profileNameDescription2": string;
/**
*
*/
"manageProfiles": string;
}; };
"_preferencesBackup": { "_preferencesBackup": {
/** /**

View File

@ -1445,6 +1445,7 @@ _preferencesProfile:
profileName: "プロファイル名" profileName: "プロファイル名"
profileNameDescription: "このデバイスを識別する名前を設定してください。" profileNameDescription: "このデバイスを識別する名前を設定してください。"
profileNameDescription2: "例: 「メインPC」、「スマホ」など" profileNameDescription2: "例: 「メインPC」、「スマホ」など"
manageProfiles: "プロファイルの管理"
_preferencesBackup: _preferencesBackup:
autoBackup: "自動バックアップ" autoBackup: "自動バックアップ"

View File

@ -1,6 +1,6 @@
{ {
"name": "misskey", "name": "misskey",
"version": "2025.5.0-beta.0", "version": "2025.5.0-rc.0",
"codename": "nasubi", "codename": "nasubi",
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<Transition :name="prefer.s.animation ? '_transition_zoom' : ''" appear> <Transition :name="prefer.s.animation ? '_transition_zoom' : ''" appear>
<div :class="[$style.root, { [$style.warn]: type === 'notFound', [$style.error]: type === 'error' }]" class="_gaps_m"> <div :class="[$style.root, { [$style.warn]: type === 'notFound', [$style.error]: type === 'error' }]" class="_gaps_m">
<img v-if="type === 'empty' && instance.infoImageUrl" :src="instance.infoImageUrl" draggable="false" :class="$style.img"/> <img v-if="type === 'empty' && instance.infoImageUrl" :src="instance.infoImageUrl" draggable="false" :class="$style.img"/>
<svg v-else-if="type === 'empty'" :class="$style.icon" viewBox="0 0 128 128" style="stroke-linecap:round;"> <svg v-else-if="type === 'empty'" :class="$style.icon" viewBox="0 0 128 128" style="stroke-linecap:round;stroke-linejoin:round;">
<g transform="matrix(1,0,0,0.9,0,12.8)"> <g transform="matrix(1,0,0,0.9,0,12.8)">
<path d="M64,88L64,48" style="fill:none;stroke:currentColor;stroke-width:8.41px;"/> <path d="M64,88L64,48" style="fill:none;stroke:currentColor;stroke-width:8.41px;"/>
</g> </g>
@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</g> </g>
</svg> </svg>
<img v-if="type === 'notFound' && instance.notFoundImageUrl" :src="instance.notFoundImageUrl" draggable="false" :class="$style.img"/> <img v-if="type === 'notFound' && instance.notFoundImageUrl" :src="instance.notFoundImageUrl" draggable="false" :class="$style.img"/>
<svg v-else-if="type === 'notFound'" :class="$style.icon" viewBox="0 0 128 128" style="stroke-linecap:round;"> <svg v-else-if="type === 'notFound'" :class="$style.icon" viewBox="0 0 128 128" style="stroke-linecap:round;stroke-linejoin:round;">
<g transform="matrix(1,0,0,1,0,12)"> <g transform="matrix(1,0,0,1,0,12)">
<path d="M64,64L64,56C72.533,55.777 80,49.333 80,40C80,31.667 73.333,24 64,24C55.667,24 47.556,31.667 48,40" style="fill:none;stroke:currentColor;stroke-width:8px;"/> <path d="M64,64L64,56C72.533,55.777 80,49.333 80,40C80,31.667 73.333,24 64,24C55.667,24 47.556,31.667 48,40" style="fill:none;stroke:currentColor;stroke-width:8px;"/>
</g> </g>
@ -31,7 +31,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</g> </g>
</svg> </svg>
<img v-if="type === 'error' && instance.serverErrorImageUrl" :src="instance.serverErrorImageUrl" draggable="false" :class="$style.img"/> <img v-if="type === 'error' && instance.serverErrorImageUrl" :src="instance.serverErrorImageUrl" draggable="false" :class="$style.img"/>
<svg v-else-if="type === 'error'" :class="$style.icon" viewBox="0 0 128 128" style="stroke-linecap:round;"> <svg v-else-if="type === 'error'" :class="$style.icon" viewBox="0 0 128 128" style="stroke-linecap:round;stroke-linejoin:round;">
<g transform="matrix(0.707107,0.707107,-0.636396,0.636396,62.0201,-24.5298)"> <g transform="matrix(0.707107,0.707107,-0.636396,0.636396,62.0201,-24.5298)">
<path d="M64,94.667L64,41.333" style="fill:none;stroke:currentColor;stroke-width:8.41px;"/> <path d="M64,94.667L64,41.333" style="fill:none;stroke:currentColor;stroke-width:8.41px;"/>
</g> </g>

View File

@ -0,0 +1,47 @@
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<SearchMarker path="/settings/profiles" :label="i18n.ts._preferencesProfile.manageProfiles" :keywords="['profile', 'settings', 'preferences', 'manage']" icon="ti ti-settings-cog">
<div class="_gaps">
<MkFolder v-for="backup in backups">
<template #label>{{ backup.name }}</template>
<MkButton danger @click="del(backup)">{{ i18n.ts.delete }}</MkButton>
</MkFolder>
</div>
</SearchMarker>
</template>
<script lang="ts" setup>
import { ref, computed } from 'vue';
import type { MenuItem } from '@/types/menu.js';
import MkButton from '@/components/MkButton.vue';
import MkFolder from '@/components/MkFolder.vue';
import * as os from '@/os.js';
import { misskeyApi } from '@/utility/misskey-api.js';
import { $i } from '@/i.js';
import { i18n } from '@/i18n.js';
import { definePage } from '@/page.js';
import { prefer } from '@/preferences.js';
import { deleteCloudBackup, listCloudBackups } from '@/preferences/utility.js';
const backups = await listCloudBackups();
function del(backup) {
deleteCloudBackup(backup.name);
}
const headerActions = computed(() => []);
const headerTabs = computed(() => []);
definePage(() => ({
title: i18n.ts._preferencesProfile.manageProfiles,
icon: 'ti ti-settings-cog',
}));
</script>
<style lang="scss" module>
</style>

View File

@ -74,12 +74,17 @@ export function getPreferencesProfileMenu(): MenuItem[] {
action: () => { action: () => {
importProfile(); importProfile();
}, },
}, {
type: 'divider',
}, {
type: 'link',
text: i18n.ts._preferencesProfile.manageProfiles + '...',
icon: 'ti ti-settings-cog',
to: '/settings/profiles',
}]; }];
if (prefer.s.devMode) { if (prefer.s.devMode) {
menu.push({ menu.push({
type: 'divider',
}, {
text: 'Copy profile as text', text: 'Copy profile as text',
icon: 'ti ti-clipboard', icon: 'ti ti-clipboard',
action: () => { action: () => {
@ -145,17 +150,30 @@ export async function cloudBackup() {
}); });
} }
export async function restoreFromCloudBackup() { export async function listCloudBackups() {
if ($i == null) return;
// TODO: 更新日時でソートして取得したい
const keys = await misskeyApi('i/registry/keys', { const keys = await misskeyApi('i/registry/keys', {
scope: ['client', 'preferences', 'backups'], scope: ['client', 'preferences', 'backups'],
}); });
if (_DEV_) console.log(keys); return keys.map(k => ({
name: k,
}));
}
if (keys.length === 0) { export async function deleteCloudBackup(key: string) {
await os.apiWithDialog('i/registry/remove', {
scope: ['client', 'preferences', 'backups'],
key,
});
}
export async function restoreFromCloudBackup() {
if ($i == null) return;
// TODO: 更新日時でソートしたい
const backups = await listCloudBackups();
if (backups.length === 0) {
os.alert({ os.alert({
type: 'warning', type: 'warning',
title: i18n.ts._preferencesBackup.noBackupsFoundTitle, title: i18n.ts._preferencesBackup.noBackupsFoundTitle,
@ -166,9 +184,9 @@ export async function restoreFromCloudBackup() {
const select = await os.select({ const select = await os.select({
title: i18n.ts._preferencesBackup.selectBackupToRestore, title: i18n.ts._preferencesBackup.selectBackupToRestore,
items: keys.map(k => ({ items: backups.map(backup => ({
text: k, text: backup.name,
value: k, value: backup.name,
})), })),
}); });
if (select.canceled) return; if (select.canceled) return;

View File

@ -180,6 +180,10 @@ export const ROUTE_DEF = [{
path: '/custom-css', path: '/custom-css',
name: 'preferences', name: 'preferences',
component: page(() => import('@/pages/settings/custom-css.vue')), component: page(() => import('@/pages/settings/custom-css.vue')),
}, {
path: '/profiles',
name: 'profiles',
component: page(() => import('@/pages/settings/profiles.vue')),
}, { }, {
path: '/accounts', path: '/accounts',
name: 'profile', name: 'profile',

View File

@ -1,7 +1,7 @@
{ {
"type": "module", "type": "module",
"name": "misskey-js", "name": "misskey-js",
"version": "2025.5.0-beta.0", "version": "2025.5.0-rc.0",
"description": "Misskey SDK for JavaScript", "description": "Misskey SDK for JavaScript",
"license": "MIT", "license": "MIT",
"main": "./built/index.js", "main": "./built/index.js",