いろいろかえた
This commit is contained in:
parent
fea64e8d94
commit
852c5d4035
20
locales/index.d.ts
vendored
20
locales/index.d.ts
vendored
|
@ -92,6 +92,10 @@ export interface Locale extends ILocale {
|
||||||
* キャンセル
|
* キャンセル
|
||||||
*/
|
*/
|
||||||
"cancel": string;
|
"cancel": string;
|
||||||
|
/**
|
||||||
|
* 自分の作成したリスト
|
||||||
|
*/
|
||||||
|
"myLists": string;
|
||||||
/**
|
/**
|
||||||
* やめておく
|
* やめておく
|
||||||
*/
|
*/
|
||||||
|
@ -128,6 +132,14 @@ export interface Locale extends ILocale {
|
||||||
* 通知の設定
|
* 通知の設定
|
||||||
*/
|
*/
|
||||||
"notificationSettings": string;
|
"notificationSettings": string;
|
||||||
|
/**
|
||||||
|
* このサーバーの公開のリスト
|
||||||
|
*/
|
||||||
|
"localListList": string;
|
||||||
|
/**
|
||||||
|
* お気に入りのリスト
|
||||||
|
*/
|
||||||
|
"favoriteLists": string;
|
||||||
/**
|
/**
|
||||||
* 基本設定
|
* 基本設定
|
||||||
*/
|
*/
|
||||||
|
@ -6628,6 +6640,14 @@ export interface Locale extends ILocale {
|
||||||
* アイコンデコレーションの最大取付個数
|
* アイコンデコレーションの最大取付個数
|
||||||
*/
|
*/
|
||||||
"avatarDecorationLimit": string;
|
"avatarDecorationLimit": string;
|
||||||
|
/**
|
||||||
|
* ピン留めリストの最大数
|
||||||
|
*/
|
||||||
|
"listPinnedLimit": string;
|
||||||
|
/**
|
||||||
|
* 他鯖のローカルTL除けるやつ(最大値5)
|
||||||
|
*/
|
||||||
|
"localTimelineAnyLimit": string;
|
||||||
};
|
};
|
||||||
"_condition": {
|
"_condition": {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -19,6 +19,7 @@ hanntennInfo: "ダークだったらライトのアイコンに、ライトだ
|
||||||
ruby: "ルビ"
|
ruby: "ルビ"
|
||||||
gotIt: "わかった"
|
gotIt: "わかった"
|
||||||
cancel: "キャンセル"
|
cancel: "キャンセル"
|
||||||
|
myLists: "自分の作成したリスト"
|
||||||
noThankYou: "やめておく"
|
noThankYou: "やめておく"
|
||||||
enterUsername: "ユーザー名を入力"
|
enterUsername: "ユーザー名を入力"
|
||||||
showGlobalTimeline: "グローバルタイムラインを表示する"
|
showGlobalTimeline: "グローバルタイムラインを表示する"
|
||||||
|
@ -28,6 +29,8 @@ noNotifications: "通知はありません"
|
||||||
instance: "サーバー"
|
instance: "サーバー"
|
||||||
settings: "設定"
|
settings: "設定"
|
||||||
notificationSettings: "通知の設定"
|
notificationSettings: "通知の設定"
|
||||||
|
localListList: "このサーバーの公開のリスト"
|
||||||
|
favoriteLists: "お気に入りのリスト"
|
||||||
basicSettings: "基本設定"
|
basicSettings: "基本設定"
|
||||||
otherSettings: "その他の設定"
|
otherSettings: "その他の設定"
|
||||||
openInWindow: "ウィンドウで開く"
|
openInWindow: "ウィンドウで開く"
|
||||||
|
@ -1711,6 +1714,8 @@ _role:
|
||||||
canSearchNotes: "ノート検索の利用"
|
canSearchNotes: "ノート検索の利用"
|
||||||
canUseTranslator: "翻訳機能の利用"
|
canUseTranslator: "翻訳機能の利用"
|
||||||
avatarDecorationLimit: "アイコンデコレーションの最大取付個数"
|
avatarDecorationLimit: "アイコンデコレーションの最大取付個数"
|
||||||
|
listPinnedLimit: "ピン留めリストの最大数"
|
||||||
|
localTimelineAnyLimit: "他鯖のローカルTL除けるやつ(最大値5)"
|
||||||
_condition:
|
_condition:
|
||||||
isLocal: "ローカルユーザー"
|
isLocal: "ローカルユーザー"
|
||||||
isRemote: "リモートユーザー"
|
isRemote: "リモートユーザー"
|
||||||
|
|
|
@ -60,6 +60,8 @@ export type RolePolicies = {
|
||||||
rateLimitFactor: number;
|
rateLimitFactor: number;
|
||||||
avatarDecorationLimit: number;
|
avatarDecorationLimit: number;
|
||||||
emojiPickerProfileLimit: number;
|
emojiPickerProfileLimit: number;
|
||||||
|
listPinnedLimit: number;
|
||||||
|
localTimelineAnyLimit: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DEFAULT_POLICIES: RolePolicies = {
|
export const DEFAULT_POLICIES: RolePolicies = {
|
||||||
|
@ -91,6 +93,8 @@ export const DEFAULT_POLICIES: RolePolicies = {
|
||||||
rateLimitFactor: 1,
|
rateLimitFactor: 1,
|
||||||
avatarDecorationLimit: 1,
|
avatarDecorationLimit: 1,
|
||||||
emojiPickerProfileLimit: 2,
|
emojiPickerProfileLimit: 2,
|
||||||
|
listPinnedLimit: 2,
|
||||||
|
localTimelineAnyLimit: 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -359,6 +363,8 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
|
||||||
rateLimitFactor: calc('rateLimitFactor', vs => Math.max(...vs)),
|
rateLimitFactor: calc('rateLimitFactor', vs => Math.max(...vs)),
|
||||||
avatarDecorationLimit: calc('avatarDecorationLimit', vs => Math.max(...vs)),
|
avatarDecorationLimit: calc('avatarDecorationLimit', vs => Math.max(...vs)),
|
||||||
emojiPickerProfileLimit: calc('emojiPickerProfileLimit', vs => Math.max(...vs)),
|
emojiPickerProfileLimit: calc('emojiPickerProfileLimit', vs => Math.max(...vs)),
|
||||||
|
listPinnedLimit: calc('listPinnedLimit', vs => Math.max(...vs)),
|
||||||
|
localTimelineAnyLimit: calc('localTimelineAnyLimit', vs => Math.max(...vs)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
|
||||||
import { CoreModule } from '@/core/CoreModule.js';
|
import { CoreModule } from '@/core/CoreModule.js';
|
||||||
|
import * as ep___users_lists_list_favorite from '@/server/api/endpoints/users/lists/list-favorite.js';
|
||||||
import * as ep___admin_meta from './endpoints/admin/meta.js';
|
import * as ep___admin_meta from './endpoints/admin/meta.js';
|
||||||
import * as ep___admin_abuseUserReports from './endpoints/admin/abuse-user-reports.js';
|
import * as ep___admin_abuseUserReports from './endpoints/admin/abuse-user-reports.js';
|
||||||
import * as ep___admin_accounts_create from './endpoints/admin/accounts/create.js';
|
import * as ep___admin_accounts_create from './endpoints/admin/accounts/create.js';
|
||||||
|
@ -733,6 +734,7 @@ const $users_featuredNotes: Provider = { provide: 'ep:users/featured-notes', use
|
||||||
const $users_lists_create: Provider = { provide: 'ep:users/lists/create', useClass: ep___users_lists_create.default };
|
const $users_lists_create: Provider = { provide: 'ep:users/lists/create', useClass: ep___users_lists_create.default };
|
||||||
const $users_lists_delete: Provider = { provide: 'ep:users/lists/delete', useClass: ep___users_lists_delete.default };
|
const $users_lists_delete: Provider = { provide: 'ep:users/lists/delete', useClass: ep___users_lists_delete.default };
|
||||||
const $users_lists_list: Provider = { provide: 'ep:users/lists/list', useClass: ep___users_lists_list.default };
|
const $users_lists_list: Provider = { provide: 'ep:users/lists/list', useClass: ep___users_lists_list.default };
|
||||||
|
const $users_lists_list_favorite: Provider = { provide: 'ep:users/lists/list-favorite', useClass: ep___users_lists_list_favorite.default };
|
||||||
const $users_lists_pull: Provider = { provide: 'ep:users/lists/pull', useClass: ep___users_lists_pull.default };
|
const $users_lists_pull: Provider = { provide: 'ep:users/lists/pull', useClass: ep___users_lists_pull.default };
|
||||||
const $users_lists_push: Provider = { provide: 'ep:users/lists/push', useClass: ep___users_lists_push.default };
|
const $users_lists_push: Provider = { provide: 'ep:users/lists/push', useClass: ep___users_lists_push.default };
|
||||||
const $users_lists_show: Provider = { provide: 'ep:users/lists/show', useClass: ep___users_lists_show.default };
|
const $users_lists_show: Provider = { provide: 'ep:users/lists/show', useClass: ep___users_lists_show.default };
|
||||||
|
@ -1119,6 +1121,7 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
|
||||||
$users_lists_create,
|
$users_lists_create,
|
||||||
$users_lists_delete,
|
$users_lists_delete,
|
||||||
$users_lists_list,
|
$users_lists_list,
|
||||||
|
$users_lists_list_favorite,
|
||||||
$users_lists_pull,
|
$users_lists_pull,
|
||||||
$users_lists_push,
|
$users_lists_push,
|
||||||
$users_lists_show,
|
$users_lists_show,
|
||||||
|
@ -1496,6 +1499,7 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
|
||||||
$users_lists_create,
|
$users_lists_create,
|
||||||
$users_lists_delete,
|
$users_lists_delete,
|
||||||
$users_lists_list,
|
$users_lists_list,
|
||||||
|
$users_lists_list_favorite,
|
||||||
$users_lists_pull,
|
$users_lists_pull,
|
||||||
$users_lists_push,
|
$users_lists_push,
|
||||||
$users_lists_show,
|
$users_lists_show,
|
||||||
|
|
|
@ -351,6 +351,7 @@ import * as ep___users_featuredNotes from './endpoints/users/featured-notes.js';
|
||||||
import * as ep___users_lists_create from './endpoints/users/lists/create.js';
|
import * as ep___users_lists_create from './endpoints/users/lists/create.js';
|
||||||
import * as ep___users_lists_delete from './endpoints/users/lists/delete.js';
|
import * as ep___users_lists_delete from './endpoints/users/lists/delete.js';
|
||||||
import * as ep___users_lists_list from './endpoints/users/lists/list.js';
|
import * as ep___users_lists_list from './endpoints/users/lists/list.js';
|
||||||
|
import * as ep___users_lists_list_favorite from './endpoints/users/lists/list-favorite.js';
|
||||||
import * as ep___users_lists_pull from './endpoints/users/lists/pull.js';
|
import * as ep___users_lists_pull from './endpoints/users/lists/pull.js';
|
||||||
import * as ep___users_lists_push from './endpoints/users/lists/push.js';
|
import * as ep___users_lists_push from './endpoints/users/lists/push.js';
|
||||||
import * as ep___users_lists_show from './endpoints/users/lists/show.js';
|
import * as ep___users_lists_show from './endpoints/users/lists/show.js';
|
||||||
|
@ -731,6 +732,7 @@ const eps = [
|
||||||
['users/lists/create', ep___users_lists_create],
|
['users/lists/create', ep___users_lists_create],
|
||||||
['users/lists/delete', ep___users_lists_delete],
|
['users/lists/delete', ep___users_lists_delete],
|
||||||
['users/lists/list', ep___users_lists_list],
|
['users/lists/list', ep___users_lists_list],
|
||||||
|
['users/lists/list-favorite', ep___users_lists_list_favorite],
|
||||||
['users/lists/pull', ep___users_lists_pull],
|
['users/lists/pull', ep___users_lists_pull],
|
||||||
['users/lists/push', ep___users_lists_push],
|
['users/lists/push', ep___users_lists_push],
|
||||||
['users/lists/show', ep___users_lists_show],
|
['users/lists/show', ep___users_lists_show],
|
||||||
|
|
|
@ -92,7 +92,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
|
|
||||||
const list = await this.userListsRepository.findOneBy({
|
const list = await this.userListsRepository.findOneBy({
|
||||||
id: ps.listId,
|
id: ps.listId,
|
||||||
userId: me.id,
|
isPublic: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (list == null) {
|
if (list == null) {
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and other misskey contributors
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import { In } from 'typeorm';
|
||||||
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
|
import { ApiError } from '@/server/api/error.js';
|
||||||
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import type { UserListsRepository, UserListFavoritesRepository } from '@/models/_.js';
|
||||||
|
import { UserListEntityService } from '@/core/entities/UserListEntityService.js';
|
||||||
|
import { QueryService } from '@/core/QueryService.js';
|
||||||
|
export const meta = {
|
||||||
|
tags: ['lists', 'account'],
|
||||||
|
|
||||||
|
requireCredential: false,
|
||||||
|
|
||||||
|
kind: 'read:account',
|
||||||
|
|
||||||
|
description: 'Show all lists that the authenticated user has created.',
|
||||||
|
|
||||||
|
res: {
|
||||||
|
type: 'array',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
ref: 'UserList',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errors: {
|
||||||
|
noSuchUser: {
|
||||||
|
message: 'No such user.',
|
||||||
|
code: 'NO_SUCH_USER',
|
||||||
|
id: 'a8af4a82-0980-4cc4-a6af-8b0ffd54465e',
|
||||||
|
},
|
||||||
|
remoteUser: {
|
||||||
|
message: 'Not allowed to load the remote user\'s list',
|
||||||
|
code: 'REMOTE_USER_NOT_ALLOWED',
|
||||||
|
id: '53858f1b-3315-4a01-81b7-db9b48d4b79a',
|
||||||
|
},
|
||||||
|
invalidParam: {
|
||||||
|
message: 'Invalid param.',
|
||||||
|
code: 'INVALID_PARAM',
|
||||||
|
id: 'ab36de0e-29e9-48cb-9732-d82f1281620d',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const paramDef = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
|
},
|
||||||
|
required: [],
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
@Injectable() // eslint-disable-next-line import/no-default-export
|
||||||
|
export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
|
constructor(
|
||||||
|
@Inject(DI.userListFavoritesRepository)
|
||||||
|
private userListFavoritesRepository: UserListFavoritesRepository,
|
||||||
|
@Inject(DI.userListsRepository)
|
||||||
|
private userListsRepository: UserListsRepository,
|
||||||
|
private userListEntityService: UserListEntityService,
|
||||||
|
private queryService: QueryService,
|
||||||
|
) {
|
||||||
|
super(meta, paramDef, async (ps, me) => {
|
||||||
|
if (!me) {
|
||||||
|
throw new ApiError(meta.errors.noSuchUser);
|
||||||
|
}
|
||||||
|
const favorites = await this.userListFavoritesRepository.findBy({ userId: me.id });
|
||||||
|
|
||||||
|
if (favorites == null) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const listIds = favorites.map(favorite => favorite.userListId);
|
||||||
|
const lists = await this.userListsRepository.findBy({ id: In(listIds) });
|
||||||
|
return await Promise.all(lists.map(async list => await this.userListEntityService.pack(list)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -51,6 +51,7 @@ export const paramDef = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
userId: { type: 'string', format: 'misskey:id' },
|
userId: { type: 'string', format: 'misskey:id' },
|
||||||
|
publicAll: { type: 'boolean', nullable: false },
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -67,22 +68,29 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
private userListEntityService: UserListEntityService,
|
private userListEntityService: UserListEntityService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
if (typeof ps.userId !== 'undefined') {
|
if (!ps.publicAll ) {
|
||||||
const user = await this.usersRepository.findOneBy({ id: ps.userId });
|
if (typeof ps.userId !== 'undefined') {
|
||||||
if (user === null) throw new ApiError(meta.errors.noSuchUser);
|
const user = await this.usersRepository.findOneBy({ id: ps.userId });
|
||||||
if (user.host !== null) throw new ApiError(meta.errors.remoteUser);
|
if (user === null) throw new ApiError(meta.errors.noSuchUser);
|
||||||
} else if (me === null) {
|
if (user.host !== null) throw new ApiError(meta.errors.remoteUser);
|
||||||
throw new ApiError(meta.errors.invalidParam);
|
} else if (me === null) {
|
||||||
|
throw new ApiError(meta.errors.invalidParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
const userLists = await this.userListsRepository.findBy(typeof ps.userId === 'undefined' && me !== null ? {
|
||||||
|
userId: me.id,
|
||||||
|
} : {
|
||||||
|
userId: ps.userId,
|
||||||
|
isPublic: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return await Promise.all(userLists.map(x => this.userListEntityService.pack(x)));
|
||||||
|
} else {
|
||||||
|
const userLists = await this.userListsRepository.findBy({
|
||||||
|
isPublic: true,
|
||||||
|
});
|
||||||
|
return await Promise.all(userLists.map(x => this.userListEntityService.pack(x)));
|
||||||
}
|
}
|
||||||
|
|
||||||
const userLists = await this.userListsRepository.findBy(typeof ps.userId === 'undefined' && me !== null ? {
|
|
||||||
userId: me.id,
|
|
||||||
} : {
|
|
||||||
userId: ps.userId,
|
|
||||||
isPublic: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
return await Promise.all(userLists.map(x => this.userListEntityService.pack(x)));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,3 +11,4 @@ export const clipsCache = new Cache<Misskey.entities.Clip[]>(1000 * 60 * 30, ()
|
||||||
export const rolesCache = new Cache(1000 * 60 * 30, () => misskeyApi('admin/roles/list'));
|
export const rolesCache = new Cache(1000 * 60 * 30, () => misskeyApi('admin/roles/list'));
|
||||||
export const userListsCache = new Cache<Misskey.entities.UserList[]>(1000 * 60 * 30, () => misskeyApi('users/lists/list'));
|
export const userListsCache = new Cache<Misskey.entities.UserList[]>(1000 * 60 * 30, () => misskeyApi('users/lists/list'));
|
||||||
export const antennasCache = new Cache<Misskey.entities.Antenna[]>(1000 * 60 * 30, () => misskeyApi('antennas/list'));
|
export const antennasCache = new Cache<Misskey.entities.Antenna[]>(1000 * 60 * 30, () => misskeyApi('antennas/list'));
|
||||||
|
export const userFavoriteListsCache = new Cache(1000 * 60 * 30, () => misskeyApi('users/lists/list-favorite'));
|
||||||
|
|
|
@ -99,7 +99,9 @@ export const ROLE_POLICIES = [
|
||||||
'userEachUserListsLimit',
|
'userEachUserListsLimit',
|
||||||
'rateLimitFactor',
|
'rateLimitFactor',
|
||||||
'avatarDecorationLimit',
|
'avatarDecorationLimit',
|
||||||
'emojiPickerProfileLimit'
|
'emojiPickerProfileLimit',
|
||||||
|
'listPinnedLimit',
|
||||||
|
'localTimelineAnyLimit',
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
// なんか動かない
|
// なんか動かない
|
||||||
|
@ -129,7 +131,7 @@ export const MFM_PARAMS: Record<typeof MFM_TAGS[number], string[]> = {
|
||||||
position: ['x=', 'y='],
|
position: ['x=', 'y='],
|
||||||
fg: ['color='],
|
fg: ['color='],
|
||||||
bg: ['color='],
|
bg: ['color='],
|
||||||
border: ['width=', 'style=', 'color=', 'radius=', 'noclip'],
|
border: ['width=', 'style=', 'color=', 'radius=', 'noclip'],
|
||||||
font: ['serif', 'monospace', 'cursive', 'fantasy', 'emoji', 'math'],
|
font: ['serif', 'monospace', 'cursive', 'fantasy', 'emoji', 'math'],
|
||||||
blur: [],
|
blur: [],
|
||||||
rainbow: ['speed=', 'delay='],
|
rainbow: ['speed=', 'delay='],
|
||||||
|
|
|
@ -23,212 +23,255 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #caption>{{ i18n.ts._role._options.descriptionOfRateLimitFactor }}</template>
|
<template #caption>{{ i18n.ts._role._options.descriptionOfRateLimitFactor }}</template>
|
||||||
</MkRange>
|
</MkRange>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
<MkFoldableSection :defaultOpen="false">
|
||||||
|
<template #header>タイムライン系</template>
|
||||||
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.gtlAvailable, 'gtlAvailable'])" class="_margin">
|
||||||
|
<template #label>{{ i18n.ts._role._options.gtlAvailable }}</template>
|
||||||
|
<template #suffix>{{ policies.gtlAvailable ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||||
|
<MkSwitch v-model="policies.gtlAvailable">
|
||||||
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
|
</MkSwitch>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.gtlAvailable, 'gtlAvailable'])">
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.ltlAvailable, 'ltlAvailable'])" class="_margin">
|
||||||
<template #label>{{ i18n.ts._role._options.gtlAvailable }}</template>
|
<template #label>{{ i18n.ts._role._options.ltlAvailable }}</template>
|
||||||
<template #suffix>{{ policies.gtlAvailable ? i18n.ts.yes : i18n.ts.no }}</template>
|
<template #suffix>{{ policies.ltlAvailable ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||||
<MkSwitch v-model="policies.gtlAvailable">
|
<MkSwitch v-model="policies.ltlAvailable">
|
||||||
<template #label>{{ i18n.ts.enable }}</template>
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
</MkFoldableSection>
|
||||||
|
<MkFoldableSection :defaultOpen="false">
|
||||||
|
<template #header>ノート系</template>
|
||||||
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.canPublicNote, 'canPublicNote'])" class="_margin">
|
||||||
|
<template #label>{{ i18n.ts._role._options.canPublicNote }}</template>
|
||||||
|
<template #suffix>{{ policies.canPublicNote ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||||
|
<MkSwitch v-model="policies.canPublicNote">
|
||||||
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
|
</MkSwitch>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.ltlAvailable, 'ltlAvailable'])">
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.canEditNote, 'canEditNote'])" class="_margin">
|
||||||
<template #label>{{ i18n.ts._role._options.ltlAvailable }}</template>
|
<template #label>{{ i18n.ts._role._options.canEditNote }}</template>
|
||||||
<template #suffix>{{ policies.ltlAvailable ? i18n.ts.yes : i18n.ts.no }}</template>
|
<template #suffix>{{ policies.canEditNote ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||||
<MkSwitch v-model="policies.ltlAvailable">
|
<MkSwitch v-model="policies.canEditNote">
|
||||||
<template #label>{{ i18n.ts.enable }}</template>
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.canPublicNote, 'canPublicNote'])">
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.canScheduleNote, 'canScheduleNote'])" class="_margin">
|
||||||
<template #label>{{ i18n.ts._role._options.canPublicNote }}</template>
|
<template #label>{{ i18n.ts._role._options.canScheduleNote }}</template>
|
||||||
<template #suffix>{{ policies.canPublicNote ? i18n.ts.yes : i18n.ts.no }}</template>
|
<template #suffix>{{ policies.canScheduleNote ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||||
<MkSwitch v-model="policies.canPublicNote">
|
<MkSwitch v-model="policies.canScheduleNote">
|
||||||
<template #label>{{ i18n.ts.enable }}</template>
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.canSearchNotes, 'canSearchNotes'])" class="_margin">
|
||||||
|
<template #label>{{ i18n.ts._role._options.canSearchNotes }}</template>
|
||||||
|
<template #suffix>{{ policies.canSearchNotes ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||||
|
<MkSwitch v-model="policies.canSearchNotes">
|
||||||
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
|
</MkSwitch>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.canEditNote, 'canEditNote'])">
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.canUseTranslator, 'canSearchNotes'])" class="_margin">
|
||||||
<template #label>{{ i18n.ts._role._options.canEditNote }}</template>
|
<template #label>{{ i18n.ts._role._options.canUseTranslator }}</template>
|
||||||
<template #suffix>{{ policies.canEditNote ? i18n.ts.yes : i18n.ts.no }}</template>
|
<template #suffix>{{ policies.canUseTranslator ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||||
<MkSwitch v-model="policies.canEditNote">
|
<MkSwitch v-model="policies.canUseTranslator">
|
||||||
<template #label>{{ i18n.ts.enable }}</template>
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.pinMax, 'pinLimit'])" class="_margin">
|
||||||
|
<template #label>{{ i18n.ts._role._options.pinMax }}</template>
|
||||||
|
<template #suffix>{{ policies.pinLimit }}</template>
|
||||||
|
<MkInput v-model="policies.pinLimit" type="number">
|
||||||
|
</MkInput>
|
||||||
|
</MkFolder>
|
||||||
|
</MkFoldableSection>
|
||||||
|
<MkFoldableSection :defaultOpen="false">
|
||||||
|
<template #header>招待系</template>
|
||||||
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.canInvite, 'canInvite'])">
|
||||||
|
<template #label>{{ i18n.ts._role._options.canInvite }}</template>
|
||||||
|
<template #suffix>{{ policies.canInvite ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||||
|
<MkSwitch v-model="policies.canInvite">
|
||||||
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
|
</MkSwitch>
|
||||||
|
</MkFolder>
|
||||||
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.inviteLimit, 'inviteLimit'])" class="_margin">
|
||||||
|
<template #label>{{ i18n.ts._role._options.inviteLimit }}</template>
|
||||||
|
<template #suffix>{{ policies.inviteLimit }}</template>
|
||||||
|
<MkInput v-model="policies.inviteLimit" type="number">
|
||||||
|
</MkInput>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.canScheduleNote, 'canScheduleNote'])">
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.inviteLimitCycle, 'inviteLimitCycle'])" class="_margin">
|
||||||
<template #label>{{ i18n.ts._role._options.canScheduleNote }}</template>
|
<template #label>{{ i18n.ts._role._options.inviteLimitCycle }}</template>
|
||||||
<template #suffix>{{ policies.canScheduleNote ? i18n.ts.yes : i18n.ts.no }}</template>
|
<template #suffix>{{ policies.inviteLimitCycle + i18n.ts._time.minute }}</template>
|
||||||
<MkSwitch v-model="policies.canScheduleNote">
|
<MkInput v-model="policies.inviteLimitCycle" type="number">
|
||||||
<template #label>{{ i18n.ts.enable }}</template>
|
<template #suffix>{{ i18n.ts._time.minute }}</template>
|
||||||
</MkSwitch>
|
</MkInput>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.canInvite, 'canInvite'])">
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.inviteExpirationTime, 'inviteExpirationTime'])" class="_margin">
|
||||||
<template #label>{{ i18n.ts._role._options.canInvite }}</template>
|
<template #label>{{ i18n.ts._role._options.inviteExpirationTime }}</template>
|
||||||
<template #suffix>{{ policies.canInvite ? i18n.ts.yes : i18n.ts.no }}</template>
|
<template #suffix>{{ policies.inviteExpirationTime + i18n.ts._time.minute }}</template>
|
||||||
<MkSwitch v-model="policies.canInvite">
|
<MkInput v-model="policies.inviteExpirationTime" type="number">
|
||||||
<template #label>{{ i18n.ts.enable }}</template>
|
<template #suffix>{{ i18n.ts._time.minute }}</template>
|
||||||
</MkSwitch>
|
</MkInput>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
</MkFoldableSection>
|
||||||
|
<MkFoldableSection :defaultOpen="false">
|
||||||
|
<template #header>PrisMisskey独自機能系</template>
|
||||||
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.emojiPickerProfileLimit, 'pickerProfileDefault'])" class="_margin">
|
||||||
|
<template #label>{{ i18n.ts._role._options.emojiPickerProfileLimit }}</template>
|
||||||
|
<template #suffix>{{ policies.emojiPickerProfileLimit }}</template>
|
||||||
|
<MkInput v-model="policies.emojiPickerProfileLimit" type="number">
|
||||||
|
</MkInput>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.emojiPickerProfileLimit, 'pickerProfileDefault'])">
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.listPinnedLimit, 'listPinnedLimit'])" class="_margin">
|
||||||
<template #label>{{ i18n.ts._role._options.emojiPickerProfileLimit }}</template>
|
<template #label>{{ i18n.ts._role._options.listPinnedLimit }}</template>
|
||||||
<template #suffix>{{ policies.emojiPickerProfileLimit }}</template>
|
<template #suffix>{{ policies.listPinnedLimit }}</template>
|
||||||
<MkInput v-model="policies.emojiPickerProfileLimit" type="number">
|
<MkInput v-model="policies.listPinnedLimit" type="number">
|
||||||
</MkInput>
|
</MkInput>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.localTimelineAnyLimit, 'localTimelineAnyLimit'])" class="_margin">
|
||||||
|
<template #label>{{ i18n.ts._role._options.localTimelineAnyLimit }}</template>
|
||||||
|
<template #suffix>{{ policies.localTimelineAnyLimit }}</template>
|
||||||
|
<MkInput v-model="policies.localTimelineAnyLimit" type="number">
|
||||||
|
</MkInput>
|
||||||
|
</MkFolder>
|
||||||
|
</MkFoldableSection>
|
||||||
|
<MkFoldableSection :defaultOpen="false">
|
||||||
|
<template #header>カスタム絵文字系</template>
|
||||||
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.canManageCustomEmojis, 'canManageCustomEmojis'])" class="_margin">
|
||||||
|
<template #label>{{ i18n.ts._role._options.canManageCustomEmojis }}</template>
|
||||||
|
<template #suffix>{{ policies.canManageCustomEmojis ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||||
|
<MkSwitch v-model="policies.canManageCustomEmojis">
|
||||||
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
|
</MkSwitch>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.inviteLimit, 'inviteLimit'])">
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.canRequestCustomEmojis, 'canRequestCustomEmojis'])" class="_margin">
|
||||||
<template #label>{{ i18n.ts._role._options.inviteLimit }}</template>
|
<template #label>{{ i18n.ts._role._options.canRequestCustomEmojis }}</template>
|
||||||
<template #suffix>{{ policies.inviteLimit }}</template>
|
<template #suffix>{{ policies.canRequestCustomEmojis ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||||
<MkInput v-model="policies.inviteLimit" type="number">
|
<MkSwitch v-model="policies.canRequestCustomEmojis">
|
||||||
</MkInput>
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
</MkFolder>
|
</MkSwitch>
|
||||||
|
</MkFolder>
|
||||||
|
</MkFoldableSection>
|
||||||
|
<MkFoldableSection :defaultOpen="false">
|
||||||
|
<template #header>ドライブ、ファイル系</template>
|
||||||
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.driveCapacity, 'driveCapacityMb'])" class="_margin">
|
||||||
|
<template #label>{{ i18n.ts._role._options.driveCapacity }}</template>
|
||||||
|
<template #suffix>{{ policies.driveCapacityMb }}MB</template>
|
||||||
|
<MkInput v-model="policies.driveCapacityMb" type="number">
|
||||||
|
<template #suffix>MB</template>
|
||||||
|
</MkInput>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.inviteLimitCycle, 'inviteLimitCycle'])">
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.alwaysMarkNsfw, 'alwaysMarkNsfw'])" class="_margin">
|
||||||
<template #label>{{ i18n.ts._role._options.inviteLimitCycle }}</template>
|
<template #label>{{ i18n.ts._role._options.alwaysMarkNsfw }}</template>
|
||||||
<template #suffix>{{ policies.inviteLimitCycle + i18n.ts._time.minute }}</template>
|
<template #suffix>{{ policies.alwaysMarkNsfw ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||||
<MkInput v-model="policies.inviteLimitCycle" type="number">
|
<MkSwitch v-model="policies.alwaysMarkNsfw">
|
||||||
<template #suffix>{{ i18n.ts._time.minute }}</template>
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
</MkInput>
|
</MkSwitch>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
</MkFoldableSection>
|
||||||
|
<MkFoldableSection :defaultOpen="false">
|
||||||
|
<template #header>アイコンデコレーション系</template>
|
||||||
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.canManageAvatarDecorations, 'canManageAvatarDecorations'])" class="_margin">
|
||||||
|
<template #label>{{ i18n.ts._role._options.canManageAvatarDecorations }}</template>
|
||||||
|
<template #suffix>{{ policies.canManageAvatarDecorations ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||||
|
<MkSwitch v-model="policies.canManageAvatarDecorations">
|
||||||
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
|
</MkSwitch>
|
||||||
|
</MkFolder>
|
||||||
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.avatarDecorationLimit, 'avatarDecorationLimit'])" class="_margin">
|
||||||
|
<template #label>{{ i18n.ts._role._options.avatarDecorationLimit }}</template>
|
||||||
|
<template #suffix>{{ policies.avatarDecorationLimit }}</template>
|
||||||
|
<MkInput v-model="policies.avatarDecorationLimit" type="number" :min="0">
|
||||||
|
</MkInput>
|
||||||
|
</MkFolder>
|
||||||
|
</MkFoldableSection>
|
||||||
|
<MkFoldableSection :defaultOpen="false">
|
||||||
|
<template #header>クリップ系</template>
|
||||||
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.clipMax, 'clipLimit'])" class="_margin">
|
||||||
|
<template #label>{{ i18n.ts._role._options.clipMax }}</template>
|
||||||
|
<template #suffix>{{ policies.clipLimit }}</template>
|
||||||
|
<MkInput v-model="policies.clipLimit" type="number">
|
||||||
|
</MkInput>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.inviteExpirationTime, 'inviteExpirationTime'])">
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.noteEachClipsMax, 'noteEachClipsLimit'])" class="_margin">
|
||||||
<template #label>{{ i18n.ts._role._options.inviteExpirationTime }}</template>
|
<template #label>{{ i18n.ts._role._options.noteEachClipsMax }}</template>
|
||||||
<template #suffix>{{ policies.inviteExpirationTime + i18n.ts._time.minute }}</template>
|
<template #suffix>{{ policies.noteEachClipsLimit }}</template>
|
||||||
<MkInput v-model="policies.inviteExpirationTime" type="number">
|
<MkInput v-model="policies.noteEachClipsLimit" type="number">
|
||||||
<template #suffix>{{ i18n.ts._time.minute }}</template>
|
</MkInput>
|
||||||
</MkInput>
|
</MkFolder>
|
||||||
</MkFolder>
|
</MkFoldableSection>
|
||||||
|
<MkFoldableSection :defaultOpen="false">
|
||||||
|
<template #header>リスト系</template>
|
||||||
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.userListMax, 'userListLimit'])" class="_margin">
|
||||||
|
<template #label>{{ i18n.ts._role._options.userListMax }}</template>
|
||||||
|
<template #suffix>{{ policies.userListLimit }}</template>
|
||||||
|
<MkInput v-model="policies.userListLimit" type="number">
|
||||||
|
</MkInput>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.canManageAvatarDecorations, 'canManageAvatarDecorations'])">
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.userEachUserListsMax, 'userEachUserListsLimit'])" class="_margin">
|
||||||
<template #label>{{ i18n.ts._role._options.canManageAvatarDecorations }}</template>
|
<template #label>{{ i18n.ts._role._options.userEachUserListsMax }}</template>
|
||||||
<template #suffix>{{ policies.canManageAvatarDecorations ? i18n.ts.yes : i18n.ts.no }}</template>
|
<template #suffix>{{ policies.userEachUserListsLimit }}</template>
|
||||||
<MkSwitch v-model="policies.canManageAvatarDecorations">
|
<MkInput v-model="policies.userEachUserListsLimit" type="number">
|
||||||
<template #label>{{ i18n.ts.enable }}</template>
|
</MkInput>
|
||||||
</MkSwitch>
|
</MkFolder>
|
||||||
</MkFolder>
|
</MkFoldableSection>
|
||||||
|
<MkFoldableSection :defaultOpen="false">
|
||||||
|
<template #header>その他</template>
|
||||||
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.antennaMax, 'antennaLimit'])" class="_margin">
|
||||||
|
<template #label>{{ i18n.ts._role._options.antennaMax }}</template>
|
||||||
|
<template #suffix>{{ policies.antennaLimit }}</template>
|
||||||
|
<MkInput v-model="policies.antennaLimit" type="number">
|
||||||
|
</MkInput>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.canManageCustomEmojis, 'canManageCustomEmojis'])">
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.wordMuteMax, 'wordMuteLimit'])" class="_margin">
|
||||||
<template #label>{{ i18n.ts._role._options.canManageCustomEmojis }}</template>
|
<template #label>{{ i18n.ts._role._options.wordMuteMax }}</template>
|
||||||
<template #suffix>{{ policies.canManageCustomEmojis ? i18n.ts.yes : i18n.ts.no }}</template>
|
<template #suffix>{{ policies.wordMuteLimit }}</template>
|
||||||
<MkSwitch v-model="policies.canManageCustomEmojis">
|
<MkInput v-model="policies.wordMuteLimit" type="number">
|
||||||
<template #label>{{ i18n.ts.enable }}</template>
|
<template #suffix>chars</template>
|
||||||
</MkSwitch>
|
</MkInput>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.canRequestCustomEmojis, 'canRequestCustomEmojis'])">
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.webhookMax, 'webhookLimit'])" class="_margin">
|
||||||
<template #label>{{ i18n.ts._role._options.canRequestCustomEmojis }}</template>
|
<template #label>{{ i18n.ts._role._options.webhookMax }}</template>
|
||||||
<template #suffix>{{ policies.canRequestCustomEmojis ? i18n.ts.yes : i18n.ts.no }}</template>
|
<template #suffix>{{ policies.webhookLimit }}</template>
|
||||||
<MkSwitch v-model="policies.canRequestCustomEmojis">
|
<MkInput v-model="policies.webhookLimit" type="number">
|
||||||
<template #label>{{ i18n.ts.enable }}</template>
|
</MkInput>
|
||||||
</MkSwitch>
|
</MkFolder>
|
||||||
</MkFolder>
|
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.canSearchNotes, 'canSearchNotes'])">
|
|
||||||
<template #label>{{ i18n.ts._role._options.canSearchNotes }}</template>
|
|
||||||
<template #suffix>{{ policies.canSearchNotes ? i18n.ts.yes : i18n.ts.no }}</template>
|
|
||||||
<MkSwitch v-model="policies.canSearchNotes">
|
|
||||||
<template #label>{{ i18n.ts.enable }}</template>
|
|
||||||
</MkSwitch>
|
|
||||||
</MkFolder>
|
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.canUseTranslator, 'canSearchNotes'])">
|
|
||||||
<template #label>{{ i18n.ts._role._options.canUseTranslator }}</template>
|
|
||||||
<template #suffix>{{ policies.canUseTranslator ? i18n.ts.yes : i18n.ts.no }}</template>
|
|
||||||
<MkSwitch v-model="policies.canUseTranslator">
|
|
||||||
<template #label>{{ i18n.ts.enable }}</template>
|
|
||||||
</MkSwitch>
|
|
||||||
</MkFolder>
|
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.driveCapacity, 'driveCapacityMb'])">
|
|
||||||
<template #label>{{ i18n.ts._role._options.driveCapacity }}</template>
|
|
||||||
<template #suffix>{{ policies.driveCapacityMb }}MB</template>
|
|
||||||
<MkInput v-model="policies.driveCapacityMb" type="number">
|
|
||||||
<template #suffix>MB</template>
|
|
||||||
</MkInput>
|
|
||||||
</MkFolder>
|
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.alwaysMarkNsfw, 'alwaysMarkNsfw'])">
|
|
||||||
<template #label>{{ i18n.ts._role._options.alwaysMarkNsfw }}</template>
|
|
||||||
<template #suffix>{{ policies.alwaysMarkNsfw ? i18n.ts.yes : i18n.ts.no }}</template>
|
|
||||||
<MkSwitch v-model="policies.alwaysMarkNsfw">
|
|
||||||
<template #label>{{ i18n.ts.enable }}</template>
|
|
||||||
</MkSwitch>
|
|
||||||
</MkFolder>
|
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.pinMax, 'pinLimit'])">
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.canHideAds, 'canHideAds'])" class="_margin">
|
||||||
<template #label>{{ i18n.ts._role._options.pinMax }}</template>
|
<template #label>{{ i18n.ts._role._options.canHideAds }}</template>
|
||||||
<template #suffix>{{ policies.pinLimit }}</template>
|
<template #suffix>{{ policies.canHideAds ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||||
<MkInput v-model="policies.pinLimit" type="number">
|
<MkSwitch v-model="policies.canHideAds">
|
||||||
</MkInput>
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
</MkFolder>
|
</MkSwitch>
|
||||||
|
</MkFolder>
|
||||||
|
</MkFoldableSection>
|
||||||
|
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.antennaMax, 'antennaLimit'])">
|
|
||||||
<template #label>{{ i18n.ts._role._options.antennaMax }}</template>
|
|
||||||
<template #suffix>{{ policies.antennaLimit }}</template>
|
|
||||||
<MkInput v-model="policies.antennaLimit" type="number">
|
|
||||||
</MkInput>
|
|
||||||
</MkFolder>
|
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.wordMuteMax, 'wordMuteLimit'])">
|
|
||||||
<template #label>{{ i18n.ts._role._options.wordMuteMax }}</template>
|
|
||||||
<template #suffix>{{ policies.wordMuteLimit }}</template>
|
|
||||||
<MkInput v-model="policies.wordMuteLimit" type="number">
|
|
||||||
<template #suffix>chars</template>
|
|
||||||
</MkInput>
|
|
||||||
</MkFolder>
|
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.webhookMax, 'webhookLimit'])">
|
|
||||||
<template #label>{{ i18n.ts._role._options.webhookMax }}</template>
|
|
||||||
<template #suffix>{{ policies.webhookLimit }}</template>
|
|
||||||
<MkInput v-model="policies.webhookLimit" type="number">
|
|
||||||
</MkInput>
|
|
||||||
</MkFolder>
|
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.clipMax, 'clipLimit'])">
|
|
||||||
<template #label>{{ i18n.ts._role._options.clipMax }}</template>
|
|
||||||
<template #suffix>{{ policies.clipLimit }}</template>
|
|
||||||
<MkInput v-model="policies.clipLimit" type="number">
|
|
||||||
</MkInput>
|
|
||||||
</MkFolder>
|
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.noteEachClipsMax, 'noteEachClipsLimit'])">
|
|
||||||
<template #label>{{ i18n.ts._role._options.noteEachClipsMax }}</template>
|
|
||||||
<template #suffix>{{ policies.noteEachClipsLimit }}</template>
|
|
||||||
<MkInput v-model="policies.noteEachClipsLimit" type="number">
|
|
||||||
</MkInput>
|
|
||||||
</MkFolder>
|
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.userListMax, 'userListLimit'])">
|
|
||||||
<template #label>{{ i18n.ts._role._options.userListMax }}</template>
|
|
||||||
<template #suffix>{{ policies.userListLimit }}</template>
|
|
||||||
<MkInput v-model="policies.userListLimit" type="number">
|
|
||||||
</MkInput>
|
|
||||||
</MkFolder>
|
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.userEachUserListsMax, 'userEachUserListsLimit'])">
|
|
||||||
<template #label>{{ i18n.ts._role._options.userEachUserListsMax }}</template>
|
|
||||||
<template #suffix>{{ policies.userEachUserListsLimit }}</template>
|
|
||||||
<MkInput v-model="policies.userEachUserListsLimit" type="number">
|
|
||||||
</MkInput>
|
|
||||||
</MkFolder>
|
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.canHideAds, 'canHideAds'])">
|
|
||||||
<template #label>{{ i18n.ts._role._options.canHideAds }}</template>
|
|
||||||
<template #suffix>{{ policies.canHideAds ? i18n.ts.yes : i18n.ts.no }}</template>
|
|
||||||
<MkSwitch v-model="policies.canHideAds">
|
|
||||||
<template #label>{{ i18n.ts.enable }}</template>
|
|
||||||
</MkSwitch>
|
|
||||||
</MkFolder>
|
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.avatarDecorationLimit, 'avatarDecorationLimit'])">
|
|
||||||
<template #label>{{ i18n.ts._role._options.avatarDecorationLimit }}</template>
|
|
||||||
<template #suffix>{{ policies.avatarDecorationLimit }}</template>
|
|
||||||
<MkInput v-model="policies.avatarDecorationLimit" type="number" :min="0">
|
|
||||||
</MkInput>
|
|
||||||
</MkFolder>
|
|
||||||
|
|
||||||
<MkButton primary rounded @click="updateBaseRole">{{ i18n.ts.save }}</MkButton>
|
<MkButton primary rounded @click="updateBaseRole">{{ i18n.ts.save }}</MkButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -6,7 +6,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template>
|
<template>
|
||||||
<MkStickyContainer>
|
<MkStickyContainer>
|
||||||
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
||||||
<MKSpacer v-if="!(typeof error === 'undefined')" :contentMax="1200">
|
|
||||||
|
<MkSpacer v-if="!(typeof error === 'undefined')" :contentMax="1200">
|
||||||
<div :class="$style.root">
|
<div :class="$style.root">
|
||||||
<img :class="$style.img" :src="serverErrorImageUrl" class="_ghost"/>
|
<img :class="$style.img" :src="serverErrorImageUrl" class="_ghost"/>
|
||||||
<p :class="$style.text">
|
<p :class="$style.text">
|
||||||
|
@ -14,10 +15,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
{{ i18n.ts.nothing }}
|
{{ i18n.ts.nothing }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</MKSpacer>
|
</MkSpacer>
|
||||||
<MkSpacer v-else-if="list" :contentMax="700" :class="$style.main">
|
<MkSpacer v-else-if="list" :contentMax="700" :class="$style.main">
|
||||||
<div v-if="list" class="members _margin">
|
<MkButton v-if="list.isLiked" v-tooltip="i18n.ts.unlike" inline :class="$style.button" asLike primary @click="unlike()"><i class="ti ti-heart-off"></i><span v-if="list.likedCount > 0" class="count">{{ list.likedCount }}</span></MkButton>
|
||||||
<div :class="$style.member_text">{{ i18n.ts.members }}</div>
|
<MkButton v-if="!list.isLiked" v-tooltip="i18n.ts.like" inline :class="$style.button" asLike @click="like()"><i class="ti ti-heart"></i><span v-if="1 > 0" class="count">{{ list.likedCount }}</span></MkButton>
|
||||||
|
<MkButton inline @click="create()"><i class="ti ti-download" :class="$style.import"></i>{{ i18n.ts.import }}</MkButton>
|
||||||
|
<MkFolder v-if="list" class="members _margin">
|
||||||
|
<template #label>{{ i18n.ts.members }}</template>
|
||||||
|
<div :class="$style.member_text"></div>
|
||||||
<div class="_gaps_s">
|
<div class="_gaps_s">
|
||||||
<div v-for="user in users" :key="user.id" :class="$style.userItem">
|
<div v-for="user in users" :key="user.id" :class="$style.userItem">
|
||||||
<MkA :class="$style.userItemBody" :to="`${userPage(user)}`">
|
<MkA :class="$style.userItemBody" :to="`${userPage(user)}`">
|
||||||
|
@ -25,10 +30,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</MkA>
|
</MkA>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</MkFolder>
|
||||||
<MkButton v-if="list.isLiked" v-tooltip="i18n.ts.unlike" inline :class="$style.button" asLike primary @click="unlike()"><i class="ti ti-heart-off"></i><span v-if="list.likedCount > 0" class="count">{{ list.likedCount }}</span></MkButton>
|
|
||||||
<MkButton v-if="!list.isLiked" v-tooltip="i18n.ts.like" inline :class="$style.button" asLike @click="like()"><i class="ti ti-heart"></i><span v-if="1 > 0" class="count">{{ list.likedCount }}</span></MkButton>
|
|
||||||
<MkButton inline @click="create()"><i class="ti ti-download" :class="$style.import"></i>{{ i18n.ts.import }}</MkButton>
|
|
||||||
</MkSpacer>
|
</MkSpacer>
|
||||||
</MkStickyContainer>
|
</MkStickyContainer>
|
||||||
</template>
|
</template>
|
||||||
|
@ -44,6 +46,7 @@ import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { serverErrorImageUrl } from '@/instance.js';
|
import { serverErrorImageUrl } from '@/instance.js';
|
||||||
|
import MkFolder from '@/components/MkFolder.vue';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
listId: string;
|
listId: string;
|
||||||
|
|
|
@ -7,44 +7,87 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkStickyContainer>
|
<MkStickyContainer>
|
||||||
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
||||||
<MkSpacer :contentMax="700">
|
<MkSpacer :contentMax="700">
|
||||||
<div class="_gaps">
|
<MkFoldableSection style="margin-bottom: 32px;">
|
||||||
<div v-if="items.length === 0" class="empty">
|
<template #header>{{ i18n.ts.favoriteLists }}</template>
|
||||||
<div class="_fullinfo">
|
|
||||||
<img :src="infoImageUrl" class="_ghost"/>
|
<div class="_gaps">
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
<div v-if="feautureList.length === 0" class="empty">
|
||||||
|
<div class="_fullinfo">
|
||||||
|
<img :src="infoImageUrl" class="_ghost"/>
|
||||||
|
<div>{{ i18n.ts.nothing }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="feautureList.length > 0" class="_gaps">
|
||||||
|
<MkA v-for="list in feautureList" :key="list.id" class="_panel" :class="$style.list" :to="`/list/${ list.id }`">
|
||||||
|
<div style="margin-bottom: 4px;">{{ list.name }} <span :class="$style.nUsers">({{ i18n.tsx.nUsers({ n: `${list.userIds.length}` }) }})</span></div>
|
||||||
|
<MkAvatars :userIds="list.userIds" :limit="10"/>
|
||||||
|
</MkA>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</MkFoldableSection>
|
||||||
|
<MkFoldableSection style="margin-bottom: 32px;">
|
||||||
|
<template #header>{{ i18n.ts.localListList }}</template>
|
||||||
|
<div class="_gaps">
|
||||||
|
<div v-if="localList.length === 0" class="empty">
|
||||||
|
<div class="_fullinfo">
|
||||||
|
<img :src="infoImageUrl" class="_ghost"/>
|
||||||
|
<div>{{ i18n.ts.nothing }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<MkButton primary rounded style="margin: 0 auto;" @click="create"><i class="ti ti-plus"></i> {{ i18n.ts.createList }}</MkButton>
|
<div v-if="localList.length > 0" class="_gaps">
|
||||||
|
<MkA v-for="list in localList" :key="list.id" class="_panel" :class="$style.list" :to="`/list/${ list.id }`">
|
||||||
<div v-if="items.length > 0" class="_gaps">
|
<div style="margin-bottom: 4px;">{{ list.name }} <span :class="$style.nUsers">({{ i18n.tsx.nUsers({ n: `${list.userIds.length}` }) }})</span></div>
|
||||||
<MkA v-for="list in items" :key="list.id" class="_panel" :class="$style.list" :to="`/my/lists/${ list.id }`">
|
<MkAvatars :userIds="list.userIds" :limit="10"/>
|
||||||
<div style="margin-bottom: 4px;">{{ list.name }} <span :class="$style.nUsers">({{ i18n.tsx.nUsers({ n: `${list.userIds.length}/${$i.policies['userEachUserListsLimit']}` }) }})</span></div>
|
</MkA>
|
||||||
<MkAvatars :userIds="list.userIds" :limit="10"/>
|
</div>
|
||||||
</MkA>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</MkFoldableSection>
|
||||||
|
<MkFoldableSection>
|
||||||
|
<template #header>{{ i18n.ts.myLists }}</template>
|
||||||
|
<div class="_gaps">
|
||||||
|
<div v-if="items.length === 0" class="empty">
|
||||||
|
<div class="_fullinfo">
|
||||||
|
<img :src="infoImageUrl" class="_ghost"/>
|
||||||
|
<div>{{ i18n.ts.nothing }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="items.length > 0" class="_gaps">
|
||||||
|
<MkA v-for="list in items" :key="list.id" class="_panel" :class="$style.list" :to="`/my/lists/${ list.id }`">
|
||||||
|
<div style="margin-bottom: 4px;">{{ list.name }} <span :class="$style.nUsers">({{ i18n.tsx.nUsers({ n: `${list.userIds.length}/${$i.policies['userEachUserListsLimit']}` }) }})</span></div>
|
||||||
|
<MkAvatars :userIds="list.userIds" :limit="10"/>
|
||||||
|
</MkA>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</MkFoldableSection>
|
||||||
</MkSpacer>
|
</MkSpacer>
|
||||||
</MkStickyContainer>
|
</MkStickyContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onActivated, computed } from 'vue';
|
import { onActivated, computed } from 'vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
|
||||||
import MkAvatars from '@/components/MkAvatars.vue';
|
import MkAvatars from '@/components/MkAvatars.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { userListsCache } from '@/cache.js';
|
import { userFavoriteListsCache, userListsCache } from '@/cache.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
import { infoImageUrl } from '@/instance.js';
|
||||||
import { signinRequired } from '@/account.js';
|
import { signinRequired } from '@/account.js';
|
||||||
|
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
||||||
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
|
|
||||||
const $i = signinRequired();
|
const $i = signinRequired();
|
||||||
|
|
||||||
const items = computed(() => userListsCache.value.value ?? []);
|
const items = computed(() => userListsCache.value.value ?? []);
|
||||||
|
const localList = await misskeyApi('users/lists/list', { publicAll: true });
|
||||||
|
const feautureList = computed(() => userFavoriteListsCache.value.value ?? []);
|
||||||
|
|
||||||
function fetch() {
|
function fetch() {
|
||||||
userListsCache.fetch();
|
userListsCache.fetch();
|
||||||
|
userFavoriteListsCache.delete();
|
||||||
|
userFavoriteListsCache.fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch();
|
fetch();
|
||||||
|
@ -67,12 +110,17 @@ const headerActions = computed(() => [{
|
||||||
userListsCache.delete();
|
userListsCache.delete();
|
||||||
fetch();
|
fetch();
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
asFullButton: true,
|
||||||
|
icon: 'ti ti-plus',
|
||||||
|
text: i18n.ts.createList,
|
||||||
|
handler: create,
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
const headerTabs = computed(() => []);
|
const headerTabs = computed(() => []);
|
||||||
|
|
||||||
definePageMetadata({
|
definePageMetadata({
|
||||||
title: i18n.ts.manageLists,
|
title: i18n.ts._exportOrImport.userLists,
|
||||||
icon: 'ti ti-list',
|
icon: 'ti ti-list',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -8,22 +8,20 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
||||||
<MkSpacer :contentMax="700" :class="$style.main">
|
<MkSpacer :contentMax="700" :class="$style.main">
|
||||||
<div v-if="list" class="_gaps">
|
<div v-if="list" class="_gaps">
|
||||||
<MkFolder>
|
<div>{{ i18n.ts.settings }}</div>
|
||||||
<template #label>{{ i18n.ts.settings }}</template>
|
|
||||||
|
|
||||||
<div class="_gaps">
|
<div class="_gaps" style="margin: 8px 0; ">
|
||||||
<MkInput v-model="name">
|
<MkInput v-model="name">
|
||||||
<template #label>{{ i18n.ts.name }}</template>
|
<template #label>{{ i18n.ts.name }}</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
<MkSwitch v-model="isPublic">{{ i18n.ts.public }}</MkSwitch>
|
<MkSwitch v-model="isPublic">{{ i18n.ts.public }}</MkSwitch>
|
||||||
<div class="_buttons">
|
<div class="_buttons">
|
||||||
<MkButton rounded primary @click="updateSettings">{{ i18n.ts.save }}</MkButton>
|
<MkButton rounded primary @click="updateSettings">{{ i18n.ts.save }}</MkButton>
|
||||||
<MkButton rounded danger @click="deleteList()">{{ i18n.ts.delete }}</MkButton>
|
<MkButton rounded danger @click="deleteList()">{{ i18n.ts.delete }}</MkButton>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</MkFolder>
|
</div>
|
||||||
|
|
||||||
<MkFolder defaultOpen>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts.members }}</template>
|
<template #label>{{ i18n.ts.members }}</template>
|
||||||
<template #caption>{{ i18n.tsx.nUsers({ n: `${list.userIds.length}/${$i.policies['userEachUserListsLimit']}` }) }}</template>
|
<template #caption>{{ i18n.tsx.nUsers({ n: `${list.userIds.length}/${$i.policies['userEachUserListsLimit']}` }) }}</template>
|
||||||
|
|
||||||
|
|
|
@ -38,9 +38,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkSwitch v-model="showFixedPostFormInChannel">{{ i18n.ts.showFixedPostFormInChannel }}</MkSwitch>
|
<MkSwitch v-model="showFixedPostFormInChannel">{{ i18n.ts.showFixedPostFormInChannel }}</MkSwitch>
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts.pinnedList }}</template>
|
<template #label>{{ i18n.ts.pinnedList }}</template>
|
||||||
<!-- 複数ピン止め管理できるようにしたいけどめんどいので一旦ひとつのみ -->
|
<div class="_margin" v-for="pinnedLists in defaultStore.reactiveState.pinnedUserLists.value">
|
||||||
<MkButton v-if="defaultStore.reactiveState.pinnedUserLists.value.length === 0" @click="setPinnedList()">{{ i18n.ts.add }}</MkButton>
|
{{ pinnedLists.name }}
|
||||||
<MkButton v-else danger @click="removePinnedList()"><i class="ti ti-trash"></i> {{ i18n.ts.remove }}</MkButton>
|
<MkButton danger @click="removePinnedList(pinnedLists.id,pinnedLists.name)"><i class="ti ti-trash"></i> {{ i18n.ts.remove }}</MkButton>
|
||||||
|
</div>
|
||||||
|
<MkButton v-if="pinnedMax > defaultStore.reactiveState.pinnedUserLists.value.length " @click="setPinnedList()">{{ i18n.ts.add }}</MkButton>
|
||||||
|
<MkButton v-if="defaultStore.reactiveState.pinnedUserLists.value.length " danger @click="removePinnedList('all')"><i class="ti ti-trash"></i> {{i18n.ts.all}}{{ i18n.ts.remove }}</MkButton>
|
||||||
|
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
<MkSwitch v-model="showMediaTimeline">{{ i18n.ts.showMediaTimeline }}<template #caption>{{ i18n.ts.showMediaTimelineInfo }} </template></MkSwitch>
|
<MkSwitch v-model="showMediaTimeline">{{ i18n.ts.showMediaTimeline }}<template #caption>{{ i18n.ts.showMediaTimelineInfo }} </template></MkSwitch>
|
||||||
<MkSwitch v-model="showGlobalTimeline">{{ i18n.ts.showGlobalTimeline }}</MkSwitch>
|
<MkSwitch v-model="showGlobalTimeline">{{ i18n.ts.showGlobalTimeline }}</MkSwitch>
|
||||||
|
@ -166,7 +170,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
</MkFoldableSection>
|
</MkFoldableSection>
|
||||||
<MkFoldableSection :defaultOpen="false" class="item">
|
<MkFoldableSection :defaultOpen="false" class="item">
|
||||||
<template #header>{{ i18n.ts.behavior }}</template>
|
<template #header>{{ i18n.ts.behavior }}</template>
|
||||||
|
|
||||||
<div class="_gaps_m">
|
<div class="_gaps_m">
|
||||||
<div class="_gaps_s">
|
<div class="_gaps_s">
|
||||||
|
@ -223,98 +227,97 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
</div>
|
</div>
|
||||||
</MkFoldableSection>
|
</MkFoldableSection>
|
||||||
<MkFoldableSection :defaultOpen="false">
|
<MkFoldableSection :defaultOpen="false">
|
||||||
|
<template #header>他のサーバーのローカルタイムラインを覗けるようにする</template>
|
||||||
|
<div class="_gaps_m">
|
||||||
|
<MkFoldableSection :defaultOpen="false">
|
||||||
|
<template #header>{{ i18n.ts.accessToken }} の発行の仕方</template>
|
||||||
|
<img width="400" src="https://files.prismisskey.space/misskey/676e4b79-7897-4ea9-b074-a98139312f76.gif">
|
||||||
|
</MkFoldableSection>
|
||||||
|
<div v-if="maxLocalTimeline >= 1">
|
||||||
|
<MkInput v-model="remoteLocalTimelineName1" placeholder="prismisskey">
|
||||||
|
<template #label>{{ i18n.ts.name }}</template>
|
||||||
|
</MkInput>
|
||||||
|
<MkInput v-model="remoteLocalTimelineDomain1" placeholder="prismisskey.space">
|
||||||
|
<template #label>サーバーURL</template>
|
||||||
|
</MkInput>
|
||||||
|
<MkInput v-model="remoteLocalTimelineToken1" placeholder="">
|
||||||
|
<template #prefix><i class="ti ti-key"></i></template>
|
||||||
|
<template #label>{{ i18n.ts.accessToken }}</template>
|
||||||
|
</MkInput>
|
||||||
|
<MkSwitch v-model="remoteLocalTimelineEnable1">
|
||||||
|
{{ i18n.ts.enable }}
|
||||||
|
</MkSwitch>
|
||||||
|
</div>
|
||||||
|
<div v-if="maxLocalTimeline >= 2">
|
||||||
|
<MkInput v-model="remoteLocalTimelineName2" placeholder="prismisskey">
|
||||||
|
<template #label>{{ i18n.ts.name }}</template>
|
||||||
|
</MkInput>
|
||||||
|
<MkInput v-model="remoteLocalTimelineDomain2" placeholder="prismisskey.space">
|
||||||
|
<template #label>サーバーURL</template>
|
||||||
|
</MkInput>
|
||||||
|
<MkInput v-model="remoteLocalTimelineToken2" placeholder="">
|
||||||
|
<template #prefix><i class="ti ti-key"></i></template>
|
||||||
|
<template #label>{{ i18n.ts.accessToken }}</template>
|
||||||
|
</MkInput>
|
||||||
|
<MkSwitch v-model="remoteLocalTimelineEnable2">
|
||||||
|
{{ i18n.ts.enable }}
|
||||||
|
</MkSwitch>
|
||||||
|
</div>
|
||||||
|
|
||||||
<template #header>他のサーバーのローカルタイムラインを覗けるようにする</template>
|
<div v-if="maxLocalTimeline >= 3">
|
||||||
<div class="_gaps_m">
|
<MkInput v-model="remoteLocalTimelineName3" placeholder="prismisskey">
|
||||||
<MkFoldableSection :defaultOpen="false">
|
<template #label>{{ i18n.ts.name }}</template>
|
||||||
<template #header>{{ i18n.ts.accessToken }} の発行の仕方</template>
|
</MkInput>
|
||||||
<img width="400" src="https://files.prismisskey.space/misskey/676e4b79-7897-4ea9-b074-a98139312f76.gif">
|
<MkInput v-model="remoteLocalTimelineDomain3" placeholder="prismisskey.space">
|
||||||
</MkFoldableSection>
|
<template #label>サーバーURL</template>
|
||||||
<div v-if="maxLocalTimeline >= 1" >
|
</MkInput>
|
||||||
<MkInput v-model="remoteLocalTimelineName1" placeholder="prismisskey">
|
<MkInput v-model="remoteLocalTimelineToken3" placeholder="">
|
||||||
<template #label>{{ i18n.ts.name }}</template>
|
<template #prefix><i class="ti ti-key"></i></template>
|
||||||
</MkInput>
|
<template #label>{{ i18n.ts.accessToken }}</template>
|
||||||
<MkInput v-model="remoteLocalTimelineDomain1" placeholder="prismisskey.space">
|
</MkInput>
|
||||||
<template #label>サーバーURL</template>
|
<MkSwitch v-model="remoteLocalTimelineEnable3">
|
||||||
</MkInput>
|
{{ i18n.ts.enable }}
|
||||||
<MkInput v-model="remoteLocalTimelineToken1" placeholder="">
|
</MkSwitch>
|
||||||
<template #prefix><i class="ti ti-key"></i></template>
|
</div>
|
||||||
<template #label>{{ i18n.ts.accessToken }}</template>
|
|
||||||
</MkInput>
|
|
||||||
<MkSwitch v-model="remoteLocalTimelineEnable1">
|
|
||||||
{{ i18n.ts.enable }}
|
|
||||||
</MkSwitch>
|
|
||||||
</div>
|
|
||||||
<div v-if="maxLocalTimeline >= 2" >
|
|
||||||
<MkInput v-model="remoteLocalTimelineName2" placeholder="prismisskey">
|
|
||||||
<template #label>{{ i18n.ts.name }}</template>
|
|
||||||
</MkInput>
|
|
||||||
<MkInput v-model="remoteLocalTimelineDomain2" placeholder="prismisskey.space">
|
|
||||||
<template #label>サーバーURL</template>
|
|
||||||
</MkInput>
|
|
||||||
<MkInput v-model="remoteLocalTimelineToken2" placeholder="">
|
|
||||||
<template #prefix><i class="ti ti-key"></i></template>
|
|
||||||
<template #label>{{ i18n.ts.accessToken }}</template>
|
|
||||||
</MkInput>
|
|
||||||
<MkSwitch v-model="remoteLocalTimelineEnable2">
|
|
||||||
{{ i18n.ts.enable }}
|
|
||||||
</MkSwitch>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="maxLocalTimeline >= 3" >
|
<div v-if="maxLocalTimeline >= 4">
|
||||||
<MkInput v-model="remoteLocalTimelineName3" placeholder="prismisskey">
|
<MkInput v-model="remoteLocalTimelineName4" placeholder="prismisskey">
|
||||||
<template #label>{{ i18n.ts.name }}</template>
|
<template #label>{{ i18n.ts.name }}</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
<MkInput v-model="remoteLocalTimelineDomain3" placeholder="prismisskey.space">
|
<MkInput v-model="remoteLocalTimelineDomain4" placeholder="prismisskey.space">
|
||||||
<template #label>サーバーURL</template>
|
<template #label>サーバーURL</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
<MkInput v-model="remoteLocalTimelineToken3" placeholder="">
|
<MkInput v-model="remoteLocalTimelineToken4" placeholder="">
|
||||||
<template #prefix><i class="ti ti-key"></i></template>
|
<template #prefix><i class="ti ti-key"></i></template>
|
||||||
<template #label>{{ i18n.ts.accessToken }}</template>
|
<template #label>{{ i18n.ts.accessToken }}</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
<MkSwitch v-model="remoteLocalTimelineEnable3">
|
<MkSwitch v-model="remoteLocalTimelineEnable4">
|
||||||
{{ i18n.ts.enable }}
|
{{ i18n.ts.enable }}
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="maxLocalTimeline >= 4" >
|
<div v-if="maxLocalTimeline >= 5">
|
||||||
<MkInput v-model="remoteLocalTimelineName4" placeholder="prismisskey">
|
<MkInput v-model="remoteLocalTimelineName5" placeholder="prismisskey">
|
||||||
<template #label>{{ i18n.ts.name }}</template>
|
<template #label>{{ i18n.ts.name }}</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
<MkInput v-model="remoteLocalTimelineDomain4" placeholder="prismisskey.space">
|
<MkInput v-model="remoteLocalTimelineDomain5" placeholder="prismisskey.space">
|
||||||
<template #label>サーバーURL</template>
|
<template #label>サーバーURL</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
<MkInput v-model="remoteLocalTimelineToken4" placeholder="">
|
<MkInput v-model="remoteLocalTimelineToken5" placeholder="">
|
||||||
<template #prefix><i class="ti ti-key"></i></template>
|
<template #prefix><i class="ti ti-key"></i></template>
|
||||||
<template #label>{{ i18n.ts.accessToken }}</template>
|
<template #label>{{ i18n.ts.accessToken }}</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
<MkSwitch v-model="remoteLocalTimelineEnable4">
|
<MkSwitch v-model="remoteLocalTimelineEnable5">
|
||||||
{{ i18n.ts.enable }}
|
{{ i18n.ts.enable }}
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="maxLocalTimeline >= 5" >
|
<MkButton @click="remoteLocaltimelineSave">
|
||||||
<MkInput v-model="remoteLocalTimelineName5" placeholder="prismisskey">
|
{{ i18n.ts.save }}
|
||||||
<template #label>{{ i18n.ts.name }}</template>
|
</MkButton>
|
||||||
</MkInput>
|
</div>
|
||||||
<MkInput v-model="remoteLocalTimelineDomain5" placeholder="prismisskey.space">
|
</MkFoldableSection>
|
||||||
<template #label>サーバーURL</template>
|
|
||||||
</MkInput>
|
|
||||||
<MkInput v-model="remoteLocalTimelineToken5" placeholder="">
|
|
||||||
<template #prefix><i class="ti ti-key"></i></template>
|
|
||||||
<template #label>{{ i18n.ts.accessToken }}</template>
|
|
||||||
</MkInput>
|
|
||||||
<MkSwitch v-model="remoteLocalTimelineEnable5">
|
|
||||||
{{ i18n.ts.enable }}
|
|
||||||
</MkSwitch>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<MkButton @click="remoteLocaltimelineSave">
|
|
||||||
{{ i18n.ts.save }}
|
|
||||||
</MkButton>
|
|
||||||
</div>
|
|
||||||
</MkFoldableSection>
|
|
||||||
<FormSection>
|
<FormSection>
|
||||||
<template #label>{{ i18n.ts.other }}</template>
|
<template #label>{{ i18n.ts.other }}</template>
|
||||||
|
|
||||||
|
@ -351,7 +354,7 @@ import MkInfo from '@/components/MkInfo.vue';
|
||||||
import { langs } from '@/config.js';
|
import { langs } from '@/config.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import {signinRequired} from '@/account.js';
|
||||||
import { unisonReload } from '@/scripts/unison-reload.js';
|
import { unisonReload } from '@/scripts/unison-reload.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
|
@ -361,6 +364,7 @@ import { claimAchievement } from '@/scripts/achievements.js';
|
||||||
import MkColorInput from '@/components/MkColorInput.vue';
|
import MkColorInput from '@/components/MkColorInput.vue';
|
||||||
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
||||||
import MkInput from '@/components/MkInput.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
|
import { userFavoriteListsCache, userListsCache } from '@/cache.js';
|
||||||
|
|
||||||
const lang = ref(miLocalStorage.getItem('lang'));
|
const lang = ref(miLocalStorage.getItem('lang'));
|
||||||
const fontSize = ref(miLocalStorage.getItem('fontSize'));
|
const fontSize = ref(miLocalStorage.getItem('fontSize'));
|
||||||
|
@ -397,7 +401,6 @@ const disableDrawer = computed(defaultStore.makeGetterSetter('disableDrawer'));
|
||||||
const disableShowingAnimatedImages = computed(defaultStore.makeGetterSetter('disableShowingAnimatedImages'));
|
const disableShowingAnimatedImages = computed(defaultStore.makeGetterSetter('disableShowingAnimatedImages'));
|
||||||
const forceShowAds = computed(defaultStore.makeGetterSetter('forceShowAds'));
|
const forceShowAds = computed(defaultStore.makeGetterSetter('forceShowAds'));
|
||||||
const loadRawImages = computed(defaultStore.makeGetterSetter('loadRawImages'));
|
const loadRawImages = computed(defaultStore.makeGetterSetter('loadRawImages'));
|
||||||
const enableCellularWithDataSaver = computed(defaultStore.makeGetterSetter('enableCellularWithDataSaver'));
|
|
||||||
const highlightSensitiveMedia = computed(defaultStore.makeGetterSetter('highlightSensitiveMedia'));
|
const highlightSensitiveMedia = computed(defaultStore.makeGetterSetter('highlightSensitiveMedia'));
|
||||||
const imageNewTab = computed(defaultStore.makeGetterSetter('imageNewTab'));
|
const imageNewTab = computed(defaultStore.makeGetterSetter('imageNewTab'));
|
||||||
const nsfw = computed(defaultStore.makeGetterSetter('nsfw'));
|
const nsfw = computed(defaultStore.makeGetterSetter('nsfw'));
|
||||||
|
@ -428,7 +431,6 @@ const disableStreamingTimeline = computed(defaultStore.makeGetterSetter('disable
|
||||||
const useGroupedNotifications = computed(defaultStore.makeGetterSetter('useGroupedNotifications'));
|
const useGroupedNotifications = computed(defaultStore.makeGetterSetter('useGroupedNotifications'));
|
||||||
const enableSeasonalScreenEffect = computed(defaultStore.makeGetterSetter('enableSeasonalScreenEffect'));
|
const enableSeasonalScreenEffect = computed(defaultStore.makeGetterSetter('enableSeasonalScreenEffect'));
|
||||||
const enableHorizontalSwipe = computed(defaultStore.makeGetterSetter('enableHorizontalSwipe'));
|
const enableHorizontalSwipe = computed(defaultStore.makeGetterSetter('enableHorizontalSwipe'));
|
||||||
const maxLocalTimeline = 3;
|
|
||||||
const remoteLocalTimelineDomain1 = ref(defaultStore.state['remoteLocalTimelineDomain1']);
|
const remoteLocalTimelineDomain1 = ref(defaultStore.state['remoteLocalTimelineDomain1']);
|
||||||
const remoteLocalTimelineToken1 = ref(defaultStore.state['remoteLocalTimelineToken1']);
|
const remoteLocalTimelineToken1 = ref(defaultStore.state['remoteLocalTimelineToken1']);
|
||||||
const remoteLocalTimelineDomain2 = ref(defaultStore.state['remoteLocalTimelineDomain2']);
|
const remoteLocalTimelineDomain2 = ref(defaultStore.state['remoteLocalTimelineDomain2']);
|
||||||
|
@ -450,7 +452,9 @@ const remoteLocalTimelineEnable2 = computed(defaultStore.makeGetterSetter('remot
|
||||||
const remoteLocalTimelineEnable3 = computed(defaultStore.makeGetterSetter('remoteLocalTimelineEnable3'));
|
const remoteLocalTimelineEnable3 = computed(defaultStore.makeGetterSetter('remoteLocalTimelineEnable3'));
|
||||||
const remoteLocalTimelineEnable4 = computed(defaultStore.makeGetterSetter('remoteLocalTimelineEnable4'));
|
const remoteLocalTimelineEnable4 = computed(defaultStore.makeGetterSetter('remoteLocalTimelineEnable4'));
|
||||||
const remoteLocalTimelineEnable5 = computed(defaultStore.makeGetterSetter('remoteLocalTimelineEnable5'));
|
const remoteLocalTimelineEnable5 = computed(defaultStore.makeGetterSetter('remoteLocalTimelineEnable5'));
|
||||||
|
const $i = signinRequired();
|
||||||
|
const pinnedMax = $i.policies?.listPinnedLimit;
|
||||||
|
const maxLocalTimeline = $i.policies?.localTimelineAnyLimit;
|
||||||
watch(lang, () => {
|
watch(lang, () => {
|
||||||
miLocalStorage.setItem('lang', lang.value as string);
|
miLocalStorage.setItem('lang', lang.value as string);
|
||||||
miLocalStorage.removeItem('locale');
|
miLocalStorage.removeItem('locale');
|
||||||
|
@ -592,7 +596,9 @@ function removeEmojiIndex(lang: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setPinnedList() {
|
async function setPinnedList() {
|
||||||
const lists = await misskeyApi('users/lists/list');
|
const myLists = await userListsCache.fetch();
|
||||||
|
const favoriteLists = await userFavoriteListsCache.fetch();
|
||||||
|
let lists = [...new Set([...myLists, ...favoriteLists])];
|
||||||
const { canceled, result: list } = await os.select({
|
const { canceled, result: list } = await os.select({
|
||||||
title: i18n.ts.selectList,
|
title: i18n.ts.selectList,
|
||||||
items: lists.map(x => ({
|
items: lists.map(x => ({
|
||||||
|
@ -600,12 +606,35 @@ async function setPinnedList() {
|
||||||
})),
|
})),
|
||||||
});
|
});
|
||||||
if (canceled) return;
|
if (canceled) return;
|
||||||
|
let pinnedLists = defaultStore.state.pinnedUserLists;
|
||||||
|
|
||||||
defaultStore.set('pinnedUserLists', [list]);
|
// Check if the id is already present in pinnedLists
|
||||||
|
if (!pinnedLists.some(pinnedList => pinnedList.id === list.id)) {
|
||||||
|
pinnedLists.push(list);
|
||||||
|
defaultStore.set('pinnedUserLists', pinnedLists);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function removePinnedList() {
|
async function removePinnedList(id,name) {
|
||||||
defaultStore.set('pinnedUserLists', []);
|
|
||||||
|
if (!id) return;
|
||||||
|
const {canceled} = await os.confirm({
|
||||||
|
type: 'warning',
|
||||||
|
text: i18n.tsx.removeAreYouSure({x: name ?? id }),
|
||||||
|
});
|
||||||
|
if (canceled) return;
|
||||||
|
|
||||||
|
if (id === 'all') {
|
||||||
|
|
||||||
|
if (canceled) return;
|
||||||
|
|
||||||
|
defaultStore.set('pinnedUserLists', []);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pinnedLists = defaultStore.state.pinnedUserLists;
|
||||||
|
const newPinnedLists = pinnedLists.filter(pinnedList => pinnedList.id !== id);
|
||||||
|
defaultStore.set('pinnedUserLists', newPinnedLists);
|
||||||
}
|
}
|
||||||
|
|
||||||
let smashCount = 0;
|
let smashCount = 0;
|
||||||
|
|
|
@ -48,7 +48,7 @@ import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { antennasCache, userListsCache } from '@/cache.js';
|
import { antennasCache, userFavoriteListsCache, userListsCache } from '@/cache.js';
|
||||||
import { deviceKind } from '@/scripts/device-kind.js';
|
import { deviceKind } from '@/scripts/device-kind.js';
|
||||||
import { MenuItem } from '@/types/menu.js';
|
import { MenuItem } from '@/types/menu.js';
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
|
@ -123,7 +123,9 @@ function top(): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function chooseList(ev: MouseEvent): Promise<void> {
|
async function chooseList(ev: MouseEvent): Promise<void> {
|
||||||
const lists = await userListsCache.fetch();
|
const myLists = await userListsCache.fetch();
|
||||||
|
const favoriteLists = await userFavoriteListsCache.fetch();
|
||||||
|
let lists = [...new Set([...myLists, ...favoriteLists])];
|
||||||
const items : MenuItem[] = [
|
const items : MenuItem[] = [
|
||||||
... lists.map(list => ({
|
... lists.map(list => ({
|
||||||
type: 'link' as const,
|
type: 'link' as const,
|
||||||
|
|
|
@ -47,6 +47,7 @@ const rootEl = shallowRef<HTMLElement>();
|
||||||
watch(() => props.listId, async () => {
|
watch(() => props.listId, async () => {
|
||||||
list.value = await misskeyApi('users/lists/show', {
|
list.value = await misskeyApi('users/lists/show', {
|
||||||
listId: props.listId,
|
listId: props.listId,
|
||||||
|
forPublic: true,
|
||||||
});
|
});
|
||||||
}, { immediate: true });
|
}, { immediate: true });
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue