Compare commits

..

17 Commits

Author SHA1 Message Date
d1025c3982
chore: group return parameter 2023-04-26 18:40:32 +02:00
781cf66e81
chore: make fuzzy matching a paramater 2023-04-26 18:40:32 +02:00
a207e26a0e
fix: make type singular 2023-04-26 18:40:31 +02:00
5c8d1b7cfd
chore(i18n): clarify translation string 2023-04-26 18:40:31 +02:00
162c020ea4
chore: use startsWith for prefix matching 2023-04-26 18:40:31 +02:00
09c9e97b35
fix: clarify user search setting 2023-04-26 18:40:31 +02:00
2671a746b1
chore: remove user margin from the component 2023-04-26 18:40:31 +02:00
8b22dd07c9
chore: remove user margin from the component 2023-04-26 18:40:31 +02:00
e9b4e4e6bb
feat(quick add magic): allow fuzzy matching of assignees when the api results are unambigous 2023-04-26 18:40:31 +02:00
4b051a668e
fix: ensure all matched quick add magic parts are correctly removed from the task 2023-04-26 18:40:31 +02:00
28ba9edf8c
fix: lint 2023-04-26 18:40:31 +02:00
571bc5c61d
feat(assignees): show user avatar in search results 2023-04-26 18:40:31 +02:00
19e00299bb
feat: show initial list of users when opening the assignees view 2023-04-26 18:40:31 +02:00
25a8ae8f6c
chore: clarify users when can still be found even if they disabled it 2023-04-26 18:40:30 +02:00
fb85bd6216
fix(quick add magic): cleanup all assignee properties 2023-04-26 18:40:30 +02:00
9af98c82ea
fix(quick add magic): use the project user service to find assignees for quick add magic 2023-04-26 18:40:30 +02:00
f6266214c9
fix(quick add magic): don't replace the prefix in every occurrence when it is present in the matched part 2023-04-26 18:40:30 +02:00
47 changed files with 6269 additions and 672 deletions

View File

@ -42,12 +42,11 @@ steps:
# - .cache
- name: dependencies
image: node:20-alpine
image: node:18-alpine
pull: always
environment:
PNPM_CACHE_FOLDER: .cache/pnpm
CYPRESS_CACHE_FOLDER: .cache/cypress
PUPPETEER_SKIP_DOWNLOAD: true
commands:
- corepack enable && pnpm config set store-dir .cache/pnpm
- pnpm install --fetch-timeout 100000
@ -55,7 +54,7 @@ steps:
# - restore-cache
- name: lint
image: node:20-alpine
image: node:18-alpine
pull: always
environment:
PNPM_CACHE_FOLDER: .cache/pnpm
@ -66,7 +65,7 @@ steps:
- dependencies
- name: build-prod
image: node:20-alpine
image: node:18-alpine
pull: always
environment:
PNPM_CACHE_FOLDER: .cache/pnpm
@ -77,7 +76,7 @@ steps:
- dependencies
- name: test-unit
image: node:20-alpine
image: node:18-alpine
pull: always
commands:
- corepack enable && pnpm config set store-dir .cache/pnpm
@ -87,7 +86,7 @@ steps:
- name: typecheck
failure: ignore
image: node:20-alpine
image: node:18-alpine
pull: always
environment:
PNPM_CACHE_FOLDER: .cache/pnpm
@ -137,9 +136,8 @@ steps:
# - dependencies
- name: deploy-preview
image: williamjackson/netlify-cli
image: node:18-alpine
pull: always
user: root # The rest runs as root and thus the permissions wouldn't work
environment:
NETLIFY_AUTH_TOKEN:
from_secret: netlify_auth_token
@ -202,7 +200,7 @@ steps:
# - .cache
- name: build
image: node:20-alpine
image: node:18-alpine
pull: always
environment:
PNPM_CACHE_FOLDER: .cache/pnpm
@ -279,7 +277,7 @@ steps:
# - .cache
- name: build
image: node:20-alpine
image: node:18-alpine
pull: always
environment:
PNPM_CACHE_FOLDER: .cache/pnpm
@ -524,6 +522,6 @@ steps:
from_secret: crowdin_key
---
kind: signature
hmac: 511c2a090e9efd4c942980d971204adb6321540bb01c92409dd9bf8463b7f6f4
hmac: 303afeb09b75a57ba88720b45dc06c8bf2c7320e19d738d8299f325438246f75
...

