diff --git a/models/setting/src/index.ts b/models/setting/src/index.ts
index 866d646ec1..7890baf728 100644
--- a/models/setting/src/index.ts
+++ b/models/setting/src/index.ts
@@ -601,7 +601,8 @@ export function createModel (builder: Builder): void {
{
id: 'properties',
label: setting.string.Properties,
- component: setting.component.SpaceTypePropertiesSectionEditor
+ component: setting.component.SpaceTypePropertiesSectionEditor,
+ withoutContainer: true
},
{
id: 'roles',
diff --git a/models/task/src/index.ts b/models/task/src/index.ts
index 33760e4421..e79272645e 100644
--- a/models/task/src/index.ts
+++ b/models/task/src/index.ts
@@ -569,7 +569,8 @@ export function createModel (builder: Builder): void {
{
id: 'properties',
label: setting.string.Properties,
- component: setting.component.SpaceTypePropertiesSectionEditor
+ component: setting.component.SpaceTypePropertiesSectionEditor,
+ withoutContainer: true
},
{
id: 'roles',
diff --git a/plugins/document-resources/src/components/teamspace/CreateTeamspace.svelte b/plugins/document-resources/src/components/teamspace/CreateTeamspace.svelte
index 4a5eb98f05..02a14d61fe 100644
--- a/plugins/document-resources/src/components/teamspace/CreateTeamspace.svelte
+++ b/plugins/document-resources/src/components/teamspace/CreateTeamspace.svelte
@@ -408,7 +408,7 @@
-
+
{#each roles as role}
diff --git a/plugins/setting-resources/src/components/spaceTypes/ManageSpaceTypeContent.svelte b/plugins/setting-resources/src/components/spaceTypes/ManageSpaceTypeContent.svelte
index 4713fb0238..d6e822567f 100644
--- a/plugins/setting-resources/src/components/spaceTypes/ManageSpaceTypeContent.svelte
+++ b/plugins/setting-resources/src/components/spaceTypes/ManageSpaceTypeContent.svelte
@@ -37,12 +37,14 @@
IconMoreV,
AnySvelteComponent,
navigate,
- getCurrentResolvedLocation
+ getCurrentResolvedLocation,
+ IconWithEmoji
} from '@hcengineering/ui'
import { createQuery, getClient } from '@hcengineering/presentation'
import { showMenu } from '@hcengineering/view-resources'
import setting, { SpaceTypeEditor } from '@hcengineering/setting'
import { Asset, getResource } from '@hcengineering/platform'
+ import view from '@hcengineering/view'
import SpaceTypeEditorComponent from './editor/SpaceTypeEditor.svelte'
import { clearSettingsStore } from '../../store'
@@ -59,6 +61,7 @@
let selectedSubObjectId: Ref | undefined
let subItemName: string | undefined
let subItemIcon: Asset | undefined
+ let subItemIconColor: number | undefined
onDestroy(resolvedLocationStore.subscribe(handleLocationChanged))
@@ -109,7 +112,7 @@
subEditor = undefined
}
- let bcItems: Array<{ title: string, icon?: Asset }> = []
+ let bcItems: Array<{ title: string, icon?: Asset | AnySvelteComponent, iconProps?: any }> = []
$: {
bcItems = []
@@ -117,7 +120,11 @@
bcItems.push({ title: type.name, icon: descriptor?.icon })
if (selectedSubObjectId) {
- bcItems.push({ title: subItemName ?? selectedSubObjectId, icon: subItemIcon })
+ bcItems.push({
+ title: subItemName ?? selectedSubObjectId,
+ icon: subItemIcon === view.ids.IconWithEmoji ? IconWithEmoji : subItemIcon,
+ iconProps: { icon: subItemIconColor }
+ })
}
}
}
@@ -193,6 +200,7 @@
this={subEditor}
bind:name={subItemName}
bind:icon={subItemIcon}
+ bind:color={subItemIconColor}
readonly={!canEdit}
spaceType={type}
{descriptor}
diff --git a/plugins/setting-resources/src/components/spaceTypes/editor/SpaceTypeEditor.svelte b/plugins/setting-resources/src/components/spaceTypes/editor/SpaceTypeEditor.svelte
index 81ba563cab..ac3aef2eb2 100644
--- a/plugins/setting-resources/src/components/spaceTypes/editor/SpaceTypeEditor.svelte
+++ b/plugins/setting-resources/src/components/spaceTypes/editor/SpaceTypeEditor.svelte
@@ -103,6 +103,3 @@
{/if}
{/if}
-
-
diff --git a/plugins/task-resources/src/components/taskTypes/TaskTypeEditor.svelte b/plugins/task-resources/src/components/taskTypes/TaskTypeEditor.svelte
index bc90f890d2..2cf3e47323 100644
--- a/plugins/task-resources/src/components/taskTypes/TaskTypeEditor.svelte
+++ b/plugins/task-resources/src/components/taskTypes/TaskTypeEditor.svelte
@@ -41,6 +41,7 @@
export let objectId: Ref
export let name: string | undefined
export let icon: Asset | undefined
+ export let color: number | undefined
export let readonly: boolean = true
const client = getClient()
@@ -59,6 +60,7 @@
$: taskType = taskTypes.find((tt) => tt._id === objectId)
$: name = taskType?.name
$: icon = taskType?.icon
+ $: color = taskType?.color
$: descriptor = client.getModel().findAllSync(task.class.TaskTypeDescriptor, { _id: taskType?.descriptor })
$: states = (taskType?.statuses.map((p) => $statusStore.byId.get(p)).filter((p) => p !== undefined) as Status[]) ?? []
diff --git a/tests/sanity/tests/chat/chat.spec.ts b/tests/sanity/tests/chat/chat.spec.ts
index 44af888e6f..0ba12e2987 100644
--- a/tests/sanity/tests/chat/chat.spec.ts
+++ b/tests/sanity/tests/chat/chat.spec.ts
@@ -1,4 +1,3 @@
-import { faker } from '@faker-js/faker'
import { expect, test } from '@playwright/test'
import { ApiEndpoint } from '../API/Api'
import { ChannelPage } from '../model/channel-page'
@@ -8,7 +7,7 @@ import { LeftSideMenuPage } from '../model/left-side-menu-page'
import { LoginPage } from '../model/login-page'
import { SelectWorkspacePage } from '../model/select-workspace-page'
import { SignInJoinPage } from '../model/signin-page'
-import { PlatformURI, generateTestData } from '../utils'
+import { PlatformURI, generateTestData, getInviteLink, generateUser, createAccount } from '../utils'
test.describe('channel tests', () => {
let leftSideMenuPage: LeftSideMenuPage
@@ -21,12 +20,7 @@ test.describe('channel tests', () => {
test.beforeEach(async ({ page, request }) => {
data = generateTestData()
- newUser2 = {
- firstName: faker.person.firstName(),
- lastName: faker.person.lastName(),
- email: faker.internet.email(),
- password: '1234'
- }
+ newUser2 = generateUser()
leftSideMenuPage = new LeftSideMenuPage(page)
chunterPage = new ChunterPage(page)
@@ -415,13 +409,9 @@ test.describe('channel tests', () => {
await page2.close()
})
- test('Checking backlinks in the Chat', async ({ browser, page }) => {
- await api.createAccount(newUser2.email, newUser2.password, newUser2.firstName, newUser2.lastName)
- await leftSideMenuPage.openProfileMenu()
- await leftSideMenuPage.inviteToWorkspace()
- await leftSideMenuPage.getInviteLink()
- const linkText = await page.locator('.antiPopup .link').textContent()
- await leftSideMenuPage.clickOnCloseInvite()
+ test('Checking backlinks in the Chat', async ({ browser, page, request }) => {
+ await createAccount(request, newUser2)
+ const linkText = await getInviteLink(page)
const page2 = await browser.newPage()
const leftSideMenuPageSecond = new LeftSideMenuPage(page2)
const channelPageSecond = new ChannelPage(page2)
diff --git a/tests/sanity/tests/documents/teamspace.spec.ts b/tests/sanity/tests/documents/teamspace.spec.ts
index 2b70b44c60..e902aa8ce0 100644
--- a/tests/sanity/tests/documents/teamspace.spec.ts
+++ b/tests/sanity/tests/documents/teamspace.spec.ts
@@ -1,8 +1,20 @@
import { test } from '@playwright/test'
-import { generateId, PlatformSetting, PlatformURI } from '../utils'
+import {
+ generateId,
+ PlatformSetting,
+ PlatformURI,
+ generateUser,
+ createAccount,
+ getInviteLink,
+ createAccountAndWorkspace,
+ generateTestData
+} from '../utils'
import { NewTeamspace } from '../model/documents/types'
import { LeftSideMenuPage } from '../model/left-side-menu-page'
import { DocumentsPage } from '../model/documents/documents-page'
+import { SignUpData } from '../model/common-types'
+import { SignInJoinPage } from '../model/signin-page'
+import { TestData } from '../chat/types'
test.use({
storageState: PlatformSetting
@@ -64,4 +76,59 @@ test.describe('Teamspace tests', () => {
await documentsPage.moreActionTeamspace(updateEditTeamspace.title, 'Edit teamspace')
await documentsPage.checkTeamspace(updateEditTeamspace)
})
+
+ test('Auto-join teamspace', async ({ page, request, browser }) => {
+ const testData: TestData = generateTestData()
+ await createAccountAndWorkspace(page, request, testData)
+ const newUser2: SignUpData = generateUser()
+ await createAccount(request, newUser2)
+
+ const autojoinTeamspace: NewTeamspace = {
+ title: `Auto-join Teamspace-${generateId()}`,
+ description: 'Auto-join Teamspace description',
+ private: false,
+ autoJoin: true
+ }
+ await leftSideMenuPage.clickDocuments()
+ await documentsPage.checkTeamspaceNotExist(autojoinTeamspace.title)
+ await documentsPage.createNewTeamspace(autojoinTeamspace)
+ const linkText = await getInviteLink(page)
+
+ const page2 = await browser.newPage()
+ await page2.goto(linkText ?? '')
+ const joinPage: SignInJoinPage = new SignInJoinPage(page2)
+ await joinPage.join(newUser2)
+ const documentsSecondPage: DocumentsPage = new DocumentsPage(page2)
+ await documentsSecondPage.clickDocumentsApp()
+ await documentsSecondPage.checkTeamspaceExist(autojoinTeamspace.title)
+ await page2.close()
+ })
+
+ test('Join teamspace', async ({ page, request, browser }) => {
+ const testData: TestData = generateTestData()
+ await createAccountAndWorkspace(page, request, testData)
+ const newUser2: SignUpData = generateUser()
+ await createAccount(request, newUser2)
+
+ const joinTeamspace: NewTeamspace = {
+ title: `Join Teamspace-${generateId()}`,
+ description: 'Join Teamspace description'
+ }
+ await leftSideMenuPage.clickDocuments()
+ await documentsPage.checkTeamspaceNotExist(joinTeamspace.title)
+ await documentsPage.createNewTeamspace(joinTeamspace)
+ const linkText = await getInviteLink(page)
+
+ const page2 = await browser.newPage()
+ await page2.goto(linkText ?? '')
+ const joinPage: SignInJoinPage = new SignInJoinPage(page2)
+ await joinPage.join(newUser2)
+ const documentsSecondPage: DocumentsPage = new DocumentsPage(page2)
+ await documentsSecondPage.clickDocumentsApp()
+ await documentsSecondPage.checkTeamspaceNotExist(joinTeamspace.title)
+ await documentsSecondPage.clickTeamspaces()
+ await documentsSecondPage.joinTeamspace(joinTeamspace.title)
+ await documentsSecondPage.checkTeamspaceExist(joinTeamspace.title)
+ await page2.close()
+ })
})
diff --git a/tests/sanity/tests/model/documents/documents-page.ts b/tests/sanity/tests/model/documents/documents-page.ts
index 7f11d1da24..ba1bc17955 100644
--- a/tests/sanity/tests/model/documents/documents-page.ts
+++ b/tests/sanity/tests/model/documents/documents-page.ts
@@ -23,8 +23,18 @@ export class DocumentsPage extends CommonPage {
readonly buttonDocument = (name: string): Locator =>
this.page.locator('button.hulyNavItem-container > span[class*="label"]', { hasText: name })
+ readonly buttonDocumentsApp = (): Locator => this.page.locator('button[id$="document:string:DocumentApplication"]')
readonly divTeamspacesParent = (): Locator =>
- this.page.locator('div#navGroup-tree-teamspaces').locator('xpath=../button[1]')
+ this.page.locator('button.hulyNavGroup-header', { hasText: 'Teamspaces' })
+
+ readonly buttonTeamspaces = (): Locator =>
+ this.page.locator('button.hulyNavItem-container', { hasText: 'Teamspaces' })
+
+ readonly rowTeamspace = (hasText: string): Locator =>
+ this.page.locator('div.hulyComponent td ', { hasText }).locator('xpath=..')
+
+ readonly buttonJoinTeamspace = (hasText: string): Locator =>
+ this.page.locator('div.hulyComponent td ', { hasText }).locator('xpath=..').locator('button[type="submit"]')
readonly buttonCreateTeamspace = (): Locator => this.page.locator('button#tree-teamspaces')
readonly formNewTeamspace = (): Locator => this.page.locator('form[id="document:string:NewTeamspace"]')
@@ -36,6 +46,7 @@ export class DocumentsPage extends CommonPage {
this.formNewTeamspace().locator('div[id="teamspace-description"] input')
readonly inputModalNewTeamspacePrivate = (): Locator => this.formNewTeamspace().locator('[id="teamspace-private"]')
+ readonly inputModalNewTeamspaceAutoJoin = (): Locator => this.formNewTeamspace().locator('[id="teamspace-autoJoin"]')
readonly buttonModalNewTeamspaceCreate = (): Locator => this.formNewTeamspace().locator('button[type="submit"]')
readonly buttonModalEditTeamspaceTitle = (): Locator =>
this.formEditTeamspace().locator('div[id="teamspace-title"] input')
@@ -56,12 +67,15 @@ export class DocumentsPage extends CommonPage {
await this.divTeamspacesParent().hover()
await this.buttonCreateTeamspace().click()
await this.inputModalNewTeamspaceTitle().fill(data.title)
- if (data.description != null) {
+ if (data?.description !== undefined) {
await this.inputModalNewTeamspaceDescription().fill(data.description)
}
- if (data.private != null) {
+ if (data.private === true) {
await this.inputModalNewTeamspacePrivate().click()
}
+ if (data.autoJoin === true) {
+ await this.inputModalNewTeamspaceAutoJoin().click()
+ }
await this.buttonModalNewTeamspaceCreate().click()
}
@@ -149,4 +163,17 @@ export class DocumentsPage extends CommonPage {
async fillMoveDocumentForm (newSpace: string): Promise {
await this.popupMoveDocument.moveToSpace(newSpace)
}
+
+ async clickDocumentsApp (): Promise {
+ await this.buttonDocumentsApp().click()
+ }
+
+ async clickTeamspaces (): Promise {
+ await this.buttonTeamspaces().click()
+ }
+
+ async joinTeamspace (name: string): Promise {
+ await expect(this.rowTeamspace(name)).toBeVisible()
+ await this.buttonJoinTeamspace(name).click()
+ }
}
diff --git a/tests/sanity/tests/model/documents/types.ts b/tests/sanity/tests/model/documents/types.ts
index 8c2530090e..77b11e3cd4 100644
--- a/tests/sanity/tests/model/documents/types.ts
+++ b/tests/sanity/tests/model/documents/types.ts
@@ -2,6 +2,7 @@ export interface NewTeamspace {
title: string
description?: string
private?: boolean
+ autoJoin?: boolean
}
export interface NewDocument {
diff --git a/tests/sanity/tests/model/login-page.ts b/tests/sanity/tests/model/login-page.ts
index 17a5c7e819..c32dd8fc26 100644
--- a/tests/sanity/tests/model/login-page.ts
+++ b/tests/sanity/tests/model/login-page.ts
@@ -21,6 +21,9 @@ export class LoginPage {
recoveryLogin = (): Locator => this.page.getByRole('link', { name: 'Log In' })
recoverySignUp = (): Locator => this.page.getByRole('link', { name: 'Sign Up' })
+ profileButton = (): Locator => this.page.locator('#profile-button')
+ popupItemButton = (hasText: string): Locator => this.page.locator('div.popup button[class*="menu"]', { hasText })
+
// ACTIONS
async goto (): Promise {
await (await this.page.goto(`${PlatformURI}/login/login`))?.finished()
@@ -50,8 +53,20 @@ export class LoginPage {
await this.buttonLogin().click()
}
+ async openProfileMenu (): Promise {
+ await this.profileButton().click()
+ }
+
// ASSERTS
+ async checkingNeedReLogin (): Promise {
+ if (await this.profileButton().isVisible()) {
+ await this.openProfileMenu()
+ await this.popupItemButton('Sign out').click()
+ await this.loginWithPassword().waitFor({ state: 'visible', timeout: 15000 })
+ }
+ }
+
async checkIfErrorMessageIsShown (): Promise {
await expect(this.invalidPasswordMessage()).toContainText('Invalid password')
}
diff --git a/tests/sanity/tests/model/tracker/templates-page.ts b/tests/sanity/tests/model/tracker/templates-page.ts
index e1a7b87006..da9408ac6c 100644
--- a/tests/sanity/tests/model/tracker/templates-page.ts
+++ b/tests/sanity/tests/model/tracker/templates-page.ts
@@ -41,13 +41,6 @@ export class TemplatePage extends CommonTrackerPage {
saveTemplateButton = (): Locator => this.page.locator('text=Save template')
editTemplateButton = (): Locator => this.page.locator('text=Edit template')
newSpaceTypeButton = (): Locator => this.page.locator('#new-space-type')
- spaceTypeButton = (name: string, category?: string): Locator =>
- this.page.locator('div#navGroup-spaceTypes button.hulyTaskNavLink-container', {
- hasText: category !== undefined ? `${name} ${category}` : name
- })
-
- addTaskTypeButton = (): Locator =>
- this.page.locator('div.hulyTableAttr-header', { hasText: 'Task types' }).locator('button[data-id="btnAdd"]')
async createNewTemplate (data: NewIssue): Promise {
await this.buttonNewTemplate().click()
@@ -124,15 +117,6 @@ export class TemplatePage extends CommonTrackerPage {
await this.newSpaceTypeButton().click()
}
- async selectSpaceType (name: string, category?: string): Promise {
- await this.spaceTypeButton(name, category).click()
- }
-
- async addTaskType (): Promise {
- console.log('[!!!] ', await this.page.locator('div.hulyTableAttr-header', { hasText: 'Task types' }).isVisible())
- await this.addTaskTypeButton().click()
- }
-
async createTemplate (templateName: string, templateContent: string): Promise {
await this.createTemplateButton().click()
await this.newTemplateInput().fill(templateName)
diff --git a/tests/sanity/tests/utils.ts b/tests/sanity/tests/utils.ts
index 02bfeff283..c883c3615e 100644
--- a/tests/sanity/tests/utils.ts
+++ b/tests/sanity/tests/utils.ts
@@ -1,8 +1,13 @@
-import { Browser, BrowserContext, Locator, Page, expect } from '@playwright/test'
+import { Browser, BrowserContext, Locator, Page, expect, APIRequestContext } from '@playwright/test'
import { allure } from 'allure-playwright'
import { faker } from '@faker-js/faker'
import { TestData } from './chat/types'
import path from 'path'
+import { LeftSideMenuPage } from './model/left-side-menu-page'
+import { SignUpData } from './model/common-types'
+import { ApiEndpoint } from './API/Api'
+import { SelectWorkspacePage } from './model/select-workspace-page'
+import { LoginPage } from './model/login-page'
export const PlatformURI = process.env.PLATFORM_URI as string
export const PlatformTransactor = process.env.PLATFORM_TRANSACTOR as string
@@ -167,3 +172,40 @@ export async function uploadFile (page: Page, fileName: string, fileUploadTestId
// Replace with a more reliable condition for determining when the upload is complete, if possible.
await page.waitForTimeout(2000)
}
+
+export async function getInviteLink (page: Page): Promise {
+ const leftSideMenuPage = new LeftSideMenuPage(page)
+ await leftSideMenuPage.openProfileMenu()
+ await leftSideMenuPage.inviteToWorkspace()
+ await leftSideMenuPage.getInviteLink()
+ const linkText = await page.locator('.antiPopup .link').textContent()
+ expect(linkText).not.toBeNull()
+ await leftSideMenuPage.clickOnCloseInvite()
+ return linkText
+}
+
+export function generateUser (): SignUpData {
+ return {
+ firstName: faker.person.firstName(),
+ lastName: faker.person.lastName(),
+ email: faker.internet.email(),
+ password: '1234'
+ }
+}
+
+export async function createAccount (request: APIRequestContext, data: SignUpData): Promise {
+ const api: ApiEndpoint = new ApiEndpoint(request)
+ await api.createAccount(data.email, data.password, data.firstName, data.lastName)
+}
+
+export async function createAccountAndWorkspace (page: Page, request: APIRequestContext, data: TestData): Promise {
+ const api: ApiEndpoint = new ApiEndpoint(request)
+ await api.createAccount(data.userName, '1234', data.firstName, data.lastName)
+ await api.createWorkspaceWithLogin(data.workspaceName, data.userName, '1234')
+ const loginPage: LoginPage = new LoginPage(page)
+ await loginPage.checkingNeedReLogin()
+ await (await page.goto(`${PlatformURI}`))?.finished()
+ await loginPage.login(data.userName, '1234')
+ const swp = new SelectWorkspacePage(page)
+ await swp.selectWorkspace(data.workspaceName)
+}