mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-22 11:01:54 +03:00
Fix role migration, remove extra rosamunds (#2190)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com> Co-authored-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
parent
a4b3cb4a44
commit
a5b1d5c278
@ -88,7 +88,8 @@ async function setRole (client: MigrationClient): Promise<void> {
|
||||
DOMAIN_TX,
|
||||
{
|
||||
_class: core.class.TxCreateDoc,
|
||||
objectClass: contact.class.Employee
|
||||
objectClass: contact.class.EmployeeAccount,
|
||||
'attributes.role': { $exists: false }
|
||||
},
|
||||
{
|
||||
'attributes.role': AccountRole.User
|
||||
|
@ -13,10 +13,11 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import core, { AccountRole, TxOperations } from '@anticrm/core'
|
||||
import core, { AccountRole, DOMAIN_TX, TxCreateDoc, TxOperations } from '@anticrm/core'
|
||||
import { MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@anticrm/model'
|
||||
import contact, { EmployeeAccount } from '@anticrm/contact'
|
||||
import recruit from '@anticrm/model-recruit'
|
||||
import { DOMAIN_CONTACT } from '@anticrm/model-contact'
|
||||
|
||||
async function createCandidate (
|
||||
tx: TxOperations,
|
||||
@ -45,20 +46,37 @@ async function createCandidate (
|
||||
}
|
||||
|
||||
export const demoOperation: MigrateOperation = {
|
||||
async migrate (client: MigrationClient): Promise<void> {},
|
||||
async migrate (client: MigrationClient): Promise<void> {
|
||||
const rosamunds = await client.find<TxCreateDoc<EmployeeAccount>>(DOMAIN_TX, {
|
||||
_class: core.class.TxCreateDoc,
|
||||
objectClass: contact.class.EmployeeAccount,
|
||||
'attributes.email': 'rosamund@hc.engineering'
|
||||
})
|
||||
const docs = await client.find(DOMAIN_CONTACT, {
|
||||
_id: { $in: rosamunds.map((p) => p.attributes.employee) }
|
||||
})
|
||||
const currentEmployees = new Set(docs.map((p) => p._id))
|
||||
for (const rosamund of rosamunds) {
|
||||
if (!currentEmployees.has(rosamund.attributes.employee)) await client.delete(DOMAIN_TX, rosamund._id)
|
||||
}
|
||||
},
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||
const tx = new TxOperations(client, core.account.System)
|
||||
const current = await tx.findOne(contact.class.EmployeeAccount, {
|
||||
const ops = new TxOperations(client, core.account.System)
|
||||
const tx = await ops.findOne(core.class.TxCreateDoc, {
|
||||
objectClass: contact.class.EmployeeAccount,
|
||||
'attributes.email': 'rosamund@hc.engineering'
|
||||
})
|
||||
const current = await ops.findOne(contact.class.EmployeeAccount, {
|
||||
email: 'rosamund@hc.engineering'
|
||||
})
|
||||
if (current === undefined) {
|
||||
const employee = await tx.createDoc(contact.class.Employee, contact.space.Employee, {
|
||||
if (tx === undefined && current === undefined) {
|
||||
const employee = await ops.createDoc(contact.class.Employee, contact.space.Employee, {
|
||||
name: 'Chen,Rosamund',
|
||||
city: 'Mountain View',
|
||||
active: true
|
||||
})
|
||||
|
||||
await tx.createDoc<EmployeeAccount>(contact.class.EmployeeAccount, core.space.Model, {
|
||||
await ops.createDoc<EmployeeAccount>(contact.class.EmployeeAccount, core.space.Model, {
|
||||
email: 'rosamund@hc.engineering',
|
||||
employee,
|
||||
name: 'Chen,Rosamund',
|
||||
@ -66,8 +84,8 @@ export const demoOperation: MigrateOperation = {
|
||||
})
|
||||
}
|
||||
|
||||
await createCandidate(tx, 'P.,Andrey', 'Monte Carlo', 'andrey@hc.engineering', 'Chief Architect')
|
||||
await createCandidate(tx, 'M.,Marina', 'Los Angeles', 'marina@hc.engineering', 'Chief Designer')
|
||||
await createCandidate(tx, 'P.,Alex', 'Krasnodar, Russia', 'alex@hc.engineering', 'Frontend Engineer')
|
||||
await createCandidate(ops, 'P.,Andrey', 'Monte Carlo', 'andrey@hc.engineering', 'Chief Architect')
|
||||
await createCandidate(ops, 'M.,Marina', 'Los Angeles', 'marina@hc.engineering', 'Chief Designer')
|
||||
await createCandidate(ops, 'P.,Alex', 'Krasnodar, Russia', 'alex@hc.engineering', 'Frontend Engineer')
|
||||
}
|
||||
}
|
||||
|
@ -170,6 +170,7 @@ export function createModel (builder: Builder): void {
|
||||
icon: notification.icon.Notifications,
|
||||
component: notification.component.NotificationSettings,
|
||||
group: 'settings',
|
||||
secured: false,
|
||||
order: 2500
|
||||
},
|
||||
notification.ids.NotificationSettings
|
||||
|
@ -84,7 +84,7 @@
|
||||
}
|
||||
okProcessing = true
|
||||
const r = okAction()
|
||||
if (r instanceof Promise && !createMore) {
|
||||
if (r instanceof Promise && createMore) {
|
||||
r.then(() => {
|
||||
okProcessing = false
|
||||
dispatch('close')
|
||||
|
@ -67,6 +67,7 @@
|
||||
"KickEmployee": "Kick an employee",
|
||||
"KickEmployeeDescr": "Are you sure you want to kick the employee out of the workspace? This action cannot be undone",
|
||||
"Email": "Email",
|
||||
"CreateEmployee": "Create an employee"
|
||||
"CreateEmployee": "Create an employee",
|
||||
"Inactive": "Inactive"
|
||||
}
|
||||
}
|
@ -67,6 +67,7 @@
|
||||
"KickEmployee": "Исключить сотрудника",
|
||||
"KickEmployeeDescr": "Вы действительно хотите выгнать сотрудника из рабочего пространства? Это действие нельзя отменить",
|
||||
"Email": "Email",
|
||||
"CreateEmployee": "Создать сотрудника"
|
||||
"CreateEmployee": "Создать сотрудника",
|
||||
"Inactive": "Не активный"
|
||||
}
|
||||
}
|
@ -14,8 +14,10 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import contact, { Contact, Organization } from '@anticrm/contact'
|
||||
import { Contact, Employee, Organization } from '@anticrm/contact'
|
||||
import { getClient } from '@anticrm/presentation'
|
||||
import { Label } from '@anticrm/ui'
|
||||
import contact from '../plugin'
|
||||
|
||||
import OrganizationPresenter from './OrganizationPresenter.svelte'
|
||||
import PersonPresenter from './PersonPresenter.svelte'
|
||||
@ -28,11 +30,22 @@
|
||||
const hierarchy = client.getHierarchy()
|
||||
return hierarchy.isDerived(value._class, contact.class.Person)
|
||||
}
|
||||
function isEmployee (value: Contact): boolean {
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
return hierarchy.isDerived(value._class, contact.class.Employee)
|
||||
}
|
||||
const toOrg = (contact: Contact) => contact as Organization
|
||||
const toEmployee = (contact: Contact) => contact as Employee
|
||||
</script>
|
||||
|
||||
{#if isPerson(value)}
|
||||
<PersonPresenter {isInteractive} {value} />
|
||||
{#if isEmployee(value) && toEmployee(value)?.active === false}
|
||||
<div class="ml-1">
|
||||
(<Label label={contact.string.Inactive} />)
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<OrganizationPresenter value={toOrg(value)} />
|
||||
{/if}
|
||||
|
@ -1,12 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { Employee } from '@anticrm/contact'
|
||||
import EmployeeStatusPresenter from './EmployeeStatusPresenter.svelte'
|
||||
import PersonPresenter from '../components/PersonPresenter.svelte'
|
||||
import { showPopup } from '@anticrm/ui'
|
||||
import EmployeePreviewPopup from './EmployeePreviewPopup.svelte'
|
||||
import { WithLookup } from '@anticrm/core'
|
||||
import { IntlString } from '@anticrm/platform'
|
||||
import type { AnyComponent, AnySvelteComponent } from '@anticrm/ui'
|
||||
import { showPopup } from '@anticrm/ui'
|
||||
import PersonPresenter from '../components/PersonPresenter.svelte'
|
||||
import EmployeePreviewPopup from './EmployeePreviewPopup.svelte'
|
||||
import EmployeeStatusPresenter from './EmployeeStatusPresenter.svelte'
|
||||
|
||||
export let value: WithLookup<Employee> | null | undefined
|
||||
export let tooltipLabels:
|
||||
|
@ -60,6 +60,7 @@ export default mergeIds(contactId, contact, {
|
||||
KickEmployee: '' as IntlString,
|
||||
KickEmployeeDescr: '' as IntlString,
|
||||
Email: '' as IntlString,
|
||||
CreateEmployee: '' as IntlString
|
||||
CreateEmployee: '' as IntlString,
|
||||
Inactive: '' as IntlString
|
||||
}
|
||||
})
|
||||
|
@ -49,7 +49,7 @@
|
||||
<span class="antiSection-header__title">
|
||||
<Label label={recruit.string.Applications} />
|
||||
</span>
|
||||
<Button icon={IconAdd} kind={'transparent'} shape={'circle'} on:click={createApp} />
|
||||
<Button id="appls.add" icon={IconAdd} kind={'transparent'} shape={'circle'} on:click={createApp} />
|
||||
</div>
|
||||
{#if applications > 0}
|
||||
<Table
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import contact, { Employee, EmployeeAccount } from '@anticrm/contact'
|
||||
import contact, { Employee, EmployeeAccount, formatName } from '@anticrm/contact'
|
||||
import { PersonPresenter } from '@anticrm/contact-resources'
|
||||
import { AccountRole, getCurrentAccount, Ref, SortingOrder } from '@anticrm/core'
|
||||
import { createQuery, getClient } from '@anticrm/presentation'
|
||||
@ -71,8 +71,13 @@
|
||||
<div class="ac-body columns">
|
||||
<div class="ac-column max">
|
||||
{#each accounts as account (account._id)}
|
||||
{@const employee = employees.get(account.employee)}
|
||||
<div class="flex-between">
|
||||
<PersonPresenter value={employees.get(account.employee)} isInteractive={false} />
|
||||
{#if employee}
|
||||
<PersonPresenter value={employee} isInteractive={false} />
|
||||
{:else}
|
||||
{formatName(account.name)}
|
||||
{/if}
|
||||
<DropdownLabelsIntl
|
||||
label={setting.string.Role}
|
||||
disabled={account.role > currentRole || (account.role === AccountRole.Owner && owners.length === 1)}
|
||||
|
@ -17,7 +17,8 @@
|
||||
import { AccountRole, getCurrentAccount } from '@anticrm/core'
|
||||
import { createQuery } from '@anticrm/presentation'
|
||||
import setting, { SettingsCategory } from '@anticrm/setting'
|
||||
import { Component, Label } from '@anticrm/ui'
|
||||
import { Component, getCurrentLocation, Label, location, navigate } from '@anticrm/ui'
|
||||
import { onDestroy } from 'svelte'
|
||||
import CategoryElement from './CategoryElement.svelte'
|
||||
|
||||
let category: SettingsCategory | undefined
|
||||
@ -41,9 +42,18 @@
|
||||
return categories.find((x) => x.name === name)
|
||||
}
|
||||
|
||||
function selectCategory (value: SettingsCategory) {
|
||||
categoryId = value.name
|
||||
category = value
|
||||
onDestroy(
|
||||
location.subscribe(async (loc) => {
|
||||
categoryId = loc.path[3]
|
||||
category = findCategory(categoryId)
|
||||
})
|
||||
)
|
||||
|
||||
function selectCategory (id: string): void {
|
||||
const loc = getCurrentLocation()
|
||||
loc.path[3] = id
|
||||
loc.path.length = 4
|
||||
navigate(loc)
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -60,7 +70,7 @@
|
||||
label={category.label}
|
||||
selected={category.name === categoryId}
|
||||
on:click={() => {
|
||||
selectCategory(category)
|
||||
selectCategory(category.name)
|
||||
}}
|
||||
/>
|
||||
{/each}
|
||||
|
@ -37,9 +37,11 @@
|
||||
}
|
||||
|
||||
async function newIssue (): Promise<void> {
|
||||
if (space) {
|
||||
showPopup(CreateIssue, { space }, 'top')
|
||||
if (!space) {
|
||||
const team = await client.findOne(tracker.class.Team, {})
|
||||
space = team?._id
|
||||
}
|
||||
showPopup(CreateIssue, { space }, 'top')
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -36,39 +36,32 @@
|
||||
let defaultProjectLabel = ''
|
||||
|
||||
const query = createQuery()
|
||||
let projects: Map<Ref<Project>, Project> = new Map<Ref<Project>, Project>()
|
||||
let rawProjects: Project[] = []
|
||||
query.query(
|
||||
tracker.class.Project,
|
||||
{},
|
||||
(res) => {
|
||||
projects = new Map(
|
||||
res.map((p) => {
|
||||
return [p._id, p]
|
||||
})
|
||||
)
|
||||
rawProjects = res
|
||||
},
|
||||
{
|
||||
sort: { modifiedOn: SortingOrder.Ascending }
|
||||
}
|
||||
)
|
||||
|
||||
$: handleSelectedProjectIdUpdated(value, projects)
|
||||
$: handleSelectedProjectIdUpdated(value, rawProjects)
|
||||
|
||||
$: translate(tracker.string.Project, {}).then((result) => (defaultProjectLabel = result))
|
||||
$: projectIcon = selectedProject?.icon ?? tracker.icon.Projects
|
||||
$: projectText = shouldShowLabel ? selectedProject?.label ?? defaultProjectLabel : undefined
|
||||
|
||||
const handleSelectedProjectIdUpdated = async (
|
||||
newProjectId: Ref<Project> | null | undefined,
|
||||
projects: Map<Ref<Project>, Project>
|
||||
) => {
|
||||
const handleSelectedProjectIdUpdated = async (newProjectId: Ref<Project> | null | undefined, projects: Project[]) => {
|
||||
if (newProjectId === null || newProjectId === undefined) {
|
||||
selectedProject = undefined
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
selectedProject = projects.get(newProjectId)
|
||||
selectedProject = projects.find((it) => it._id === newProjectId)
|
||||
}
|
||||
|
||||
const handleProjectEditorOpened = async (event: MouseEvent): Promise<void> => {
|
||||
@ -79,7 +72,7 @@
|
||||
|
||||
const projectsInfo = [
|
||||
{ id: null, icon: tracker.icon.Projects, label: tracker.string.NoProject },
|
||||
...Array.from(projects.values()).map((p) => ({
|
||||
...rawProjects.map((p) => ({
|
||||
id: p._id,
|
||||
icon: p.icon,
|
||||
text: p.label
|
||||
|
@ -66,8 +66,9 @@
|
||||
ev.stopPropagation()
|
||||
const loc = getCurrentLocation()
|
||||
loc.path[1] = settingId
|
||||
loc.path[2] = 'classes'
|
||||
loc.path.length = 3
|
||||
loc.path[2] = 'setting'
|
||||
loc.path[3] = 'classes'
|
||||
loc.path.length = 4
|
||||
loc.query = { _class }
|
||||
loc.fragment = undefined
|
||||
navigate(loc)
|
||||
|
@ -457,8 +457,9 @@ export async function setRole (email: string, workspace: string, role: AccountRo
|
||||
const existingAccount = await ops.findOne(contact.class.EmployeeAccount, { email })
|
||||
|
||||
if (existingAccount !== undefined) {
|
||||
const value = isNaN(Number(role)) ? 0 : Number(role)
|
||||
await ops.update(existingAccount, {
|
||||
role
|
||||
role: value
|
||||
})
|
||||
}
|
||||
} finally {
|
||||
|
@ -78,7 +78,7 @@ test.describe('recruit tests', () => {
|
||||
|
||||
// Click on Add button
|
||||
// await page.click('.applications-container .flex-row-center .flex-center')
|
||||
await page.click('text=Applications There are no applications for this talent. New Application >> button')
|
||||
await page.click('button[id="appls.add"]')
|
||||
|
||||
await page.click('button:has-text("Vacancy")')
|
||||
|
||||
|
@ -44,13 +44,13 @@ test.describe('contact tests', () => {
|
||||
// Click button:has-text("Settings")
|
||||
await page.hover('button:has-text("Settings")')
|
||||
await page.click('button:has-text("Settings")')
|
||||
// Click text=Workspace Integrations >> button
|
||||
await page.click('text=Workspace Integrations >> button')
|
||||
// Click text=Workspace Notifications >> button
|
||||
await page.click('text=Workspace Notifications >> button')
|
||||
await page.click('text=Templates')
|
||||
// Click .flex-center.icon-button
|
||||
await page.click('#create-template >> .flex-center.icon-button')
|
||||
// Click [placeholder="New\ template"]
|
||||
await page.click('[placeholder="New\\ template"]')
|
||||
// await page.click('[placeholder="New\\ template"]')
|
||||
// Fill [placeholder="New\ template"]
|
||||
await page.fill('[placeholder="New\\ template"]', 't1')
|
||||
|
||||
@ -77,7 +77,8 @@ test.describe('contact tests', () => {
|
||||
// await page.click('text=Workspace')
|
||||
await page.hover('button:has-text("Settings")')
|
||||
await page.click('button:has-text("Settings")')
|
||||
await page.click('text=Workspace Integrations >> button')
|
||||
// Click text=Workspace Notifications >> button
|
||||
await page.click('text=Workspace Notifications >> button')
|
||||
// Click button:has-text("Manage Statuses")
|
||||
await page.click('text="Manage Statuses"')
|
||||
// Click text=Vacancies
|
||||
|
@ -49,6 +49,7 @@ async function fillIssueForm (
|
||||
}
|
||||
|
||||
async function createIssue (page: Page, props: IssueProps): Promise<void> {
|
||||
await page.waitForSelector('span:has-text("Default")')
|
||||
await page.click('button:has-text("New issue")')
|
||||
await fillIssueForm(page, props)
|
||||
await page.click('button:has-text("Save issue")')
|
||||
|
@ -12,7 +12,7 @@ function toHex (value: number, chars: number): string {
|
||||
return result
|
||||
}
|
||||
|
||||
let counter = (Math.random() * (1 << 24)) | 0
|
||||
let counter = 0
|
||||
const random = toHex((Math.random() * (1 << 24)) | 0, 6) + toHex((Math.random() * (1 << 16)) | 0, 4)
|
||||
|
||||
function timestamp (): string {
|
||||
|
Loading…
Reference in New Issue
Block a user