View File

@ -3,7 +3,7 @@
# │─││ │││ │ │
# ┘─┘┘─┘┘┘─┘┘─┘
FROM --platform=$BUILDPLATFORM node:20-alpine AS builder
FROM --platform=$BUILDPLATFORM node:18-alpine AS builder
WORKDIR /build
@ -13,7 +13,6 @@ ENV PNPM_CACHE_FOLDER .cache/pnpm/
COPY package.json ./
COPY pnpm-lock.yaml ./
COPY patches /build/patches
RUN if [ "$USE_RELEASE" != true ]; then \
# https://pnpm.io/installation#using-corepack

View File

@ -1,5 +1,5 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"extends": "@vue/tsconfig/tsconfig.web.json",
"include": ["./**/*", "../support/**/*", "../factories/**/*"],
"compilerOptions": {
"baseUrl": ".",

0
docker/injector.sh Executable file → Normal file
View File

0
docker/ipv6-disable.sh Executable file → Normal file
View File

View File

@ -4,6 +4,7 @@
pid /tmp/nginx.pid;
worker_processes auto;
worker_rlimit_nofile 65535;
events {
multi_accept on;

View File

@ -13,7 +13,7 @@
},
"homepage": "https://vikunja.io/",
"funding": "https://opencollective.com/vikunja",
"packageManager": "pnpm@8.5.0",
"packageManager": "pnpm@8.3.1",
"keywords": [
"todo",
"productivity",
@ -53,37 +53,37 @@
"@infectoone/vue-ganttastic": "2.1.4",
"@intlify/unplugin-vue-i18n": "0.10.0",
"@kyvg/vue3-notification": "2.9.0",
"@sentry/tracing": "7.51.2",
"@sentry/vue": "7.51.2",
"@vueuse/core": "10.1.2",
"axios": "1.4.0",
"@sentry/tracing": "7.49.0",
"@sentry/vue": "7.49.0",
"@vueuse/core": "10.1.0",
"axios": "1.3.6",
"blurhash": "2.0.5",
"bulma-css-variables": "0.9.33",
"camel-case": "4.1.2",
"codemirror": "5.65.13",
"date-fns": "2.30.0",
"codemirror": "5.65.12",
"date-fns": "2.29.3",
"dayjs": "1.11.7",
"dompurify": "3.0.3",
"dompurify": "3.0.2",
"easymde": "2.18.0",
"fast-deep-equal": "3.1.3",
"flatpickr": "4.6.13",
"flexsearch": "0.7.31",
"floating-vue": "2.0.0-beta.20",
"highlight.js": "11.8.0",
"highlight.js": "11.7.0",
"is-touch-device": "1.0.1",
"klona": "2.0.6",
"lodash.debounce": "4.0.8",
"marked": "5.0.2",
"pinia": "2.0.36",
"marked": "4.3.0",
"pinia": "2.0.35",
"register-service-worker": "1.7.2",
"snake-case": "3.0.4",
"sortablejs": "1.15.0",
"ufo": "1.1.2",
"ufo": "1.1.1",
"vue": "3.2.47",
"vue-advanced-cropper": "2.8.8",
"vue-flatpickr-component": "11.0.3",
"vue-i18n": "9.2.2",
"vue-router": "4.2.0",
"vue-router": "4.1.6",
"workbox-precaching": "6.5.4",
"zhyswan-vuedraggable": "4.1.3"
},
@ -91,54 +91,54 @@
"@4tw/cypress-drag-drop": "2.2.3",
"@cypress/vite-dev-server": "5.0.5",
"@cypress/vue": "5.0.5",
"@faker-js/faker": "8.0.0",
"@faker-js/faker": "7.6.0",
"@histoire/plugin-screenshot": "0.16.1",
"@histoire/plugin-vue": "0.16.1",
"@rushstack/eslint-patch": "1.2.0",
"@tsconfig/node18": "2.0.1",
"@types/codemirror": "5.60.7",
"@types/dompurify": "3.0.2",
"@types/flexsearch": "0.7.3",
"@types/is-touch-device": "1.0.0",
"@types/lodash.debounce": "4.0.7",
"@types/marked": "4.3.0",
"@types/node": "18.16.8",
"@types/marked": "4.0.8",
"@types/node": "18.16.1",
"@types/postcss-preset-env": "7.7.0",
"@types/sortablejs": "1.15.1",
"@typescript-eslint/eslint-plugin": "5.59.5",
"@typescript-eslint/parser": "5.59.5",
"@typescript-eslint/eslint-plugin": "5.59.1",
"@typescript-eslint/parser": "5.59.1",
"@vitejs/plugin-legacy": "4.0.3",
"@vitejs/plugin-vue": "4.2.3",
"@vitejs/plugin-vue": "4.2.0",
"@vue/eslint-config-typescript": "11.0.3",
"@vue/test-utils": "2.3.2",
"@vue/tsconfig": "0.4.0",
"@vue/tsconfig": "0.1.3",
"autoprefixer": "10.4.14",
"browserslist": "4.21.5",
"caniuse-lite": "1.0.30001486",
"caniuse-lite": "1.0.30001481",
"css-has-pseudo": "5.0.2",
"csstype": "3.1.2",
"cypress": "12.12.0",
"cypress": "12.10.0",
"esbuild": "0.17.18",
"eslint": "8.40.0",
"eslint-plugin-vue": "9.12.0",
"happy-dom": "9.10.9",
"eslint": "8.39.0",
"eslint-plugin-vue": "9.11.0",
"happy-dom": "9.9.2",
"histoire": "0.16.1",
"netlify-cli": "14.2.1",
"postcss": "8.4.23",
"postcss-easing-gradients": "3.0.1",
"postcss-easings": "3.0.1",
"postcss-focus-within": "7.0.2",
"postcss-preset-env": "8.3.2",
"rollup": "3.21.6",
"rollup": "3.21.0",
"rollup-plugin-visualizer": "5.9.0",
"sass": "1.62.1",
"start-server-and-test": "2.0.0",
"typescript": "5.0.4",
"vite": "4.3.5",
"vite": "4.3.3",
"vite-plugin-inject-preload": "1.3.1",
"vite-plugin-pwa": "0.14.7",
"vite-svg-loader": "4.0.0",
"vitest": "0.31.0",
"vue-tsc": "1.6.4",
"vitest": "0.30.1",
"vue-tsc": "1.4.4",
"wait-on": "7.0.1",
"workbox-cli": "6.5.4"
},

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@
],
"packageRules": [
{
"matchPackageNames": ["happy-dom"],
"matchPackageNames": ["netlify-cli", "happy-dom"],
"extends": ["schedule:weekly"]
},
{

View File

@ -33,9 +33,9 @@ const promiseExec = cmd => {
}
(async function () {
let stdout = await promiseExec(`/home/node/docker-netlify-cli/node_modules/.bin/netlify link --id ${siteId}`)
let stdout = await promiseExec(`./node_modules/.bin/netlify link --id ${siteId}`)
console.log(stdout)
stdout = await promiseExec(`/home/node/docker-netlify-cli/node_modules/.bin/netlify deploy --alias ${alias}`)
stdout = await promiseExec(`./node_modules/.bin/netlify deploy --alias ${alias}`)
console.log(stdout)
const data = await fetch(prIssueCommentsUrl).then(response => response.json())

View File

@ -1 +1 @@
4a7c1293c7b12e9ab476cdf35251a407c6a1cd005d22c06df994222cccfb25cde5f47d15866a098c9d739778fee4dc19 ./scripts/deploy-preview-netlify.mjs
57af69409e66bc87f4f2fc5822dd8d3c2eb47c601f81af1ac4a56f3e2d80837b1a2de06f4ff57695ec379b7c15b881e3 ./scripts/deploy-preview-netlify.mjs

View File

@ -140,18 +140,6 @@ export const KEYBOARD_SHORTCUTS : ShortcutGroup[] = [
title: 'keyboardShortcuts.task.description',
keys: ['e'],
},
{
title: 'keyboardShortcuts.task.priority',
keys: ['p'],
},
{
title: 'keyboardShortcuts.task.delete',
keys: ['shift', 'delete'],
},
{
title: 'keyboardShortcuts.task.favorite',
keys: ['s'],
},
],
},
]
]

