Uberf 10285 refactor header button (#8655)

Signed-off-by: Anton Alexeyev <alexeyev.anton@gmail.com>
This commit is contained in:
utkaka 2025-04-22 22:33:02 +07:00 committed by GitHub
parent 74d1dcc83d
commit b159c0610a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 383 additions and 313 deletions

View File

@ -1018,24 +1018,28 @@ export function createModel (builder: Builder): void {
},
override: [recruit.action.CreateGlobalApplication]
})
createAction(builder, {
action: view.actionImpl.ShowPopup,
actionProps: {
component: recruit.component.CreateCandidate,
element: 'top'
createAction(
builder,
{
action: view.actionImpl.ShowPopup,
actionProps: {
component: recruit.component.CreateCandidate,
element: 'top'
},
label: recruit.string.CreateTalent,
icon: recruit.icon.Create,
keyBinding: ['keyC'],
input: 'none',
category: recruit.category.Recruit,
target: core.class.Doc,
context: {
mode: ['workbench', 'browser'],
application: recruit.app.Recruit,
group: 'create'
}
},
label: recruit.string.CreateTalent,
icon: recruit.icon.Create,
keyBinding: ['keyC'],
input: 'none',
category: recruit.category.Recruit,
target: core.class.Doc,
context: {
mode: ['workbench', 'browser'],
application: recruit.app.Recruit,
group: 'create'
}
})
recruit.action.CreateTalent
)
createAction(builder, {
action: view.actionImpl.ShowPopup,

View File

@ -0,0 +1,130 @@
<!--
// Copyright © 2025 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 { HeaderButtonAction, SelectPopupValueType } from '../types'
import { checkPermission, Client, getCurrentAccount, hasAccountRole, TxOperations } from '@hcengineering/core'
import { ButtonWithDropdown, Button, Loading, IconAdd, IconDropdown } from '../index'
export let mainActionId: number | string | null = null
export let loading = false
export let client: TxOperations & Client
export let actions: HeaderButtonAction[] = []
export let visibleActions: string[] = []
let allowedActions: HeaderButtonAction[] = []
let items: HeaderButtonAction[] = []
let mainAction: HeaderButtonAction | undefined = undefined
$: filterVisibleActions(allowedActions, visibleActions)
function filterVisibleActions (allowed: HeaderButtonAction[], visible: (string | number | null)[]): void {
items = allowed.filter((action) => visible.includes(action.id))
mainAction = items.find((a) => a.id === mainActionId)
if (mainAction === undefined && items.length > 0) {
mainAction = items[0]
}
}
async function filterAllowedActions (): Promise<SelectPopupValueType[]> {
const result: HeaderButtonAction[] = []
for (const action of actions) {
if (await isActionAllowed(action)) {
result.push(action)
}
action.keyBinding = await action.keyBindingPromise
}
allowedActions = result
return result
}
async function isActionAllowed (action: HeaderButtonAction): Promise<boolean> {
if (action.accountRole === undefined && action.permission === undefined) return true
if (action.accountRole !== undefined && hasAccountRole(getCurrentAccount(), action.accountRole)) return true
return (
action.permission !== undefined && (await checkPermission(client, action.permission.id, action.permission.space))
)
}
</script>
{#await filterAllowedActions()}
<Loading shrink />
{:then filtered}
{#if mainAction !== undefined}
{#if loading}
<Loading shrink />
{:else}
<div class="antiNav-subheader">
{#if items.length === 1}
<Button
icon={IconAdd}
justify="left"
kind="primary"
label={mainAction.label}
width="100%"
on:click={mainAction.callback}
showTooltip={{
direction: 'bottom',
label: mainAction.label,
keys: mainAction.keyBinding
}}
>
<div slot="content" class="draft-circle-container">
{#if mainAction.draft === true}
<div class="draft-circle" />
{/if}
</div>
</Button>
{:else}
<ButtonWithDropdown
icon={IconAdd}
justify={'left'}
kind={'primary'}
label={mainAction.label}
dropdownItems={items}
dropdownIcon={IconDropdown}
on:dropdown-selected={(ev) => {
items.find((a) => a.id === ev.detail)?.callback()
}}
on:click={mainAction.callback}
mainButtonId={mainAction.id !== null ? String(mainAction.id).replaceAll(':', '-') : undefined}
showTooltipMain={{
direction: 'bottom',
label: mainAction.label,
keys: mainAction.keyBinding
}}
>
<div slot="content" class="draft-circle-container">
{#if mainAction.draft === true}
<div class="draft-circle" />
{/if}
</div>
</ButtonWithDropdown>
{/if}
</div>
{/if}
{/if}
{/await}
<style lang="scss">
.draft-circle-container {
margin-left: auto;
padding-right: 12px;
}
.draft-circle {
height: 6px;
width: 6px;
background-color: var(--primary-bg-color);
border-radius: 50%;
}
</style>

View File

@ -54,6 +54,7 @@ export { getCurrentLocation, locationToUrl, navigate, location, setLocationStora
export { default as EditBox } from './components/EditBox.svelte'
export { default as Label } from './components/Label.svelte'
export { default as Button } from './components/Button.svelte'
export { default as HeaderButton } from './components/HeaderButton.svelte'
export { default as ButtonWithDropdown } from './components/ButtonWithDropdown.svelte'
export { default as ButtonGroup } from './components/ButtonGroup.svelte'
export { default as Status } from './components/Status.svelte'

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
import { type Timestamp } from '@hcengineering/core'
import { type AccountRole, type Permission, type Timestamp, type Ref, type TypedSpace } from '@hcengineering/core'
import type {
Asset,
IntlString,
@ -510,6 +510,21 @@ export interface SelectPopupValueType {
}
}
/**
* @public
*/
export interface HeaderButtonAction extends SelectPopupValueType {
callback: () => void
keyBindingPromise?: Promise<string[] | undefined>
keyBinding?: string[] | undefined
draft?: boolean
accountRole?: AccountRole
permission?: {
id: Ref<Permission>
space: Ref<TypedSpace>
}
}
/**
* @public
*/

View File

@ -13,17 +13,9 @@
// limitations under the License.
-->
<script lang="ts">
import { AccountRole, Ref, Space, getCurrentAccount, hasAccountRole } from '@hcengineering/core'
import { AccountRole, Ref, Space, getCurrentAccount } from '@hcengineering/core'
import { createQuery, getClient } from '@hcengineering/presentation'
import {
Button,
ButtonWithDropdown,
IconAdd,
IconDropdown,
Loading,
SelectPopupValueType,
showPopup
} from '@hcengineering/ui'
import { HeaderButton, showPopup } from '@hcengineering/ui'
import { openDoc } from '@hcengineering/view-resources'
import { Analytics } from '@hcengineering/analytics'
import { DocumentEvents } from '@hcengineering/document'
@ -71,64 +63,37 @@
showPopup(CreateTeamspace, {}, 'top')
}
async function dropdownItemSelected (res?: SelectPopupValueType['id']): Promise<void> {
if (res === document.string.CreateDocument) {
await newDocument()
} else if (res === document.string.CreateTeamspace) {
await newTeamspace()
let mainActionId: string | undefined = undefined
let visibleActions: string[] = []
function updateActions (teamspace: boolean): void {
mainActionId = document.string.CreateDocument
if (teamspace) {
visibleActions = [document.string.CreateTeamspace, document.string.CreateDocument]
} else {
visibleActions = [document.string.CreateTeamspace]
}
}
const dropdownItems = hasAccountRole(me, AccountRole.User)
? [
{ id: document.string.CreateDocument, label: document.string.CreateDocument },
{ id: document.string.CreateTeamspace, label: document.string.CreateTeamspace }
]
: [{ id: document.string.CreateDocument, label: document.string.CreateDocument }]
$: updateActions(hasTeamspace)
</script>
{#if loading}
<Loading shrink />
{:else if hasAccountRole(getCurrentAccount(), AccountRole.User) || hasTeamspace}
<div class="antiNav-subheader">
{#if hasAccountRole(getCurrentAccount(), AccountRole.User)}
{#if hasTeamspace}
<ButtonWithDropdown
icon={IconAdd}
justify={'left'}
kind={'primary'}
label={document.string.CreateDocument}
on:click={newDocument}
mainButtonId={'new-document'}
dropdownIcon={IconDropdown}
{dropdownItems}
on:dropdown-selected={(ev) => {
void dropdownItemSelected(ev.detail)
}}
/>
{:else}
<Button
id={'new-teamspace'}
icon={IconAdd}
label={document.string.CreateTeamspace}
justify={'left'}
width={'100%'}
kind={'primary'}
gap={'large'}
on:click={newTeamspace}
/>
{/if}
{:else if hasTeamspace}
<Button
id={'new-document'}
icon={IconAdd}
label={document.string.CreateDocument}
justify={'left'}
width={'100%'}
kind={'primary'}
gap={'large'}
on:click={newDocument}
/>
{/if}
</div>
{/if}
<HeaderButton
{loading}
{client}
{mainActionId}
{visibleActions}
actions={[
{
id: document.string.CreateTeamspace,
label: document.string.CreateTeamspace,
accountRole: AccountRole.Maintainer,
callback: newTeamspace
},
{
id: document.string.CreateDocument,
label: document.string.CreateDocument,
accountRole: AccountRole.User,
callback: newDocument
}
]}
/>

View File

@ -13,15 +13,14 @@
// limitations under the License.
-->
<script lang="ts">
import { AccountRole, Ref, getCurrentAccount, hasAccountRole } from '@hcengineering/core'
import { type Drive, DriveEvents } from '@hcengineering/drive'
import { createQuery } from '@hcengineering/presentation'
import { Button, ButtonWithDropdown, IconAdd, IconDropdown, Loading, SelectPopupValueType } from '@hcengineering/ui'
import { AccountRole, Ref, getCurrentAccount } from '@hcengineering/core'
import { type Drive } from '@hcengineering/drive'
import { createQuery, getClient } from '@hcengineering/presentation'
import { HeaderButton } from '@hcengineering/ui'
import drive from '../plugin'
import { getFolderIdFromFragment } from '../navigation'
import { showCreateDrivePopup, showCreateFolderPopup, uploadFilesToDrivePopup } from '../utils'
import { Analytics } from '@hcengineering/analytics'
export let currentSpace: Ref<Drive> | undefined
export let currentFragment: string | undefined
@ -29,6 +28,7 @@
const me = getCurrentAccount()
const query = createQuery()
const client = getClient()
let loading = true
let hasDrive = false
@ -44,16 +44,6 @@
$: parent = getFolderIdFromFragment(currentFragment ?? '') ?? drive.ids.Root
async function handleDropdownItemSelected (res?: SelectPopupValueType['id']): Promise<void> {
if (res === drive.string.CreateDrive) {
await handleCreateDrive()
} else if (res === drive.string.CreateFolder) {
await handleCreateFolder()
} else if (res === drive.string.UploadFile) {
await handleUploadFile()
}
}
async function handleCreateDrive (): Promise<void> {
await showCreateDrivePopup()
}
@ -68,47 +58,42 @@
}
}
const dropdownItems = hasAccountRole(me, AccountRole.User)
? [
{ id: drive.string.CreateDrive, label: drive.string.CreateDrive, icon: drive.icon.Drive },
{ id: drive.string.CreateFolder, label: drive.string.CreateFolder, icon: drive.icon.Folder },
{ id: drive.string.UploadFile, label: drive.string.UploadFile, icon: drive.icon.File }
]
: [
{ id: drive.string.CreateFolder, label: drive.string.CreateFolder, icon: drive.icon.Folder },
{ id: drive.string.UploadFile, label: drive.string.UploadFile, icon: drive.icon.File }
]
let visibleActions: string[] = []
function updateActions (hasSpace: boolean): void {
if (hasSpace) {
visibleActions = [drive.string.CreateDrive, drive.string.CreateFolder, drive.string.UploadFile]
} else {
visibleActions = [drive.string.CreateDrive]
}
}
$: updateActions(hasDrive)
</script>
{#if loading}
<Loading shrink />
{:else}
<div class="antiNav-subheader">
{#if hasDrive}
<ButtonWithDropdown
icon={IconAdd}
justify={'left'}
kind={'primary'}
label={drive.string.UploadFile}
mainButtonId={'new-document'}
dropdownIcon={IconDropdown}
{dropdownItems}
disabled={currentSpace === undefined}
on:click={handleUploadFile}
on:dropdown-selected={(ev) => {
void handleDropdownItemSelected(ev.detail)
}}
/>
{:else}
<Button
icon={IconAdd}
label={drive.string.CreateDrive}
justify={'left'}
width={'100%'}
kind={'primary'}
gap={'large'}
on:click={handleCreateDrive}
/>
{/if}
</div>
{/if}
<HeaderButton
{loading}
{client}
mainActionId={drive.string.UploadFile}
{visibleActions}
actions={[
{
id: drive.string.CreateDrive,
label: drive.string.CreateDrive,
icon: drive.icon.Drive,
accountRole: AccountRole.Maintainer,
callback: handleCreateDrive
},
{
id: drive.string.CreateFolder,
label: drive.string.CreateFolder,
icon: drive.icon.Folder,
callback: handleCreateFolder
},
{
id: drive.string.UploadFile,
label: drive.string.UploadFile,
icon: drive.icon.File,
callback: handleUploadFile
}
]}
/>

View File

@ -13,26 +13,29 @@
// limitations under the License.
-->
<script lang="ts">
import { Button, showPopup, IconAdd } from '@hcengineering/ui'
import { showPopup, HeaderButton } from '@hcengineering/ui'
import lead from '../plugin'
import CreateCustomer from './CreateCustomer.svelte'
import { AccountRole, getCurrentAccount, hasAccountRole } from '@hcengineering/core'
import { AccountRole } from '@hcengineering/core'
import { getClient } from '@hcengineering/presentation'
const client = getClient()
async function newIssue (): Promise<void> {
showPopup(CreateCustomer, {}, 'top')
}
</script>
{#if hasAccountRole(getCurrentAccount(), AccountRole.User)}
<div class="antiNav-subheader">
<Button
icon={IconAdd}
label={lead.string.CreateCustomerLabel}
justify={'left'}
width={'100%'}
kind={'primary'}
gap={'large'}
on:click={newIssue}
/>
</div>
{/if}
<HeaderButton
{client}
mainActionId={lead.string.CreateCustomerLabel}
visibleActions={[lead.string.CreateCustomerLabel]}
actions={[
{
id: lead.string.CreateCustomerLabel,
label: lead.string.CreateCustomerLabel,
accountRole: AccountRole.User,
callback: newIssue
}
]}
/>

View File

@ -14,17 +14,23 @@
-->
<script lang="ts">
import { Analytics } from '@hcengineering/analytics'
import { AccountRole, getCurrentAccount, hasAccountRole } from '@hcengineering/core'
import { MultipleDraftController } from '@hcengineering/presentation'
import { AccountRole } from '@hcengineering/core'
import { getClient, MultipleDraftController } from '@hcengineering/presentation'
import { RecruitEvents } from '@hcengineering/recruit'
import { Button, IconAdd, showPopup } from '@hcengineering/ui'
import { HeaderButton, showPopup } from '@hcengineering/ui'
import { onDestroy } from 'svelte'
import recruit from '../plugin'
import CreateCandidate from './CreateCandidate.svelte'
import view from '@hcengineering/view'
let draftExists = false
const client = getClient()
const draftController = new MultipleDraftController(recruit.mixin.Candidate)
const newRecruitKeyBindingPromise = client
.findOne(view.class.Action, { _id: recruit.action.CreateTalent })
.then((p) => p?.keyBinding)
onDestroy(
draftController.hasNext((res) => {
draftExists = res
@ -35,37 +41,36 @@
showPopup(CreateCandidate, { shouldSaveDraft: true }, 'top')
Analytics.handleEvent(RecruitEvents.NewTalentButtonClicked)
}
let mainActionId: string | undefined = undefined
let visibleActions: string[] = []
function updateActions (draft: boolean): void {
mainActionId = draft ? recruit.string.ResumeDraft : recruit.string.CreateTalent
visibleActions = [mainActionId]
}
$: updateActions(draftExists)
</script>
{#if hasAccountRole(getCurrentAccount(), AccountRole.User)}
<div class="antiNav-subheader">
<Button
icon={IconAdd}
label={draftExists ? recruit.string.ResumeDraft : recruit.string.CreateTalent}
justify={'left'}
kind={'primary'}
width={'100%'}
gap={'large'}
on:click={newCandidate}
>
<div slot="content" class="draft-circle-container">
{#if draftExists}
<div class="draft-circle" />
{/if}
</div>
</Button>
</div>
{/if}
<style lang="scss">
.draft-circle-container {
margin-left: auto;
}
.draft-circle {
height: 6px;
width: 6px;
background-color: var(--primary-bg-color);
border-radius: 50%;
}
</style>
<HeaderButton
{client}
{mainActionId}
{visibleActions}
actions={[
{
id: recruit.string.CreateTalent,
label: recruit.string.CreateTalent,
accountRole: AccountRole.User,
keyBindingPromise: newRecruitKeyBindingPromise,
callback: newCandidate
},
{
id: recruit.string.ResumeDraft,
label: recruit.string.ResumeDraft,
draft: true,
accountRole: AccountRole.User,
keyBindingPromise: newRecruitKeyBindingPromise,
callback: newCandidate
}
]}
/>

View File

@ -45,7 +45,8 @@
"@hcengineering/task": "^0.6.20",
"@hcengineering/calendar": "^0.6.24",
"@hcengineering/ui": "^0.6.15",
"@hcengineering/tags": "^0.6.16"
"@hcengineering/tags": "^0.6.16",
"@hcengineering/view": "^0.6.13"
},
"repository": "https://github.com/hcengineering/platform",
"publishConfig": {

View File

@ -19,6 +19,7 @@ import { plugin } from '@hcengineering/platform'
import type { ProjectTypeDescriptor, TaskType } from '@hcengineering/task'
import { AnyComponent, Location, ResolvedLocation } from '@hcengineering/ui'
import type { Applicant, ApplicantMatch, Candidate, Opinion, Review, Vacancy, VacancyList } from './types'
import { Action } from '@hcengineering/view'
export * from './types'
export * from './analytics'
@ -45,6 +46,9 @@ const recruit = plugin(recruitId, {
descriptors: {
VacancyType: '' as Ref<ProjectTypeDescriptor>
},
action: {
CreateTalent: '' as Ref<Action<Doc, any>>
},
mixin: {
Candidate: '' as Ref<Mixin<Candidate>>,
VacancyList: '' as Ref<Mixin<VacancyList>>,

View File

@ -14,17 +14,10 @@
-->
<script lang="ts">
import { Analytics } from '@hcengineering/analytics'
import core, {
AccountRole,
Ref,
Space,
getCurrentAccount,
hasAccountRole,
checkPermission
} from '@hcengineering/core'
import core, { AccountRole, Ref, Space } from '@hcengineering/core'
import { MultipleDraftController, createQuery, getClient } from '@hcengineering/presentation'
import { TrackerEvents } from '@hcengineering/tracker'
import { Button, ButtonWithDropdown, IconAdd, IconDropdown, SelectPopupValueType, showPopup } from '@hcengineering/ui'
import { HeaderButton, showPopup } from '@hcengineering/ui'
import view from '@hcengineering/view'
import { onDestroy } from 'svelte'
@ -34,15 +27,35 @@
export let currentSpace: Ref<Space> | undefined
let closed = true
let draftExists = false
let projectExists = false
let loading = true
const query = createQuery()
const client = getClient()
const draftController = new MultipleDraftController(tracker.ids.IssueDraft)
const newIssueKeyBindingPromise = client
.findOne(view.class.Action, { _id: tracker.action.NewIssue })
.then((p) => p?.keyBinding)
onDestroy(
draftController.hasNext((res) => {
draftExists = res
})
)
query.query(tracker.class.Project, {}, (res) => {
projectExists = res.length > 0
loading = false
})
function newProject (): void {
closed = false
showPopup(tracker.component.CreateProject, {}, 'top', () => {
closed = true
})
}
function newIssue (): void {
closed = false
Analytics.handleEvent(TrackerEvents.NewIssueButtonClicked)
@ -51,115 +64,54 @@
})
}
const query = createQuery()
let projectExists = false
query.query(tracker.class.Project, {}, (res) => {
projectExists = res.length > 0
})
const client = getClient()
$: label = draftExists || !closed ? tracker.string.ResumeDraft : tracker.string.NewIssue
let keys: string[] | undefined = undefined
let canCreateProject = hasAccountRole(getCurrentAccount(), AccountRole.Maintainer)
function dropdownItemSelected (res?: SelectPopupValueType['id']): void {
if (res == null) return
if (res === tracker.string.CreateProject) {
closed = false
showPopup(tracker.component.CreateProject, {}, 'top', () => {
closed = true
})
let mainActionId: string | undefined = undefined
let visibleActions: string[] = []
function updateActions (draft: boolean, project: boolean, closed: boolean): void {
mainActionId = draft || !closed ? tracker.string.ResumeDraft : tracker.string.NewIssue
if (project) {
visibleActions = [tracker.string.CreateProject, mainActionId, tracker.string.Import]
} else {
newIssue()
visibleActions = [tracker.string.CreateProject]
}
}
void client.findOne(view.class.Action, { _id: tracker.action.NewIssue }).then((p) => (keys = p?.keyBinding))
if (!canCreateProject) {
void checkPermission(client, core.permission.CreateProject, core.space.Space).then((hasPermission) => {
canCreateProject = hasPermission
})
}
function getAvailableActions (): SelectPopupValueType[] {
const result = []
if (canCreateProject) {
result.push({
id: tracker.string.CreateProject,
label: tracker.string.CreateProject
})
}
result.push({
id: tracker.string.NewIssue,
label: tracker.string.NewIssue
})
if (hasAccountRole(getCurrentAccount(), AccountRole.User)) {
result.push({
id: tracker.string.Import,
label: tracker.string.Import
})
}
return result
}
$: updateActions(draftExists, projectExists, closed)
</script>
<div class="antiNav-subheader">
{#if projectExists}
<ButtonWithDropdown
icon={IconAdd}
justify={'left'}
kind={'primary'}
{label}
on:click={newIssue}
dropdownItems={getAvailableActions()}
dropdownIcon={IconDropdown}
on:dropdown-selected={(ev) => {
dropdownItemSelected(ev.detail)
}}
mainButtonId={'new-issue'}
showTooltipMain={{
direction: 'bottom',
label,
keys
}}
>
<div slot="content" class="draft-circle-container">
{#if draftExists}
<div class="draft-circle" />
{/if}
</div>
</ButtonWithDropdown>
{:else}
<Button
disabled={!canCreateProject}
icon={IconAdd}
justify="left"
kind="primary"
label={tracker.string.CreateProject}
width="100%"
on:click={() => {
showPopup(tracker.component.CreateProject, {}, 'top', () => {
closed = true
})
}}
/>
{/if}
</div>
<style lang="scss">
.draft-circle-container {
margin-left: auto;
padding-right: 12px;
}
.draft-circle {
height: 6px;
width: 6px;
background-color: var(--primary-bg-color);
border-radius: 50%;
}
</style>
<HeaderButton
{loading}
{client}
{mainActionId}
{visibleActions}
actions={[
{
id: tracker.string.CreateProject,
label: tracker.string.CreateProject,
accountRole: AccountRole.Maintainer,
permission: {
id: core.permission.CreateProject,
space: core.space.Space
},
callback: newProject
},
{
id: tracker.string.ResumeDraft,
label: tracker.string.ResumeDraft,
draft: true,
keyBindingPromise: newIssueKeyBindingPromise,
callback: newIssue
},
{
id: tracker.string.NewIssue,
label: tracker.string.NewIssue,
keyBindingPromise: newIssueKeyBindingPromise,
callback: newIssue
},
{
id: tracker.string.Import,
label: tracker.string.Import,
accountRole: AccountRole.User,
callback: newIssue
}
]}
/>

View File

@ -18,7 +18,7 @@ export class DocumentsPage extends CommonPage {
readonly popupMoveDocument: DocumentMovePopup
readonly buttonCreateDocument = (): Locator =>
this.page.locator('div[data-float="navigator"] button[id="new-document"]')
this.page.locator('div[data-float="navigator"] button[id="document-string-CreateDocument"]')
readonly buttonDocumentWrapper = (name: string): Locator =>
this.page.locator(`button.hulyNavItem-container:has-text("${name}")`)

View File

@ -10,7 +10,8 @@ export class IssuesPage extends CommonTrackerPage {
modelSelectorAll = (): Locator => this.page.locator('label[data-id="tab-all"]')
issues = (): Locator => this.page.locator('.antiPanel-navigator').locator('text="Issues"')
subIssues = (): Locator => this.page.locator('button:has-text("Add sub-issue")')
newIssue = (): Locator => this.page.locator('#new-issue')
newIssue = (): Locator => this.page.locator('#tracker-string-NewIssue')
resumeDraft = (): Locator => this.page.locator('#tracker-string-ResumeDraft')
modelSelectorActive = (): Locator => this.page.locator('label[data-id="tab-active"]')
modelSelectorBacklog = (): Locator => this.page.locator('label[data-id="tab-backlog"]')
buttonCreateNewIssue = (): Locator => this.page.locator('button > div', { hasText: 'New issue' })
@ -156,7 +157,7 @@ export class IssuesPage extends CommonTrackerPage {
estimationSpan = (): Locator => this.page.locator('.estimation-container >> span').first()
okButton = (): Locator => this.page.getByRole('button', { name: 'Ok', exact: true })
newIssueButton = (): Locator => this.page.locator('#new-issue')
newIssueButton = (): Locator => this.page.locator('#tracker-string-NewIssue')
issueNameInput = (): Locator => this.page.locator('#issue-name >> input')
issueDescriptionInput = (): Locator => this.page.locator('#issue-description >> [contenteditable]')
statusEditor = (): Locator => this.page.locator('#status-editor')
@ -232,6 +233,10 @@ export class IssuesPage extends CommonTrackerPage {
await this.newIssue().click()
}
async clickOnResumeDraft (): Promise<void> {
await this.resumeDraft().click()
}
async navigateToMyIssues (): Promise<void> {
await this.myIssuesButton().click()
}

View File

@ -45,7 +45,7 @@ test.describe('Tracker sub-issues tests', () => {
await fillIssueForm(page, props)
await page.keyboard.press('Escape')
await page.keyboard.press('Escape')
await issuesPage.clickOnNewIssue()
await issuesPage.clickOnResumeDraft()
await checkIssueDraft(page, props)
})

View File

@ -161,7 +161,7 @@ test.describe('Tracker tests', () => {
await issuesPage.inputTextPlaceholderFill('1')
await issuesPage.setDueDate('24')
await issuesPage.pressEscapeTwice()
await issuesPage.clickOnNewIssue()
await issuesPage.clickOnResumeDraft()
await checkIssueDraft(page, {
name: issueName,
description: issueName,