mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-15 04:49:00 +00:00
Vacancy configure (#1962)
Signed-off-by: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com>
This commit is contained in:
parent
a4353b0fc7
commit
c6ff5f19ec
@ -10,6 +10,10 @@ Platform:
|
||||
- Fix skills/labels selection and show real usage counter
|
||||
- Fix skills/labels activity
|
||||
|
||||
HR:
|
||||
|
||||
- Allow to configure vacancy table
|
||||
|
||||
## 0.6.22
|
||||
|
||||
Platform:
|
||||
|
@ -201,7 +201,7 @@ export function createModel (builder: Builder): void {
|
||||
editor: contact.component.PersonEditor
|
||||
})
|
||||
|
||||
builder.mixin(contact.class.Channel, core.class.Class, view.mixin.AttributePresenter, {
|
||||
builder.mixin(contact.class.Channel, core.class.Class, view.mixin.CollectionPresenter, {
|
||||
presenter: contact.component.ChannelsPresenter
|
||||
})
|
||||
|
||||
|
@ -134,10 +134,6 @@ export function createModel (builder: Builder): void {
|
||||
}
|
||||
})
|
||||
|
||||
builder.mixin(core.class.Space, core.class.Class, view.mixin.AttributePresenter, {
|
||||
presenter: recruit.component.VacancyItemPresenter
|
||||
})
|
||||
|
||||
builder.mixin(recruit.class.Applicant, core.class.Class, view.mixin.CollectionEditor, {
|
||||
editor: recruit.component.Applications
|
||||
})
|
||||
@ -269,6 +265,26 @@ export function createModel (builder: Builder): void {
|
||||
hiddenKeys: ['name']
|
||||
})
|
||||
|
||||
builder.createDoc(view.class.Viewlet, core.space.Model, {
|
||||
attachTo: recruit.class.Vacancy,
|
||||
descriptor: view.viewlet.Table,
|
||||
config: [
|
||||
'',
|
||||
{
|
||||
key: '@applications',
|
||||
label: recruit.string.Applications
|
||||
},
|
||||
'$lookup.company',
|
||||
'location',
|
||||
'description',
|
||||
{
|
||||
key: '@applications.modifiedOn',
|
||||
label: core.string.Modified
|
||||
}
|
||||
],
|
||||
hiddenKeys: ['name', 'space', 'modifiedOn']
|
||||
})
|
||||
|
||||
builder.createDoc(view.class.Viewlet, core.space.Model, {
|
||||
attachTo: recruit.class.Applicant,
|
||||
descriptor: task.viewlet.StatusTable,
|
||||
|
@ -16,10 +16,10 @@
|
||||
<script lang="ts">
|
||||
import { Doc, DocumentQuery } from '@anticrm/core'
|
||||
import { createQuery, getClient } from '@anticrm/presentation'
|
||||
import { Tooltip, Button, Icon, IconAdd, Label, Loading, SearchEdit, showPopup } from '@anticrm/ui'
|
||||
import view, { Viewlet, ViewletPreference } from '@anticrm/view'
|
||||
import { Button, Icon, IconAdd, Label, Loading, SearchEdit, showPopup } from '@anticrm/ui'
|
||||
import type { Filter } from '@anticrm/view'
|
||||
import { ActionContext, TableBrowser, ViewletSetting, FilterButton } from '@anticrm/view-resources'
|
||||
import view, { Viewlet, ViewletPreference } from '@anticrm/view'
|
||||
import { ActionContext, FilterButton, TableBrowser, ViewletSettingButton } from '@anticrm/view-resources'
|
||||
import contact from '../plugin'
|
||||
import CreateContact from './CreateContact.svelte'
|
||||
|
||||
@ -90,17 +90,7 @@
|
||||
kind={'primary'}
|
||||
on:click={(ev) => showCreateDialog(ev)}
|
||||
/>
|
||||
{#if viewlet}
|
||||
<Tooltip label={view.string.CustomizeView}>
|
||||
<Button
|
||||
icon={view.icon.Setting}
|
||||
kind={'transparent'}
|
||||
on:click={() => {
|
||||
showPopup(ViewletSetting, { viewlet })
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
<ViewletSettingButton {viewlet} />
|
||||
</div>
|
||||
|
||||
{#if viewlet}
|
||||
|
@ -14,23 +14,22 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { createQuery, getClient } from '@anticrm/presentation'
|
||||
import ui, {
|
||||
Button,
|
||||
EditWithIcon,
|
||||
eventToHTMLElement,
|
||||
Icon,
|
||||
IconAdd,
|
||||
IconSearch,
|
||||
Label,
|
||||
showPopup,
|
||||
IconAdd,
|
||||
eventToHTMLElement,
|
||||
Loading,
|
||||
Tooltip
|
||||
showPopup
|
||||
} from '@anticrm/ui'
|
||||
import CreateProduct from './CreateProduct.svelte'
|
||||
import inventory from '../plugin'
|
||||
import { TableBrowser, ViewletSetting } from '@anticrm/view-resources'
|
||||
import { createQuery, getClient } from '@anticrm/presentation'
|
||||
import view, { Viewlet, ViewletPreference } from '@anticrm/view'
|
||||
import { TableBrowser, ViewletSettingButton } from '@anticrm/view-resources'
|
||||
import inventory from '../plugin'
|
||||
import CreateProduct from './CreateProduct.svelte'
|
||||
|
||||
let search = ''
|
||||
$: resultQuery = search === '' ? {} : { $search: search }
|
||||
@ -89,17 +88,7 @@
|
||||
kind={'primary'}
|
||||
on:click={(ev) => showCreateDialog(ev)}
|
||||
/>
|
||||
{#if descr}
|
||||
<Tooltip label={view.string.CustomizeView}>
|
||||
<Button
|
||||
icon={view.icon.Setting}
|
||||
kind={'transparent'}
|
||||
on:click={() => {
|
||||
showPopup(ViewletSetting, { viewlet: descr })
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
<ViewletSettingButton viewlet={descr} />
|
||||
</div>
|
||||
|
||||
{#if descr}
|
||||
|
@ -16,9 +16,9 @@
|
||||
<script lang="ts">
|
||||
import { Doc, DocumentQuery } from '@anticrm/core'
|
||||
import { createQuery, getClient } from '@anticrm/presentation'
|
||||
import { Tooltip, Button, Icon, Label, Loading, showPopup, SearchEdit } from '@anticrm/ui'
|
||||
import { Icon, Label, Loading, SearchEdit } from '@anticrm/ui'
|
||||
import view, { Viewlet, ViewletPreference } from '@anticrm/view'
|
||||
import { ViewletSetting, TableBrowser } from '@anticrm/view-resources'
|
||||
import { TableBrowser, ViewletSettingButton } from '@anticrm/view-resources'
|
||||
import lead from '../plugin'
|
||||
|
||||
let search = ''
|
||||
@ -70,17 +70,7 @@
|
||||
updateResultQuery(search)
|
||||
}}
|
||||
/>
|
||||
{#if descr}
|
||||
<Tooltip label={view.string.CustomizeView}>
|
||||
<Button
|
||||
icon={view.icon.Setting}
|
||||
kind={'transparent'}
|
||||
on:click={() => {
|
||||
showPopup(ViewletSetting, { viewlet: descr })
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
<ViewletSettingButton viewlet={descr} />
|
||||
</div>
|
||||
|
||||
{#if descr}
|
||||
|
@ -17,10 +17,10 @@
|
||||
import { createQuery, getClient } from '@anticrm/presentation'
|
||||
import { Applicant } from '@anticrm/recruit'
|
||||
import task from '@anticrm/task'
|
||||
import { Tooltip, Button, Icon, IconAdd, Label, Loading, SearchEdit, showPopup } from '@anticrm/ui'
|
||||
import view, { Viewlet, ViewletPreference } from '@anticrm/view'
|
||||
import { Button, Icon, IconAdd, Label, Loading, SearchEdit, showPopup } from '@anticrm/ui'
|
||||
import type { Filter } from '@anticrm/view'
|
||||
import { TableBrowser, ViewletSetting, FilterButton } from '@anticrm/view-resources'
|
||||
import view, { Viewlet, ViewletPreference } from '@anticrm/view'
|
||||
import { FilterButton, TableBrowser, ViewletSettingButton } from '@anticrm/view-resources'
|
||||
import recruit from '../plugin'
|
||||
import CreateApplication from './CreateApplication.svelte'
|
||||
|
||||
@ -83,17 +83,7 @@
|
||||
}}
|
||||
/>
|
||||
<Button icon={IconAdd} label={recruit.string.ApplicationCreateLabel} kind={'primary'} on:click={showCreateDialog} />
|
||||
{#if descr}
|
||||
<Tooltip label={view.string.CustomizeView}>
|
||||
<Button
|
||||
icon={view.icon.Setting}
|
||||
kind={'transparent'}
|
||||
on:click={() => {
|
||||
showPopup(ViewletSetting, { viewlet: descr })
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
<ViewletSettingButton viewlet={descr} />
|
||||
</div>
|
||||
|
||||
{#if descr}
|
||||
|
@ -17,10 +17,10 @@
|
||||
import contact from '@anticrm/contact'
|
||||
import { Doc, DocumentQuery } from '@anticrm/core'
|
||||
import { createQuery, getClient } from '@anticrm/presentation'
|
||||
import { Tooltip, showPopup, Icon, Label, Loading, SearchEdit, Button, IconAdd } from '@anticrm/ui'
|
||||
import view, { Viewlet, ViewletPreference } from '@anticrm/view'
|
||||
import { Button, Icon, IconAdd, Label, Loading, SearchEdit, showPopup } from '@anticrm/ui'
|
||||
import type { Filter } from '@anticrm/view'
|
||||
import { ActionContext, TableBrowser, ViewletSetting, FilterButton } from '@anticrm/view-resources'
|
||||
import view, { Viewlet, ViewletPreference } from '@anticrm/view'
|
||||
import { ActionContext, FilterButton, TableBrowser, ViewletSettingButton } from '@anticrm/view-resources'
|
||||
import recruit from '../plugin'
|
||||
import CreateCandidate from './CreateCandidate.svelte'
|
||||
|
||||
@ -83,17 +83,7 @@
|
||||
}}
|
||||
/>
|
||||
<Button icon={IconAdd} label={recruit.string.CandidateCreateLabel} kind={'primary'} on:click={showCreateDialog} />
|
||||
{#if descr}
|
||||
<Tooltip label={view.string.CustomizeView}>
|
||||
<Button
|
||||
icon={view.icon.Setting}
|
||||
kind={'transparent'}
|
||||
on:click={() => {
|
||||
showPopup(ViewletSetting, { viewlet: descr })
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
<ViewletSettingButton viewlet={descr} />
|
||||
</div>
|
||||
|
||||
<ActionContext
|
||||
|
@ -14,20 +14,14 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import core, { Doc, DocumentQuery, Ref } from '@anticrm/core'
|
||||
import { createQuery } from '@anticrm/presentation'
|
||||
import { createQuery, getClient } from '@anticrm/presentation'
|
||||
import { Vacancy } from '@anticrm/recruit'
|
||||
import { Button, getCurrentLocation, Icon, IconAdd, Label, navigate, SearchEdit, showPopup } from '@anticrm/ui'
|
||||
import { TableBrowser } from '@anticrm/view-resources'
|
||||
import { Button, Icon, IconAdd, Label, Loading, SearchEdit, showPopup } from '@anticrm/ui'
|
||||
import view, { BuildModelKey, Filter, Viewlet, ViewletPreference } from '@anticrm/view'
|
||||
import { FilterButton, TableBrowser, ViewletSettingButton } from '@anticrm/view-resources'
|
||||
import recruit from '../plugin'
|
||||
import CreateVacancy from './CreateVacancy.svelte'
|
||||
|
||||
function action (vacancy: Ref<Vacancy>): void {
|
||||
const loc = getCurrentLocation()
|
||||
loc.path[2] = vacancy
|
||||
loc.path.length = 3
|
||||
navigate(loc)
|
||||
}
|
||||
|
||||
let search: string = ''
|
||||
let resultQuery: DocumentQuery<Doc> = {}
|
||||
|
||||
@ -69,12 +63,82 @@
|
||||
const modifiedSorting = (a: Doc, b: Doc) =>
|
||||
(applications?.get(b._id as Ref<Vacancy>)?.modifiedOn ?? 0) -
|
||||
(applications?.get(a._id as Ref<Vacancy>)?.modifiedOn ?? 0) ?? 0
|
||||
|
||||
const replacedKeys: Map<string, BuildModelKey> = new Map<string, BuildModelKey>([
|
||||
[
|
||||
'@applications',
|
||||
{
|
||||
key: '@applications',
|
||||
presenter: recruit.component.VacancyCountPresenter,
|
||||
label: recruit.string.Applications,
|
||||
props: { applications },
|
||||
sortingKey: '@applications',
|
||||
sortingFunction: applicationSorting
|
||||
}
|
||||
],
|
||||
[
|
||||
'@applications.modifiedOn',
|
||||
{
|
||||
key: '',
|
||||
presenter: recruit.component.VacancyModifiedPresenter,
|
||||
label: core.string.Modified,
|
||||
props: { applications },
|
||||
sortingKey: 'modifiedOn',
|
||||
sortingFunction: modifiedSorting
|
||||
}
|
||||
]
|
||||
])
|
||||
|
||||
const client = getClient()
|
||||
let filters: Filter[] = []
|
||||
|
||||
let descr: Viewlet | undefined
|
||||
let loading = true
|
||||
|
||||
const preferenceQuery = createQuery()
|
||||
let preference: ViewletPreference | undefined
|
||||
|
||||
client
|
||||
.findOne<Viewlet>(view.class.Viewlet, {
|
||||
attachTo: recruit.class.Vacancy,
|
||||
descriptor: view.viewlet.Table
|
||||
})
|
||||
.then((res) => {
|
||||
descr = res
|
||||
if (res !== undefined) {
|
||||
preferenceQuery.query(
|
||||
view.class.ViewletPreference,
|
||||
{
|
||||
attachedTo: res._id
|
||||
},
|
||||
(res) => {
|
||||
preference = res[0]
|
||||
loading = false
|
||||
},
|
||||
{ limit: 1 }
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
function createConfig (descr: Viewlet, preference: ViewletPreference | undefined): (string | BuildModelKey)[] {
|
||||
const base = preference?.config ?? descr.config
|
||||
const result: (string | BuildModelKey)[] = []
|
||||
for (const key of base) {
|
||||
if (typeof key === 'string') {
|
||||
result.push(replacedKeys.get(key) ?? key)
|
||||
} else {
|
||||
result.push(replacedKeys.get(key.key) ?? key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="ac-header full">
|
||||
<div class="ac-header__wrap-title">
|
||||
<div class="ac-header__icon"><Icon icon={recruit.icon.Vacancy} size={'small'} /></div>
|
||||
<span class="ac-header__title"><Label label={recruit.string.Vacancies} /></span>
|
||||
<div class="ml-4"><FilterButton _class={recruit.mixin.Candidate} bind:filters /></div>
|
||||
</div>
|
||||
<SearchEdit
|
||||
bind:value={search}
|
||||
@ -83,40 +147,22 @@
|
||||
}}
|
||||
/>
|
||||
<Button icon={IconAdd} label={recruit.string.VacancyCreateLabel} kind={'primary'} on:click={showCreateDialog} />
|
||||
<ViewletSettingButton viewlet={descr} />
|
||||
</div>
|
||||
<TableBrowser
|
||||
_class={recruit.class.Vacancy}
|
||||
config={[
|
||||
{
|
||||
key: '',
|
||||
presenter: recruit.component.VacancyItemPresenter,
|
||||
label: recruit.string.Vacancy,
|
||||
sortingKey: 'name',
|
||||
props: { action }
|
||||
},
|
||||
{
|
||||
key: '',
|
||||
presenter: recruit.component.VacancyCountPresenter,
|
||||
label: recruit.string.Applications,
|
||||
props: { applications },
|
||||
sortingKey: '@applications',
|
||||
sortingFunction: applicationSorting
|
||||
},
|
||||
'$lookup.company',
|
||||
'location',
|
||||
'description',
|
||||
{
|
||||
key: '',
|
||||
presenter: recruit.component.VacancyModifiedPresenter,
|
||||
label: core.string.Modified,
|
||||
props: { applications },
|
||||
sortingKey: 'modifiedOn',
|
||||
sortingFunction: modifiedSorting
|
||||
}
|
||||
]}
|
||||
query={{
|
||||
...resultQuery,
|
||||
archived: false
|
||||
}}
|
||||
showNotification
|
||||
/>
|
||||
{#if descr}
|
||||
{#if loading}
|
||||
<Loading />
|
||||
{:else}
|
||||
<TableBrowser
|
||||
_class={recruit.class.Vacancy}
|
||||
config={createConfig(descr, preference)}
|
||||
options={descr.options}
|
||||
query={{
|
||||
...resultQuery,
|
||||
archived: false
|
||||
}}
|
||||
bind:filters
|
||||
showNotification
|
||||
/>
|
||||
{/if}
|
||||
{/if}
|
||||
|
@ -15,23 +15,54 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { Vacancy } from '@anticrm/recruit'
|
||||
import { Icon } from '@anticrm/ui'
|
||||
import { getPanelURI } from '@anticrm/ui/src/panelup'
|
||||
import {
|
||||
ActionIcon,
|
||||
getCurrentLocation,
|
||||
Icon,
|
||||
IconEdit,
|
||||
Location,
|
||||
locationToUrl,
|
||||
navigate,
|
||||
showPanel
|
||||
} from '@anticrm/ui'
|
||||
import recruit from '../plugin'
|
||||
|
||||
export let value: Vacancy
|
||||
export let inline: boolean = false
|
||||
|
||||
function editVacancy (): void {
|
||||
showPanel(recruit.component.EditVacancy, value._id, value._class, 'content')
|
||||
}
|
||||
|
||||
function getLoc (): Location {
|
||||
const loc = getCurrentLocation()
|
||||
loc.path[2] = value._id
|
||||
loc.path.length = 3
|
||||
return loc
|
||||
}
|
||||
|
||||
function getLink (): string {
|
||||
const loc = getLoc()
|
||||
return document.location.origin + locationToUrl(loc)
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if value}
|
||||
<a
|
||||
class="flex-presenter"
|
||||
class:inline-presenter={inline}
|
||||
href="#{getPanelURI(recruit.component.EditVacancy, value._id, value._class, 'content')}"
|
||||
>
|
||||
<div class="flex-presenter" class:inline-presenter={inline}>
|
||||
<div class="icon">
|
||||
<Icon icon={recruit.icon.Vacancy} size={'small'} />
|
||||
</div>
|
||||
<span class="label">{value.name}</span>
|
||||
</a>
|
||||
<a
|
||||
on:click|preventDefault={(e) => {
|
||||
navigate(getLoc())
|
||||
e.preventDefault()
|
||||
}}
|
||||
href={getLink()}
|
||||
>
|
||||
<span class="label">{value.name}</span>
|
||||
</a>
|
||||
<div class="action">
|
||||
<ActionIcon label={recruit.string.Edit} size={'small'} icon={IconEdit} action={editVacancy} />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -43,7 +43,7 @@
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
|
||||
$: lookup = buildConfigLookup(hierarchy, _class, config)
|
||||
$: lookup = options?.lookup ?? buildConfigLookup(hierarchy, _class, config)
|
||||
|
||||
let sortKey = 'modifiedOn'
|
||||
let sortOrder = SortingOrder.Descending
|
||||
|
@ -102,27 +102,26 @@
|
||||
|
||||
const allAttributes = hierarchy.getAllAttributes(viewlet.attachTo)
|
||||
for (const [, attribute] of allAttributes) {
|
||||
if (attribute.hidden === true || attribute.label === undefined) continue
|
||||
if (viewlet.hiddenKeys?.includes(attribute.name)) continue
|
||||
if (hierarchy.isDerived(attribute.type._class, core.class.Collection)) continue
|
||||
const value = getValue(attribute.name, attribute.type)
|
||||
if (result.findIndex((p) => p.value === value) !== -1) continue
|
||||
if (hierarchy.isDerived(attribute.type._class, core.class.Collection)) continue
|
||||
if (viewlet.hiddenKeys?.includes(value)) continue
|
||||
if (attribute.hidden !== true && attribute.label !== undefined) {
|
||||
const typeClassId = getAttributePresenterClass(attribute)
|
||||
const typeClass = hierarchy.getClass(typeClassId)
|
||||
let presenter = hierarchy.as(typeClass, view.mixin.AttributePresenter).presenter
|
||||
let parent = typeClass.extends
|
||||
while (presenter === undefined && parent !== undefined) {
|
||||
const pclazz = hierarchy.getClass(parent)
|
||||
presenter = hierarchy.as(pclazz, view.mixin.AttributePresenter).presenter
|
||||
parent = pclazz.extends
|
||||
}
|
||||
if (presenter === undefined) continue
|
||||
result.push({
|
||||
value,
|
||||
label: attribute.label,
|
||||
enabled: false
|
||||
})
|
||||
const typeClassId = getAttributePresenterClass(attribute)
|
||||
const typeClass = hierarchy.getClass(typeClassId)
|
||||
let presenter = hierarchy.as(typeClass, view.mixin.AttributePresenter).presenter
|
||||
let parent = typeClass.extends
|
||||
while (presenter === undefined && parent !== undefined) {
|
||||
const pclazz = hierarchy.getClass(parent)
|
||||
presenter = hierarchy.as(pclazz, view.mixin.AttributePresenter).presenter
|
||||
parent = pclazz.extends
|
||||
}
|
||||
if (presenter === undefined) continue
|
||||
result.push({
|
||||
value,
|
||||
label: attribute.label,
|
||||
enabled: false
|
||||
})
|
||||
}
|
||||
|
||||
return preference === undefined ? result : setStatus(result, preference)
|
||||
|
@ -0,0 +1,34 @@
|
||||
<!--
|
||||
// Copyright © 2022 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Button, showPopup, Tooltip } from '@anticrm/ui'
|
||||
import { Viewlet } from '@anticrm/view'
|
||||
import ViewletSetting from './ViewletSetting.svelte'
|
||||
import view from '../plugin'
|
||||
|
||||
export let viewlet: Viewlet | undefined
|
||||
</script>
|
||||
|
||||
{#if viewlet}
|
||||
<Tooltip label={view.string.CustomizeView}>
|
||||
<Button
|
||||
icon={view.icon.Setting}
|
||||
kind={'transparent'}
|
||||
on:click={() => {
|
||||
showPopup(ViewletSetting, { viewlet })
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
{/if}
|
@ -16,40 +16,40 @@
|
||||
import { Resources } from '@anticrm/platform'
|
||||
import { getEventPopupPositionElement, PopupAlignment } from '@anticrm/ui'
|
||||
import { actionImpl } from './actionImpl'
|
||||
import ActionsPopup from './components/ActionsPopup.svelte'
|
||||
import BooleanEditor from './components/BooleanEditor.svelte'
|
||||
import BooleanPresenter from './components/BooleanPresenter.svelte'
|
||||
import BooleanTruePresenter from './components/BooleanTruePresenter.svelte'
|
||||
import ClassAttributeBar from './components/ClassAttributeBar.svelte'
|
||||
import ClassPresenter from './components/ClassPresenter.svelte'
|
||||
import ColorsPopup from './components/ColorsPopup.svelte'
|
||||
import DateEditor from './components/DateEditor.svelte'
|
||||
import DatePresenter from './components/DatePresenter.svelte'
|
||||
import SpacePresenter from './components/SpacePresenter.svelte'
|
||||
import StringEditor from './components/StringEditor.svelte'
|
||||
import StringPresenter from './components/StringPresenter.svelte'
|
||||
import DocAttributeBar from './components/DocAttributeBar.svelte'
|
||||
import EditBoxPopup from './components/EditBoxPopup.svelte'
|
||||
import EditDoc from './components/EditDoc.svelte'
|
||||
import EnumEditor from './components/EnumEditor.svelte'
|
||||
import FilterBar from './components/filter/FilterBar.svelte'
|
||||
import ObjectFilter from './components/filter/ObjectFilter.svelte'
|
||||
import TimestampFilter from './components/filter/TimestampFilter.svelte'
|
||||
import ValueFilter from './components/filter/ValueFilter.svelte'
|
||||
import HTMLPresenter from './components/HTMLPresenter.svelte'
|
||||
import IntlStringPresenter from './components/IntlStringPresenter.svelte'
|
||||
import GithubPresenter from './components/linkPresenters/GithubPresenter.svelte'
|
||||
import YoutubePresenter from './components/linkPresenters/YoutubePresenter.svelte'
|
||||
import Menu from './components/Menu.svelte'
|
||||
import NumberEditor from './components/NumberEditor.svelte'
|
||||
import NumberPresenter from './components/NumberPresenter.svelte'
|
||||
import ObjectPresenter from './components/ObjectPresenter.svelte'
|
||||
import RolePresenter from './components/RolePresenter.svelte'
|
||||
import SpacePresenter from './components/SpacePresenter.svelte'
|
||||
import StringEditor from './components/StringEditor.svelte'
|
||||
import StringPresenter from './components/StringPresenter.svelte'
|
||||
import Table from './components/Table.svelte'
|
||||
import TableBrowser from './components/TableBrowser.svelte'
|
||||
import TimestampPresenter from './components/TimestampPresenter.svelte'
|
||||
import UpDownNavigator from './components/UpDownNavigator.svelte'
|
||||
import GithubPresenter from './components/linkPresenters/GithubPresenter.svelte'
|
||||
import YoutubePresenter from './components/linkPresenters/YoutubePresenter.svelte'
|
||||
import ActionsPopup from './components/ActionsPopup.svelte'
|
||||
import DocAttributeBar from './components/DocAttributeBar.svelte'
|
||||
import ViewletSetting from './components/ViewletSetting.svelte'
|
||||
import TableBrowser from './components/TableBrowser.svelte'
|
||||
import ValueFilter from './components/filter/ValueFilter.svelte'
|
||||
import ObjectFilter from './components/filter/ObjectFilter.svelte'
|
||||
import TimestampFilter from './components/filter/TimestampFilter.svelte'
|
||||
import ClassPresenter from './components/ClassPresenter.svelte'
|
||||
import FilterBar from './components/filter/FilterBar.svelte'
|
||||
import EditBoxPopup from './components/EditBoxPopup.svelte'
|
||||
import BooleanTruePresenter from './components/BooleanTruePresenter.svelte'
|
||||
import EnumEditor from './components/EnumEditor.svelte'
|
||||
import ClassAttributeBar from './components/ClassAttributeBar.svelte'
|
||||
import ViewletSettingButton from './components/ViewletSettingButton.svelte'
|
||||
|
||||
function PositionElementAlignment (e?: Event): PopupAlignment | undefined {
|
||||
return getEventPopupPositionElement(e)
|
||||
@ -58,10 +58,10 @@ function PositionElementAlignment (e?: Event): PopupAlignment | undefined {
|
||||
export { getActions, invokeAction } from './actions'
|
||||
export { default as ActionContext } from './components/ActionContext.svelte'
|
||||
export { default as ActionHandler } from './components/ActionHandler.svelte'
|
||||
export { default as FilterButton } from './components/filter/FilterButton.svelte'
|
||||
export { default as LinkPresenter } from './components/LinkPresenter.svelte'
|
||||
export { default as ContextMenu } from './components/Menu.svelte'
|
||||
export { default as TableBrowser } from './components/TableBrowser.svelte'
|
||||
export { default as LinkPresenter } from './components/LinkPresenter.svelte'
|
||||
export { default as FilterButton } from './components/filter/FilterButton.svelte'
|
||||
export * from './context'
|
||||
export * from './selection'
|
||||
export { buildModel, getCollectionCounter, getObjectPresenter, LoadingProps } from './utils'
|
||||
@ -75,7 +75,7 @@ export {
|
||||
Menu,
|
||||
SpacePresenter,
|
||||
UpDownNavigator,
|
||||
ViewletSetting,
|
||||
ViewletSettingButton,
|
||||
FilterBar,
|
||||
ClassAttributeBar
|
||||
}
|
||||
@ -88,7 +88,6 @@ export default async (): Promise<Resources> => ({
|
||||
ValueFilter,
|
||||
TimestampFilter,
|
||||
TableBrowser,
|
||||
ViewletSetting,
|
||||
SpacePresenter,
|
||||
StringEditor,
|
||||
StringPresenter,
|
||||
|
@ -48,16 +48,20 @@ export interface LoadingProps {
|
||||
export async function getObjectPresenter (
|
||||
client: Client,
|
||||
_class: Ref<Class<Obj>>,
|
||||
preserveKey: BuildModelKey
|
||||
preserveKey: BuildModelKey,
|
||||
isCollectionAttr: boolean = false
|
||||
): Promise<AttributeModel> {
|
||||
const clazz = client.getHierarchy().getClass(_class)
|
||||
const presenterMixin = client.getHierarchy().as(clazz, view.mixin.AttributePresenter)
|
||||
const hierarchy = client.getHierarchy()
|
||||
const mixin = isCollectionAttr ? view.mixin.CollectionPresenter : view.mixin.AttributePresenter
|
||||
const clazz = hierarchy.getClass(_class)
|
||||
let mixinClazz = hierarchy.getClass(_class)
|
||||
let presenterMixin = hierarchy.as(clazz, mixin)
|
||||
while (presenterMixin.presenter === undefined && mixinClazz.extends !== undefined) {
|
||||
presenterMixin = hierarchy.as(mixinClazz, mixin)
|
||||
mixinClazz = hierarchy.getClass(mixinClazz.extends)
|
||||
}
|
||||
if (presenterMixin.presenter === undefined) {
|
||||
if (clazz.extends !== undefined) {
|
||||
return await getObjectPresenter(client, clazz.extends, preserveKey)
|
||||
} else {
|
||||
throw new Error('object presenter not found for ' + JSON.stringify(preserveKey))
|
||||
}
|
||||
throw new Error('object presenter not found for ' + JSON.stringify(preserveKey))
|
||||
}
|
||||
const presenter = await getResource(presenterMixin.presenter)
|
||||
const key = preserveKey.sortingKey ?? preserveKey.key
|
||||
@ -132,7 +136,8 @@ export async function getPresenter<T extends Doc> (
|
||||
_class: Ref<Class<T>>,
|
||||
key: BuildModelKey,
|
||||
preserveKey: BuildModelKey,
|
||||
lookup?: Lookup<T>
|
||||
lookup?: Lookup<T>,
|
||||
isCollectionAttr: boolean = false
|
||||
): Promise<AttributeModel> {
|
||||
if (key.presenter !== undefined) {
|
||||
const { presenter, label, sortingKey } = key
|
||||
@ -146,7 +151,7 @@ export async function getPresenter<T extends Doc> (
|
||||
}
|
||||
}
|
||||
if (key.key.length === 0) {
|
||||
return await getObjectPresenter(client, _class, preserveKey)
|
||||
return await getObjectPresenter(client, _class, preserveKey, isCollectionAttr)
|
||||
} else {
|
||||
if (key.key.startsWith('$lookup')) {
|
||||
if (lookup === undefined) {
|
||||
@ -262,7 +267,7 @@ async function getLookupPresenter<T extends Doc> (
|
||||
const lookupClass = getLookupClass(key.key, lookup, _class)
|
||||
const lookupProperty = getLookupProperty(key.key)
|
||||
const lookupKey = { ...key, key: lookupProperty[0] }
|
||||
const model = await getPresenter(client, lookupClass[0], lookupKey, preserveKey)
|
||||
const model = await getPresenter(client, lookupClass[0], lookupKey, preserveKey, undefined, lookupClass[2])
|
||||
model.label = getLookupLabel(client, lookupClass[1], lookupClass[0], lookupKey, lookupProperty[1])
|
||||
return model
|
||||
}
|
||||
@ -292,7 +297,7 @@ export function getLookupClass<T extends Doc> (
|
||||
key: string,
|
||||
lookup: Lookup<T>,
|
||||
parent: Ref<Class<T>>
|
||||
): [Ref<Class<Doc>>, Ref<Class<Doc>>] {
|
||||
): [Ref<Class<Doc>>, Ref<Class<Doc>>, boolean] {
|
||||
const _class = getLookup(key, lookup, parent)
|
||||
if (_class === undefined) {
|
||||
throw new Error('lookup class does not provided for ' + key)
|
||||
@ -313,7 +318,7 @@ function getLookup (
|
||||
key: string,
|
||||
lookup: Lookup<any>,
|
||||
parent: Ref<Class<Doc>>
|
||||
): [Ref<Class<Doc>>, Ref<Class<Doc>>] | undefined {
|
||||
): [Ref<Class<Doc>>, Ref<Class<Doc>>, boolean] | undefined {
|
||||
const parts = key.split('$lookup.').filter((p) => p.length > 0)
|
||||
const currentKey = parts[0].split('.').filter((p) => p.length > 0)[0]
|
||||
const current = (lookup as any)[currentKey]
|
||||
@ -325,13 +330,17 @@ function getLookup (
|
||||
return getLookup(nestedKey, current[1], current[0])
|
||||
}
|
||||
if (Array.isArray(current)) {
|
||||
return [current[0], parent]
|
||||
return [current[0], parent, false]
|
||||
}
|
||||
if (current === undefined && lookup._id !== undefined) {
|
||||
const reverse = (lookup._id as any)[currentKey]
|
||||
return reverse !== undefined ? [reverse, parent] : undefined
|
||||
return reverse !== undefined
|
||||
? Array.isArray(reverse)
|
||||
? [reverse[0], parent, true]
|
||||
: [reverse, parent, true]
|
||||
: undefined
|
||||
}
|
||||
return current !== undefined ? [current, parent] : undefined
|
||||
return current !== undefined ? [current, parent, false] : undefined
|
||||
}
|
||||
|
||||
export function getBooleanLabel (value: boolean | undefined): IntlString {
|
||||
|
@ -391,7 +391,6 @@ const view = plugin(viewId, {
|
||||
component: {
|
||||
ObjectPresenter: '' as AnyComponent,
|
||||
EditDoc: '' as AnyComponent,
|
||||
ViewletSetting: '' as AnyComponent,
|
||||
SpacePresenter: '' as AnyComponent,
|
||||
BooleanTruePresenter: '' as AnyComponent
|
||||
},
|
||||
|
@ -17,14 +17,14 @@
|
||||
import core, { WithLookup } from '@anticrm/core'
|
||||
import { IntlString } from '@anticrm/platform'
|
||||
import presentation, { createQuery, getClient } from '@anticrm/presentation'
|
||||
import { AnyComponent, showPanel, Button, Icon, SearchEdit, showPopup, Tooltip, IconAdd } from '@anticrm/ui'
|
||||
import { AnyComponent, Button, Icon, IconAdd, SearchEdit, showPanel, showPopup, Tooltip } from '@anticrm/ui'
|
||||
import type { Filter } from '@anticrm/view'
|
||||
import view, { Viewlet } from '@anticrm/view'
|
||||
import { ViewletSetting } from '@anticrm/view-resources'
|
||||
import { ViewletSettingButton } from '@anticrm/view-resources'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import plugin from '../plugin'
|
||||
import { classIcon } from '../utils'
|
||||
import Header from './Header.svelte'
|
||||
import type { Filter } from '@anticrm/view'
|
||||
|
||||
export let spaceId: Ref<Space> | undefined
|
||||
export let createItemDialog: AnyComponent | undefined
|
||||
@ -115,16 +115,6 @@
|
||||
{#if createItemDialog}
|
||||
<Button icon={IconAdd} label={createItemLabel} kind={'primary'} on:click={(ev) => showCreateDialog(ev)} />
|
||||
{/if}
|
||||
{#if viewlet}
|
||||
<Tooltip label={view.string.CustomizeView}>
|
||||
<Button
|
||||
icon={view.icon.Setting}
|
||||
kind={'transparent'}
|
||||
on:click={() => {
|
||||
showPopup(ViewletSetting, { viewlet })
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
<ViewletSettingButton {viewlet} />
|
||||
{/if}
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user