View File

@ -48,7 +48,6 @@ const displayName = computed(() => getDisplayName(props.user))
<style lang="scss" scoped>
.user {
margin: .5rem;
display: flex;
justify-items: center;

View File

@ -20,7 +20,8 @@
:user="n.notification.doer"
:show-username="false"
:avatar-size="16"
v-if="n.notification.doer"/>
v-if="n.notification.doer"
/>
<div class="detail">
<div>
<span class="has-text-weight-bold mr-1" v-if="n.notification.doer">

View File

@ -12,12 +12,15 @@
>
<template #tag="{item: user}">
<span class="assignee">
<user :avatar-size="32" :show-username="false" :user="user"/>
<user :avatar-size="32" :show-username="false" :user="user" class="m-2"/>
<BaseButton @click="removeAssignee(user)" class="remove-assignee" v-if="!disabled">
<icon icon="times"/>
</BaseButton>
</span>
</template>
<template #searchResult="{option: user}">
<user :avatar-size="24" :show-username="true" :user="user"/>
</template>
</Multiselect>
</template>
@ -104,11 +107,6 @@ async function removeAssignee(user: IUser) {
}
async function findUser(query: string) {
if (query === '') {
foundUsers.value = []
return
}
const response = await projectUserService.getAll({projectId: props.projectId}, {s: query}) as IUser[]
// Filter the results to not include users who are already assigned

View File

@ -56,6 +56,7 @@
:key="task.id + 'assignee' + a.id + i"
:show-username="false"
:user="a"
class="m-2"
/>
<!-- FIXME: use popup -->

View File

@ -894,10 +894,7 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -894,10 +894,7 @@
"color": "Změnit barvu tohoto úkolu",
"move": "Move this task to another project",
"reminder": "Spravovat připomenutí této úlohy",
"description": "Přepnout úpravy popisu úkolu",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Přepnout úpravy popisu úkolu"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Verze frontendu: {version}",
"apiVersion": "Verze API: {version}"
}
}
}

