feat(activities): let creators lock edit and delete to themselves
Add editPolicy (default creator-only), enforce it in the API, surface clear permission messages, and drop the redundant edit menu now that detail is editable. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -29,6 +29,7 @@ import {
|
||||
startOfLocalDay,
|
||||
} from '@/lib/jalali';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { canMutateActivity } from '@/lib/activity-access';
|
||||
import ActivityCommentSheet from '@/components/activities/ActivityCommentSheet.vue';
|
||||
import JalaliDateInput from '@/components/JalaliDateInput.vue';
|
||||
|
||||
@@ -200,6 +201,7 @@ function clearNoteMedia() {
|
||||
const isClosed = computed(
|
||||
() => activity.value?.status === 'done' || activity.value?.status === 'canceled',
|
||||
);
|
||||
const canMutate = computed(() => canMutateActivity(activity.value, auth.user));
|
||||
const needsEveryone = computed(
|
||||
() => activity.value?.completionMode === 'all' && (activity.value.assignees?.length ?? 0) > 1,
|
||||
);
|
||||
@@ -407,6 +409,10 @@ async function runAction() {
|
||||
error.value = '';
|
||||
try {
|
||||
if (isClosed.value) {
|
||||
if (!canMutate.value) {
|
||||
error.value = 'شما مجوز ویرایش این فعالیت را ندارید.';
|
||||
return;
|
||||
}
|
||||
await api.patch(`/activities/${id}`, { status: 'open' });
|
||||
await load(id);
|
||||
emit('changed');
|
||||
@@ -525,7 +531,13 @@ function openFull() {
|
||||
<a-divider :style="{ margin: '16px 0 12px' }" />
|
||||
<a-flex justify="space-between" align="center" :style="{ marginBottom: '8px' }">
|
||||
<a-typography-text strong>یادداشت</a-typography-text>
|
||||
<a-button type="primary" shape="circle" aria-label="یادداشت جدید" @click="commentOpen = true">
|
||||
<a-button
|
||||
type="primary"
|
||||
shape="circle"
|
||||
aria-label="یادداشت جدید"
|
||||
:disabled="!canMutate"
|
||||
@click="commentOpen = true"
|
||||
>
|
||||
<template #icon><PlusOutlined /></template>
|
||||
</a-button>
|
||||
</a-flex>
|
||||
@@ -630,12 +642,16 @@ function openFull() {
|
||||
<a-flex align="center" :gap="8">
|
||||
<a-select
|
||||
v-model:value="postponeKey"
|
||||
:disabled="saving || loading || isClosed"
|
||||
:disabled="saving || loading || isClosed || !canMutate"
|
||||
:options="postponeChoices.map((item) => ({ value: item.key, label: item.label }))"
|
||||
:dropdown-style="{ zIndex: 1200 }"
|
||||
style="flex: 1"
|
||||
/>
|
||||
<a-button type="primary" :disabled="saving || loading || isClosed || !postponeReady" @click="applyPostpone">
|
||||
<a-button
|
||||
type="primary"
|
||||
:disabled="saving || loading || isClosed || !canMutate || !postponeReady"
|
||||
@click="applyPostpone"
|
||||
>
|
||||
تعویق
|
||||
</a-button>
|
||||
</a-flex>
|
||||
@@ -644,12 +660,17 @@ function openFull() {
|
||||
v-model="customDue"
|
||||
mode="datetime"
|
||||
placeholder="تاریخ و ساعت"
|
||||
:disabled="!canMutate"
|
||||
/>
|
||||
</a-flex>
|
||||
|
||||
<a-divider :style="{ margin: '16px 0 12px' }" />
|
||||
<a-flex justify="space-between" align="center" wrap="wrap" :gap="8">
|
||||
<a-button type="primary" :disabled="saving || loading" @click="runAction">
|
||||
<a-button
|
||||
type="primary"
|
||||
:disabled="saving || loading || (isClosed && !canMutate)"
|
||||
@click="runAction"
|
||||
>
|
||||
{{ actionLabel }}
|
||||
</a-button>
|
||||
<a-button type="link" @click="openFull">مشاهدهٔ کامل</a-button>
|
||||
|
||||
Reference in New Issue
Block a user