diff --git a/packages/text-editor/lang/en.json b/packages/text-editor/lang/en.json index 86caa10c6e..3ea6ef35ef 100644 --- a/packages/text-editor/lang/en.json +++ b/packages/text-editor/lang/en.json @@ -47,6 +47,8 @@ "TableOptions": "Customize table", "Width": "Width", "Height": "Height", - "Unset": "Unset" + "Unset": "Unset", + "Image": "Image", + "SeparatorLine": "Separator line" } } diff --git a/packages/text-editor/lang/es.json b/packages/text-editor/lang/es.json index 134c76d6d5..d0be8ca066 100644 --- a/packages/text-editor/lang/es.json +++ b/packages/text-editor/lang/es.json @@ -45,6 +45,8 @@ "TableOptions": "Personalizar tabla", "Width": "Ancho", "Height": "Alto", - "Unset": "Anular" + "Unset": "Anular", + "Image": "Imagen", + "SeparatorLine": "Línea de separación" } } \ No newline at end of file diff --git a/packages/text-editor/lang/pt.json b/packages/text-editor/lang/pt.json index a01073b380..3b14665522 100644 --- a/packages/text-editor/lang/pt.json +++ b/packages/text-editor/lang/pt.json @@ -45,6 +45,8 @@ "TableOptions": "Personalizar tabela", "Width": "Largura", "Height": "Altura", - "Unset": "Anular" + "Unset": "Anular", + "Image": "Imagem", + "SeparatorLine": "linha separadora" } } \ No newline at end of file diff --git a/packages/text-editor/lang/ru.json b/packages/text-editor/lang/ru.json index b08ddbe178..52cb3bd163 100644 --- a/packages/text-editor/lang/ru.json +++ b/packages/text-editor/lang/ru.json @@ -47,6 +47,8 @@ "TableOptions": "Настроить таблицу", "Width": "Ширина", "Height": "Высота", - "Unset": "Убрать" + "Unset": "Убрать", + "Image": "Изображение", + "SeparatorLine": "Разделительная линия" } } diff --git a/packages/text-editor/src/components/CollaborativeAttributeBox.svelte b/packages/text-editor/src/components/CollaborativeAttributeBox.svelte index e184433fdc..06a2b93c69 100644 --- a/packages/text-editor/src/components/CollaborativeAttributeBox.svelte +++ b/packages/text-editor/src/components/CollaborativeAttributeBox.svelte @@ -119,6 +119,7 @@ {readonly} field={key.key} canEmbedFiles={false} + withSideMenu={false} on:focus on:blur on:update diff --git a/packages/text-editor/src/components/CollaborativeTextEditor.svelte b/packages/text-editor/src/components/CollaborativeTextEditor.svelte index 78ce8a9b95..4de9f33b3d 100644 --- a/packages/text-editor/src/components/CollaborativeTextEditor.svelte +++ b/packages/text-editor/src/components/CollaborativeTextEditor.svelte @@ -18,9 +18,20 @@ import { type Class, type CollaborativeDoc, type Doc, type Ref } from '@hcengineering/core' import { type DocumentId, type PlatformDocumentId } from '@hcengineering/collaborator-client' import { IntlString, getMetadata, translate } from '@hcengineering/platform' - import presentation from '@hcengineering/presentation' import { markupToJSON } from '@hcengineering/text' - import { AnySvelteComponent, Button, IconSize, Loading, ThrottledCaller, themeStore } from '@hcengineering/ui' + import presentation, { getFileUrl, getImageSize } from '@hcengineering/presentation' + import view from '@hcengineering/view' + import { + AnySvelteComponent, + Button, + IconSize, + Loading, + PopupAlignment, + getEventPositionElement, + getPopupPositionElement, + ThrottledCaller, + themeStore + } from '@hcengineering/ui' import { AnyExtension, Editor, FocusPosition, mergeAttributes } from '@tiptap/core' import Collaboration, { isChangeOrigin } from '@tiptap/extension-collaboration' import CollaborationCursor from '@tiptap/extension-collaboration-cursor' @@ -45,6 +56,7 @@ TextFormatCategory, TextNodeAction } from '../types' + import { addTableHandler } from '../utils' import CollaborationUsers from './CollaborationUsers.svelte' import ImageStyleToolbar from './ImageStyleToolbar.svelte' @@ -55,9 +67,11 @@ import { ImageExtension } from './extension/imageExt' import { type FileAttachFunction } from './extension/types' import { FileExtension } from './extension/fileExt' + import { LeftMenuExtension } from './extension/leftMenu' + import { InlineCommandsExtension } from './extension/inlineCommands' import { InlinePopupExtension } from './extension/inlinePopup' import { InlineStyleToolbarExtension } from './extension/inlineStyleToolbar' - import { completionConfig } from './extensions' + import { completionConfig, inlineCommandsConfig } from './extensions' export let collaborativeDoc: CollaborativeDoc export let initialCollaborativeDoc: CollaborativeDoc | undefined = undefined @@ -98,6 +112,8 @@ export let canShowPopups = true export let canEmbedFiles = true export let canEmbedImages = true + export let withSideMenu = true + export let withInlineCommands = true const dispatch = createEventDispatcher() @@ -166,13 +182,33 @@ insertTemplate: (name, markup) => { editor?.commands.insertContent(markupToJSON(markup)) }, + insertTable: (options: { rows?: number, cols?: number, withHeaderRow?: boolean }) => { + editor?.commands.insertTable(options) + }, + insertCodeBlock: () => { + editor?.commands.insertContent( + { + type: 'codeBlock', + content: [{ type: 'text', text: ' ' }] + }, + { + updateSelection: false + } + ) + }, + insertContent: (content) => { + editor?.commands.insertContent(content) + }, + insertSeparatorLine: () => { + editor?.commands.setHorizontalRule() + }, focus: () => { focus() } } - function handleAction (a: RefAction, evt?: Event): void { - a.action(evt?.target as HTMLElement, editorHandler) + function handleAction (a: RefAction, evt?: MouseEvent): void { + a.action(evt?.target as HTMLElement, editorHandler, evt) } $: commandHandler = textEditorCommandHandler(editor) @@ -258,6 +294,123 @@ }) ) } + if (withSideMenu) { + optionalExtensions.push( + LeftMenuExtension.configure({ + width: 20, + height: 20, + marginX: 8, + className: 'tiptap-left-menu', + icon: view.icon.Add, + iconProps: { + className: 'svg-tiny', + fill: 'currentColor' + }, + items: [ + ...(canEmbedImages ? [{ id: 'image', label: textEditorPlugin.string.Image, icon: view.icon.Image }] : []), + { id: 'table', label: textEditorPlugin.string.Table, icon: view.icon.Table2 }, + { id: 'code-block', label: textEditorPlugin.string.CodeBlock, icon: view.icon.CodeBlock }, + { id: 'separator-line', label: textEditorPlugin.string.SeparatorLine, icon: view.icon.SeparatorLine } + ], + handleSelect: handleLeftMenuClick + }) + ) + } + if (withInlineCommands) { + optionalExtensions.push( + InlineCommandsExtension.configure( + inlineCommandsConfig(handleLeftMenuClick, attachFile === undefined || !canEmbedImages ? ['image'] : []) + ) + ) + } + } + + let inputImage: HTMLInputElement + + export function handleAttachImage (): void { + inputImage.click() + } + + async function createInlineImage (file: File): Promise { + if (!file.type.startsWith('image/') || attachFile === undefined) { + return + } + + const attached = await attachFile(file) + if (attached === undefined) { + return + } + + const size = await getImageSize( + file, + getFileUrl(attached.file, 'full', getMetadata(presentation.metadata.UploadURL)) + ) + + editor.commands.insertContent( + { + type: 'image', + attrs: { + 'file-id': attached.file, + width: Math.round(size.width / size.pixelRatio) + } + }, + { + updateSelection: false + } + ) + } + + async function fileSelected (): Promise { + if (readonly) return + const list = inputImage.files + if (list === null || list.length === 0) return + for (let index = 0; index < list.length; index++) { + const file = list.item(index) + if (file !== null) { + await createInlineImage(file) + } + } + inputImage.value = '' + } + + async function handleLeftMenuClick (id: string, pos: number, targetItem?: MouseEvent | HTMLElement): Promise { + editor.commands.focus(pos, { scrollIntoView: false }) + + switch (id) { + case 'image': + handleAttachImage() + break + case 'table': { + let position: PopupAlignment | undefined = undefined + if (targetItem !== undefined) { + position = + targetItem instanceof MouseEvent ? getEventPositionElement(targetItem) : getPopupPositionElement(targetItem) + } + + // We need to trigger it asynchronously in order for the editor to finish its focus event + // Otherwise, it hoggs the focus from the popup and keyboard navigation doesn't work + setTimeout(() => { + addTableHandler(editor.commands.insertTable, position) + }) + break + } + case 'code-block': + // For some reason .setCodeBlock doesnt work in our case + editor.commands.insertContent( + { + type: 'codeBlock', + content: [{ type: 'text', text: ' ' }] + }, + { + updateSelection: false + } + ) + editor.commands.focus(pos, { scrollIntoView: false }) + break + case 'separator-line': + editor.commands.setHorizontalRule() + break + } } const throttle = new ThrottledCaller(100) @@ -353,6 +506,16 @@ }) +
+ + + { + updateStyle() + }} +/> + + +
{ + close() + }} +/> +
{ + wPopup = element.clientWidth + updateStyle() + }} +> + +
+ + diff --git a/packages/text-editor/src/components/ReferenceInput.svelte b/packages/text-editor/src/components/ReferenceInput.svelte index 4e3916c67a..4aa67e84c2 100644 --- a/packages/text-editor/src/components/ReferenceInput.svelte +++ b/packages/text-editor/src/components/ReferenceInput.svelte @@ -77,6 +77,18 @@ insertTemplate: (name, markup) => { textEditor?.insertMarkup(markup) }, + insertTable (options: { rows?: number, cols?: number, withHeaderRow?: boolean }) { + textEditor?.insertTable(options) + }, + insertCodeBlock: () => { + textEditor?.insertCodeBlock() + }, + insertSeparatorLine: () => { + textEditor?.insertSeparatorLine() + }, + insertContent: (content) => { + textEditor?.insertContent(content) + }, focus: () => { textEditor?.focus() } diff --git a/packages/text-editor/src/components/StyledTextBox.svelte b/packages/text-editor/src/components/StyledTextBox.svelte index 74d3801ad4..4745caf1b9 100644 --- a/packages/text-editor/src/components/StyledTextBox.svelte +++ b/packages/text-editor/src/components/StyledTextBox.svelte @@ -1,7 +1,7 @@ +
{ textEditor?.insertText(text) }, @@ -94,6 +94,18 @@ textEditor?.insertMarkup(markup) dispatch('template', name) }, + insertTable (options: { rows?: number, cols?: number, withHeaderRow?: boolean }) { + textEditor?.insertTable(options) + }, + insertCodeBlock: (pos?: number) => { + textEditor?.insertCodeBlock(pos) + }, + insertSeparatorLine: () => { + textEditor?.insertSeparatorLine() + }, + insertContent: (value, options) => { + textEditor?.insertContent(value, options) + }, focus: () => { textEditor?.focus() } diff --git a/packages/text-editor/src/components/TextEditor.svelte b/packages/text-editor/src/components/TextEditor.svelte index 2fb8d5048c..08aa350cf4 100644 --- a/packages/text-editor/src/components/TextEditor.svelte +++ b/packages/text-editor/src/components/TextEditor.svelte @@ -19,7 +19,7 @@ import { EmptyMarkup, getMarkup, markupToJSON } from '@hcengineering/text' import { themeStore } from '@hcengineering/ui' - import { AnyExtension, Editor, FocusPosition, mergeAttributes } from '@tiptap/core' + import { AnyExtension, Content, Editor, FocusPosition, mergeAttributes } from '@tiptap/core' import Placeholder from '@tiptap/extension-placeholder' import { createEventDispatcher, onDestroy, onMount } from 'svelte' @@ -34,6 +34,9 @@ import { InlineStyleToolbarExtension } from './extension/inlineStyleToolbar' import { SubmitExtension } from './extension/submit' import { EditorKit } from '../kits/editor-kit' + import { getFileUrl, getImageSize } from '@hcengineering/presentation' + import { FileAttachFunction } from './extension/types' + import { ParseOptions } from '@tiptap/pm/model' export let content: Markup = '' export let placeholder: IntlString = textEditorPlugin.string.EditorPlaceholder @@ -43,6 +46,7 @@ export let editorAttributes: Record = {} export let boundary: HTMLElement | undefined = undefined export let autofocus: FocusPosition = false + export let attachFile: FileAttachFunction | undefined = undefined let element: HTMLElement let editor: Editor @@ -85,6 +89,36 @@ export function insertText (text: string): void { editor.commands.insertContent(text) } + export function insertTable (options: { rows?: number, cols?: number, withHeaderRow?: boolean }) { + editor.commands.insertTable(options) + } + export function insertCodeBlock (pos?: number): void { + editor.commands.insertContent( + { + type: 'codeBlock', + content: [{ type: 'text', text: ' ' }] + }, + { + updateSelection: false + } + ) + + if (pos !== undefined) { + editor.commands.focus(pos, { scrollIntoView: false }) + } + } + export function insertSeparatorLine (): void { + editor.commands.setHorizontalRule() + } + export function insertContent ( + value: Content, + options?: { + parseOptions?: ParseOptions + updateSelection?: boolean + } + ): void { + editor.commands.insertContent(value, options) + } export function insertMarkup (markup: Markup): void { editor.commands.insertContent(markupToJSON(markup)) diff --git a/packages/text-editor/src/components/TextEditorStyleToolbar.svelte b/packages/text-editor/src/components/TextEditorStyleToolbar.svelte index 7a704571ef..36832871d7 100644 --- a/packages/text-editor/src/components/TextEditorStyleToolbar.svelte +++ b/packages/text-editor/src/components/TextEditorStyleToolbar.svelte @@ -15,13 +15,11 @@ + + + + + + diff --git a/packages/text-editor/src/index.ts b/packages/text-editor/src/index.ts index cfcbdce8ff..a24d562eea 100644 --- a/packages/text-editor/src/index.ts +++ b/packages/text-editor/src/index.ts @@ -34,6 +34,7 @@ export { default as StyledTextEditor } from './components/StyledTextEditor.svelt export { default as TextEditor } from './components/TextEditor.svelte' export { default as TextEditorStyleToolbar } from './components/TextEditorStyleToolbar.svelte' export { default as AttachIcon } from './components/icons/Attach.svelte' +export { default as TableIcon } from './components/icons/Table.svelte' export { default as TableOfContents } from './components/toc/TableOfContents.svelte' export * from './components/node-view' export { default } from './plugin' diff --git a/packages/text-editor/src/plugin.ts b/packages/text-editor/src/plugin.ts index 2303fccd5b..549bfa9b0c 100644 --- a/packages/text-editor/src/plugin.ts +++ b/packages/text-editor/src/plugin.ts @@ -78,6 +78,8 @@ export default plugin(textEditorId, { TableOptions: '' as IntlString, Width: '' as IntlString, Height: '' as IntlString, - Unset: '' as IntlString + Unset: '' as IntlString, + Image: '' as IntlString, + SeparatorLine: '' as IntlString } }) diff --git a/packages/text-editor/src/types.ts b/packages/text-editor/src/types.ts index c8a957f273..84f6a6d33f 100644 --- a/packages/text-editor/src/types.ts +++ b/packages/text-editor/src/types.ts @@ -1,8 +1,9 @@ import { type Asset, type IntlString, type Resource } from '@hcengineering/platform' import { type Account, type Doc, type Markup, type Ref } from '@hcengineering/core' import type { AnySvelteComponent } from '@hcengineering/ui' -import { type Editor, type SingleCommands } from '@tiptap/core' import { type RelativePosition } from 'yjs' +import { type Content, type Editor, type SingleCommands } from '@tiptap/core' +import { type ParseOptions } from '@tiptap/pm/model' /** * @public @@ -11,12 +12,22 @@ export interface TextEditorHandler { insertText: (html: string) => void insertMarkup: (markup: Markup) => void insertTemplate: (name: string, markup: string) => void + insertTable: (options: { rows?: number, cols?: number, withHeaderRow?: boolean }) => void + insertCodeBlock: (pos?: number) => void + insertSeparatorLine: () => void + insertContent: ( + value: Content, + options?: { + parseOptions?: ParseOptions + updateSelection?: boolean + } + ) => void focus: () => void } /** * @public */ -export type RefInputAction = (element: HTMLElement, editor: TextEditorHandler) => void +export type RefInputAction = (element: HTMLElement, editor: TextEditorHandler, event?: MouseEvent) => void /** * A contribution to reference input control, to allow to add more actions to it. * @public diff --git a/packages/text-editor/src/utils.ts b/packages/text-editor/src/utils.ts index 9d17198e44..3fd19a2da4 100644 --- a/packages/text-editor/src/utils.ts +++ b/packages/text-editor/src/utils.ts @@ -14,6 +14,9 @@ // import { type Attribute } from '@tiptap/core' +import { showPopup, SelectPopup, type PopupAlignment } from '@hcengineering/ui' + +import { mInsertTable } from './components/extensions' export function getDataAttribute ( name: string, @@ -37,3 +40,28 @@ export function getDataAttribute ( ...(options ?? {}) } } + +export async function addTableHandler ( + insertTable: (options: { rows?: number, cols?: number, withHeaderRow?: boolean }) => void, + alignment?: PopupAlignment +): Promise { + showPopup( + SelectPopup, + { + value: mInsertTable.map((it) => ({ id: it.label, text: it.label })) + }, + alignment ?? 'center', + (val) => { + if (val !== undefined) { + const tab = mInsertTable.find((it) => it.label === val) + if (tab !== undefined) { + insertTable({ + cols: tab.cols, + rows: tab.rows, + withHeaderRow: tab.header + }) + } + } + } + ) +} diff --git a/packages/theme/styles/_layouts.scss b/packages/theme/styles/_layouts.scss index f74b1004f1..d3e43dd3a0 100644 --- a/packages/theme/styles/_layouts.scss +++ b/packages/theme/styles/_layouts.scss @@ -901,6 +901,10 @@ a.no-line { &.disabled { pointer-events: none; } } +.hidden { + visibility: hidden; +} + .lines-limit-2, .lines-limit-4 { min-width: 0; overflow: hidden; diff --git a/packages/ui/src/components/SelectPopup.svelte b/packages/ui/src/components/SelectPopup.svelte index ce1d6c716d..64a031498f 100644 --- a/packages/ui/src/components/SelectPopup.svelte +++ b/packages/ui/src/components/SelectPopup.svelte @@ -33,7 +33,7 @@ export let value: SelectPopupValueType[] export let width: 'medium' | 'large' | 'full' = 'medium' export let size: 'small' | 'medium' | 'large' = 'small' - export let onSelect: ((value: SelectPopupValueType['id']) => void) | undefined = undefined + export let onSelect: ((value: SelectPopupValueType['id'], event?: Event) => void) | undefined = undefined export let showShadow: boolean = true export let embedded: boolean = false export let loading = false @@ -59,27 +59,32 @@ } } - function onKeydown (key: KeyboardEvent): void { + export function onKeydown (key: KeyboardEvent): boolean { if (key.code === 'Tab') { dispatch('close') key.preventDefault() key.stopPropagation() + return true } if (key.code === 'ArrowUp') { key.stopPropagation() key.preventDefault() list.select(selection - 1) + return true } if (key.code === 'ArrowDown') { key.stopPropagation() key.preventDefault() list.select(selection + 1) + return true } if (key.code === 'Enter') { key.preventDefault() key.stopPropagation() sendSelect(value[selection].id) + return true } + return false } const manager = createFocusManager() diff --git a/plugins/attachment-resources/src/components/AttachmentStyleBoxCollabEditor.svelte b/plugins/attachment-resources/src/components/AttachmentStyleBoxCollabEditor.svelte index 66a8e36b5c..6501379783 100644 --- a/plugins/attachment-resources/src/components/AttachmentStyleBoxCollabEditor.svelte +++ b/plugins/attachment-resources/src/components/AttachmentStyleBoxCollabEditor.svelte @@ -18,13 +18,21 @@ import { Account, Doc, Ref, generateId } from '@hcengineering/core' import { IntlString, getResource, setPlatformStatus, unknownError } from '@hcengineering/platform' import { KeyedAttribute, createQuery, getClient } from '@hcengineering/presentation' - import textEditor, { AttachIcon, CollaborativeAttributeBox, RefAction } from '@hcengineering/text-editor' - import { AnySvelteComponent, navigate } from '@hcengineering/ui' - import view from '@hcengineering/view' import { getCollaborationUser, getObjectLinkFragment } from '@hcengineering/view-resources' + import textEditor, { + AttachIcon, + CollaborativeAttributeBox, + RefAction, + TableIcon, + TextEditorHandler, + addTableHandler + } from '@hcengineering/text-editor' + import { AnySvelteComponent, getEventPositionElement, getPopupPositionElement, navigate } from '@hcengineering/ui' + import view from '@hcengineering/view' + import { defaultRefActions, getModelRefActions } from '@hcengineering/text-editor/src/components/editor/actions' + import AttachmentsGrid from './AttachmentsGrid.svelte' import { uploadFile } from '../utils' - import { defaultRefActions, getModelRefActions } from '@hcengineering/text-editor/src/components/editor/actions' export let object: Doc export let key: KeyedAttribute @@ -58,6 +66,12 @@ icon: AttachIcon, action: handleAttach, order: 1001 + }, + { + label: textEditor.string.Table, + icon: TableIcon, + action: handleTable, + order: 1501 } ] } else { @@ -94,6 +108,12 @@ return editor?.isFocused() ?? false } + export function handleTable (element: HTMLElement, editorHandler: TextEditorHandler, event?: MouseEvent): void { + const position = event !== undefined ? getEventPositionElement(event) : getPopupPositionElement(element) + + addTableHandler(editorHandler.insertTable, position) + } + export function handleAttach (): void { inputFile.click() } diff --git a/plugins/view-assets/assets/icons.svg b/plugins/view-assets/assets/icons.svg index 85b88570dd..1af8f00d44 100644 --- a/plugins/view-assets/assets/icons.svg +++ b/plugins/view-assets/assets/icons.svg @@ -119,4 +119,26 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/view-assets/src/index.ts b/plugins/view-assets/src/index.ts index c30893732f..23090d4ad9 100644 --- a/plugins/view-assets/src/index.ts +++ b/plugins/view-assets/src/index.ts @@ -44,5 +44,10 @@ loadMetadata(view.icon, { Star: `${icons}#star`, Eye: `${icons}#eye`, EyeCrossed: `${icons}#eye-crossed`, - CheckCircle: `${icons}#check-circle` + CheckCircle: `${icons}#check-circle`, + Add: `${icons}#add`, + Image: `${icons}#image`, + Table2: `${icons}#table2`, + CodeBlock: `${icons}#code-block`, + SeparatorLine: `${icons}#separator-line` }) diff --git a/plugins/view/src/index.ts b/plugins/view/src/index.ts index 27f258dc0a..87eb0f6a54 100644 --- a/plugins/view/src/index.ts +++ b/plugins/view/src/index.ts @@ -222,7 +222,12 @@ const view = plugin(viewId, { Star: '' as Asset, Eye: '' as Asset, EyeCrossed: '' as Asset, - CheckCircle: '' as Asset + CheckCircle: '' as Asset, + Add: '' as Asset, + Image: '' as Asset, + Table2: '' as Asset, + CodeBlock: '' as Asset, + SeparatorLine: '' as Asset }, category: { General: '' as Ref, diff --git a/tests/sanity/tests/model/planning/planning-page.ts b/tests/sanity/tests/model/planning/planning-page.ts index 3e55956149..3e44f6f084 100644 --- a/tests/sanity/tests/model/planning/planning-page.ts +++ b/tests/sanity/tests/model/planning/planning-page.ts @@ -37,7 +37,7 @@ export class PlanningPage extends CalendarPage { this.page = page this.pageHeader = page.locator('div[class*="navigator"] div[class*="header"]', { hasText: 'Planning' }) this.buttonCreateNewToDo = page.locator('div[class*="toDos-container"] button.button') - this.inputPopupCreateTitle = page.locator('div.popup input') + this.inputPopupCreateTitle = page.locator('div.popup input[type="text"]') this.inputPopupCreateDescription = page.locator('div.popup div.tiptap') this.inputPanelCreateDescription = page.locator('div.hulyModal-container div.tiptap') this.buttonPopupCreateDueDate = page.locator( diff --git a/tests/sanity/tests/model/recruiting/vacancy-details-page.ts b/tests/sanity/tests/model/recruiting/vacancy-details-page.ts index 26fe1662ec..d49694aab5 100644 --- a/tests/sanity/tests/model/recruiting/vacancy-details-page.ts +++ b/tests/sanity/tests/model/recruiting/vacancy-details-page.ts @@ -19,7 +19,7 @@ export class VacancyDetailsPage extends CommonRecruitingPage { this.inputDescription = page.locator('div[class*="full"] div.tiptap') this.buttonInputDescription = page.locator('button > span', { hasText: 'Description' }) this.buttonInputLocation = page.locator('button > span', { hasText: 'Location' }) - this.inputAttachFile = page.locator('div[class*="full"] input[name="file"]') + this.inputAttachFile = page.locator('div[class*="full"] input[name="file"]#fileInput') this.buttonInputCompany = page.locator('button > div', { hasText: 'Company' }) this.buttonInputDueDate = page.locator('button > div', { hasText: 'Due date' }) this.buttonDatePopupSave = page.locator('div.popup button[type="submit"]') diff --git a/tests/sanity/tests/model/tracker/issues-page.ts b/tests/sanity/tests/model/tracker/issues-page.ts index 735c76dd6a..c78775ba7a 100644 --- a/tests/sanity/tests/model/tracker/issues-page.ts +++ b/tests/sanity/tests/model/tracker/issues-page.ts @@ -63,7 +63,7 @@ export class IssuesPage extends CommonTrackerPage { 'form[id="tracker:string:NewIssue"] div#milestone-editor button' ) this.buttonPopupCreateNewIssueDuedate = page.locator('form[id="tracker:string:NewIssue"] div#duedate-editor button') - this.inputPopupCreateNewIssueFile = page.locator('form[id="tracker:string:NewIssue"] input[type="file"]') + this.inputPopupCreateNewIssueFile = page.locator('form[id="tracker:string:NewIssue"] input[type="file"]#file') this.textPopupCreateNewIssueFile = page.locator('div[class*="attachments"] > div[class*="attachment"]') this.buttonCreateIssue = page.locator('button > span', { hasText: 'Create issue' }) this.inputSearch = page.locator('input[placeholder="Search"]') diff --git a/tests/sanity/tests/model/tracker/templates-page.ts b/tests/sanity/tests/model/tracker/templates-page.ts index dea010a8eb..9994abdf65 100644 --- a/tests/sanity/tests/model/tracker/templates-page.ts +++ b/tests/sanity/tests/model/tracker/templates-page.ts @@ -19,7 +19,7 @@ export class TemplatePage extends CommonTrackerPage { super(page) this.page = page this.buttonNewTemplate = page.locator('button > span', { hasText: 'Template' }) - this.inputIssueTitle = page.locator('form[id$="NewProcess"] input') + this.inputIssueTitle = page.locator('form[id$="NewProcess"] input[type="text"]') this.inputIssueDescription = page.locator('form[id$="NewProcess"] div.tiptap') this.buttonPopupCreateNewTemplatePriority = page.locator( 'form[id$="NewProcess"] div.antiCard-pool > button:first-child'