Fix HR issues. (#2418)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev 2022-12-05 23:27:49 +07:00 committed by GitHub
parent 2ed837ac59
commit e16f1921d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 169 additions and 51 deletions

2
.vscode/launch.json vendored
View File

@ -27,7 +27,7 @@
"ts-node/register"
],
"sourceMaps": true,
"cwd": "${workspaceRoot}/server/server",
"cwd": "${workspaceRoot}/pods/server",
"protocol": "inspector"
},
{

View File

@ -266,9 +266,9 @@ export function devTool (
program
.command('backup-restore <dirName> <workspace> [date]')
.description('dump workspace transactions and minio resources')
.action(async (dirName, workspace, date, cmd) => {
.action(async (dirName: string, workspace: string, date, cmd) => {
const storage = await createFileBackupStorage(dirName)
return await restore(transactorUrl, workspace, storage, parseInt(date ?? '-1'))
return await restore(transactorUrl, getWorkspaceId(workspace, productId), storage, parseInt(date ?? '-1'))
})
program

View File

@ -113,7 +113,7 @@ export class TChannel extends TAttachedDoc implements Channel {
@Model(contact.class.Person, contact.class.Contact)
@UX(contact.string.Person, contact.icon.Person, undefined, 'name')
export class TPerson extends TContact implements Person {
@Prop(TypeDate(), contact.string.Birthday)
@Prop(TypeDate(false, false), contact.string.Birthday)
birthday?: Timestamp
}

View File

@ -305,6 +305,9 @@ export function createModel (builder: Builder): void {
builder.mixin(core.class.Class, core.class.Class, view.mixin.IgnoreActions, {
actions: [view.action.Delete]
})
builder.mixin(core.class.Attribute, core.class.Class, view.mixin.IgnoreActions, {
actions: [view.action.Delete]
})
createAction(builder, {
action: view.actionImpl.ShowPopup,
@ -341,6 +344,46 @@ export function createModel (builder: Builder): void {
)
// builder.mixin(core.class.Space, core.class.Class, setting.mixin.Editable, {})
createAction(builder, {
action: view.actionImpl.UpdateDocument,
actionProps: {
key: 'hidden',
value: true
},
query: {
hidden: { $in: [false, undefined, null] }
},
label: setting.string.HideAttribute,
input: 'any',
icon: view.icon.Setting,
category: setting.category.Settings,
target: core.class.Attribute,
context: {
mode: ['context', 'browser'],
group: 'edit'
}
})
createAction(builder, {
action: view.actionImpl.UpdateDocument,
actionProps: {
key: 'hidden',
value: false
},
query: {
hidden: true
},
label: setting.string.ShowAttribute,
input: 'any',
icon: view.icon.Setting,
category: setting.category.Settings,
target: core.class.Attribute,
context: {
mode: ['context', 'browser'],
group: 'edit'
}
})
}
export { settingOperation } from './migration'

View File

@ -51,6 +51,7 @@
export let allowDeselect = false
export let component: AnySvelteComponent | undefined = undefined
export let componentProps: any | undefined = undefined
export let autoSelect = true
let selected: Space | undefined
@ -61,10 +62,10 @@
async function updateSelected (value: Ref<Space> | undefined) {
selected = value !== undefined ? await client.findOne(_class, { ...(spaceQuery ?? {}), _id: value }) : undefined
if (selected === undefined) {
if (selected === undefined && autoSelect) {
selected = await client.findOne(_class, { ...(spaceQuery ?? {}) })
if (selected !== undefined) {
value = selected._id
value = selected._id ?? undefined
dispatch('change', value)
dispatch('space', selected)
}
@ -89,8 +90,8 @@
},
!$$slots.content ? eventToHTMLElement(ev) : getEventPositionElement(ev),
(result) => {
if (result) {
value = result._id
if (result !== undefined) {
value = result?._id ?? undefined
dispatch('change', value)
mgr?.setFocusPos(focusIndex)
}
@ -100,6 +101,7 @@
</script>
{#if $$slots.content}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div id="space.selector" class="w-full h-full flex-streatch" on:click={showSpacesPopup}>
<slot name="content" />
</div>
@ -116,7 +118,7 @@
showTooltip={{ label, direction: labelDirection }}
on:click={showSpacesPopup}
>
<span slot="content" class="overflow-label disabled text-sm">
<span slot="content" class="overflow-label disabled text-sm" class:dark-color={value == null}>
{#if selected}{selected.name}{:else}<Label {label} />{/if}
</span>
</Button>

View File

@ -32,6 +32,7 @@
export let focus = true
export let component: AnySvelteComponent | undefined = undefined
export let componentProps: any | undefined = undefined
export let autoSelect = true
export let create: ObjectCreate | undefined = undefined
</script>
@ -51,6 +52,7 @@
{width}
{component}
{componentProps}
{autoSelect}
bind:value={space}
on:change={(evt) => {
space = evt.detail

View File

@ -118,6 +118,7 @@
$: hideIcon = size === 'x-large' || (size === 'large' && kind !== 'link')
</script>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div {id} bind:this={container} class="min-w-0" class:w-full={width === '100%'} class:h-full={$$slots.content}>
{#if $$slots.content}
<div
@ -129,7 +130,12 @@
</div>
{:else}
<Button {focusIndex} width={width ?? 'min-content'} {size} {kind} {justify} {showTooltip} on:click={_click}>
<span slot="content" class="overflow-label flex-grow" class:flex-between={showNavigate && selected}>
<span
slot="content"
class="overflow-label flex-grow"
class:flex-between={showNavigate && selected}
class:dark-color={value == null}
>
<div
class="disabled"
style:width={showNavigate && selected

View File

@ -36,6 +36,7 @@
export let labelDirection: TooltipAlignment | undefined = undefined
export let focusIndex = -1
export let autoSelect: boolean = true
export let useFlexGrow = false
let container: HTMLElement
let opened: boolean = false
@ -52,7 +53,7 @@
const mgr = getFocusManager()
</script>
<div bind:this={container} class="min-w-0">
<div bind:this={container} class="min-w-0" class:flex-grow={useFlexGrow}>
<Button
{focusIndex}
{icon}
@ -75,7 +76,7 @@
}
}}
>
<span slot="content" class="overflow-label disabled">
<span slot="content" class="overflow-label disabled" class:dark-color={selectedItem === undefined}>
{#if selectedItem}{selectedItem.label}{:else}<Label label={label ?? ui.string.NotSelected} />{/if}
</span>
</Button>

View File

@ -272,6 +272,7 @@
adaptValue()
</script>
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<button
bind:this={datePresenter}
class="datetime-button {kind}"
@ -292,7 +293,7 @@
>
{#if edits[0].value > -1}
{edits[0].value.toString().padStart(2, '0')}
{:else}ДД{/if}
{:else}DD{/if}
</span>
<span class="separator">.</span>
<span
@ -305,7 +306,7 @@
>
{#if edits[1].value > -1}
{edits[1].value.toString().padStart(2, '0')}
{:else}ММ{/if}
{:else}MM{/if}
</span>
<span class="separator">.</span>
<span
@ -318,7 +319,7 @@
>
{#if edits[2].value > -1}
{edits[2].value.toString().padStart(4, '0')}
{:else}ГГГГ{/if}
{:else}YYYY{/if}
</span>
{#if withTime}
<div class="time-divider" />
@ -332,7 +333,7 @@
>
{#if edits[3].value > -1}
{edits[3].value.toString().padStart(2, '0')}
{:else}ЧЧ{/if}
{:else}HH{/if}
</span>
<span class="separator">:</span>
<span
@ -345,10 +346,11 @@
>
{#if edits[4].value > -1}
{edits[4].value.toString().padStart(2, '0')}
{:else}ММ{/if}
{:else}MM{/if}
</span>
{/if}
{#if value}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
bind:this={closeBtn}
class="close-btn"
@ -388,7 +390,9 @@
{/if}
{/if}
{:else}
<div class="dark-color">
<Label label={labelNull} />
</div>
{/if}
{/if}
</button>
@ -502,8 +506,8 @@
padding: 0 0.875rem;
width: 100%;
height: 2rem;
&:hover {
color: var(--caption-color);
&:hover {
background-color: var(--body-color);
border-color: var(--divider-color);
.btn-icon {

View File

@ -37,6 +37,7 @@
{justify}
allowDeselect
{width}
autoSelect={false}
focus={false}
bind:space={value}
on:change={(e) => onChange(e.detail)}

View File

@ -62,6 +62,10 @@
"ImportEnumCopy": "Copy enum values from clipboard",
"CreateMixin": "Create Mixin",
"OldNames": "Old values",
"NewClassName": "Type new class name or select from previous values..."
"NewClassName": "Type new class name or select from previous values...",
"ShowAttribute": "Show attribute",
"HideAttribute": "Hide attribute",
"Visibility": "Visibility",
"Hidden": "Hidden"
}
}

View File

@ -62,6 +62,11 @@
"ImportEnumCopy": "Загрузить значения справочника из буфера обмена",
"CreateMixin": "Создать Миксин",
"OldNames": "Предыдушие значения",
"NewClassName": "Введите новое имя класса или выберете прошлое значение..."
"NewClassName": "Введите новое имя класса или выберете прошлое значение...",
"ShowAttribute": "Hide",
"HideAttribute": "Show",
"Visibility": "Видимость",
"Hidden": "Спрятанный"
}
}

View File

@ -26,7 +26,7 @@
RefTo,
Type
} from '@hcengineering/core'
import { IntlString } from '@hcengineering/platform'
import { getResource, IntlString } from '@hcengineering/platform'
import presentation, { createQuery, getClient, MessageBox } from '@hcengineering/presentation'
import {
Action,
@ -44,10 +44,12 @@
showPopup
} from '@hcengineering/ui'
import view from '@hcengineering/view'
import { getContextActions } from '@hcengineering/view-resources/src/actions'
import settings from '../plugin'
import CreateAttribute from './CreateAttribute.svelte'
import EditAttribute from './EditAttribute.svelte'
import EditClassLabel from './EditClassLabel.svelte'
export let _class: Ref<Class<Doc>>
const client = getClient()
@ -65,10 +67,16 @@
function getCustomAttributes (_class: Ref<Class<Doc>>): AnyAttribute[] {
const cl = hierarchy.getClass(_class)
const attributes = Array.from(hierarchy.getAllAttributes(_class, cl.extends).values())
const filtred = attributes.filter((p) => !p.hidden)
return filtred
// const filtred = attributes.filter((p) => !p.hidden)
return attributes
}
const attrQuery = createQuery()
$: attrQuery.query(core.class.Attribute, { attributeOf: _class }, () => {
attributes = getCustomAttributes(_class)
})
function update () {
attributes = getCustomAttributes(_class)
}
@ -108,15 +116,28 @@
action: async () => {
editAttribute(attribute, exist)
}
},
{
}
]
if (attribute.isCustom) {
actions.push({
label: presentation.string.Remove,
icon: IconDelete,
action: async () => {
removeAttribute(attribute, exist)
}
})
}
]
const extra = await getContextActions(client, attribute, { mode: 'context' })
actions.push(
...extra.map((it) => ({
label: it.label,
icon: it.icon,
action: async (_: any, evt: Event) => {
const r = await getResource(it.action)
r(attribute, evt, it.actionProps)
}
}))
)
showPopup(Menu, { actions }, getEventPositionElement(ev), () => {})
}
@ -179,6 +200,11 @@
<Label label={settings.string.Type} />
</div>
</th>
<th>
<div class="antiTable-cells">
<Label label={settings.string.Visibility} />
</div>
</th>
<th>
<div class="antiTable-cells">
<Label label={settings.string.Custom} />
@ -192,23 +218,17 @@
<tr
class="antiTable-body__row"
on:contextmenu={(ev) => {
if (attr.isCustom) {
ev.preventDefault()
showMenu(ev, attr)
}
}}
>
<!-- <td class='select-text'>
{attr.name}
</td> -->
<td>
<div class="antiTable-cells__firstCell">
<Label label={attr.label} />
{#if attr.isCustom}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div id="context-menu" class="antiTable-cells__firstCell-menuRow" on:click={(ev) => showMenu(ev, attr)}>
<IconMoreV size={'small'} />
</div>
{/if}
</div>
</td>
<td class="select-text">
@ -224,6 +244,11 @@
{/await}
{/if}
</td>
<td>
{#if attr.hidden}
<Label label={settings.string.Hidden} />
{/if}
</td>
<td>
<Component is={view.component.BooleanTruePresenter} props={{ value: attr.isCustom ?? false }} />
</td>

View File

@ -52,6 +52,7 @@
{#each classes as cl}
{@const clazz = hierarchy.getClass(cl)}
{@const desc = getDescendants(cl)}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
class="ac-column__list-item"
class:ac-column__list-selected={cl === _class}

View File

@ -66,6 +66,7 @@
</div>
<div class="overflow-y-auto">
{#each enums as value}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
class="ac-column__list-item"
class:selected={selected === value}

View File

@ -41,6 +41,7 @@
</div>
<div class="flex-col overflow-y-auto">
{#each folders as f (f._id)}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="flex-between item" class:selected={f._id === folder?._id} on:click={() => select(f)}>
<div class="icon flex-no-shrink mr-4">
<Component is={f.icon} />

View File

@ -112,6 +112,7 @@
</div>
<div id="templates" class="flex-col overflow-y-auto">
{#each templates as t (t._id)}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="ac-column__list-item" class:selected={t._id === template?._id} on:click={() => select(t)}>
<AttributeEditor maxWidth={'15rem'} _class={task.class.KanbanTemplate} object={t} key="title" />
{#if templates.length > 1}

View File

@ -56,6 +56,10 @@ export default mergeIds(settingId, setting, {
ImportEnumCopy: '' as IntlString,
CreateMixin: '' as IntlString,
OldNames: '' as IntlString,
NewClassName: '' as IntlString
NewClassName: '' as IntlString,
HideAttribute: '' as IntlString,
ShowAttribute: '' as IntlString,
Visibility: '' as IntlString,
Hidden: '' as IntlString
}
})

View File

@ -50,9 +50,8 @@
}}
>
<div class="color" style:background-color={getPlatformColor(value.color ?? 0)} />
<span class="overflow-label ml-1-5 caption-color"
>{value.title}-
<Icon icon={tagIcon} size={'small'} />
<span class="overflow-label ml-1-5 caption-color">
{value.title}
</span>
{#if isEditable}
<button class="btn-close" on:click|stopPropagation={() => dispatch('remove', value.tag)}>

View File

@ -15,7 +15,7 @@
<script lang="ts">
import core, { Class, Doc, Ref } from '@hcengineering/core'
import { IntlString } from '@hcengineering/platform'
import { AttributesBar, getClient, KeyedAttribute } from '@hcengineering/presentation'
import { AttributesBar, getAttribute, getClient, KeyedAttribute } from '@hcengineering/presentation'
import setting, { settingId } from '@hcengineering/setting'
import { Button, getCurrentLocation, Label, navigate } from '@hcengineering/ui'
import { getFiltredKeys, isCollectionAttr } from '../utils'
@ -27,7 +27,6 @@
export let allowedCollections: string[] = []
export let readonly = false
export let showLabel: IntlString | undefined = undefined
export let defaultCollapsed = false
export let draft = false
export let showHeader: boolean = true
@ -35,7 +34,6 @@
const hierarchy = client.getHierarchy()
let keys: KeyedAttribute[] = []
let collapsed: boolean = defaultCollapsed
function updateKeys (_class: Ref<Class<Doc>>, ignoreKeys: string[], to: Ref<Class<Doc>> | undefined): void {
const filtredKeys = getFiltredKeys(hierarchy, _class, ignoreKeys, to)
@ -44,7 +42,15 @@
$: updateKeys(_class, ignoreKeys, to)
$: nonEmpty = keys.find((it) => getAttribute(client, object, it) != null)
$: label = showLabel ?? hierarchy.getClass(_class).label
function getCollapsed (_class: Ref<Class<Doc>>, nonEmpty?: KeyedAttribute): boolean {
return nonEmpty === undefined
}
$: collapsed = getCollapsed(_class, nonEmpty)
</script>
<!-- svelte-ignore a11y-click-events-have-key-events -->

View File

@ -31,6 +31,8 @@
{#each mixins as mixin}
{@const to = !hierarchy.hasMixin(mixin, setting.mixin.UserMixin) ? object._class : mixin.extends}
{#if !hierarchy.hasMixin(mixin, setting.mixin.Editable) || hierarchy.as(mixin, setting.mixin.Editable).value}
{#key mixin._id}
<ClassAttributeBar _class={mixin._id} {object} {ignoreKeys} {to} {allowedCollections} on:update />
{/key}
{/if}
{/each}

View File

@ -88,11 +88,15 @@
function getMixins (parentClass: Ref<Class<Doc>>, object: Doc, showAllMixins: boolean): void {
if (object === undefined || parentClass === undefined) return
const descendants = hierarchy.getDescendants(parentClass).map((p) => hierarchy.getClass(p))
mixins = descendants.filter(
(m) =>
m.kind === ClassifierKind.MIXIN &&
!ignoreMixins.has(m._id) &&
(hierarchy.hasMixin(object, m._id) || showAllMixins)
(hierarchy.hasMixin(object, m._id) ||
(showAllMixins &&
// hierarchy.isDerived(hierarchy.getBaseClass(m._id), realObjectClass)
hierarchy.isDerived(realObjectClass, hierarchy.getBaseClass(m._id))))
)
}

View File

@ -46,6 +46,11 @@
bind:selected={value}
{items}
{label}
useFlexGrow={true}
justify={'left'}
size={'large'}
kind={'link'}
width={'100%'}
autoSelect={false}
on:selected={(e) => {
onChange(e.detail)

View File

@ -33,6 +33,7 @@
}
</script>
<!-- svelte-ignore a11y-click-events-have-key-events -->
{#if kind === 'link'}
<div
class="link-container"
@ -74,9 +75,9 @@
border: 1px solid transparent;
border-radius: 0.25rem;
cursor: pointer;
color: var(--caption-color);
&:hover {
color: var(--caption-color);
background-color: var(--body-color);
border-color: var(--divider-color);
}

View File

@ -176,7 +176,7 @@ class ElasticDataAdapter implements DbAdapter {
)
const operations = part.flatMap((doc) => [
{ index: { _index: this.workspaceId, _id: doc._id } },
{ index: { _index: toWorkspaceString(this.workspaceId), _id: doc._id } },
(doc as FullTextData).data
])