spec(role/ScheduledNote): ロールで予約投稿の個数・予約の最大日数を制御できるように (MisskeyIO#906)
This commit is contained in:
parent
f0f86f1121
commit
8821e3e81b
13 changed files with 148 additions and 23 deletions
|
@ -1794,6 +1794,8 @@ _role:
|
||||||
ltlAvailable: "Can view the local timeline"
|
ltlAvailable: "Can view the local timeline"
|
||||||
canPublicNote: "Can send public notes"
|
canPublicNote: "Can send public notes"
|
||||||
canScheduleNote: "Can schedule notes"
|
canScheduleNote: "Can schedule notes"
|
||||||
|
scheduleNoteLimit: "Maximum number of scheduled notes"
|
||||||
|
scheduleNoteMaxDays: "Maximum number of days that note can be scheduled"
|
||||||
canInitiateConversation: "Can mention, reply or quote"
|
canInitiateConversation: "Can mention, reply or quote"
|
||||||
canCreateContent: "Can create contents"
|
canCreateContent: "Can create contents"
|
||||||
canUpdateContent: "Can edit contents"
|
canUpdateContent: "Can edit contents"
|
||||||
|
@ -2324,6 +2326,7 @@ _postForm:
|
||||||
d: "What do you want to say?"
|
d: "What do you want to say?"
|
||||||
e: "Start writing..."
|
e: "Start writing..."
|
||||||
f: "Waiting for you to write..."
|
f: "Waiting for you to write..."
|
||||||
|
policyScheduleNoteMaxDaysExceeded: "The maximum number of days you can schedule notes for with your current support plan is {max}.\nYou can upgrade your plan [here](https://go.misskey.io/donate)."
|
||||||
tosAndGuidelinesInfo: "Before posting, please read the [Terms of Service]({tosUrl}) and [NSFW Guidelines](https://go.misskey.io/media-guideline)."
|
tosAndGuidelinesInfo: "Before posting, please read the [Terms of Service]({tosUrl}) and [NSFW Guidelines](https://go.misskey.io/media-guideline)."
|
||||||
_profile:
|
_profile:
|
||||||
name: "Name"
|
name: "Name"
|
||||||
|
|
13
locales/index.d.ts
vendored
13
locales/index.d.ts
vendored
|
@ -7019,6 +7019,14 @@ export interface Locale extends ILocale {
|
||||||
* 予約投稿の許可
|
* 予約投稿の許可
|
||||||
*/
|
*/
|
||||||
"canScheduleNote": string;
|
"canScheduleNote": string;
|
||||||
|
/**
|
||||||
|
* 予約投稿の最大数
|
||||||
|
*/
|
||||||
|
"scheduleNoteLimit": string;
|
||||||
|
/**
|
||||||
|
* 予約投稿の最大日数
|
||||||
|
*/
|
||||||
|
"scheduleNoteMaxDays": string;
|
||||||
/**
|
/**
|
||||||
* メンション、リプライ、引用の許可
|
* メンション、リプライ、引用の許可
|
||||||
*/
|
*/
|
||||||
|
@ -9067,6 +9075,11 @@ export interface Locale extends ILocale {
|
||||||
*/
|
*/
|
||||||
"f": string;
|
"f": string;
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* 現在の支援プランで予約できる日数の上限は{max}日です。
|
||||||
|
* [ここ](https://go.misskey.io/donate)からプランをアップグレードできます。
|
||||||
|
*/
|
||||||
|
"policyScheduleNoteMaxDaysExceeded": ParameterizedString<"max">;
|
||||||
/**
|
/**
|
||||||
* 投稿する前に、[利用規約]({tosUrl})と[NSFWガイドライン](https://go.misskey.io/media-guideline)を必ずお読みください。
|
* 投稿する前に、[利用規約]({tosUrl})と[NSFWガイドライン](https://go.misskey.io/media-guideline)を必ずお読みください。
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1808,6 +1808,8 @@ _role:
|
||||||
ltlAvailable: "ローカルタイムラインの閲覧"
|
ltlAvailable: "ローカルタイムラインの閲覧"
|
||||||
canPublicNote: "パブリック投稿の許可"
|
canPublicNote: "パブリック投稿の許可"
|
||||||
canScheduleNote: "予約投稿の許可"
|
canScheduleNote: "予約投稿の許可"
|
||||||
|
scheduleNoteLimit: "予約投稿の最大数"
|
||||||
|
scheduleNoteMaxDays: "予約投稿の最大日数"
|
||||||
canInitiateConversation: "メンション、リプライ、引用の許可"
|
canInitiateConversation: "メンション、リプライ、引用の許可"
|
||||||
canCreateContent: "コンテンツの作成"
|
canCreateContent: "コンテンツの作成"
|
||||||
canUpdateContent: "コンテンツの編集"
|
canUpdateContent: "コンテンツの編集"
|
||||||
|
@ -2377,6 +2379,7 @@ _postForm:
|
||||||
d: "言いたいことは?"
|
d: "言いたいことは?"
|
||||||
e: "ここに書いてください"
|
e: "ここに書いてください"
|
||||||
f: "あなたが書くのを待っています..."
|
f: "あなたが書くのを待っています..."
|
||||||
|
policyScheduleNoteMaxDaysExceeded: "現在の支援プランで予約できる日数の上限は{max}日です。\n[ここ](https://go.misskey.io/donate)からプランをアップグレードできます。"
|
||||||
tosAndGuidelinesInfo: "投稿する前に、[利用規約]({tosUrl})と[NSFWガイドライン](https://go.misskey.io/media-guideline)を必ずお読みください。"
|
tosAndGuidelinesInfo: "投稿する前に、[利用規約]({tosUrl})と[NSFWガイドライン](https://go.misskey.io/media-guideline)を必ずお読みください。"
|
||||||
|
|
||||||
_profile:
|
_profile:
|
||||||
|
|
|
@ -1791,6 +1791,8 @@ _role:
|
||||||
ltlAvailable: "로컬 타임라인 보이기"
|
ltlAvailable: "로컬 타임라인 보이기"
|
||||||
canPublicNote: "공개 노트 허용"
|
canPublicNote: "공개 노트 허용"
|
||||||
canScheduleNote: "노트 예약 허용"
|
canScheduleNote: "노트 예약 허용"
|
||||||
|
scheduleNoteLimit: "노트 예약 한도"
|
||||||
|
scheduleNoteMaxDays: "노트 예약 최대 일수"
|
||||||
mentionMax: "노트에 넣을 수 있는 멘션 수"
|
mentionMax: "노트에 넣을 수 있는 멘션 수"
|
||||||
canCreateContent: "컨텐츠 생성 허용"
|
canCreateContent: "컨텐츠 생성 허용"
|
||||||
canUpdateContent: "컨텐츠 수정 허용"
|
canUpdateContent: "컨텐츠 수정 허용"
|
||||||
|
@ -2310,6 +2312,7 @@ _postForm:
|
||||||
d: "말하고 싶은 게 있나요?"
|
d: "말하고 싶은 게 있나요?"
|
||||||
e: "여기에 적어 주세요"
|
e: "여기에 적어 주세요"
|
||||||
f: "글 쓰기를 기다려요…"
|
f: "글 쓰기를 기다려요…"
|
||||||
|
policyScheduleNoteMaxDaysExceeded: "현재 지원 플랜의 예약 가능한 최대 일수는 {max}일입니다.\n[여기](https://go.misskey.io/donate)에서 플랜을 업그레이드할 수 있습니다."
|
||||||
tosAndGuidelinesInfo: "노트를 게시하기 전에 [이용약관]({tosUrl})과 [NSFW 가이드라인](https://go.misskey.io/media-guideline)을 반드시 읽어 주세요."
|
tosAndGuidelinesInfo: "노트를 게시하기 전에 [이용약관]({tosUrl})과 [NSFW 가이드라인](https://go.misskey.io/media-guideline)을 반드시 읽어 주세요."
|
||||||
_profile:
|
_profile:
|
||||||
name: "이름"
|
name: "이름"
|
||||||
|
|
|
@ -425,6 +425,15 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||||
throw new IdentifiableError('7cc42034-f7ab-4f7c-87b4-e00854479080', 'User has no permission to schedule notes.');
|
throw new IdentifiableError('7cc42034-f7ab-4f7c-87b4-e00854479080', 'User has no permission to schedule notes.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((data.scheduledAt.getTime() - Date.now()) / 86_400_000 > policies.scheduleNoteMaxDays) {
|
||||||
|
throw new IdentifiableError('506006cf-3092-4ae1-8145-b025001c591f', `User can schedule notes up to ${policies.scheduleNoteMaxDays} days in the future.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const scheduledCount = await this.scheduledNotesRepository.countBy({ userId: user.id });
|
||||||
|
if (scheduledCount >= policies.scheduleNoteLimit) {
|
||||||
|
throw new IdentifiableError('7fc78d25-d947-45c1-9547-02257b98cab3', `User can schedule up to ${policies.scheduleNoteLimit} notes.`);
|
||||||
|
}
|
||||||
|
|
||||||
const draft = await this.insertScheduledNote(user, data);
|
const draft = await this.insertScheduledNote(user, data);
|
||||||
|
|
||||||
await this.queueService.createScheduledNoteJob(draft.id, draft.scheduledAt!);
|
await this.queueService.createScheduledNoteJob(draft.id, draft.scheduledAt!);
|
||||||
|
|
|
@ -37,6 +37,8 @@ export type RolePolicies = {
|
||||||
ltlAvailable: boolean;
|
ltlAvailable: boolean;
|
||||||
canPublicNote: boolean;
|
canPublicNote: boolean;
|
||||||
canScheduleNote: boolean;
|
canScheduleNote: boolean;
|
||||||
|
scheduleNoteLimit: number;
|
||||||
|
scheduleNoteMaxDays: number;
|
||||||
canInitiateConversation: boolean;
|
canInitiateConversation: boolean;
|
||||||
canCreateContent: boolean;
|
canCreateContent: boolean;
|
||||||
canUpdateContent: boolean;
|
canUpdateContent: boolean;
|
||||||
|
@ -79,6 +81,8 @@ export const DEFAULT_POLICIES: RolePolicies = {
|
||||||
ltlAvailable: true,
|
ltlAvailable: true,
|
||||||
canPublicNote: true,
|
canPublicNote: true,
|
||||||
canScheduleNote: true,
|
canScheduleNote: true,
|
||||||
|
scheduleNoteLimit: 10,
|
||||||
|
scheduleNoteMaxDays: 365,
|
||||||
canInitiateConversation: true,
|
canInitiateConversation: true,
|
||||||
canCreateContent: true,
|
canCreateContent: true,
|
||||||
canUpdateContent: true,
|
canUpdateContent: true,
|
||||||
|
@ -392,6 +396,8 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
|
||||||
ltlAvailable: calc('ltlAvailable', vs => vs.some(v => v === true)),
|
ltlAvailable: calc('ltlAvailable', vs => vs.some(v => v === true)),
|
||||||
canPublicNote: calc('canPublicNote', vs => vs.some(v => v === true)),
|
canPublicNote: calc('canPublicNote', vs => vs.some(v => v === true)),
|
||||||
canScheduleNote: calc('canScheduleNote', vs => vs.some(v => v === true)),
|
canScheduleNote: calc('canScheduleNote', vs => vs.some(v => v === true)),
|
||||||
|
scheduleNoteLimit: calc('scheduleNoteLimit', vs => Math.max(...vs)),
|
||||||
|
scheduleNoteMaxDays: calc('scheduleNoteMaxDays', vs => Math.max(...vs)),
|
||||||
canInitiateConversation: calc('canInitiateConversation', vs => vs.some(v => v === true)),
|
canInitiateConversation: calc('canInitiateConversation', vs => vs.some(v => v === true)),
|
||||||
canCreateContent: calc('canCreateContent', vs => vs.some(v => v === true)),
|
canCreateContent: calc('canCreateContent', vs => vs.some(v => v === true)),
|
||||||
canUpdateContent: calc('canUpdateContent', vs => vs.some(v => v === true)),
|
canUpdateContent: calc('canUpdateContent', vs => vs.some(v => v === true)),
|
||||||
|
|
|
@ -184,6 +184,14 @@ export const packedRolePoliciesSchema = {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
},
|
},
|
||||||
|
scheduleNoteLimit: {
|
||||||
|
type: 'integer',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
scheduleNoteMaxDays: {
|
||||||
|
type: 'integer',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
canInitiateConversation: {
|
canInitiateConversation: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
|
|
|
@ -155,18 +155,26 @@ export const meta = {
|
||||||
id: 'e577d185-8179-4a17-b47f-6093985558e6',
|
id: 'e577d185-8179-4a17-b47f-6093985558e6',
|
||||||
},
|
},
|
||||||
|
|
||||||
cannotScheduleToFarFuture: {
|
|
||||||
message: 'Cannot schedule to the far future.',
|
|
||||||
code: 'CANNOT_SCHEDULE_TO_FAR_FUTURE',
|
|
||||||
id: 'ea102856-e8da-4ae9-a98a-0326821bd177',
|
|
||||||
},
|
|
||||||
|
|
||||||
cannotScheduleSameTime: {
|
cannotScheduleSameTime: {
|
||||||
message: 'Cannot schedule multiple notes at the same time.',
|
message: 'Cannot schedule multiple notes at the same time.',
|
||||||
code: 'CANNOT_SCHEDULE_SAME_TIME',
|
code: 'CANNOT_SCHEDULE_SAME_TIME',
|
||||||
id: '187a8fab-fd83-4ae6-a46c-0f6f07784634',
|
id: '187a8fab-fd83-4ae6-a46c-0f6f07784634',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
tooManyScheduledNotes: {
|
||||||
|
message: 'You cannot schedule notes any more.',
|
||||||
|
code: 'TOO_MANY_SCHEDULED_NOTES',
|
||||||
|
kind: 'permission',
|
||||||
|
id: '9e33041f-f6fb-414d-98c1-591466e55287'
|
||||||
|
},
|
||||||
|
|
||||||
|
cannotScheduleToFarFuture: {
|
||||||
|
message: 'Cannot schedule to the far future.',
|
||||||
|
code: 'CANNOT_SCHEDULE_TO_FAR_FUTURE',
|
||||||
|
kind: 'permission',
|
||||||
|
id: 'ea102856-e8da-4ae9-a98a-0326821bd177',
|
||||||
|
},
|
||||||
|
|
||||||
rolePermissionDenied: {
|
rolePermissionDenied: {
|
||||||
message: 'You are not assigned to a required role.',
|
message: 'You are not assigned to a required role.',
|
||||||
code: 'ROLE_PERMISSION_DENIED',
|
code: 'ROLE_PERMISSION_DENIED',
|
||||||
|
@ -462,11 +470,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
logger.error('Cannot schedule to the past.', { scheduledAt });
|
logger.error('Cannot schedule to the past.', { scheduledAt });
|
||||||
throw new ApiError(meta.errors.cannotScheduleToPast);
|
throw new ApiError(meta.errors.cannotScheduleToPast);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scheduledAt.getTime() - now.getTime() > ms('1year')) {
|
|
||||||
logger.error('Cannot schedule to the far future.', { scheduledAt });
|
|
||||||
throw new ApiError(meta.errors.cannotScheduleToFarFuture);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 投稿を作成
|
// 投稿を作成
|
||||||
|
@ -517,10 +520,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
logger.error('Failed to create a note.', { error: err });
|
logger.error('Failed to create a note.', { error: err });
|
||||||
|
|
||||||
if (err instanceof IdentifiableError) {
|
if (err instanceof IdentifiableError) {
|
||||||
if (err.id === '689ee33f-f97c-479a-ac49-1b9f8140af99') throw new ApiError(meta.errors.containsProhibitedWords);
|
if (err.id === '689ee33f-f97c-479a-ac49-1b9f8140af99') throw new ApiError(meta.errors.containsProhibitedWords, { message: err.message });
|
||||||
if (err.id === '9f466dab-c856-48cd-9e65-ff90ff750580') throw new ApiError(meta.errors.containsTooManyMentions);
|
if (err.id === '9f466dab-c856-48cd-9e65-ff90ff750580') throw new ApiError(meta.errors.containsTooManyMentions, { message: err.message });
|
||||||
if (err.id === '7cc42034-f7ab-4f7c-87b4-e00854479080') throw new ApiError(meta.errors.rolePermissionDenied);
|
if (err.id === '5ea8e4f5-9d64-4e6c-92b8-9e2b5a4756bc') throw new ApiError(meta.errors.cannotScheduleSameTime, { message: err.message });
|
||||||
if (err.id === '5ea8e4f5-9d64-4e6c-92b8-9e2b5a4756bc') throw new ApiError(meta.errors.cannotScheduleSameTime);
|
if (err.id === '7fc78d25-d947-45c1-9547-02257b98cab3') throw new ApiError(meta.errors.tooManyScheduledNotes, { message: err.message });
|
||||||
|
if (err.id === '506006cf-3092-4ae1-8145-b025001c591f') throw new ApiError(meta.errors.cannotScheduleToFarFuture, { message: err.message });
|
||||||
|
if (err.id === '7cc42034-f7ab-4f7c-87b4-e00854479080') throw new ApiError(meta.errors.rolePermissionDenied, { message: err.message });
|
||||||
}
|
}
|
||||||
|
|
||||||
throw err;
|
throw err;
|
||||||
|
|
|
@ -82,8 +82,18 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
<input v-show="withHashtags" ref="hashtagsInputEl" v-model="hashtags" class="mk-input-text" :class="$style.hashtags" :placeholder="i18n.ts.hashtags" list="hashtags">
|
<input v-show="withHashtags" ref="hashtagsInputEl" v-model="hashtags" class="mk-input-text" :class="$style.hashtags" :placeholder="i18n.ts.hashtags" list="hashtags">
|
||||||
<div v-if="scheduledTime" :class="$style.scheduledTime">
|
<div v-if="scheduledTime" :class="$style.scheduledTime">
|
||||||
<div><i class="ti ti-calendar-clock"></i></div>
|
<div>
|
||||||
<span>{{ i18n.tsx.willBePostedAt({ x: dateTimeFormat.format(scheduledTime) }) }}</span>
|
<div style="display: flex; gap: 4px" :style="scheduledTimeExceededPolicy ? 'color: var(--error)' : undefined">
|
||||||
|
<span style="margin-right: 4px"><i class="ti ti-calendar-clock"></i></span>
|
||||||
|
<component :is="scheduledTimeExceededPolicy ? 'del' : 'span'" :style="scheduledTimeExceededPolicy ? 'opacity: 0.6' : undefined">
|
||||||
|
{{ i18n.tsx.willBePostedAt({ x: dateTimeFormat.format(scheduledTime) }) }}
|
||||||
|
</component>
|
||||||
|
</div>
|
||||||
|
<div v-if="scheduledTimeExceededPolicy" style="display: flex; gap: 4px; margin-top: 4px; color: var(--infoWarnFg)">
|
||||||
|
<span style="margin-right: 4px"><i class="ti ti-exclamation-circle"></i></span>
|
||||||
|
<Mfm :text="i18n.tsx._postForm.policyScheduleNoteMaxDaysExceeded({ max: $i.policies.scheduleNoteMaxDays })"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<button class="_button" style="margin-left: auto" @click="scheduledTime = null"><i class="ti ti-x"></i></button>
|
<button class="_button" style="margin-left: auto" @click="scheduledTime = null"><i class="ti ti-x"></i></button>
|
||||||
</div>
|
</div>
|
||||||
<MkInfo v-if="files.length > 0 && instance.tosUrl" warn style="margin-top: 8px;" :rounded="false">
|
<MkInfo v-if="files.length > 0 && instance.tosUrl" warn style="margin-top: 8px;" :rounded="false">
|
||||||
|
@ -219,6 +229,9 @@ if (props.initialVisibleUsers) {
|
||||||
}
|
}
|
||||||
const reactionAcceptance = ref(defaultStore.state.reactionAcceptance);
|
const reactionAcceptance = ref(defaultStore.state.reactionAcceptance);
|
||||||
const scheduledTime = ref<Date | null>(null);
|
const scheduledTime = ref<Date | null>(null);
|
||||||
|
const scheduledTimeExceededPolicy = computed(() =>
|
||||||
|
scheduledTime.value ? (scheduledTime.value.getTime() - Date.now()) / 86_400_000 > $i!.policies.scheduleNoteMaxDays : false
|
||||||
|
);
|
||||||
const autocompleteTextareaInput = ref<Autocomplete | null>(null);
|
const autocompleteTextareaInput = ref<Autocomplete | null>(null);
|
||||||
const autocompleteCwInput = ref<Autocomplete | null>(null);
|
const autocompleteCwInput = ref<Autocomplete | null>(null);
|
||||||
const autocompleteHashtagsInput = ref<Autocomplete | null>(null);
|
const autocompleteHashtagsInput = ref<Autocomplete | null>(null);
|
||||||
|
@ -285,16 +298,20 @@ const maxTextLength = computed((): number => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const canPost = computed((): boolean => {
|
const canPost = computed((): boolean => {
|
||||||
return !props.mock && !posting.value && !posted.value &&
|
return !props.mock
|
||||||
(
|
&& !posting.value
|
||||||
|
&& !posted.value
|
||||||
|
&& (
|
||||||
1 <= textLength.value ||
|
1 <= textLength.value ||
|
||||||
1 <= files.value.length ||
|
1 <= files.value.length ||
|
||||||
poll.value != null ||
|
poll.value != null ||
|
||||||
renote.value != null ||
|
renote.value != null ||
|
||||||
(reply.value != null && quoteId.value != null)
|
(reply.value != null && quoteId.value != null)
|
||||||
) &&
|
)
|
||||||
(textLength.value <= maxTextLength.value) &&
|
&& (textLength.value <= maxTextLength.value)
|
||||||
(!poll.value || poll.value.choices.length >= 2);
|
&& (!poll.value || poll.value.choices.length >= 2)
|
||||||
|
&& !scheduledTimeExceededPolicy.value
|
||||||
|
;
|
||||||
});
|
});
|
||||||
|
|
||||||
const withHashtags = computed(defaultStore.makeGetterSetter('postFormWithHashtags'));
|
const withHashtags = computed(defaultStore.makeGetterSetter('postFormWithHashtags'));
|
||||||
|
@ -1393,8 +1410,10 @@ defineExpose({
|
||||||
|
|
||||||
.scheduledTime {
|
.scheduledTime {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 8px 24px;
|
padding: 8px 12px;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 90%;
|
||||||
background: var(--infoBg);
|
background: var(--infoBg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,6 +79,8 @@ export const ROLE_POLICIES = [
|
||||||
'ltlAvailable',
|
'ltlAvailable',
|
||||||
'canPublicNote',
|
'canPublicNote',
|
||||||
'canScheduleNote',
|
'canScheduleNote',
|
||||||
|
'scheduleNoteLimit',
|
||||||
|
'scheduleNoteMaxDays',
|
||||||
'canInitiateConversation',
|
'canInitiateConversation',
|
||||||
'canCreateContent',
|
'canCreateContent',
|
||||||
'canUpdateContent',
|
'canUpdateContent',
|
||||||
|
|
|
@ -185,6 +185,44 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.scheduleNoteLimit, 'scheduleNoteLimit'])">
|
||||||
|
<template #label>{{ i18n.ts._role._options.scheduleNoteLimit }}</template>
|
||||||
|
<template #suffix>
|
||||||
|
<span v-if="role.policies.scheduleNoteLimit.useDefault" :class="$style.useDefaultLabel">{{ i18n.ts._role.useBaseValue }}</span>
|
||||||
|
<span v-else>{{ role.policies.scheduleNoteLimit.value }}</span>
|
||||||
|
<span :class="$style.priorityIndicator"><i :class="getPriorityIcon(role.policies.scheduleNoteLimit)"></i></span>
|
||||||
|
</template>
|
||||||
|
<div class="_gaps">
|
||||||
|
<MkSwitch v-model="role.policies.scheduleNoteLimit.useDefault" :readonly="readonly">
|
||||||
|
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||||
|
</MkSwitch>
|
||||||
|
<MkInput v-model="role.policies.scheduleNoteLimit.value" :disabled="role.policies.scheduleNoteLimit.useDefault" type="number" :readonly="readonly">
|
||||||
|
</MkInput>
|
||||||
|
<MkRange v-model="role.policies.scheduleNoteLimit.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
|
||||||
|
<template #label>{{ i18n.ts._role.priority }}</template>
|
||||||
|
</MkRange>
|
||||||
|
</div>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.scheduleNoteMaxDays, 'scheduleNoteMaxDays'])">
|
||||||
|
<template #label>{{ i18n.ts._role._options.scheduleNoteMaxDays }}</template>
|
||||||
|
<template #suffix>
|
||||||
|
<span v-if="role.policies.scheduleNoteMaxDays.useDefault" :class="$style.useDefaultLabel">{{ i18n.ts._role.useBaseValue }}</span>
|
||||||
|
<span v-else>{{ role.policies.scheduleNoteMaxDays.value }}</span>
|
||||||
|
<span :class="$style.priorityIndicator"><i :class="getPriorityIcon(role.policies.scheduleNoteMaxDays)"></i></span>
|
||||||
|
</template>
|
||||||
|
<div class="_gaps">
|
||||||
|
<MkSwitch v-model="role.policies.scheduleNoteMaxDays.useDefault" :readonly="readonly">
|
||||||
|
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||||
|
</MkSwitch>
|
||||||
|
<MkInput v-model="role.policies.scheduleNoteMaxDays.value" :disabled="role.policies.scheduleNoteMaxDays.useDefault" type="number" :readonly="readonly">
|
||||||
|
</MkInput>
|
||||||
|
<MkRange v-model="role.policies.scheduleNoteMaxDays.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
|
||||||
|
<template #label>{{ i18n.ts._role.priority }}</template>
|
||||||
|
</MkRange>
|
||||||
|
</div>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.canInitiateConversation, 'canInitiateConversation'])">
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.canInitiateConversation, 'canInitiateConversation'])">
|
||||||
<template #label>{{ i18n.ts._role._options.canInitiateConversation }}</template>
|
<template #label>{{ i18n.ts._role._options.canInitiateConversation }}</template>
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
|
|
|
@ -56,6 +56,20 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.scheduleNoteLimit, 'scheduleNoteLimit'])">
|
||||||
|
<template #label>{{ i18n.ts._role._options.scheduleNoteLimit }}</template>
|
||||||
|
<template #suffix>{{ policies.scheduleNoteLimit }}</template>
|
||||||
|
<MkInput v-model="policies.scheduleNoteLimit" type="number">
|
||||||
|
</MkInput>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.scheduleNoteMaxDays, 'scheduleNoteMaxDays'])">
|
||||||
|
<template #label>{{ i18n.ts._role._options.scheduleNoteMaxDays }}</template>
|
||||||
|
<template #suffix>{{ policies.scheduleNoteMaxDays }}</template>
|
||||||
|
<MkInput v-model="policies.scheduleNoteMaxDays" type="number">
|
||||||
|
</MkInput>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.canInitiateConversation, 'canInitiateConversation'])">
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.canInitiateConversation, 'canInitiateConversation'])">
|
||||||
<template #label>{{ i18n.ts._role._options.canInitiateConversation }}</template>
|
<template #label>{{ i18n.ts._role._options.canInitiateConversation }}</template>
|
||||||
<template #suffix>{{ policies.canInitiateConversation ? i18n.ts.yes : i18n.ts.no }}</template>
|
<template #suffix>{{ policies.canInitiateConversation ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||||
|
|
|
@ -5078,6 +5078,8 @@ export type components = {
|
||||||
ltlAvailable: boolean;
|
ltlAvailable: boolean;
|
||||||
canPublicNote: boolean;
|
canPublicNote: boolean;
|
||||||
canScheduleNote: boolean;
|
canScheduleNote: boolean;
|
||||||
|
scheduleNoteLimit: number;
|
||||||
|
scheduleNoteMaxDays: number;
|
||||||
canInitiateConversation: boolean;
|
canInitiateConversation: boolean;
|
||||||
canCreateContent: boolean;
|
canCreateContent: boolean;
|
||||||
canUpdateContent: boolean;
|
canUpdateContent: boolean;
|
||||||
|
|
Loading…
Reference in a new issue