mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-23 11:31:57 +03:00
UBER-615 HR Schedule UI fixes (#3565)
Signed-off-by: Alexander Onnikov <alexander.onnikov@xored.com>
This commit is contained in:
parent
eaaef54fa6
commit
32fd80c971
@ -308,6 +308,27 @@ export function createModel (builder: Builder): void {
|
||||
hr.action.EditDepartment
|
||||
)
|
||||
|
||||
createAction(
|
||||
builder,
|
||||
{
|
||||
action: view.actionImpl.ShowPopup,
|
||||
actionProps: {
|
||||
component: hr.component.CreateDepartment,
|
||||
element: 'top',
|
||||
fillProps: {
|
||||
_id: 'space'
|
||||
}
|
||||
},
|
||||
label: hr.string.CreateDepartment,
|
||||
icon: hr.icon.Department,
|
||||
input: 'focus',
|
||||
category: hr.category.HR,
|
||||
target: hr.class.Department,
|
||||
context: { mode: 'context', application: hr.app.HR, group: 'create' }
|
||||
},
|
||||
hr.action.CreateDepartment
|
||||
)
|
||||
|
||||
createAction(
|
||||
builder,
|
||||
{
|
||||
@ -339,7 +360,8 @@ export function createModel (builder: Builder): void {
|
||||
input: 'any',
|
||||
category: hr.category.HR,
|
||||
target: hr.class.Request,
|
||||
context: { mode: 'context', application: hr.app.HR, group: 'create' }
|
||||
context: { mode: 'context', application: hr.app.HR, group: 'create' },
|
||||
override: [view.action.Open]
|
||||
},
|
||||
hr.action.EditRequest
|
||||
)
|
||||
@ -350,7 +372,7 @@ export function createModel (builder: Builder): void {
|
||||
action: hr.actionImpl.EditRequestType,
|
||||
actionProps: {},
|
||||
label: hr.string.EditRequestType,
|
||||
icon: view.icon.Open,
|
||||
icon: view.icon.Edit,
|
||||
input: 'any',
|
||||
category: hr.category.HR,
|
||||
target: hr.class.Request,
|
||||
|
@ -41,6 +41,7 @@ export default mergeIds(hrId, hr, {
|
||||
},
|
||||
component: {
|
||||
Structure: '' as AnyComponent,
|
||||
CreateDepartment: '' as AnyComponent,
|
||||
EditDepartment: '' as AnyComponent,
|
||||
DepartmentStaff: '' as AnyComponent,
|
||||
DepartmentEditor: '' as AnyComponent,
|
||||
@ -54,6 +55,7 @@ export default mergeIds(hrId, hr, {
|
||||
HR: '' as Ref<ActionCategory>
|
||||
},
|
||||
action: {
|
||||
CreateDepartment: '' as Ref<Action>,
|
||||
EditDepartment: '' as Ref<Action>,
|
||||
ArchiveDepartment: '' as Ref<Action>,
|
||||
EditRequest: '' as Ref<Action>,
|
||||
|
@ -235,7 +235,7 @@
|
||||
)`
|
||||
divScroll.style.webkitMaskImage = gradient
|
||||
}
|
||||
if (divHScroll && horizontal) {
|
||||
if (divHScroll && horizontal && !noFade) {
|
||||
const gradientH = `linear-gradient(
|
||||
90deg,
|
||||
rgba(0, 0, 0, 1) ${shiftLeft}px,
|
||||
|
@ -250,7 +250,7 @@
|
||||
{#if rows.length}
|
||||
{@const dep = departmentById.get(department)}
|
||||
|
||||
<Scroller fade={{ multipler: { top: headerHeightRem, bottom: 0, left: headerWidthRem } }} horizontal>
|
||||
<Scroller horizontal fade={{ multipler: { top: headerHeightRem, left: headerWidthRem } }} noFade>
|
||||
<div bind:clientWidth={containerWidth} class="timeline">
|
||||
{#key [containerWidthRem, columnWidthRem, headerWidthRem]}
|
||||
<!-- Resource Header -->
|
||||
@ -314,7 +314,14 @@
|
||||
{#each tracks as track, trackIndex}
|
||||
{#each track.elements as element}
|
||||
{@const request = element.request}
|
||||
<div class="timeline-event-wrapper" style={getElementStyle(element, trackIndex)}>
|
||||
<div
|
||||
class="timeline-event-wrapper"
|
||||
style={getElementStyle(element, trackIndex)}
|
||||
use:tooltip={{
|
||||
component: RequestsPopup,
|
||||
props: { requests: [request._id] }
|
||||
}}
|
||||
>
|
||||
<ScheduleRequest {request} {editable} shouldShowDescription={element.length > 1} />
|
||||
</div>
|
||||
{/each}
|
||||
|
@ -16,7 +16,7 @@
|
||||
import hr, { Request, RequestType } from '@hcengineering/hr'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { closeTooltip, Icon, Label, showPopup } from '@hcengineering/ui'
|
||||
import { ContextMenu, HTMLPresenter } from '@hcengineering/view-resources'
|
||||
import { ContextMenu } from '@hcengineering/view-resources'
|
||||
|
||||
export let request: Request
|
||||
export let editable: boolean = false
|
||||
@ -30,10 +30,8 @@
|
||||
})
|
||||
}
|
||||
|
||||
function isAvailable (type: RequestType, request: Request): boolean {
|
||||
// TODO Move availability to the Request model
|
||||
const available = type.value >= 0
|
||||
return available
|
||||
function isAvailable (type: RequestType): boolean {
|
||||
return type.value >= 0
|
||||
}
|
||||
|
||||
function click (e: MouseEvent, request: Request) {
|
||||
@ -43,11 +41,13 @@
|
||||
closeTooltip()
|
||||
showPopup(ContextMenu, { object: request }, e.target as HTMLElement)
|
||||
}
|
||||
|
||||
$: description = shouldShowDescription ? request.description.replace(/<[^>]*>/g, '').trim() : ''
|
||||
</script>
|
||||
|
||||
{#await getType(request) then type}
|
||||
{#if type}
|
||||
{@const available = isAvailable(type, request)}
|
||||
{@const available = isAvailable(type)}
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
@ -66,8 +66,8 @@
|
||||
|
||||
{#if shouldShowDescription}
|
||||
<span class="overflow-label">
|
||||
{#if request.description !== ''}
|
||||
<HTMLPresenter value={request.description} />
|
||||
{#if description !== ''}
|
||||
{description}
|
||||
{:else if type}
|
||||
<Label label={type.label} />
|
||||
{/if}
|
||||
|
@ -16,6 +16,10 @@
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import { Department } from '@hcengineering/hr'
|
||||
import { getResource } from '@hcengineering/platform'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { Action, IconEdit } from '@hcengineering/ui'
|
||||
import { getActions as getContributedActions } from '@hcengineering/view-resources'
|
||||
|
||||
import hr from '../../plugin'
|
||||
|
||||
@ -27,27 +31,48 @@
|
||||
export let selected: Ref<Department> | undefined
|
||||
export let level = 0
|
||||
|
||||
const client = getClient()
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
function getDescendants (department: Ref<Department>): Ref<Department>[] {
|
||||
return (descendants.get(department) ?? []).map((p) => p._id)
|
||||
return (descendants.get(department) ?? []).sort((a, b) => a.name.localeCompare(b.name)).map((p) => p._id)
|
||||
}
|
||||
|
||||
async function getActions (obj: Department): Promise<Action[]> {
|
||||
const result: Action[] = []
|
||||
const extraActions = await getContributedActions(client, obj, obj._class)
|
||||
for (const act of extraActions) {
|
||||
result.push({
|
||||
icon: act.icon ?? IconEdit,
|
||||
label: act.label,
|
||||
action: async (ctx: any, evt: Event) => {
|
||||
const impl = await getResource(act.action)
|
||||
await impl(obj, evt, act.actionProps)
|
||||
}
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function handleDepartmentSelected (department: Ref<Department>): void {
|
||||
dispatch('selected', department)
|
||||
}
|
||||
|
||||
$: _departments = departments.map((it) => departmentById.get(it)).filter((it) => it !== undefined) as Department[]
|
||||
$: _descendants = new Map(_departments.map((it) => [it._id, getDescendants(it._id)]))
|
||||
</script>
|
||||
|
||||
{#each departments as dep}
|
||||
{@const department = departmentById.get(dep)}
|
||||
{@const desc = getDescendants(dep)}
|
||||
{#each _departments as department}
|
||||
{@const desc = _descendants.get(department._id) ?? []}
|
||||
|
||||
{#if department}
|
||||
<TreeElement
|
||||
_id={department._id}
|
||||
icon={hr.icon.Department}
|
||||
title={department.name}
|
||||
selected={selected === department._id}
|
||||
node={desc.length > 0}
|
||||
actions={() => getActions(department)}
|
||||
{level}
|
||||
on:click={() => handleDepartmentSelected(department._id)}
|
||||
>
|
||||
|
@ -34,19 +34,11 @@
|
||||
<NavHeader label={hr.string.HRApplication} />
|
||||
|
||||
<Scroller shrink>
|
||||
<!-- TODO Specials -->
|
||||
|
||||
<div class="antiNav-divider short line" />
|
||||
|
||||
<TreeNode label={hr.string.Departments} parent>
|
||||
<DepartmentsHierarchy {departments} {descendants} {departmentById} selected={department} on:selected />
|
||||
</TreeNode>
|
||||
|
||||
<!-- TODO Add Positions -->
|
||||
<!-- <div class="antiNav-divider short line" /> -->
|
||||
|
||||
<!-- <TreeNode label={hr.string.Positions} parent> -->
|
||||
<!-- </TreeNode> -->
|
||||
</Scroller>
|
||||
|
||||
<NavFooter />
|
||||
|
@ -13,11 +13,14 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { Doc, Ref } from '@hcengineering/core'
|
||||
import type { Asset, IntlString } from '@hcengineering/platform'
|
||||
import type { AnySvelteComponent } from '@hcengineering/ui'
|
||||
import { Icon, IconChevronDown, Label } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { Icon, IconChevronDown, IconMoreH, Label, Menu, showPopup } from '@hcengineering/ui'
|
||||
import { Action } from '@hcengineering/view'
|
||||
|
||||
export let _id: Ref<Doc> | undefined = undefined
|
||||
export let icon: Asset | AnySvelteComponent | undefined = undefined
|
||||
export let iconProps: Record<string, any> | undefined = undefined
|
||||
export let label: IntlString | undefined = undefined
|
||||
@ -27,6 +30,15 @@
|
||||
export let collapsed = false
|
||||
export let selected = false
|
||||
export let level = 0
|
||||
export let actions: (originalEvent?: MouseEvent) => Promise<Action[]> = async () => []
|
||||
|
||||
let hovered = false
|
||||
async function onMenuClick (ev: MouseEvent) {
|
||||
showPopup(Menu, { actions: await actions(ev), ctx: _id }, ev.target as HTMLElement, () => {
|
||||
hovered = false
|
||||
})
|
||||
hovered = true
|
||||
}
|
||||
|
||||
$: style = `padding-left: calc(${level} * 1.25rem);`
|
||||
|
||||
@ -36,10 +48,10 @@
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class="antiNav-element"
|
||||
class:hovered
|
||||
class:selected
|
||||
class:parent
|
||||
class:collapsed
|
||||
class:child={!node}
|
||||
{style}
|
||||
on:click={() => {
|
||||
if (selected) {
|
||||
@ -59,12 +71,25 @@
|
||||
</span>
|
||||
|
||||
{#if node}
|
||||
<div class="an-element__icon-arrow" class:collapsed>
|
||||
<div
|
||||
class="an-element__icon-arrow"
|
||||
class:collapsed
|
||||
on:click={(e) => {
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
collapsed = !collapsed
|
||||
}}
|
||||
>
|
||||
<IconChevronDown size={'small'} />
|
||||
</div>
|
||||
{/if}
|
||||
</span>
|
||||
|
||||
<div class="an-element__tool" on:click|preventDefault|stopPropagation={onMenuClick}>
|
||||
<IconMoreH size={'small'} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if node && !collapsed}
|
||||
<div class="antiNav-element__dropbox"><slot /></div>
|
||||
{/if}
|
||||
|
@ -14,6 +14,7 @@
|
||||
//
|
||||
|
||||
import { Resources } from '@hcengineering/platform'
|
||||
import CreateDepartment from './components/CreateDepartment.svelte'
|
||||
import DepartmentEditor from './components/DepartmentEditor.svelte'
|
||||
import DepartmentStaff from './components/DepartmentStaff.svelte'
|
||||
import EditDepartment from './components/EditDepartment.svelte'
|
||||
@ -34,6 +35,7 @@ async function editRequestType (object: Request): Promise<void> {
|
||||
export default async (): Promise<Resources> => ({
|
||||
component: {
|
||||
Structure,
|
||||
CreateDepartment,
|
||||
EditDepartment,
|
||||
DepartmentStaff,
|
||||
DepartmentEditor,
|
||||
|
Loading…
Reference in New Issue
Block a user