View File

@ -894,10 +894,7 @@
"color": "Skift farven på denne opgave",
"move": "Move this task to another project",
"reminder": "Administrer påmindelser om denne opgave",
"description": "Slå redigering af opgavebeskrivelse til/fra",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Slå redigering af opgavebeskrivelse til/fra"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -894,10 +894,7 @@
"color": "Die Farbe dieser Aufgabe ändern",
"move": "Move this task to another project",
"reminder": "Erinnerungen für diese Aufgabe verwalten",
"description": "Aufgabenbeschreibung bearbeiten",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Aufgabenbeschreibung bearbeiten"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend-Version: {version}",
"apiVersion": "API-Version: {version}"
}
}
}

View File

@ -894,10 +894,7 @@
"color": "Die Farbe dieser Aufgabe ändern",
"move": "Move this task to another project",
"reminder": "Erinnerungen für diese Aufgabe verwalten",
"description": "Aufgabenbeschreibung bearbeiten",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Aufgabenbeschreibung bearbeiten"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -78,8 +78,8 @@
"savedSuccess": "The settings were successfully updated.",
"emailReminders": "Send me reminders for tasks via Email",
"overdueReminders": "Send me a summary of my undone overdue tasks every day",
"discoverableByName": "Let other users find me when they search for my name",
"discoverableByEmail": "Let other users find me when they search for my full email",
"discoverableByName": "Allow other users to add me as a member to teams or projects when they search for my name",
"discoverableByEmail": "Allow other users to add me as a member to teams or projects when they search for my full email",
"playSoundWhenDone": "Play a sound when marking tasks as done",
"weekStart": "Week starts on",
"weekStartSunday": "Sunday",
@ -897,10 +897,7 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1059,4 +1056,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -894,10 +894,7 @@
"color": "Cambia el color de esta tarea",
"move": "Move this task to another project",
"reminder": "Administrar recordatorios de esta tarea",
"description": "Editar la descripción de la tarea",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Editar la descripción de la tarea"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "Versión de la API: {version}"
}
}
}

