mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-26 19:44:57 +02:00
[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:
+2
-1
@@ -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}
|
||||
|
||||
+2
-1
@@ -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}
|
||||
|
||||
+3
-2
@@ -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>
|
||||
|
||||
+5
@@ -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'
|
||||
|
||||
Reference in New Issue
Block a user