mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-28 04:25:03 +02:00
UBERF-6001: Roles management (#4994)
Signed-off-by: Alexey Zinoviev <alexey.zinoviev@xored.com>
This commit is contained in:
@@ -13,9 +13,20 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { deepEqual } from 'fast-equals'
|
||||
import { Employee } from '@hcengineering/contact'
|
||||
import { AccountArrayEditor, AssigneeBox } from '@hcengineering/contact-resources'
|
||||
import core, { Account, Data, DocumentUpdate, Ref, generateId, getCurrentAccount } from '@hcengineering/core'
|
||||
import core, {
|
||||
Account,
|
||||
Data,
|
||||
DocumentUpdate,
|
||||
RolesAssignment,
|
||||
Ref,
|
||||
Role,
|
||||
SortingOrder,
|
||||
generateId,
|
||||
getCurrentAccount
|
||||
} from '@hcengineering/core'
|
||||
import { Asset } from '@hcengineering/platform'
|
||||
import presentation, { Card, createQuery, getClient } from '@hcengineering/presentation'
|
||||
import task, { ProjectType } from '@hcengineering/task'
|
||||
@@ -25,11 +36,9 @@
|
||||
Button,
|
||||
Component,
|
||||
EditBox,
|
||||
IconEdit,
|
||||
IconWithEmoji,
|
||||
Label,
|
||||
Toggle,
|
||||
eventToHTMLElement,
|
||||
getColorNumberByText,
|
||||
getPlatformColorDef,
|
||||
getPlatformColorForTextDef,
|
||||
@@ -38,14 +47,12 @@
|
||||
} from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view'
|
||||
import { IconPicker } from '@hcengineering/view-resources'
|
||||
import { typeStore, taskTypeStore } from '@hcengineering/task-resources'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import tracker from '../../plugin'
|
||||
import StatusSelector from '../issues/StatusSelector.svelte'
|
||||
import ChangeIdentity from './ChangeIdentity.svelte'
|
||||
import { typeStore, taskTypeStore } from '@hcengineering/task-resources'
|
||||
|
||||
export let project: Project | undefined = undefined
|
||||
|
||||
export let namePlaceholder: string = ''
|
||||
export let descriptionPlaceholder: string = ''
|
||||
|
||||
@@ -65,6 +72,7 @@
|
||||
let projectsIdentifiers = new Set<string>()
|
||||
let isSaving = false
|
||||
let defaultStatus: Ref<IssueStatus> | undefined = project?.defaultIssueStatus
|
||||
let rolesAssignment: RolesAssignment | undefined
|
||||
|
||||
let changeIdentityRef: HTMLElement
|
||||
|
||||
@@ -99,8 +107,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
function getRolesAssignment (): RolesAssignment {
|
||||
if (project === undefined || typeType?.targetClass === undefined || roles === undefined) {
|
||||
return {}
|
||||
}
|
||||
|
||||
const asMixin = hierarchy.as(project, typeType?.targetClass)
|
||||
|
||||
return roles.reduce<RolesAssignment>((prev, { _id }) => {
|
||||
prev[_id] = (asMixin as any)[_id]
|
||||
|
||||
return prev
|
||||
}, {})
|
||||
}
|
||||
|
||||
async function updateProject (): Promise<void> {
|
||||
if (!project) {
|
||||
if (!project || typeType?.targetClass === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -147,11 +169,20 @@
|
||||
isSaving = false
|
||||
}
|
||||
|
||||
if (rolesAssignment && !deepEqual(rolesAssignment, getRolesAssignment())) {
|
||||
await client.updateMixin(
|
||||
project._id,
|
||||
tracker.class.Project,
|
||||
core.space.Space,
|
||||
typeType.targetClass,
|
||||
rolesAssignment
|
||||
)
|
||||
}
|
||||
|
||||
close()
|
||||
}
|
||||
|
||||
let typeId: Ref<ProjectType> | undefined = project?.type
|
||||
|
||||
$: typeType = typeId !== undefined ? $typeStore.get(typeId) : undefined
|
||||
|
||||
$: if (defaultStatus === undefined && typeType !== undefined) {
|
||||
@@ -171,8 +202,14 @@
|
||||
const succeeded = await ops.commit()
|
||||
|
||||
if (succeeded) {
|
||||
// Add vacancy mixin
|
||||
await client.createMixin(projectId, tracker.class.Project, core.space.Space, typeType.targetClass, {})
|
||||
// Add space type's mixin with roles assignments
|
||||
await client.createMixin(
|
||||
projectId,
|
||||
tracker.class.Project,
|
||||
core.space.Space,
|
||||
typeType.targetClass,
|
||||
rolesAssignment ?? {}
|
||||
)
|
||||
|
||||
close(projectId)
|
||||
} else {
|
||||
@@ -207,6 +244,52 @@
|
||||
}
|
||||
|
||||
$: identifier = identifier.toLocaleUpperCase().replaceAll('-', '_').replaceAll(' ', '_').substring(0, 5)
|
||||
|
||||
let roles: Role[] = []
|
||||
const rolesQuery = createQuery()
|
||||
$: if (typeType !== undefined) {
|
||||
rolesQuery.query(
|
||||
core.class.Role,
|
||||
{ attachedTo: typeType._id },
|
||||
(res) => {
|
||||
roles = res
|
||||
|
||||
if (rolesAssignment === undefined && typeType !== undefined) {
|
||||
rolesAssignment = getRolesAssignment()
|
||||
}
|
||||
},
|
||||
{
|
||||
sort: {
|
||||
name: SortingOrder.Ascending
|
||||
}
|
||||
}
|
||||
)
|
||||
} else {
|
||||
rolesQuery.unsubscribe()
|
||||
}
|
||||
|
||||
function handleMembersChanged (newMembers: Ref<Account>[]): void {
|
||||
// If a member was removed we need to remove it from any roles assignments as well
|
||||
const newMembersSet = new Set(newMembers)
|
||||
const removedMembersSet = new Set(members.filter((m) => !newMembersSet.has(m)))
|
||||
|
||||
if (removedMembersSet.size > 0 && rolesAssignment !== undefined) {
|
||||
for (const [key, value] of Object.entries(rolesAssignment)) {
|
||||
rolesAssignment[key as Ref<Role>] =
|
||||
value !== undefined ? value.filter((m) => !removedMembersSet.has(m)) : undefined
|
||||
}
|
||||
}
|
||||
|
||||
members = newMembers
|
||||
}
|
||||
|
||||
function handleRoleAssignmentChanged (roleId: Ref<Role>, newMembers: Ref<Account>[]): void {
|
||||
if (rolesAssignment === undefined) {
|
||||
rolesAssignment = {}
|
||||
}
|
||||
|
||||
rolesAssignment[roleId] = newMembers
|
||||
}
|
||||
</script>
|
||||
|
||||
<Card
|
||||
@@ -326,19 +409,6 @@
|
||||
<Toggle bind:on={isPrivate} disabled={!isPrivate && members.length === 0} />
|
||||
</div>
|
||||
|
||||
<div class="antiGrid-row">
|
||||
<div class="antiGrid-row__header">
|
||||
<Label label={tracker.string.Members} />
|
||||
</div>
|
||||
<AccountArrayEditor
|
||||
value={members}
|
||||
label={tracker.string.Members}
|
||||
onChange={(refs) => (members = refs)}
|
||||
kind={'regular'}
|
||||
size={'large'}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="antiGrid-row">
|
||||
<div class="antiGrid-row__header">
|
||||
<Label label={tracker.string.DefaultAssignee} />
|
||||
@@ -369,6 +439,38 @@
|
||||
size={'large'}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="antiGrid-row">
|
||||
<div class="antiGrid-row__header">
|
||||
<Label label={tracker.string.Members} />
|
||||
</div>
|
||||
<AccountArrayEditor
|
||||
value={members}
|
||||
label={tracker.string.Members}
|
||||
onChange={handleMembersChanged}
|
||||
kind={'regular'}
|
||||
size={'large'}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{#each roles as role}
|
||||
<div class="antiGrid-row">
|
||||
<div class="antiGrid-row__header">
|
||||
<Label label={tracker.string.RoleLabel} params={{ role: role.name }} />
|
||||
</div>
|
||||
<AccountArrayEditor
|
||||
value={rolesAssignment?.[role._id] ?? []}
|
||||
label={tracker.string.Members}
|
||||
includeItems={members}
|
||||
readonly={members.length === 0}
|
||||
onChange={(refs) => {
|
||||
handleRoleAssignmentChanged(role._id, refs)
|
||||
}}
|
||||
kind={'regular'}
|
||||
size={'large'}
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user