View File

@ -894,10 +894,7 @@
"color": "Changer la couleur de cette tâche",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Version : {version}",
"apiVersion": "Version de lAPI : {version}"
}
}
}

View File

@ -894,10 +894,7 @@
"color": "Cambia il colore di questa attività",
"move": "Move this task to another project",
"reminder": "Gestisci i promemoria di questa attività",
"description": "Attiva/Disattiva modifica della descrizione dell'attività",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Attiva/Disattiva modifica della descrizione dell'attività"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Versione Frontend: {version}",
"apiVersion": "Versione API: {version}"
}
}
}

View File

@ -894,10 +894,7 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -894,10 +894,7 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend versie: {version}",
"apiVersion": "API Versie: {version}"
}
}
}

View File

@ -894,10 +894,7 @@
"color": "Endre fargen på denne oppgaven",
"move": "Flytt denne oppgaven til et annet prosjekt",
"reminder": "Behandle påminnelser om denne oppgaven",
"description": "Veksle redigering av oppgavebeskrivelsen",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Veksle redigering av oppgavebeskrivelsen"
},
"project": {
"title": "Prosjektvisning",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend versjon: {version}",
"apiVersion": "API versjon: {version}"
}
}
}

View File

@ -894,10 +894,7 @@
"color": "Zmień kolor tego zadania",
"move": "Move this task to another project",
"reminder": "Zarządzaj przypomnieniami o tym zadaniu",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Wersja frontendu: {version}",
"apiVersion": "Wersja API: {version}"
}
}
}

View File

@ -894,10 +894,7 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -894,10 +894,7 @@
"color": "Alterar a cor desta tarefa",
"move": "Mover esta tarefa para outro projeto",
"reminder": "Gerir lembretes desta tarefa",
"description": "Alternar edição da descrição da tarefa",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Alternar edição da descrição da tarefa"
},
"project": {
"title": "Vista do Projeto",
@ -1056,4 +1053,4 @@
"frontendVersion": "Versão Atual: {version}",
"apiVersion": "Versão da API: {version}"
}
}
}

View File

@ -894,10 +894,7 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -894,10 +894,7 @@
"color": "Изменить цвет этой задачи",
"move": "Переместить эту задачу в другой проект",
"reminder": "Управление напоминаниями об этой задаче",
"description": "Включить изменение описания задачи",
"delete": "Удалить задачу",
"priority": "Изменить приоритет задачи",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Включить изменение описания задачи"
},
"project": {
"title": "Просмотр проекта",
@ -1056,4 +1053,4 @@
"frontendVersion": "Версия фронтенда: {version}",
"apiVersion": "Версия API: {version}"
}
}
}

View File

@ -894,10 +894,7 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -894,10 +894,7 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -894,10 +894,7 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -894,10 +894,7 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -894,10 +894,7 @@
"color": "Thay đổi màu công việc này",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Phiên bản giao diện người dùng: {version}",
"apiVersion": "Phiên bản API: {version}"
}
}
}

