[EZQMS-732, EZQMS-737]: Restrict type configuration, allow deleting roles (#5512)

Signed-off-by: Alexey Zinoviev <alexey.zinoviev@xored.com>
This commit is contained in:
Alexey Zinoviev
2024-05-05 21:18:30 +07:00
committed by GitHub
parent bb29cebdd9
commit 3cbec84e5b
29 changed files with 396 additions and 117 deletions
@@ -19,8 +19,9 @@
export let type: ProjectType | undefined
export let descriptor: ProjectTypeDescriptor | undefined
export let disabled: boolean = true
</script>
{#if descriptor !== undefined && type !== undefined}
<ComponentExtensions extension={task.extensions.ProjectEditorExtension} props={{ type }} />
<ComponentExtensions extension={task.extensions.ProjectEditorExtension} props={{ type, disabled }} />
{/if}
@@ -19,12 +19,13 @@
export let type: ProjectType | undefined
export let descriptor: ProjectTypeDescriptor | undefined
export let disabled: boolean = true
</script>
{#if descriptor !== undefined}
<div class="hulyTableAttr-header font-medium-12">
<IconFolder size="small" />
<span><Label label={task.string.Collections} /></span>
<ButtonIcon kind="primary" icon={IconAdd} size="small" on:click={() => {}} />
<ButtonIcon kind="primary" icon={IconAdd} size="small" {disabled} on:click={() => {}} />
</div>
{/if}
@@ -19,12 +19,13 @@
export let type: ProjectType | undefined
export let descriptor: ProjectTypeDescriptor | undefined
export let disabled: boolean = true
</script>
<SpaceTypeGeneralSectionEditor {type} {descriptor}>
<SpaceTypeGeneralSectionEditor {type} {descriptor} {disabled}>
<svelte:fragment slot="extra">
{#if descriptor?.editor}
<Component is={descriptor.editor} props={{ type }} />
<Component is={descriptor.editor} props={{ type }} {disabled} />
{/if}
</svelte:fragment>
</SpaceTypeGeneralSectionEditor>
@@ -27,6 +27,7 @@
export let type: ProjectType | undefined
export let descriptor: ProjectTypeDescriptor | undefined
export let disabled: boolean = true
let taskTypes: TaskType[] = []
const taskTypesQuery = createQuery()
@@ -62,7 +63,11 @@
kind="primary"
icon={IconAdd}
size="small"
{disabled}
on:click={(ev) => {
if (disabled) {
return
}
$settingsStore = { id: 'createTaskType', component: CreateTaskType, props: { type, descriptor } }
}}
/>
@@ -57,6 +57,7 @@
export let icon: Asset | undefined
export let canDelete: boolean = true
export let selectableStates: Status[] = []
export let readonly: boolean = true
$: _taskType = $taskTypeStore.get(taskType._id) as TaskType
$: _type = $typeStore.get(type._id) as ProjectType
@@ -96,6 +97,7 @@
!selectableStates.some((it) => it.name === value)
async function save (): Promise<void> {
if (readonly) return
if (total > 0 && value.trim() !== status?.name?.trim()) {
// We should ask for changes approve.
showPopup(
@@ -226,6 +228,7 @@
oldStatus: Ref<Status>,
newStatus: Ref<Status>
): Promise<void> {
if (readonly) return
const projects = await client.findAll(task.class.Project, { type: type._id })
while (true) {
const docs = await client.findAll(
@@ -250,7 +253,7 @@
}
function onDelete (): void {
if (status === undefined) return
if (status === undefined || readonly) return
const estatus = status
showPopup(
DeleteStateConfirmationPopup,
@@ -293,6 +296,7 @@
}
function onDuplicate (): void {
if (readonly) return
let pattern = ''
let inc = 2
@@ -336,35 +340,38 @@
type={'type-aside'}
okLabel={status === undefined ? presentation.string.Create : presentation.string.Save}
okAction={save}
canSave={needUpdate}
canSave={needUpdate && !readonly}
onCancel={() => {
clearSettingsStore()
}}
>
<svelte:fragment slot="actions">
<ButtonIcon
icon={IconDelete}
size={'small'}
kind={'tertiary'}
disabled={status === undefined || !canDelete}
on:click={onDelete}
/>
<ButtonIcon
icon={IconCopy}
size={'small'}
kind={'tertiary'}
disabled={status === undefined}
on:click={onDuplicate}
/>
{#if !readonly}
<ButtonIcon
icon={IconDelete}
size={'small'}
kind={'tertiary'}
disabled={status === undefined || !canDelete || readonly}
on:click={onDelete}
/>
<ButtonIcon
icon={IconCopy}
size={'small'}
kind={'tertiary'}
disabled={status === undefined || readonly}
on:click={onDuplicate}
/>
{/if}
</svelte:fragment>
<div class="hulyModal-content__titleGroup">
<ModernEditbox bind:value label={task.string.StatusName} size={'large'} kind={'ghost'} />
<ModernEditbox bind:value label={task.string.StatusName} size={'large'} kind={'ghost'} disabled={readonly} />
<TextArea
placeholder={task.string.Description}
width={'100%'}
height={'4.5rem'}
margin={'var(--spacing-1) var(--spacing-2)'}
noFocusBorder
disabled={readonly}
bind:value={description}
/>
</div>
@@ -374,7 +381,7 @@
<ButtonMenu
items={categories}
selected={category}
disabled={!allowEditCategory}
disabled={!allowEditCategory || readonly}
icon={categories.find((it) => it.id === category)?.icon}
label={categories.find((it) => it.id === category)?.label}
kind={'secondary'}
@@ -395,6 +402,7 @@
label={items[selected].label}
kind={'secondary'}
size={'small'}
disabled={readonly}
on:selected={(event) => {
if (event.detail) {
selected = items.findIndex((it) => it.id === event.detail)
@@ -413,8 +421,10 @@
<ColorsPopup
selected={getPlatformColorDef(color ?? 0, $themeStore.dark).name}
embedded
disabled={readonly}
columns={'auto'}
on:close={(evt) => {
if (readonly) return
color = evt.detail
icon = undefined
}}
@@ -423,7 +433,9 @@
<EmojiPopup
embedded
selected={fromCodePoint(color ?? 0)}
disabled={readonly}
on:close={(evt) => {
if (readonly) return
color = evt.detail.codePointAt(0)
icon = iconWithEmoji
}}
@@ -26,6 +26,7 @@
export let taskType: TaskType
export let type: ProjectType
export let states: Status[] = []
export let readonly: boolean = true
const dispatch = createEventDispatcher()
@@ -35,6 +36,7 @@
let opened: Ref<Status> | undefined
function dragswap (ev: MouseEvent, i: number): boolean {
if (readonly) return false
const s = selected as number
if (i < s) {
return ev.offsetY < elements[i].offsetHeight / 2
@@ -45,6 +47,7 @@
}
function dragover (ev: MouseEvent, i: number): void {
if (readonly) return
const s = selected as number
if (dragswap(ev, i)) {
;[states[i], states[s]] = [states[s], states[i]]
@@ -53,6 +56,7 @@
}
function onMove (to: number): void {
if (readonly) return
dispatch('move', {
stateID: dragState,
position: to
@@ -130,7 +134,8 @@
color,
icons,
canDelete: sameCategory.length > 1,
selectableStates: sameCategory.filter((it) => it._id !== _status._id)
selectableStates: sameCategory.filter((it) => it._id !== _status._id),
readonly
}
}
}
@@ -151,7 +156,7 @@
bind:this={elements[prevIndex + i]}
class="hulyTableAttr-content__row"
class:selected={state._id === opened}
draggable={true}
draggable={!readonly}
on:click={() => {
handleSelect(state)
}}
@@ -41,6 +41,7 @@
export let objectId: Ref<TaskType>
export let name: string | undefined
export let icon: Asset | undefined
export let readonly: boolean = true
const client = getClient()
@@ -79,6 +80,9 @@
}
function selectIcon (el: MouseEvent): void {
if (readonly) {
return
}
const icons: Asset[] = [descriptor[0].icon]
showPopup(
@@ -94,7 +98,7 @@
}
function handleAddStatus (): void {
if (taskType === undefined) {
if (taskType === undefined || readonly) {
return
}
@@ -134,14 +138,18 @@
}
void client.diffUpdate(taskType, { kind: evt.detail })
}}
{readonly}
/>
<ButtonIcon
icon={TaskTypeIcon}
iconProps={{ value: taskType }}
size={'large'}
kind={'secondary'}
on:click={selectIcon}
/>
{#if !readonly}
<ButtonIcon
icon={TaskTypeIcon}
iconProps={{ value: taskType }}
size={'large'}
kind={'secondary'}
disabled={readonly}
on:click={selectIcon}
/>
{/if}
</div>
<ModernButton
icon={IconSquareExpand}
@@ -154,12 +162,15 @@
/>
</div>
<AttributeEditor
_class={task.class.TaskType}
object={taskType}
key="name"
editKind={'modern-ghost-large'}
/>
<div class="name" class:editable={!readonly}>
<AttributeEditor
_class={task.class.TaskType}
object={taskType}
key="name"
editKind={'modern-ghost-large'}
editable={!readonly}
/>
</div>
<div class="flex-row-center mt-4 ml-4 mr-4 gap-4">
<div class="flex-no-shrink trans-title uppercase">
@@ -185,12 +196,19 @@
<div class="hulyTableAttr-header font-medium-12">
<Icon icon={task.icon.ManageTemplates} size={'small'} />
<span><Label label={plugin.string.ProcessStates} /></span>
<ButtonIcon kind={'primary'} icon={IconAdd} size={'small'} on:click={handleAddStatus} />
<ButtonIcon
kind={'primary'}
icon={IconAdd}
size={'small'}
on:click={handleAddStatus}
disabled={readonly}
/>
</div>
<StatesProjectEditor
{taskType}
type={spaceType}
{states}
{readonly}
on:delete={async (evt) => {
if (taskType === undefined) {
return
@@ -207,7 +225,7 @@
})
}}
on:move={async (evt) => {
if (taskType === undefined) {
if (taskType === undefined || readonly) {
return
}
const index = taskType.statuses.findIndex((p) => p === evt.detail.stateID)
@@ -229,9 +247,24 @@
/>
</div>
<ClassAttributes ofClass={taskType.ofClass} _class={taskType.targetClass} showHierarchy />
<ClassAttributes ofClass={taskType.ofClass} _class={taskType.targetClass} showHierarchy disabled={readonly} />
</div>
</Scroller>
</div>
</div>
{/if}
<style lang="scss">
.name {
width: 100%;
font-weight: 500;
margin-left: 1rem;
display: flex;
align-items: center;
font-size: 1.5rem;
&.editable {
margin-left: 0;
}
}
</style>
@@ -1,5 +1,4 @@
<script lang="ts">
import { getEmbeddedLabel } from '@hcengineering/platform'
import { TaskTypeKind } from '@hcengineering/task'
import { Label, ButtonMenu } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'