mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-23 05:53:09 +03:00
Edit contact (#621)
Signed-off-by: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com>
This commit is contained in:
parent
65268ecff6
commit
556399f2e1
@ -53,14 +53,23 @@ export function createModel (builder: Builder): void {
|
||||
presenter: attachment.component.AttachmentPresenter
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.TxViewlet, core.space.Model, {
|
||||
objectClass: attachment.class.Attachment,
|
||||
icon: attachment.icon.Attachment,
|
||||
txClass: core.class.TxCreateDoc,
|
||||
component: attachment.activity.TxAttachmentCreate,
|
||||
label: attachment.string.AddAttachment,
|
||||
display: 'emphasized'
|
||||
}, attachment.ids.TxAttachmentCreate)
|
||||
builder.mixin(attachment.class.Attachment, core.class.Class, view.mixin.AttributeEditor, {
|
||||
editor: attachment.component.Attachments
|
||||
})
|
||||
|
||||
builder.createDoc(
|
||||
activity.class.TxViewlet,
|
||||
core.space.Model,
|
||||
{
|
||||
objectClass: attachment.class.Attachment,
|
||||
icon: attachment.icon.Attachment,
|
||||
txClass: core.class.TxCreateDoc,
|
||||
component: attachment.activity.TxAttachmentCreate,
|
||||
label: attachment.string.AddAttachment,
|
||||
display: 'emphasized'
|
||||
},
|
||||
attachment.ids.TxAttachmentCreate
|
||||
)
|
||||
}
|
||||
|
||||
export default attachment
|
||||
|
@ -33,6 +33,7 @@
|
||||
"@anticrm/core": "~0.6.11",
|
||||
"@anticrm/ui": "~0.6.0",
|
||||
"@anticrm/platform": "~0.6.5",
|
||||
"@anticrm/contact": "~0.6.2"
|
||||
"@anticrm/contact": "~0.6.2",
|
||||
"@anticrm/model-chunter": "~0.6.0"
|
||||
}
|
||||
}
|
||||
|
@ -15,11 +15,21 @@
|
||||
|
||||
import type { Domain, Type, Ref } from '@anticrm/core'
|
||||
import { DOMAIN_MODEL, IndexKind } from '@anticrm/core'
|
||||
import { Builder, Model, Prop, TypeString, UX, Index } from '@anticrm/model'
|
||||
import { Builder, Model, Prop, TypeString, UX, Index, Collection } from '@anticrm/model'
|
||||
import type { IntlString, Asset } from '@anticrm/platform'
|
||||
|
||||
import chunter from '@anticrm/model-chunter'
|
||||
import core, { TAccount, TDoc, TSpace, TType } from '@anticrm/model-core'
|
||||
import type { Contact, Person, Persons, Organization, Organizations, Employee, Channel, ChannelProvider, EmployeeAccount } from '@anticrm/contact'
|
||||
import type {
|
||||
Contact,
|
||||
Person,
|
||||
Persons,
|
||||
Organization,
|
||||
Organizations,
|
||||
Employee,
|
||||
Channel,
|
||||
ChannelProvider,
|
||||
EmployeeAccount
|
||||
} from '@anticrm/contact'
|
||||
import workbench from '@anticrm/model-workbench'
|
||||
import view from '@anticrm/model-view'
|
||||
import attachment from '@anticrm/model-attachment'
|
||||
@ -55,28 +65,26 @@ export class TContact extends TDoc implements Contact {
|
||||
@Prop(TypeChannels(), 'Contact Info' as IntlString)
|
||||
channels!: Channel[]
|
||||
|
||||
@Prop(TypeString(), 'Attachments' as IntlString)
|
||||
@Prop(Collection(attachment.class.Attachment), 'Attachments' as IntlString)
|
||||
attachments?: number
|
||||
|
||||
@Prop(TypeString(), 'Comments' as IntlString)
|
||||
@Prop(Collection(chunter.class.Comment), 'Comments' as IntlString)
|
||||
comments?: number
|
||||
}
|
||||
|
||||
@Model(contact.class.Person, contact.class.Contact)
|
||||
@UX('Person' as IntlString)
|
||||
@UX('Person' as IntlString, contact.icon.Person)
|
||||
export class TPerson extends TContact implements Person {
|
||||
@Prop(TypeString(), 'City' as IntlString)
|
||||
city!: string
|
||||
}
|
||||
|
||||
@Model(contact.class.Organization, contact.class.Contact)
|
||||
@UX('Organization' as IntlString)
|
||||
export class TOrganization extends TContact implements Organization {
|
||||
}
|
||||
@UX('Organization' as IntlString, contact.icon.Company)
|
||||
export class TOrganization extends TContact implements Organization {}
|
||||
|
||||
@Model(contact.class.Employee, contact.class.Person)
|
||||
export class TEmployee extends TPerson implements Employee {
|
||||
}
|
||||
export class TEmployee extends TPerson implements Employee {}
|
||||
|
||||
@Model(contact.class.EmployeeAccount, core.class.Account)
|
||||
export class TEmployeeAccount extends TAccount implements EmployeeAccount {
|
||||
@ -93,7 +101,17 @@ export class TOrganizations extends TSpace implements Organizations {}
|
||||
export class TPersons extends TSpace implements Persons {}
|
||||
|
||||
export function createModel (builder: Builder): void {
|
||||
builder.createModel(TChannelProvider, TTypeChannels, TContact, TPerson, TPersons, TOrganization, TOrganizations, TEmployee, TEmployeeAccount)
|
||||
builder.createModel(
|
||||
TChannelProvider,
|
||||
TTypeChannels,
|
||||
TContact,
|
||||
TPerson,
|
||||
TPersons,
|
||||
TOrganization,
|
||||
TOrganizations,
|
||||
TEmployee,
|
||||
TEmployeeAccount
|
||||
)
|
||||
|
||||
builder.mixin(contact.class.Persons, core.class.Class, workbench.mixin.SpaceView, {
|
||||
view: {
|
||||
@ -136,7 +154,7 @@ export function createModel (builder: Builder): void {
|
||||
descriptor: view.viewlet.Table,
|
||||
open: contact.component.EditPerson,
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
options: { },
|
||||
options: {},
|
||||
config: [
|
||||
'',
|
||||
'city',
|
||||
@ -151,13 +169,8 @@ export function createModel (builder: Builder): void {
|
||||
descriptor: view.viewlet.Table,
|
||||
open: contact.component.EditOrganization,
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
options: { },
|
||||
config: [
|
||||
'',
|
||||
{ presenter: attachment.component.AttachmentsPresenter, label: 'Files' },
|
||||
'modifiedOn',
|
||||
'channels'
|
||||
]
|
||||
options: {},
|
||||
config: ['', { presenter: attachment.component.AttachmentsPresenter, label: 'Files' }, 'modifiedOn', 'channels']
|
||||
})
|
||||
|
||||
builder.mixin(contact.class.Person, core.class.Class, view.mixin.ObjectEditor, {
|
||||
@ -176,42 +189,72 @@ export function createModel (builder: Builder): void {
|
||||
presenter: contact.component.ChannelsPresenter
|
||||
})
|
||||
|
||||
builder.createDoc(contact.class.ChannelProvider, core.space.Model, {
|
||||
label: 'Email' as IntlString,
|
||||
icon: contact.icon.Email,
|
||||
placeholder: 'john.appleseed@apple.com'
|
||||
}, contact.channelProvider.Email)
|
||||
builder.createDoc(
|
||||
contact.class.ChannelProvider,
|
||||
core.space.Model,
|
||||
{
|
||||
label: 'Email' as IntlString,
|
||||
icon: contact.icon.Email,
|
||||
placeholder: 'john.appleseed@apple.com'
|
||||
},
|
||||
contact.channelProvider.Email
|
||||
)
|
||||
|
||||
builder.createDoc(contact.class.ChannelProvider, core.space.Model, {
|
||||
label: 'Phone' as IntlString,
|
||||
icon: contact.icon.Phone,
|
||||
placeholder: '+1 555 333 7777'
|
||||
}, contact.channelProvider.Phone)
|
||||
builder.createDoc(
|
||||
contact.class.ChannelProvider,
|
||||
core.space.Model,
|
||||
{
|
||||
label: 'Phone' as IntlString,
|
||||
icon: contact.icon.Phone,
|
||||
placeholder: '+1 555 333 7777'
|
||||
},
|
||||
contact.channelProvider.Phone
|
||||
)
|
||||
|
||||
builder.createDoc(contact.class.ChannelProvider, core.space.Model, {
|
||||
label: 'LinkedIn' as IntlString,
|
||||
icon: contact.icon.LinkedIn,
|
||||
placeholder: 'https://linkedin.com/in/jappleseed'
|
||||
}, contact.channelProvider.LinkedIn)
|
||||
builder.createDoc(
|
||||
contact.class.ChannelProvider,
|
||||
core.space.Model,
|
||||
{
|
||||
label: 'LinkedIn' as IntlString,
|
||||
icon: contact.icon.LinkedIn,
|
||||
placeholder: 'https://linkedin.com/in/jappleseed'
|
||||
},
|
||||
contact.channelProvider.LinkedIn
|
||||
)
|
||||
|
||||
builder.createDoc(contact.class.ChannelProvider, core.space.Model, {
|
||||
label: 'Twitter' as IntlString,
|
||||
icon: contact.icon.Twitter,
|
||||
placeholder: '@appleseed'
|
||||
}, contact.channelProvider.Twitter)
|
||||
builder.createDoc(
|
||||
contact.class.ChannelProvider,
|
||||
core.space.Model,
|
||||
{
|
||||
label: 'Twitter' as IntlString,
|
||||
icon: contact.icon.Twitter,
|
||||
placeholder: '@appleseed'
|
||||
},
|
||||
contact.channelProvider.Twitter
|
||||
)
|
||||
|
||||
builder.createDoc(contact.class.ChannelProvider, core.space.Model, {
|
||||
label: 'GitHub' as IntlString,
|
||||
icon: contact.icon.GitHub,
|
||||
placeholder: '@appleseed'
|
||||
}, contact.channelProvider.GitHub)
|
||||
builder.createDoc(
|
||||
contact.class.ChannelProvider,
|
||||
core.space.Model,
|
||||
{
|
||||
label: 'GitHub' as IntlString,
|
||||
icon: contact.icon.GitHub,
|
||||
placeholder: '@appleseed'
|
||||
},
|
||||
contact.channelProvider.GitHub
|
||||
)
|
||||
|
||||
builder.createDoc(core.class.Space, core.space.Model, {
|
||||
name: 'Employees',
|
||||
description: 'Employees',
|
||||
private: false,
|
||||
members: []
|
||||
}, contact.space.Employee)
|
||||
builder.createDoc(
|
||||
core.class.Space,
|
||||
core.space.Model,
|
||||
{
|
||||
name: 'Employees',
|
||||
description: 'Employees',
|
||||
private: false,
|
||||
members: []
|
||||
},
|
||||
contact.space.Employee
|
||||
)
|
||||
|
||||
builder.mixin(contact.class.Person, core.class.Class, view.mixin.AttributePresenter, {
|
||||
presenter: contact.component.PersonPresenter
|
||||
|
@ -14,32 +14,58 @@
|
||||
//
|
||||
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import type { Account, AnyAttribute, AttachedDoc, Class, ClassifierKind, Doc, Domain, Mixin, Obj, Ref, Space, Timestamp, Type, Collection, RefTo } from '@anticrm/core'
|
||||
import type {
|
||||
Account,
|
||||
AnyAttribute,
|
||||
AttachedDoc,
|
||||
Class,
|
||||
ClassifierKind,
|
||||
Doc,
|
||||
Domain,
|
||||
Mixin,
|
||||
Obj,
|
||||
Ref,
|
||||
Space,
|
||||
Timestamp,
|
||||
Type,
|
||||
Collection,
|
||||
RefTo
|
||||
} from '@anticrm/core'
|
||||
import { DOMAIN_MODEL } from '@anticrm/core'
|
||||
import { Model, Prop, TypeTimestamp } from '@anticrm/model'
|
||||
import { Model, Prop, TypeRef, TypeString, TypeTimestamp } from '@anticrm/model'
|
||||
import core from './component'
|
||||
|
||||
// C O R E
|
||||
@Model(core.class.Obj, core.class.Obj)
|
||||
export class TObj implements Obj {
|
||||
@Prop(TypeRef(core.class.Class), 'Class' as IntlString)
|
||||
_class!: Ref<Class<this>>
|
||||
}
|
||||
|
||||
@Model(core.class.Doc, core.class.Obj)
|
||||
export class TDoc extends TObj implements Doc {
|
||||
@Prop(TypeRef(core.class.Doc), 'Id' as IntlString)
|
||||
_id!: Ref<this>
|
||||
|
||||
@Prop(TypeRef(core.class.Space), 'Space' as IntlString)
|
||||
space!: Ref<Space>
|
||||
|
||||
@Prop(TypeTimestamp(), 'Modified On' as IntlString)
|
||||
modifiedOn!: Timestamp
|
||||
|
||||
@Prop(TypeRef(core.class.Account), 'Modiified By' as IntlString)
|
||||
modifiedBy!: Ref<Account>
|
||||
}
|
||||
|
||||
@Model(core.class.AttachedDoc, core.class.Doc)
|
||||
export class TAttachedDoc extends TDoc implements AttachedDoc {
|
||||
@Prop(TypeRef(core.class.Doc), 'Attached to' as IntlString)
|
||||
attachedTo!: Ref<Doc>
|
||||
|
||||
@Prop(TypeRef(core.class.Class), 'Attached to class' as IntlString)
|
||||
attachedToClass!: Ref<Class<Doc>>
|
||||
|
||||
@Prop(TypeString(), 'Collection' as IntlString)
|
||||
collection!: string
|
||||
}
|
||||
|
||||
|
@ -51,17 +51,11 @@ export class TVacancy extends TSpaceWithStates implements Vacancy {
|
||||
export class TCandidates extends TSpace implements Candidates {}
|
||||
|
||||
@Model(recruit.class.Candidate, contact.class.Person)
|
||||
@UX('Candidate' as IntlString)
|
||||
@UX('Candidate' as IntlString, contact.icon.Person)
|
||||
export class TCandidate extends TPerson implements Candidate {
|
||||
@Prop(TypeString(), 'Title' as IntlString)
|
||||
title?: string
|
||||
|
||||
@Prop(Collection(attachment.class.Attachment), 'Attachments' as IntlString)
|
||||
attachments?: number
|
||||
|
||||
@Prop(Collection(chunter.class.Comment), 'Comments' as IntlString)
|
||||
comments?: number
|
||||
|
||||
@Prop(Collection(recruit.class.Applicant), 'Applications' as IntlString)
|
||||
applications?: number
|
||||
|
||||
@ -109,6 +103,10 @@ export function createModel (builder: Builder): void {
|
||||
}
|
||||
})
|
||||
|
||||
builder.mixin(recruit.class.Applicant, core.class.Class, view.mixin.AttributeEditor, {
|
||||
editor: recruit.component.Applications
|
||||
})
|
||||
|
||||
builder.createDoc(workbench.class.Application, core.space.Model, {
|
||||
label: recruit.string.RecruitApplication,
|
||||
icon: recruit.icon.RecruitApplication,
|
||||
|
@ -50,7 +50,8 @@ export default mergeIds(recruitId, recruit, {
|
||||
ApplicationPresenter: '' as AnyComponent,
|
||||
ApplicationsPresenter: '' as AnyComponent,
|
||||
EditVacancy: '' as AnyComponent,
|
||||
TemplatesIcon: '' as AnyComponent
|
||||
TemplatesIcon: '' as AnyComponent,
|
||||
Applications: '' as AnyComponent
|
||||
},
|
||||
space: {
|
||||
CandidatesPublic: '' as Ref<Space>
|
||||
|
@ -16,8 +16,24 @@
|
||||
|
||||
import { onDestroy } from 'svelte'
|
||||
|
||||
import { Doc, Ref, Class, DocumentQuery, FindOptions, Client, Hierarchy, Tx, getCurrentAccount, ModelDb, TxResult, TxOperations, AnyAttribute, RefTo } from '@anticrm/core'
|
||||
import core from '@anticrm/core'
|
||||
import core, {
|
||||
Doc,
|
||||
Ref,
|
||||
Class,
|
||||
DocumentQuery,
|
||||
FindOptions,
|
||||
Client,
|
||||
Hierarchy,
|
||||
Tx,
|
||||
getCurrentAccount,
|
||||
ModelDb,
|
||||
TxResult,
|
||||
TxOperations,
|
||||
AnyAttribute,
|
||||
RefTo,
|
||||
Collection,
|
||||
AttachedDoc
|
||||
} from '@anticrm/core'
|
||||
import { LiveQuery as LQ } from '@anticrm/query'
|
||||
import { getMetadata } from '@anticrm/platform'
|
||||
|
||||
@ -57,7 +73,7 @@ export function setClient (_client: Client): void {
|
||||
liveQuery = new LQ(_client)
|
||||
client = new UIClient(_client, liveQuery)
|
||||
_client.notify = (tx: Tx) => {
|
||||
liveQuery.tx(tx).catch(err => console.log(err))
|
||||
liveQuery.tx(tx).catch((err) => console.log(err))
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,16 +81,26 @@ export class LiveQuery {
|
||||
private unsubscribe = () => {}
|
||||
|
||||
constructor () {
|
||||
onDestroy(() => { console.log('onDestroy query'); this.unsubscribe() })
|
||||
onDestroy(() => {
|
||||
console.log('onDestroy query')
|
||||
this.unsubscribe()
|
||||
})
|
||||
}
|
||||
|
||||
query<T extends Doc>(_class: Ref<Class<T>>, query: DocumentQuery<T>, callback: (result: T[]) => void, options?: FindOptions<T>): void {
|
||||
query<T extends Doc>(
|
||||
_class: Ref<Class<T>>,
|
||||
query: DocumentQuery<T>,
|
||||
callback: (result: T[]) => void,
|
||||
options?: FindOptions<T>
|
||||
): void {
|
||||
this.unsubscribe()
|
||||
this.unsubscribe = liveQuery.query(_class, query, callback, options)
|
||||
}
|
||||
}
|
||||
|
||||
export function createQuery (): LiveQuery { return new LiveQuery() }
|
||||
export function createQuery (): LiveQuery {
|
||||
return new LiveQuery()
|
||||
}
|
||||
|
||||
export function getFileUrl (file: string): string {
|
||||
const uploadUrl = getMetadata(login.metadata.UploadUrl)
|
||||
@ -91,5 +117,8 @@ export function getAttributePresenterClass (attribute: AnyAttribute): Ref<Class<
|
||||
if (attrClass === core.class.RefTo) {
|
||||
attrClass = (attribute.type as RefTo<Doc>).to
|
||||
}
|
||||
if (attrClass === core.class.Collection) {
|
||||
attrClass = (attribute.type as Collection<AttachedDoc>).of
|
||||
}
|
||||
return attrClass
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
import attachment from '../plugin'
|
||||
import type { Attachment } from '@anticrm/attachment'
|
||||
import type { Class, Doc, Ref, Space } from '@anticrm/core'
|
||||
import { setPlatformStatus, unknownError } from '@anticrm/platform'
|
||||
import { IntlString, setPlatformStatus, unknownError } from '@anticrm/platform'
|
||||
import { createQuery, getClient } from '@anticrm/presentation'
|
||||
import { CircleButton, IconAdd, Label, Spinner } from '@anticrm/ui'
|
||||
import { Table } from '@anticrm/view-resources'
|
||||
@ -142,7 +142,7 @@
|
||||
flex-direction: column;
|
||||
|
||||
.title {
|
||||
margin-right: .75rem;
|
||||
margin-right: 0.75rem;
|
||||
font-weight: 500;
|
||||
font-size: 1.25rem;
|
||||
color: var(--theme-caption-color);
|
||||
@ -154,6 +154,6 @@
|
||||
color: var(--theme-caption-color);
|
||||
background: var(--theme-bg-accent-color);
|
||||
border: 1px dashed var(--theme-zone-border-lite);
|
||||
border-radius: .75rem;
|
||||
border-radius: 0.75rem;
|
||||
}
|
||||
</style>
|
||||
|
143
plugins/contact-resources/src/components/EditContact.svelte
Normal file
143
plugins/contact-resources/src/components/EditContact.svelte
Normal file
@ -0,0 +1,143 @@
|
||||
<!--
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 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 { createEventDispatcher } from 'svelte'
|
||||
import { Class, Doc, Ref } from '@anticrm/core'
|
||||
import { Component, AnyComponent } from '@anticrm/ui'
|
||||
import { AttributesBar, getClient, createQuery, getAttributePresenterClass } from '@anticrm/presentation'
|
||||
import { Panel } from '@anticrm/panel'
|
||||
import contact from '../plugin'
|
||||
import { Contact, formatName } from '@anticrm/contact'
|
||||
import core from '@anticrm/core'
|
||||
import { Asset } from '@anticrm/platform'
|
||||
import view from '@anticrm/view'
|
||||
|
||||
export let _id: Ref<Contact>
|
||||
let object: Contact
|
||||
let rightSection: AnyComponent | undefined
|
||||
let fullSize: boolean = false
|
||||
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
const docKeys: Set<string> = new Set<string>(hierarchy.getAllAttributes(core.class.AttachedDoc).keys())
|
||||
|
||||
const query = createQuery()
|
||||
$: _id &&
|
||||
query.query(contact.class.Contact, { _id }, (result) => {
|
||||
object = result[0]
|
||||
})
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let keys: string[] = []
|
||||
let collectionKeys: string[] = []
|
||||
|
||||
function getFiltredKeys (ignoreKeys: string[]): string[] {
|
||||
let keys = Array.from(hierarchy.getAllAttributes(object._class).keys())
|
||||
keys = keys.filter((k) => !docKeys.has(k))
|
||||
keys = keys.filter((k) => !ignoreKeys.includes(k))
|
||||
return keys
|
||||
}
|
||||
|
||||
function getKeys (ignoreKeys: string[]): void {
|
||||
const filtredKeys = getFiltredKeys(ignoreKeys)
|
||||
keys = collectionsFilter(filtredKeys, false)
|
||||
collectionKeys = collectionsFilter(filtredKeys, true)
|
||||
}
|
||||
|
||||
function collectionsFilter (keys: string[], get: boolean): string[] {
|
||||
const result: string[] = []
|
||||
for (const key of keys) {
|
||||
if (isCollectionAttr(key) === get) result.push(key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function isCollectionAttr (key: string): boolean {
|
||||
const attribute = hierarchy.getAttribute(object._class, key)
|
||||
return hierarchy.isDerived(attribute.type._class, core.class.Collection)
|
||||
}
|
||||
|
||||
async function getEditor (_class: Ref<Class<Doc>>): Promise<AnyComponent> {
|
||||
const clazz = hierarchy.getClass(_class)
|
||||
const editorMixin = hierarchy.as(clazz, view.mixin.ObjectEditor)
|
||||
if (editorMixin?.editor == null && clazz.extends != null) return getEditor(clazz.extends)
|
||||
return editorMixin.editor
|
||||
}
|
||||
|
||||
async function getCollectionEditor (key: string): Promise<AnyComponent> {
|
||||
const attribute = hierarchy.getAttribute(object._class, key)
|
||||
const attrClass = getAttributePresenterClass(attribute)
|
||||
const clazz = client.getHierarchy().getClass(attrClass)
|
||||
const editorMixin = client.getHierarchy().as(clazz, view.mixin.AttributeEditor)
|
||||
return editorMixin.editor
|
||||
}
|
||||
|
||||
$: icon = object && (hierarchy.getClass(object._class).icon as Asset)
|
||||
</script>
|
||||
|
||||
{#if object !== undefined}
|
||||
<Panel
|
||||
{icon}
|
||||
title={formatName(object.name)}
|
||||
{rightSection}
|
||||
{fullSize}
|
||||
{object}
|
||||
on:close={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
>
|
||||
<div slot="subtitle">
|
||||
{#if keys}
|
||||
<AttributesBar {object} {keys} />
|
||||
{/if}
|
||||
</div>
|
||||
{#await getEditor(object._class) then is}
|
||||
<Component
|
||||
{is}
|
||||
props={{ object }}
|
||||
on:open={(ev) => {
|
||||
getKeys(ev.detail.ignoreKeys)
|
||||
}}
|
||||
on:click={(ev) => {
|
||||
fullSize = true
|
||||
rightSection = ev.detail.presenter
|
||||
}}
|
||||
/>
|
||||
{/await}
|
||||
{#each collectionKeys as collection}
|
||||
<div class="mt-14">
|
||||
{#await getCollectionEditor(collection) then is}
|
||||
<Component {is} props={{ objectId: object._id, _class: object._class, space: object.space }} />
|
||||
{/await}
|
||||
</div>
|
||||
{/each}
|
||||
</Panel>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.name {
|
||||
font-weight: 500;
|
||||
font-size: 1.25rem;
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
.channels {
|
||||
margin-top: 0.75rem;
|
||||
span {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -14,30 +14,20 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { createEventDispatcher, onMount } from 'svelte'
|
||||
import { getCurrentAccount, Ref, Space } from '@anticrm/core'
|
||||
import { CircleButton, EditBox, showPopup, IconEdit, IconAdd, Label, AnyComponent } from '@anticrm/ui'
|
||||
import { CircleButton, EditBox, showPopup, IconEdit, IconAdd, Label, IconActivity } from '@anticrm/ui'
|
||||
import { getClient, createQuery, Channels } from '@anticrm/presentation'
|
||||
import { Panel } from '@anticrm/panel'
|
||||
import setting from '@anticrm/setting'
|
||||
import { IntegrationType } from '@anticrm/setting'
|
||||
import contact from '../plugin'
|
||||
import { Organization } from '@anticrm/contact'
|
||||
import Company from './icons/Company.svelte'
|
||||
import { Attachments } from '@anticrm/attachment-resources'
|
||||
|
||||
export let _id: Ref<Organization>
|
||||
let object: Organization
|
||||
let rightSection: AnyComponent | undefined
|
||||
let fullSize: boolean = false
|
||||
export let object: Organization
|
||||
|
||||
const client = getClient()
|
||||
|
||||
const query = createQuery()
|
||||
$: query.query(contact.class.Organization, { _id }, (result) => {
|
||||
object = result[0]
|
||||
})
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
function saveChannels (result: any) {
|
||||
@ -57,28 +47,23 @@
|
||||
$: settingsQuery.query(setting.class.Integration, { space: accountId as string as Ref<Space> }, (res) => {
|
||||
integrations = new Set(res.map((p) => p.type))
|
||||
})
|
||||
|
||||
onMount(() => {
|
||||
dispatch('open', { ignoreKeys: ['comments', 'name', 'channels'] })
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if object !== undefined}
|
||||
<Panel
|
||||
icon={contact.icon.Company}
|
||||
title={object.name}
|
||||
{rightSection}
|
||||
{fullSize}
|
||||
{object}
|
||||
on:close={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
>
|
||||
<div class="flex-row-center">
|
||||
<div class="mr-8 flex-center logo">
|
||||
<Company size={'large'} />
|
||||
<div class="flex-row-center">
|
||||
<div class="mr-8 flex-center logo">
|
||||
<Company size={'large'} />
|
||||
</div>
|
||||
<div class="flex-grow flex-col">
|
||||
<div class="name">
|
||||
<EditBox placeholder="John" maxWidth="20rem" bind:value={object.name} on:change={nameChange} />
|
||||
</div>
|
||||
<div class="flex-col">
|
||||
<div class="name">
|
||||
<EditBox placeholder="John" maxWidth="20rem" bind:value={object.name} on:change={nameChange} />
|
||||
</div>
|
||||
<div class="flex-row-center channels">
|
||||
<div class="flex-between channels">
|
||||
<div class="flex-row-center">
|
||||
{#if !object.channels || object.channels.length === 0}
|
||||
<CircleButton
|
||||
icon={IconAdd}
|
||||
@ -91,17 +76,7 @@
|
||||
/>
|
||||
<span><Label label={contact.string.AddSocialLinks} /></span>
|
||||
{:else}
|
||||
<Channels
|
||||
value={object.channels}
|
||||
size={'small'}
|
||||
{integrations}
|
||||
on:click={(ev) => {
|
||||
if (ev.detail.presenter) {
|
||||
fullSize = true
|
||||
rightSection = ev.detail.presenter
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Channels value={object.channels} size={'small'} {integrations} on:click />
|
||||
<div class="ml-1">
|
||||
<CircleButton
|
||||
icon={IconEdit}
|
||||
@ -115,13 +90,16 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="flex-row-center">
|
||||
<a href={'#'} class="flex-row-center" on:click>
|
||||
<CircleButton icon={IconActivity} size={'small'} primary on:click />
|
||||
<span class="ml-2 small-text">View activity</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-14">
|
||||
<Attachments objectId={object._id} _class={object._class} space={object.space} />
|
||||
</div>
|
||||
</Panel>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
|
@ -1,47 +1,35 @@
|
||||
<!--
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 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 { createEventDispatcher } from 'svelte'
|
||||
import { createEventDispatcher, onMount } from 'svelte'
|
||||
import { getCurrentAccount, Ref, Space } from '@anticrm/core'
|
||||
import { CircleButton, EditBox, showPopup, IconEdit, IconAdd, Label, AnyComponent } from '@anticrm/ui'
|
||||
import { AttributesBar, getClient, createQuery, Channels, Avatar } from '@anticrm/presentation'
|
||||
import { Panel } from '@anticrm/panel'
|
||||
import { CircleButton, EditBox, showPopup, IconEdit, IconAdd, Label, IconActivity } from '@anticrm/ui'
|
||||
import { getClient, createQuery, Channels, Avatar } from '@anticrm/presentation'
|
||||
import setting from '@anticrm/setting'
|
||||
import { IntegrationType } from '@anticrm/setting'
|
||||
import contact from '../plugin'
|
||||
import { combineName, formatName, getFirstName, getLastName, Person } from '@anticrm/contact'
|
||||
import { Attachments } from '@anticrm/attachment-resources'
|
||||
import { combineName, getFirstName, getLastName, Person } from '@anticrm/contact'
|
||||
|
||||
export let _id: Ref<Person>
|
||||
let object: Person
|
||||
let rightSection: AnyComponent | undefined
|
||||
let fullSize: boolean = false
|
||||
export let object: Person
|
||||
|
||||
let firstName = ''
|
||||
let lastName = ''
|
||||
let firstName = getFirstName(object.name)
|
||||
let lastName = getLastName(object.name)
|
||||
|
||||
const client = getClient()
|
||||
|
||||
const query = createQuery()
|
||||
$: query.query(contact.class.Person, { _id }, (result) => {
|
||||
object = result[0]
|
||||
firstName = getFirstName(result[0].name)
|
||||
lastName = getLastName(result[0].name)
|
||||
})
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
function saveChannels (result: any) {
|
||||
@ -69,33 +57,26 @@
|
||||
$: settingsQuery.query(setting.class.Integration, { space: accountId as string as Ref<Space> }, (res) => {
|
||||
integrations = new Set(res.map((p) => p.type))
|
||||
})
|
||||
|
||||
onMount(() => {
|
||||
dispatch('open', { ignoreKeys: ['comments', 'name', 'channels'] })
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if object !== undefined}
|
||||
<Panel
|
||||
icon={contact.icon.Person}
|
||||
title={formatName(object.name)}
|
||||
{rightSection}
|
||||
{fullSize}
|
||||
{object}
|
||||
on:close={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
>
|
||||
<AttributesBar {object} keys={['city']} slot="subtitle" />
|
||||
|
||||
<div class="flex-row-center">
|
||||
<div class="mr-8">
|
||||
<Avatar avatar={object.avatar} size={'x-large'} />
|
||||
<div class="flex-row-center">
|
||||
<div class="mr-8">
|
||||
<Avatar avatar={object.avatar} size={'x-large'} />
|
||||
</div>
|
||||
<div class="flex-grow flex-col">
|
||||
<div class="name">
|
||||
<EditBox placeholder="John" maxWidth="20rem" bind:value={firstName} on:change={firstNameChange} />
|
||||
</div>
|
||||
<div class="flex-col">
|
||||
<div class="name">
|
||||
<EditBox placeholder="John" maxWidth="20rem" bind:value={firstName} on:change={firstNameChange} />
|
||||
</div>
|
||||
<div class="name">
|
||||
<EditBox placeholder="Appleseed" maxWidth="20rem" bind:value={lastName} on:change={lastNameChange} />
|
||||
</div>
|
||||
<div class="flex-row-center channels">
|
||||
<div class="name">
|
||||
<EditBox placeholder="Appleseed" maxWidth="20rem" bind:value={lastName} on:change={lastNameChange} />
|
||||
</div>
|
||||
<div class="flex-between channels">
|
||||
<div class="flex-row-center">
|
||||
{#if !object.channels || object.channels.length === 0}
|
||||
<CircleButton
|
||||
icon={IconAdd}
|
||||
@ -108,17 +89,7 @@
|
||||
/>
|
||||
<span><Label label={contact.string.AddSocialLinks} /></span>
|
||||
{:else}
|
||||
<Channels
|
||||
value={object.channels}
|
||||
size={'small'}
|
||||
{integrations}
|
||||
on:click={(ev) => {
|
||||
if (ev.detail.presenter) {
|
||||
fullSize = true
|
||||
rightSection = ev.detail.presenter
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Channels value={object.channels} size={'small'} {integrations} on:click />
|
||||
<div class="ml-1">
|
||||
<CircleButton
|
||||
icon={IconEdit}
|
||||
@ -132,13 +103,16 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="flex-row-center">
|
||||
<a href={'#'} class="flex-row-center" on:click>
|
||||
<CircleButton icon={IconActivity} size={'small'} primary on:click />
|
||||
<span class="ml-2 small-text">View activity</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-14">
|
||||
<Attachments objectId={object._id} _class={object._class} space={object.space} />
|
||||
</div>
|
||||
</Panel>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
|
@ -14,22 +14,15 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { getResource } from '@anticrm/platform'
|
||||
import { Person } from '@anticrm/contact'
|
||||
import { getClient } from '@anticrm/presentation'
|
||||
import { showPopup } from '@anticrm/ui'
|
||||
import view from '@anticrm/view'
|
||||
import Company from './icons/Company.svelte'
|
||||
import EditContact from './EditContact.svelte'
|
||||
|
||||
export let value: Person
|
||||
|
||||
async function onClick () {
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
const clazz = hierarchy.getClass(value._class)
|
||||
const editorMixin = hierarchy.as(clazz, view.mixin.ObjectEditor)
|
||||
const editor = await getResource(editorMixin.editor)
|
||||
showPopup(editor, { _id: value._id }, 'full')
|
||||
showPopup(EditContact, { _id: value._id }, 'full')
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -15,20 +15,14 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { formatName, Person } from '@anticrm/contact'
|
||||
import { getResource } from '@anticrm/platform'
|
||||
import { Avatar, getClient } from '@anticrm/presentation'
|
||||
import { Avatar } from '@anticrm/presentation'
|
||||
import { showPopup } from '@anticrm/ui'
|
||||
import view from '@anticrm/view'
|
||||
import EditContact from './EditContact.svelte'
|
||||
|
||||
export let value: Person
|
||||
|
||||
async function onClick () {
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
const clazz = hierarchy.getClass(value._class)
|
||||
const editorMixin = hierarchy.as(clazz, view.mixin.ObjectEditor)
|
||||
const editor = await getResource(editorMixin.editor)
|
||||
showPopup(editor, { _id: value._id }, 'full')
|
||||
showPopup(EditContact, { _id: value._id }, 'full')
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 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
|
||||
@ -13,39 +14,24 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { createEventDispatcher, onMount } from 'svelte'
|
||||
import { getCurrentAccount, Ref, Space } from '@anticrm/core'
|
||||
import { CircleButton, EditBox, showPopup, IconAdd, Label, AnyComponent, IconActivity } from '@anticrm/ui'
|
||||
import { getClient, createQuery, Channels, AttributeEditor, AttributesBar, Avatar } from '@anticrm/presentation'
|
||||
import { Panel } from '@anticrm/panel'
|
||||
import { CircleButton, EditBox, showPopup, IconAdd, Label, IconActivity } from '@anticrm/ui'
|
||||
import { getClient, createQuery, Channels, AttributeEditor, Avatar } from '@anticrm/presentation'
|
||||
import type { Candidate } from '@anticrm/recruit'
|
||||
import Contact from './icons/Contact.svelte'
|
||||
import Edit from './icons/Edit.svelte'
|
||||
import Applications from './Applications.svelte'
|
||||
import { Attachments } from '@anticrm/attachment-resources'
|
||||
|
||||
import recruit from '../plugin'
|
||||
import setting from '@anticrm/setting'
|
||||
import { IntegrationType } from '@anticrm/setting'
|
||||
import contact, { combineName, formatName, getFirstName, getLastName } from '@anticrm/contact'
|
||||
import contact, { combineName, getFirstName, getLastName } from '@anticrm/contact'
|
||||
|
||||
export let _id: Ref<Candidate>
|
||||
let object: Candidate
|
||||
let rightSection: AnyComponent | undefined
|
||||
let fullSize: boolean = false
|
||||
export let object: Candidate
|
||||
|
||||
let firstName = ''
|
||||
let lastName = ''
|
||||
let firstName = getFirstName(object.name)
|
||||
let lastName = getLastName(object.name)
|
||||
|
||||
const client = getClient()
|
||||
|
||||
const query = createQuery()
|
||||
$: query.query(recruit.class.Candidate, { _id }, (result) => {
|
||||
object = result[0]
|
||||
firstName = getFirstName(result[0].name)
|
||||
lastName = getLastName(result[0].name)
|
||||
})
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
function saveChannels (result: any) {
|
||||
@ -67,115 +53,73 @@
|
||||
})
|
||||
}
|
||||
|
||||
const openActivity = (): void => {
|
||||
rightSection = undefined
|
||||
fullSize = true
|
||||
}
|
||||
|
||||
const accountId = getCurrentAccount()._id
|
||||
let integrations: Set<Ref<IntegrationType>> = new Set<Ref<IntegrationType>>()
|
||||
const settingsQuery = createQuery()
|
||||
$: settingsQuery.query(setting.class.Integration, { space: accountId as string as Ref<Space> }, (res) => {
|
||||
integrations = new Set(res.map((p) => p.type))
|
||||
})
|
||||
|
||||
onMount(() => {
|
||||
dispatch('open', { ignoreKeys: ['comments', 'name', 'channels', 'title'] })
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if object !== undefined}
|
||||
<Panel
|
||||
icon={Contact}
|
||||
title={formatName(object.name)}
|
||||
{rightSection}
|
||||
{fullSize}
|
||||
{object}
|
||||
on:close={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
>
|
||||
<AttributesBar {object} keys={['city', 'onsite', 'remote', 'source']} slot="subtitle" />
|
||||
|
||||
<div class="flex-row-center">
|
||||
<div class="mr-8">
|
||||
<Avatar avatar={object.avatar} size={'x-large'} />
|
||||
<div class="flex-row-center">
|
||||
<div class="mr-8">
|
||||
<Avatar avatar={object.avatar} size={'x-large'} />
|
||||
</div>
|
||||
<div class="flex-grow flex-col">
|
||||
<div class="name">
|
||||
<EditBox placeholder="John" maxWidth="20rem" bind:value={firstName} on:change={firstNameChange} />
|
||||
</div>
|
||||
<div class="name">
|
||||
<EditBox placeholder="Appleseed" maxWidth="20rem" bind:value={lastName} on:change={lastNameChange} />
|
||||
</div>
|
||||
<div class="title">
|
||||
<AttributeEditor maxWidth="20rem" _class={recruit.class.Candidate} {object} key="title" />
|
||||
</div>
|
||||
<div class="flex-grow flex-col">
|
||||
<div class="name">
|
||||
<EditBox placeholder="John" maxWidth="20rem" bind:value={firstName} on:change={firstNameChange} />
|
||||
</div>
|
||||
<div class="name">
|
||||
<EditBox placeholder="Appleseed" maxWidth="20rem" bind:value={lastName} on:change={lastNameChange} />
|
||||
</div>
|
||||
<div class="title">
|
||||
<AttributeEditor maxWidth="20rem" _class={recruit.class.Candidate} {object} key="title" />
|
||||
</div>
|
||||
|
||||
<div class="separator" />
|
||||
<div class="separator" />
|
||||
|
||||
<div class="flex-between">
|
||||
<div class="flex-row-center">
|
||||
{#if !object.channels || object.channels.length === 0}
|
||||
<div class="flex-between">
|
||||
<div class="flex-row-center">
|
||||
{#if !object.channels || object.channels.length === 0}
|
||||
<CircleButton
|
||||
icon={IconAdd}
|
||||
size={'small'}
|
||||
selected
|
||||
on:click={(ev) =>
|
||||
showPopup(contact.component.SocialEditor, { values: object.channels ?? [] }, ev.target, (result) => {
|
||||
saveChannels(result)
|
||||
})}
|
||||
/>
|
||||
<span class="ml-2"><Label label={'Add social links'} /></span>
|
||||
{:else}
|
||||
<Channels value={object.channels} {integrations} size={'small'} on:click />
|
||||
<div class="ml-1">
|
||||
<CircleButton
|
||||
icon={IconAdd}
|
||||
icon={Edit}
|
||||
size={'small'}
|
||||
selected
|
||||
on:click={(ev) =>
|
||||
showPopup(contact.component.SocialEditor, { values: object.channels ?? [] }, ev.target, (result) => {
|
||||
saveChannels(result)
|
||||
})}
|
||||
/>
|
||||
<span class="ml-2"><Label label={'Add social links'} /></span>
|
||||
{:else}
|
||||
<Channels
|
||||
value={object.channels}
|
||||
{integrations}
|
||||
size={'small'}
|
||||
on:click={(ev) => {
|
||||
if (ev.detail.presenter) {
|
||||
fullSize = true
|
||||
rightSection = ev.detail.presenter
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<div class="ml-1">
|
||||
<CircleButton
|
||||
icon={Edit}
|
||||
size={'small'}
|
||||
on:click={(ev) =>
|
||||
showPopup(
|
||||
contact.component.SocialEditor,
|
||||
{ values: object.channels ?? [] },
|
||||
ev.target,
|
||||
(result) => {
|
||||
saveChannels(result)
|
||||
}
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="flex-row-center">
|
||||
<a href={'#'} class="flex-row-center" on:click={openActivity}>
|
||||
<CircleButton icon={IconActivity} size={'small'} primary on:click={openActivity} />
|
||||
<span class="ml-2 small-text">View activity</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex-row-center">
|
||||
<a href={'#'} class="flex-row-center" on:click>
|
||||
<CircleButton icon={IconActivity} size={'small'} primary on:click />
|
||||
<span class="ml-2 small-text">View activity</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-14">
|
||||
<Applications objectId={object._id} _class={object._class} space={object.space} />
|
||||
</div>
|
||||
|
||||
<div class="mt-14">
|
||||
<Attachments
|
||||
objectId={object._id}
|
||||
_class={object._class}
|
||||
space={object.space}
|
||||
noLabel={recruit.string.NoAttachmentsForCandidate}
|
||||
/>
|
||||
</div>
|
||||
</Panel>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
|
@ -25,6 +25,7 @@ import EditVacancy from './components/EditVacancy.svelte'
|
||||
import ApplicationPresenter from './components/ApplicationPresenter.svelte'
|
||||
import ApplicationsPresenter from './components/ApplicationsPresenter.svelte'
|
||||
import TemplatesIcon from './components/TemplatesIcon.svelte'
|
||||
import Applications from './components/Applications.svelte'
|
||||
|
||||
import { showPopup } from '@anticrm/ui'
|
||||
import { Resources } from '@anticrm/platform'
|
||||
@ -47,6 +48,7 @@ export default async (): Promise<Resources> => ({
|
||||
ApplicationPresenter,
|
||||
ApplicationsPresenter,
|
||||
EditVacancy,
|
||||
TemplatesIcon
|
||||
TemplatesIcon,
|
||||
Applications
|
||||
}
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user