From efef235447583466c07173622b4a2e3b152c40b7 Mon Sep 17 00:00:00 2001 From: Artyom Savchenko Date: Sat, 21 Feb 2026 14:13:13 +0700 Subject: [PATCH 1/9] Add ability to group by issues by project (#10531) Signed-off-by: Artem Savchenko --- models/tracker/src/viewlets.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/models/tracker/src/viewlets.ts b/models/tracker/src/viewlets.ts index 3ec1ad6bb6..65cd94aa0f 100644 --- a/models/tracker/src/viewlets.ts +++ b/models/tracker/src/viewlets.ts @@ -29,6 +29,7 @@ export const issuesOptions = (kanban: boolean): ViewOptionsModel => ({ 'kind', 'assignee', 'priority', + 'space', 'component', 'milestone', 'createdBy', From 5f7f712be3baf09836874c41e4899f368096f79e Mon Sep 17 00:00:00 2001 From: Artyom Savchenko Date: Sat, 21 Feb 2026 14:55:46 +0700 Subject: [PATCH 2/9] =?UTF-8?q?Revert=20"Fix:=20password=20signup=20crashe?= =?UTF-8?q?s=20with=20JSON=20parse=20error=20when=20MAIL=5FURL=20is=20c?= =?UTF-8?q?=E2=80=A6"=20(#10534)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit f391dd0a5d5e6cc7d20cbd2732922ad7cd9df8bf. --- .../src/__tests__/signupTokenGuard.test.ts | 97 ------------------- .../src/components/SignupForm.svelte | 4 +- server/account-service/src/index.ts | 7 +- 3 files changed, 6 insertions(+), 102 deletions(-) delete mode 100644 plugins/login-resources/src/__tests__/signupTokenGuard.test.ts diff --git a/plugins/login-resources/src/__tests__/signupTokenGuard.test.ts b/plugins/login-resources/src/__tests__/signupTokenGuard.test.ts deleted file mode 100644 index 36383162b9..0000000000 --- a/plugins/login-resources/src/__tests__/signupTokenGuard.test.ts +++ /dev/null @@ -1,97 +0,0 @@ -// 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. - -/** - * Tests for the token guard fix in SignupForm.svelte (issue #10518). - * - * When MAIL_URL is configured the account service returns token: undefined - * to force email confirmation. The signup handler must skip logIn() in that - * case — calling logIn() without a token triggers PUT /cookie with no - * Authorization header, which returns 401 and crashes the client's JSON - * parser with "Unexpected token". - */ - -interface LoginInfo { - account: string - name?: string - token?: string -} - -/** - * Mirrors the fixed logic from SignupForm.svelte: - * - * if (result != null) { - * if (result.token != null) { - * await logIn(result) - * } - * goTo('confirmationSend') - * } - */ -async function handleSignupResult ( - result: LoginInfo | null, - logIn: (info: LoginInfo) => Promise, - goTo: (page: string) => void -): Promise { - if (result != null) { - if (result.token != null) { - await logIn(result) - } - goTo('confirmationSend') - } -} - -describe('SignupForm token guard (issue #10518)', () => { - let logIn: jest.Mock - let goTo: jest.Mock - - beforeEach(() => { - logIn = jest.fn().mockResolvedValue(undefined) - goTo = jest.fn() - }) - - it('skips logIn and redirects to confirmationSend when token is undefined (MAIL_URL configured)', async () => { - // Server returns token: undefined when email confirmation is required - const result: LoginInfo = { account: 'acc-uuid', name: 'Alice Smith', token: undefined } - - await handleSignupResult(result, logIn, goTo) - - expect(logIn).not.toHaveBeenCalled() - expect(goTo).toHaveBeenCalledWith('confirmationSend') - }) - - it('skips logIn and redirects to confirmationSend when token is absent', async () => { - const result: LoginInfo = { account: 'acc-uuid' } - - await handleSignupResult(result, logIn, goTo) - - expect(logIn).not.toHaveBeenCalled() - expect(goTo).toHaveBeenCalledWith('confirmationSend') - }) - - it('calls logIn then redirects to confirmationSend when token is present (no MAIL_URL)', async () => { - const result: LoginInfo = { account: 'acc-uuid', name: 'Bob Jones', token: 'eyJhbGciOiJIUzI1NiJ9.test' } - - await handleSignupResult(result, logIn, goTo) - - expect(logIn).toHaveBeenCalledTimes(1) - expect(logIn).toHaveBeenCalledWith(result) - expect(goTo).toHaveBeenCalledWith('confirmationSend') - }) - - it('calls neither logIn nor goTo when result is null (signup error)', async () => { - await handleSignupResult(null, logIn, goTo) - - expect(logIn).not.toHaveBeenCalled() - expect(goTo).not.toHaveBeenCalled() - }) -}) diff --git a/plugins/login-resources/src/components/SignupForm.svelte b/plugins/login-resources/src/components/SignupForm.svelte index 2deb62ed38..6c888b88c2 100644 --- a/plugins/login-resources/src/components/SignupForm.svelte +++ b/plugins/login-resources/src/components/SignupForm.svelte @@ -95,9 +95,7 @@ status = loginStatus if (result != null) { - if (result.token != null) { - await logIn(result) - } + await logIn(result) goTo('confirmationSend') } } diff --git a/server/account-service/src/index.ts b/server/account-service/src/index.ts index 93da5a3784..577cb1d91f 100644 --- a/server/account-service/src/index.ts +++ b/server/account-service/src/index.ts @@ -306,8 +306,11 @@ export function serveAccount (measureCtx: MeasureContext, brandings: BrandingMap router.put('/cookie', async (ctx) => { const token = extractToken(ctx.request.headers) if (token === undefined) { - ctx.status = 401 - ctx.body = { error: new Status(Severity.ERROR, platform.status.Unauthorized, {}) } + ctx.body = JSON.stringify({ + error: new Status(Severity.ERROR, platform.status.Unauthorized, {}) + }) + ctx.res.writeHead(401) + ctx.res.end() return } From 25bafb5d13a5e19e6774be4036587926c02a7331 Mon Sep 17 00:00:00 2001 From: Artyom Savchenko Date: Sat, 21 Feb 2026 21:57:35 +0700 Subject: [PATCH 3/9] Fix bump with foundation packages (#10536) Signed-off-by: Artem Savchenko --- common/scripts/bump.js | 47 ++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/common/scripts/bump.js b/common/scripts/bump.js index 56bd8f1a84..3ef140a9d0 100755 --- a/common/scripts/bump.js +++ b/common/scripts/bump.js @@ -1,35 +1,51 @@ const fs = require('fs') +const path = require('path') const execSync = require('child_process').execSync const repo = '@hcengineering' const packages = {} const pathes = {} const jsons = {} +const repoRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf-8' }).trim() function fillPackages (config) { - for (const package of config.projects) { - if (!package.name.startsWith(repo)) continue + for (const project of config.projects) { + const packageName = project.name ?? project.packageName + if (typeof packageName !== 'string' || !packageName.startsWith(repo)) continue + const projectPath = project.path ?? project.projectFolder ?? path.relative(repoRoot, project.fullPath ?? '') + if (typeof projectPath !== 'string' || projectPath.length === 0) continue + const fullProjectPath = path.resolve(repoRoot, projectPath) - packages[package.name] = { - version: package.version, - path: package.path + packages[packageName] = { + version: project.version, + path: fullProjectPath } - pathes[package.path] = package.name + pathes[fullProjectPath] = packageName - const file = package.path + '/package.json' - const raw = fs.readFileSync(file) - jsons[package.name] = JSON.parse(raw) + const file = path.join(fullProjectPath, 'package.json') + if (!fs.existsSync(file)) { + console.log('skip, package.json not found:', file) + continue + } + + const raw = fs.readFileSync(file) + jsons[packageName] = JSON.parse(raw) } } function bumpPackage (name, newVersion) { const json = jsons[name] + if (json === undefined) return json.version = newVersion - if (typeof json.dependencies === 'object') { - for (const [dependency] of Object.entries(json.dependencies)) { + const depTypes = ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies'] + for (const depType of depTypes) { + if (typeof json[depType] !== 'object') continue + for (const [dependency, currentVersion] of Object.entries(json[depType])) { if (packages[dependency] !== undefined) { - json.dependencies[dependency] = `^${newVersion}` + json[depType][dependency] = String(currentVersion).startsWith('workspace:') + ? `workspace:^${newVersion}` + : `^${newVersion}` } } } @@ -44,7 +60,7 @@ function publish (name) { const package = packages[name] try { console.log('publishing', name) - execSync(`cd ${package.path} && npm publish && cd ../..`, { encoding: 'utf-8' }) + execSync('npm publish', { encoding: 'utf-8', cwd: package.path }) } catch (err) { console.log(err) } @@ -54,7 +70,7 @@ function fix (name) { const package = packages[name] try { console.log('fixing', name) - execSync(`cd ${package.path} && npm pkg fix && cd ../..`, { encoding: 'utf-8' }) + execSync('npm pkg fix', { encoding: 'utf-8', cwd: package.path }) } catch (err) { console.log(err) } @@ -89,7 +105,8 @@ function main () { for (const packageName of packageNames) { const package = packages[packageName] - const file = package.path + '/package.json' + if (jsons[packageName] === undefined) continue + const file = path.join(package.path, 'package.json') const res = JSON.stringify(jsons[packageName], undefined, 2) fs.writeFileSync(file, res + '\n') } From a46dd77f9e6b417edd79ecd74bca6d049d7373bf Mon Sep 17 00:00:00 2001 From: Artyom Savchenko Date: Sat, 21 Feb 2026 21:57:49 +0700 Subject: [PATCH 4/9] Show actions button instead of 'Copy all' (#10537) Signed-off-by: Artem Savchenko --- .../components/CopyAsMarkdownButton.svelte | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/plugins/converter-resources/src/components/CopyAsMarkdownButton.svelte b/plugins/converter-resources/src/components/CopyAsMarkdownButton.svelte index ff75df291c..b09753503b 100644 --- a/plugins/converter-resources/src/components/CopyAsMarkdownButton.svelte +++ b/plugins/converter-resources/src/components/CopyAsMarkdownButton.svelte @@ -2,13 +2,13 @@ // Copyright © 2026 Hardcore Engineering Inc. // // Licensed under the Eclipse Public License, Version 2.0 (the "License"); -// you may not use it except in compliance with the License. You may obtain +// 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 --> {#if hasData} - -