fix(acl): dölj redigeringsknappen för användare utan edit-rättighet
Some checks failed
build-and-push / build (push) Failing after 1m3s
Some checks failed
build-and-push / build (push) Failing after 1m3s
VisualEditors 'Börja redigera'-banner styrdes bara av internt state och visades för alla, även publika läs-användare. Ny editable-prop gate:ar bannern och tvingar läsläge när rättigheten saknas. SourceEditor får en readonly-prop (CodeMirror-Compartment) så Source-fliken inte längre är redigerbar utan rättighet. Versionsvyn är nu alltid read-only. Backend nekade redan save utan Edit/Create — detta var enbart ett UI-fel. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,14 +1,18 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onBeforeUnmount, watch } from 'vue'
|
||||
import { EditorView, basicSetup } from 'codemirror'
|
||||
import { EditorState } from '@codemirror/state'
|
||||
import { EditorState, Compartment } from '@codemirror/state'
|
||||
import { markdown } from '@codemirror/lang-markdown'
|
||||
import { oneDark } from '@codemirror/theme-one-dark'
|
||||
|
||||
const model = defineModel<string>({ required: true })
|
||||
const props = withDefaults(defineProps<{ readonly?: boolean }>(), { readonly: false })
|
||||
const container = ref<HTMLElement | null>(null)
|
||||
let view: EditorView | null = null
|
||||
|
||||
const readonlyCompartment = new Compartment()
|
||||
const readonlyExtensions = (ro: boolean) => [EditorState.readOnly.of(ro), EditorView.editable.of(!ro)]
|
||||
|
||||
onMounted(() => {
|
||||
if (!container.value) return
|
||||
|
||||
@@ -20,6 +24,7 @@ onMounted(() => {
|
||||
basicSetup,
|
||||
markdown(),
|
||||
oneDark,
|
||||
readonlyCompartment.of(readonlyExtensions(props.readonly)),
|
||||
EditorView.updateListener.of((update) => {
|
||||
if (update.docChanged) {
|
||||
model.value = update.state.doc.toString()
|
||||
@@ -30,6 +35,10 @@ onMounted(() => {
|
||||
})
|
||||
})
|
||||
|
||||
watch(() => props.readonly, (ro) => {
|
||||
view?.dispatch({ effects: readonlyCompartment.reconfigure(readonlyExtensions(ro)) })
|
||||
})
|
||||
|
||||
// Sync external model changes into CodeMirror.
|
||||
watch(model, (adoc) => {
|
||||
if (!view) return
|
||||
|
||||
@@ -14,9 +14,15 @@ import ImageEditDialog from './ImageEditDialog.vue'
|
||||
import LinkDialog from './LinkDialog.vue'
|
||||
|
||||
const model = defineModel<string>({ required: true })
|
||||
const props = defineProps<{ slug?: string }>()
|
||||
const props = withDefaults(defineProps<{ slug?: string; editable?: boolean }>(), { editable: true })
|
||||
|
||||
const isEditing = ref(false)
|
||||
|
||||
// Force read mode if edit permission disappears (e.g. navigating to a doc
|
||||
// the user may not edit while this component instance is reused).
|
||||
watch(() => props.editable, (editable) => {
|
||||
if (!editable) isEditing.value = false
|
||||
})
|
||||
const showImagePicker = ref(false)
|
||||
const showImageEditor = ref(false)
|
||||
const showLinkDialog = ref({ open: false, url: '', text: '' })
|
||||
@@ -473,9 +479,9 @@ function handleEditorClick(e: MouseEvent) {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Banner when not editing -->
|
||||
<!-- Banner when not editing (hidden entirely without edit permission) -->
|
||||
<div
|
||||
v-if="!isEditing"
|
||||
v-if="!isEditing && props.editable"
|
||||
class="bg-indigo-50 dark:bg-slate-800/80 border-b border-indigo-100 dark:border-slate-700/60 flex items-center justify-between p-2 flex-shrink-0"
|
||||
>
|
||||
<span class="text-sm text-indigo-700 dark:text-indigo-300 ml-2">Läsläge</span>
|
||||
|
||||
@@ -357,11 +357,13 @@ function formatDate(dateStr: string) {
|
||||
<VisualEditor
|
||||
v-else-if="versionEditorMode === 'visual'"
|
||||
:slug="slug"
|
||||
:editable="false"
|
||||
:model-value="versionContent"
|
||||
@update:model-value="() => {}"
|
||||
/>
|
||||
<SourceEditor
|
||||
v-else
|
||||
readonly
|
||||
:model-value="versionContent"
|
||||
@update:model-value="() => {}"
|
||||
/>
|
||||
@@ -370,8 +372,8 @@ function formatDate(dateStr: string) {
|
||||
<!-- Normal editor -->
|
||||
<template v-else>
|
||||
<div v-if="loading" class="p-6 text-slate-400 animate-pulse">Loading…</div>
|
||||
<VisualEditor v-else-if="editorMode === 'visual'" v-model="content" :slug="slug" />
|
||||
<SourceEditor v-else v-model="content" />
|
||||
<VisualEditor v-else-if="editorMode === 'visual'" v-model="content" :slug="slug" :editable="canEditDoc" />
|
||||
<SourceEditor v-else v-model="content" :readonly="!canEditDoc" />
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user