View File

@ -894,10 +894,7 @@
"color": "更改此任务的颜色",
"move": "Move this task to another project",
"reminder": "管理此任务的提醒",
"description": "切换编辑时的任务描述",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "切换编辑时的任务描述"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "前端版本:{version}",
"apiVersion": "API 版本:{version}"
}
}
}

View File

@ -894,10 +894,7 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -5,7 +5,7 @@ import type { IUser } from '@/modelTypes/IUser'
import type { IFile } from '@/modelTypes/IFile'
import type { IAttachment } from '@/modelTypes/IAttachment'
export const SUPPORTED_IMAGE_SUFFIX = ['.jpg','.jpeg', '.png', '.bmp', '.gif']
export const SUPPORTED_IMAGE_SUFFIX = ['.jpg', '.png', '.bmp', '.gif']
export default class AttachmentModel extends AbstractModel<IAttachment> implements IAttachment {
id = 0

View File

@ -691,6 +691,14 @@ describe('Parse Task Text', () => {
expect(result.assignees).toHaveLength(1)
expect(result.assignees[0]).toBe('today')
})
it('should recognize an email address', () => {
const text = 'Lorem Ipsum @email@example.com'
const result = parseTaskText(text)
expect(result.text).toBe('Lorem Ipsum @email@example.com')
expect(result.assignees).toHaveLength(1)
expect(result.assignees[0]).toBe('email@example.com')
})
})
describe('Recurring Dates', () => {

View File

@ -109,7 +109,9 @@ const getItemsFromPrefix = (text: string, prefix: string): string[] => {
return
}
p = p.replace(prefix, '')
if (p.startsWith(prefix)) {
p = p.substring(1)
}
let itemText
if (p.charAt(0) === '\'') {
@ -120,8 +122,8 @@ const getItemsFromPrefix = (text: string, prefix: string): string[] => {
// Only until the next space
itemText = p.split(' ')[0]
}
if(itemText !== '') {
if (itemText !== '') {
items.push(itemText)
}
})
@ -278,13 +280,16 @@ const getRepeats = (text: string): repeatParsedResult => {
export const cleanupItemText = (text: string, items: string[], prefix: string): string => {
items.forEach(l => {
if (l === '') {
return
}
text = text
.replace(`${prefix}'${l}' `, '')
.replace(`${prefix}'${l}'`, '')
.replace(`${prefix}"${l}" `, '')
.replace(`${prefix}"${l}"`, '')
.replace(`${prefix}${l} `, '')
.replace(`${prefix}${l}`, '')
.replace(new RegExp(`\\${prefix}'${l}' `, 'ig'), '')
.replace(new RegExp(`\\${prefix}'${l}'`, 'ig'), '')
.replace(new RegExp(`\\${prefix}"${l}" `, 'ig'), '')
.replace(new RegExp(`\\${prefix}"${l}"`, 'ig'), '')
.replace(new RegExp(`\\${prefix}${l} `, 'ig'), '')
.replace(new RegExp(`\\${prefix}${l}`, 'ig'), '')
})
return text
}

View File

@ -5,7 +5,6 @@ import router from '@/router'
import TaskService from '@/services/task'
import TaskAssigneeService from '@/services/taskAssignee'
import LabelTaskService from '@/services/labelTask'
import UserService from '@/services/user'
import {playPop} from '@/helpers/playPop'
import {getQuickAddMagicMode} from '@/helpers/quickAddMagicMode'
@ -29,12 +28,21 @@ import {useProjectStore} from '@/stores/projects'
import {useAttachmentStore} from '@/stores/attachments'
import {useKanbanStore} from '@/stores/kanban'
import {useBaseStore} from '@/stores/base'
import ProjectUserService from '@/services/projectUsers'
interface MatchedAssignee extends IUser {
match: string,
}
// IDEA: maybe use a small fuzzy search here to prevent errors
function findPropertyByValue(object, key, value) {
return Object.values(object).find(
(l) => l[key]?.toLowerCase() === value.toLowerCase(),
)
function findPropertyByValue(object, key, value, fuzzy: boolean = false) {
return Object.values(object).find(l => {
if (fuzzy) {
return l[key]?.toLowerCase().includes(value.toLowerCase())
}
return l[key]?.toLowerCase() === value.toLowerCase()
})
}
// Check if the user exists in the search results
@ -42,9 +50,19 @@ function validateUser(
users: IUser[],
query: IUser['username'] | IUser['name'] | IUser['email'],
) {
return findPropertyByValue(users, 'username', query) ||
if (users.length === 1) {
return (
findPropertyByValue(users, 'username', query, true) ||
findPropertyByValue(users, 'name', query, true) ||
findPropertyByValue(users, 'email', query, true)
)
}
return (
findPropertyByValue(users, 'username', query) ||
findPropertyByValue(users, 'name', query) ||
findPropertyByValue(users, 'email', query)
)
}
// Check if the label exists
@ -63,14 +81,18 @@ async function addLabelToTask(task: ITask, label: ILabel) {
return response
}
async function findAssignees(parsedTaskAssignees: string[]): Promise<IUser[]> {
async function findAssignees(parsedTaskAssignees: string[], projectId: number): Promise<MatchedAssignee[]> {
if (parsedTaskAssignees.length <= 0) {
return []
}
const userService = new UserService()
const userService = new ProjectUserService()
const assignees = parsedTaskAssignees.map(async a => {
const users = await userService.getAll({}, {s: a})
const users = (await userService.getAll({projectId}, {s: a}))
.map(u => ({
...u,
match: a,
}))
return validateUser(users, a)
})
@ -388,15 +410,15 @@ export const useTaskStore = defineStore('task', () => {
cancel()
throw new Error('NO_PROJECT')
}
const assignees = await findAssignees(parsedTask.assignees)
const assignees = await findAssignees(parsedTask.assignees, foundProjectId)
// Only clean up those assignees from the task title which actually exist
let cleanedTitle = parsedTask.text
if (assignees.length > 0) {
const assigneePrefix = PREFIXES[quickAddMagicMode]?.assignee
if (assigneePrefix) {
cleanedTitle = cleanupItemText(cleanedTitle, assignees.map(a => a.username), assigneePrefix)
cleanedTitle = cleanupItemText(cleanedTitle, assignees.map(a => a.match), assigneePrefix)
}
}

View File

@ -322,7 +322,6 @@
@click="setFieldActive('priority')"
variant="secondary"
icon="exclamation"
v-shortcut="'p'"
>
{{ $t('task.detail.actions.priority') }}
</x-button>
@ -407,7 +406,6 @@
@click="toggleFavorite"
variant="secondary"
:icon="task.isFavorite ? 'star' : ['far', 'star']"
v-shortcut="'s'"
>
{{
task.isFavorite ? $t('task.detail.actions.unfavorite') : $t('task.detail.actions.favorite')
@ -418,7 +416,6 @@
icon="trash-alt"
:shadow="false"
class="is-danger is-outlined has-no-border"
v-shortcut="'Shift+Delete'"
>
{{ $t('task.detail.actions.delete') }}
</x-button>

View File

@ -1,5 +1,5 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"extends": "@vue/tsconfig/tsconfig.web.json",
"include": ["env.d.ts", "src/**/*.d.ts", "src/**/*", "src/**/*.vue", "src/**/*.json"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {

View File

@ -1,8 +1,5 @@
{
"extends": [
"@tsconfig/node18/tsconfig.json",
"@vue/tsconfig/tsconfig.json"
],
"extends": "@vue/tsconfig/tsconfig.node.json",
"include": ["vite.config.*", "vitest.config.*", "cypress.config.*", "env.config.d.ts"],
"compilerOptions": {
"composite": true,