Skip to content

Commit

Permalink
enhance: 連合モードにあわせてフロントエンドを変化させるように (#15112)
Browse files Browse the repository at this point in the history
* enhance(backend): metaにfederation modeに関する情報を公開

* enhance(frontend): 登録画面の注意書きを追加

* enhance(frontend): aboutページ・サーバー情報

* enhance(frontend): サーバー統計

* enhance(frontend): みつけるページ

* enhance(frontend): 検索

* enhance(frontend): ユーザー選択

* enhance(frontend): 設定画面

* enhance(frontend): ウィジェット

* enhance(frontend): リモートで開くオプション

* Update Changelog

* enhance(frontend): ステータスバー

* i18n

---------

Co-authored-by: syuilo <[email protected]>
  • Loading branch information
kakkokari-gtyih and syuilo authored Jan 14, 2025
1 parent 64501c6 commit 5445b02
Show file tree
Hide file tree
Showing 23 changed files with 150 additions and 68 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- Enhance: PC画面でチャンネルが複数列で表示されるように
(Cherry-picked from https://github.com/Otaku-Social/maniakey/pull/13)
- Enhance: 照会に失敗した場合、その理由を表示するように
- Enhance: 連合がホワイトリスト化・無効化されているサーバー向けのデザイン修正
- Enhance: AiScriptのセーブデータを明示的に削除する関数`Mk:remove`を追加
- Enhance: AiScriptの拡張API関数において引数の型チェックをより厳格に
- Fix: 画面サイズが変わった際にナビゲーションバーが自動で折りたたまれない問題を修正
Expand Down
8 changes: 8 additions & 0 deletions locales/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5230,6 +5230,14 @@ export interface Locale extends ILocale {
* 注意事項を理解した上でオンにします。
*/
"acknowledgeNotesAndEnable": string;
/**
* このサーバーはホワイトリスト連合で運用されています。管理者が指定したサーバー以外とやり取りすることはできません。
*/
"federationSpecified": string;
/**
* このサーバーは連合が無効化されています。他のサーバーのユーザーとやり取りすることはできません。
*/
"federationDisabled": string;
"_accountSettings": {
/**
* コンテンツの表示にログインを必須にする
Expand Down
2 changes: 2 additions & 0 deletions locales/ja-JP.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1303,6 +1303,8 @@ lockdown: "ロックダウン"
pleaseSelectAccount: "アカウントを選択してください"
availableRoles: "利用可能なロール"
acknowledgeNotesAndEnable: "注意事項を理解した上でオンにします。"
federationSpecified: "このサーバーはホワイトリスト連合で運用されています。管理者が指定したサーバー以外とやり取りすることはできません。"
federationDisabled: "このサーバーは連合が無効化されています。他のサーバーのユーザーとやり取りすることはできません。"

_accountSettings:
requireSigninToViewContents: "コンテンツの表示にログインを必須にする"
Expand Down
1 change: 1 addition & 0 deletions packages/backend/src/core/entities/MetaEntityService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ export class MetaEntityService {
enableUrlPreview: instance.urlPreviewEnabled,
noteSearchableScope: (this.config.meilisearch == null || this.config.meilisearch.scope !== 'local') ? 'global' : 'local',
maxFileSize: this.config.maxFileSize,
federation: this.meta.federation,
};

return packed;
Expand Down
5 changes: 5 additions & 0 deletions packages/backend/src/models/json-schema/meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,11 @@ export const packedMetaLiteSchema = {
type: 'number',
optional: false, nullable: false,
},
federation: {
type: 'string',
enum: ['all', 'specified', 'none'],
optional: false, nullable: false,
},
},
} as const;

Expand Down
18 changes: 11 additions & 7 deletions packages/frontend/src/components/MkInstanceStats.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div :class="$style.chart">
<div class="selects">
<MkSelect v-model="chartSrc" style="margin: 0; flex: 1;">
<optgroup :label="i18n.ts.federation">
<optgroup v-if="shouldShowFederation" :label="i18n.ts.federation">
<option value="federation">{{ i18n.ts._charts.federation }}</option>
<option value="ap-request">{{ i18n.ts._charts.apRequest }}</option>
</optgroup>
Expand All @@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<optgroup :label="i18n.ts.notes">
<option value="notes">{{ i18n.ts._charts.notesIncDec }}</option>
<option value="local-notes">{{ i18n.ts._charts.localNotesIncDec }}</option>
<option value="remote-notes">{{ i18n.ts._charts.remoteNotesIncDec }}</option>
<option v-if="shouldShowFederation" value="remote-notes">{{ i18n.ts._charts.remoteNotesIncDec }}</option>
<option value="notes-total">{{ i18n.ts._charts.notesTotal }}</option>
</optgroup>
<optgroup :label="i18n.ts.drive">
Expand All @@ -46,9 +46,9 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkSelect v-model="heatmapSrc" style="margin: 0 0 12px 0;">
<option value="active-users">Active users</option>
<option value="notes">Notes</option>
<option value="ap-requests-inbox-received">AP Requests: inboxReceived</option>
<option value="ap-requests-deliver-succeeded">AP Requests: deliverSucceeded</option>
<option value="ap-requests-deliver-failed">AP Requests: deliverFailed</option>
<option v-if="shouldShowFederation" value="ap-requests-inbox-received">AP Requests: inboxReceived</option>
<option v-if="shouldShowFederation" value="ap-requests-deliver-succeeded">AP Requests: deliverSucceeded</option>
<option v-if="shouldShowFederation" value="ap-requests-deliver-failed">AP Requests: deliverFailed</option>
</MkSelect>
<div class="_panel" :class="$style.heatmap">
<MkHeatmap :src="heatmapSrc" :label="'Read & Write'"/>
Expand All @@ -65,7 +65,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
</MkFoldableSection>

<MkFoldableSection class="item">
<MkFoldableSection v-if="shouldShowFederation" class="item">
<template #header>Federation</template>
<div :class="$style.federation">
<div class="pies">
Expand All @@ -84,13 +84,15 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>

<script lang="ts" setup>
import { onMounted, ref, shallowRef } from 'vue';
import { onMounted, ref, computed, shallowRef } from 'vue';
import { Chart } from 'chart.js';
import MkSelect from '@/components/MkSelect.vue';
import MkChart from '@/components/MkChart.vue';
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
import { $i } from '@/account.js';
import * as os from '@/os.js';
import { misskeyApiGet } from '@/scripts/misskey-api.js';
import { instance } from '@/instance.js';
import { i18n } from '@/i18n.js';
import MkHeatmap, { type HeatmapSource } from '@/components/MkHeatmap.vue';
import MkFoldableSection from '@/components/MkFoldableSection.vue';
Expand All @@ -100,6 +102,8 @@ import { initChart } from '@/scripts/init-chart.js';

initChart();

const shouldShowFederation = computed(() => instance.federation !== 'none' || $i?.isModerator);

const chartLimit = 500;
const chartSpan = ref<'hour' | 'day'>('hour');
const chartSrc = ref('active-users');
Expand Down
6 changes: 4 additions & 2 deletions packages/frontend/src/components/MkSignupDialog.rules.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<MkSpacer :marginMin="20" :marginMax="28">
<div class="_gaps_m">
<div v-if="instance.disableRegistration">
<MkInfo warn>{{ i18n.ts.invitationRequiredToRegister }}</MkInfo>
<div v-if="instance.disableRegistration || instance.federation !== 'all'" class="_gaps_s">
<MkInfo v-if="instance.disableRegistration" warn>{{ i18n.ts.invitationRequiredToRegister }}</MkInfo>
<MkInfo v-if="instance.federation === 'specified'" warn>{{ i18n.ts.federationSpecified }}</MkInfo>
<MkInfo v-else-if="instance.federation === 'none'" warn>{{ i18n.ts.federationDisabled }}</MkInfo>
</div>

<div style="text-align: center;">
Expand Down
11 changes: 7 additions & 4 deletions packages/frontend/src/components/MkUserSelectDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #header>{{ i18n.ts.selectUser }}</template>
<div>
<div :class="$style.form">
<MkInput v-if="localOnly" v-model="username" :autofocus="true" @update:modelValue="search">
<MkInput v-if="computedLocalOnly" v-model="username" :autofocus="true" @update:modelValue="search">
<template #label>{{ i18n.ts.username }}</template>
<template #prefix>@</template>
</MkInput>
Expand Down Expand Up @@ -61,7 +61,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>

<script lang="ts" setup>
import { onMounted, ref, shallowRef } from 'vue';
import { onMounted, ref, computed, shallowRef } from 'vue';
import * as Misskey from 'misskey-js';
import MkInput from '@/components/MkInput.vue';
import FormSplit from '@/components/form/split.vue';
Expand All @@ -70,6 +70,7 @@ import { misskeyApi } from '@/scripts/misskey-api.js';
import { defaultStore } from '@/store.js';
import { i18n } from '@/i18n.js';
import { $i } from '@/account.js';
import { instance } from '@/instance.js';
import { host as currentHost, hostname } from '@@/js/config.js';

const emit = defineEmits<{
Expand All @@ -86,6 +87,8 @@ const props = withDefaults(defineProps<{
localOnly: false,
});

const computedLocalOnly = computed(() => props.localOnly || instance.federation === 'none');

const username = ref('');
const host = ref('');
const users = ref<Misskey.entities.UserLite[]>([]);
Expand All @@ -100,7 +103,7 @@ function search() {
}
misskeyApi('users/search-by-username-and-host', {
username: username.value,
host: props.localOnly ? '.' : host.value,
host: computedLocalOnly.value ? '.' : host.value,
limit: 10,
detail: false,
}).then(_users => {
Expand Down Expand Up @@ -142,7 +145,7 @@ onMounted(() => {
}).then(foundUsers => {
let _users = foundUsers;
_users = _users.filter((u) => {
if (props.localOnly) {
if (computedLocalOnly.value) {
return u.host == null;
} else {
return true;
Expand Down
6 changes: 4 additions & 2 deletions packages/frontend/src/components/MkVisitorDashboard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<!-- eslint-disable-next-line vue/no-v-html -->
<div v-html="instance.description || i18n.ts.headlineMisskey"></div>
</div>
<div v-if="instance.disableRegistration" :class="$style.mainWarn">
<MkInfo warn>{{ i18n.ts.invitationRequiredToRegister }}</MkInfo>
<div v-if="instance.disableRegistration || instance.federation !== 'all'" :class="$style.mainWarn" class="_gaps_s">
<MkInfo v-if="instance.disableRegistration" warn>{{ i18n.ts.invitationRequiredToRegister }}</MkInfo>
<MkInfo v-if="instance.federation === 'specified'" warn>{{ i18n.ts.federationSpecified }}</MkInfo>
<MkInfo v-else-if="instance.federation === 'none'" warn>{{ i18n.ts.federationDisabled }}</MkInfo>
</div>
<div class="_gaps_s" :class="$style.mainActions">
<MkButton :class="$style.mainAction" full rounded gradate data-cy-signup style="margin-right: 12px;" @click="signup()">{{ i18n.ts.joinThisServer }}</MkButton>
Expand Down
19 changes: 15 additions & 4 deletions packages/frontend/src/components/MkWidgets.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<header :class="$style.editHeader">
<MkSelect v-model="widgetAdderSelected" style="margin-bottom: var(--MI-margin)" data-cy-widget-select>
<template #label>{{ i18n.ts.selectWidget }}</template>
<option v-for="widget in widgetDefs" :key="widget" :value="widget">{{ i18n.ts._widgets[widget] }}</option>
<option v-for="widget in _widgetDefs" :key="widget" :value="widget">{{ i18n.ts._widgets[widget] }}</option>
</MkSelect>
<MkButton inline primary data-cy-widget-add @click="addWidget"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton>
<MkButton inline @click="emit('exit')">{{ i18n.ts.close }}</MkButton>
Expand All @@ -34,7 +34,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
</Sortable>
</template>
<component :is="`widget-${widget.name}`" v-for="widget in widgets" v-else :key="widget.id" :ref="el => widgetRefs[widget.id] = el" :class="$style.widget" :widget="widget" @updateProps="updateWidget(widget.id, $event)" @contextmenu.stop="onContextmenu(widget, $event)"/>
<component :is="`widget-${widget.name}`" v-for="widget in _widgets" v-else :key="widget.id" :ref="el => widgetRefs[widget.id] = el" :class="$style.widget" :widget="widget" @updateProps="updateWidget(widget.id, $event)" @contextmenu.stop="onContextmenu(widget, $event)"/>
</div>
</template>

Expand All @@ -50,13 +50,14 @@ export type DefaultStoredWidget = {
</script>

<script lang="ts" setup>
import { defineAsyncComponent, ref } from 'vue';
import { defineAsyncComponent, ref, computed } from 'vue';
import { v4 as uuid } from 'uuid';
import MkSelect from '@/components/MkSelect.vue';
import MkButton from '@/components/MkButton.vue';
import { widgets as widgetDefs } from '@/widgets/index.js';
import { widgets as widgetDefs, federationWidgets } from '@/widgets/index.js';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { instance } from '@/instance.js';
import { isLink } from '@@/js/is-link.js';

const Sortable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default));
Expand All @@ -66,6 +67,16 @@ const props = defineProps<{
edit: boolean;
}>();

const _widgetDefs = computed(() => {
if (instance.federation === 'none') {
return widgetDefs.filter(x => !federationWidgets.includes(x));
} else {
return widgetDefs;
}
});

const _widgets = computed(() => props.widgets.filter(x => _widgetDefs.value.includes(x.name)));

const emit = defineEmits<{
(ev: 'updateWidgets', widgets: Widget[]): void;
(ev: 'addWidget', widget: Widget): void;
Expand Down
47 changes: 30 additions & 17 deletions packages/frontend/src/pages/about.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkSpacer v-else-if="tab === 'emojis'" :contentMax="1000" :marginMin="20">
<XEmojis/>
</MkSpacer>
<MkSpacer v-else-if="tab === 'federation'" :contentMax="1000" :marginMin="20">
<MkSpacer v-else-if="instance.federation !== 'none' && tab === 'federation'" :contentMax="1000" :marginMin="20">
<XFederation/>
</MkSpacer>
<MkSpacer v-else-if="tab === 'charts'" :contentMax="1000" :marginMin="20">
Expand All @@ -25,6 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only

<script lang="ts" setup>
import { computed, defineAsyncComponent, ref, watch } from 'vue';
import { instance } from '@/instance.js';
import { i18n } from '@/i18n.js';
import { claimAchievement } from '@/scripts/achievements.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
Expand All @@ -51,22 +52,34 @@ watch(tab, () => {

const headerActions = computed(() => []);

const headerTabs = computed(() => [{
key: 'overview',
title: i18n.ts.overview,
}, {
key: 'emojis',
title: i18n.ts.customEmojis,
icon: 'ti ti-icons',
}, {
key: 'federation',
title: i18n.ts.federation,
icon: 'ti ti-whirl',
}, {
key: 'charts',
title: i18n.ts.charts,
icon: 'ti ti-chart-line',
}]);
const headerTabs = computed(() => {
const items = [];

items.push({
key: 'overview',
title: i18n.ts.overview,
}, {
key: 'emojis',
title: i18n.ts.customEmojis,
icon: 'ti ti-icons',
});

if (instance.federation !== 'none') {
items.push({
key: 'federation',
title: i18n.ts.federation,
icon: 'ti ti-whirl',
});
}

items.push({
key: 'charts',
title: i18n.ts.charts,
icon: 'ti ti-chart-line',
});

return items;
});

definePageMetadata(() => ({
title: i18n.ts.instanceInfo,
Expand Down
3 changes: 2 additions & 1 deletion packages/frontend/src/pages/explore.users.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only

<template>
<MkSpacer :contentMax="1200">
<MkTab v-model="origin" style="margin-bottom: var(--MI-margin);">
<MkTab v-if="instance.federation !== 'none'" v-model="origin" style="margin-bottom: var(--MI-margin);">
<option value="local">{{ i18n.ts.local }}</option>
<option value="remote">{{ i18n.ts.remote }}</option>
</MkTab>
Expand Down Expand Up @@ -69,6 +69,7 @@ import MkUserList from '@/components/MkUserList.vue';
import MkFoldableSection from '@/components/MkFoldableSection.vue';
import MkTab from '@/components/MkTab.vue';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { instance } from '@/instance.js';
import { i18n } from '@/i18n.js';

const props = defineProps<{
Expand Down
22 changes: 12 additions & 10 deletions packages/frontend/src/pages/search.note.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,17 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #header>{{ i18n.ts.options }}</template>

<div class="_gaps_m">
<MkRadios v-model="hostSelect">
<template #label>{{ i18n.ts.host }}</template>
<option value="all" default>{{ i18n.ts.all }}</option>
<option value="local">{{ i18n.ts.local }}</option>
<option v-if="noteSearchableScope === 'global'" value="specified">{{ i18n.ts.specifyHost }}</option>
</MkRadios>
<MkInput v-if="noteSearchableScope === 'global'" v-model="hostInput" :disabled="hostSelect !== 'specified'" :large="true" type="search">
<template #prefix><i class="ti ti-server"></i></template>
</MkInput>
<template v-if="instance.federation !== 'none'">
<MkRadios v-model="hostSelect">
<template #label>{{ i18n.ts.host }}</template>
<option value="all" default>{{ i18n.ts.all }}</option>
<option value="local">{{ i18n.ts.local }}</option>
<option v-if="noteSearchableScope === 'global'" value="specified">{{ i18n.ts.specifyHost }}</option>
</MkRadios>
<MkInput v-if="noteSearchableScope === 'global'" v-model="hostInput" :disabled="hostSelect !== 'specified'" :large="true" type="search">
<template #prefix><i class="ti ti-server"></i></template>
</MkInput>
</template>

<MkFolder :defaultOpen="true">
<template #label>{{ i18n.ts.specifyUser }}</template>
Expand Down Expand Up @@ -102,7 +104,7 @@ setHostSelectWithInput(hostInput.value, undefined);
watch(hostInput, setHostSelectWithInput);

const searchHost = computed(() => {
if (hostSelect.value === 'local') return '.';
if (hostSelect.value === 'local' || instance.federation === 'none') return '.';
if (hostSelect.value === 'specified') return hostInput.value;
return null;
});
Expand Down
5 changes: 3 additions & 2 deletions packages/frontend/src/pages/search.user.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkInput v-model="searchQuery" :large="true" :autofocus="true" type="search" @enter.prevent="search">
<template #prefix><i class="ti ti-search"></i></template>
</MkInput>
<MkRadios v-model="searchOrigin" @update:modelValue="search()">
<MkRadios v-if="instance.federation !== 'none'" v-model="searchOrigin" @update:modelValue="search()">
<option value="combined">{{ i18n.ts.all }}</option>
<option value="local">{{ i18n.ts.local }}</option>
<option value="remote">{{ i18n.ts.remote }}</option>
Expand All @@ -33,6 +33,7 @@ import MkInput from '@/components/MkInput.vue';
import MkRadios from '@/components/MkRadios.vue';
import MkButton from '@/components/MkButton.vue';
import { i18n } from '@/i18n.js';
import { instance } from '@/instance.js';
import * as os from '@/os.js';
import MkFoldableSection from '@/components/MkFoldableSection.vue';
import { misskeyApi } from '@/scripts/misskey-api.js';
Expand Down Expand Up @@ -113,7 +114,7 @@ async function search() {
limit: 10,
params: {
query: query,
origin: searchOrigin.value,
origin: instance.federation === 'none' ? 'local' : searchOrigin.value,
},
};

Expand Down
Loading

0 comments on commit 5445b02

Please sign in to comment.