diff --git a/frontend/src/components/tasks/partials/RelatedTasks.vue b/frontend/src/components/tasks/partials/RelatedTasks.vue
index 95ff3b17d..3f9eef36b 100644
--- a/frontend/src/components/tasks/partials/RelatedTasks.vue
+++ b/frontend/src/components/tasks/partials/RelatedTasks.vue
@@ -36,7 +36,7 @@
+
component is too much resulting in a
// weired positioning of the checkbox. Setting the height here is a workaround until we fix the styling
// of the component.
diff --git a/frontend/tests/e2e/task/related-tasks-quick-add-magic.spec.ts b/frontend/tests/e2e/task/related-tasks-quick-add-magic.spec.ts
new file mode 100644
index 000000000..935b1cf9d
--- /dev/null
+++ b/frontend/tests/e2e/task/related-tasks-quick-add-magic.spec.ts
@@ -0,0 +1,96 @@
+import {test, expect} from '../../support/fixtures'
+import {ProjectFactory} from '../../factories/project'
+import {TaskFactory} from '../../factories/task'
+import {UserFactory} from '../../factories/user'
+import {createDefaultViews} from '../project/prepareProjects'
+import {login} from '../../support/authenticateUser'
+
+async function openRelatedTasksForm(page) {
+ await page.locator('.task-view .action-buttons .button').filter({hasText: 'Add Relation'}).click()
+ const input = page.locator('.task-relations .multiselect input').first()
+ await expect(input).toBeVisible()
+ return input
+}
+
+test.describe('Related tasks quick add magic', () => {
+ test('Applies a label parsed via *prefix to the new related task', async ({authenticatedPage: page}) => {
+ const project = (await ProjectFactory.create(1, {id: 1, title: 'Project A'}))[0]
+ await createDefaultViews(project.id)
+ const parent = (await TaskFactory.create(1, {id: 1, title: 'Parent task', project_id: project.id}, false))[0]
+
+ await page.goto(`/tasks/${parent.id}`)
+ const input = await openRelatedTasksForm(page)
+ await input.fill('Subtask one *Urgent')
+ await input.press('Enter')
+
+ const relatedTaskLink = page.locator('.task-relations .related-tasks .task a').filter({hasText: 'Subtask one'})
+ await expect(relatedTaskLink).toBeVisible({timeout: 10000})
+ // Quick add magic strips the *Urgent prefix from the title
+ await expect(relatedTaskLink).not.toContainText('*Urgent')
+
+ await relatedTaskLink.click()
+ await expect(page).toHaveURL(/\/tasks\/\d+/)
+ await expect(page.locator('.task-view .details.labels-list .multiselect .input-wrapper span.tag').filter({hasText: 'Urgent'}))
+ .toBeVisible({timeout: 10000})
+ })
+
+ test('Applies a priority parsed via !prefix to the new related task', async ({authenticatedPage: page}) => {
+ const project = (await ProjectFactory.create(1, {id: 1, title: 'Project A'}))[0]
+ await createDefaultViews(project.id)
+ const parent = (await TaskFactory.create(1, {id: 1, title: 'Parent task', project_id: project.id}, false))[0]
+
+ await page.goto(`/tasks/${parent.id}`)
+ const input = await openRelatedTasksForm(page)
+ await input.fill('Important work !4')
+ await input.press('Enter')
+
+ const relatedTaskLink = page.locator('.task-relations .related-tasks .task a').filter({hasText: 'Important work'})
+ await expect(relatedTaskLink).toBeVisible({timeout: 10000})
+ await expect(relatedTaskLink).not.toContainText('!4')
+
+ await relatedTaskLink.click()
+ // Priority 4 is "Urgent"
+ await expect(page.locator('.task-view .columns.details select').first()).toHaveValue('4', {timeout: 10000})
+ })
+
+ test('Creates the related task in another project via +project prefix', async ({authenticatedPage: page}) => {
+ const projectA = (await ProjectFactory.create(1, {id: 1, title: 'Source'}))[0]
+ await createDefaultViews(projectA.id)
+ const projectB = (await ProjectFactory.create(1, {id: 2, title: 'TargetProject'}, false))[0]
+ await createDefaultViews(projectB.id, 5)
+ const parent = (await TaskFactory.create(1, {id: 1, title: 'Parent task', project_id: projectA.id}, false))[0]
+
+ await page.goto(`/tasks/${parent.id}`)
+ const input = await openRelatedTasksForm(page)
+ await input.fill('Cross task +TargetProject')
+ await input.press('Enter')
+
+ const relatedTaskRow = page.locator('.task-relations .related-tasks .task').filter({hasText: 'Cross task'})
+ await expect(relatedTaskRow).toBeVisible({timeout: 10000})
+ await expect(relatedTaskRow.locator('a')).not.toContainText('+TargetProject')
+ // Cross-project marker shows the other project name
+ await expect(relatedTaskRow.locator('.different-project')).toContainText('TargetProject')
+ })
+
+ test('Keeps the title literal when quick add magic is disabled', async ({page, apiContext}) => {
+ const user = (await UserFactory.create(1, {
+ frontend_settings: JSON.stringify({
+ quickAddMagicMode: 'disabled',
+ }),
+ }))[0]
+ const project = (await ProjectFactory.create(1, {id: 1, title: 'Project A', owner_id: user.id}))[0]
+ await createDefaultViews(project.id)
+ const parent = (await TaskFactory.create(1, {id: 1, title: 'Parent task', project_id: project.id, created_by_id: user.id}, false))[0]
+
+ await login(page, apiContext, user)
+ await page.goto(`/tasks/${parent.id}`)
+
+ const input = await openRelatedTasksForm(page)
+ await input.fill('Buy milk *Urgent')
+ await input.press('Enter')
+
+ // With magic disabled, the prefix stays in the title verbatim
+ await expect(page.locator('.task-relations .related-tasks .task a').filter({hasText: 'Buy milk *Urgent'}))
+ .toBeVisible({timeout: 10000})
+ })
+})