From c3f85fcb1988603a58104552b35101b13e93b06e Mon Sep 17 00:00:00 2001 From: kolaente Date: Tue, 29 Aug 2023 09:19:52 +0200 Subject: [PATCH 01/13] chore: format --- .../quick-actions/quick-actions.vue | 53 ++++++++++--------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/src/components/quick-actions/quick-actions.vue b/src/components/quick-actions/quick-actions.vue index a6a5d47ce..ff3652bfc 100644 --- a/src/components/quick-actions/quick-actions.vue +++ b/src/components/quick-actions/quick-actions.vue @@ -134,7 +134,7 @@ function closeQuickActions() { } const foundProjects = computed(() => { - const { project } = parsedQuery.value + const {project} = parsedQuery.value if ( searchMode.value === SEARCH_MODE.ALL || searchMode.value === SEARCH_MODE.PROJECTS || @@ -190,7 +190,7 @@ const results = computed(() => { ].filter((i) => i.items.length > 0) }) -const loading = computed(() => +const loading = computed(() => taskService.loading || projectStore.isLoading || teamService.loading, @@ -262,7 +262,7 @@ const searchMode = computed(() => { if (query.value === '') { return SEARCH_MODE.ALL } - const { text, project, labels, assignees } = parsedQuery.value + const {text, project, labels, assignees} = parsedQuery.value if (assignees.length === 0 && text !== '') { return SEARCH_MODE.TASKS } @@ -292,12 +292,12 @@ const isNewTaskCommand = computed(() => ( const taskSearchTimeout = ref | null>(null) -type Filter = {by: string, value: string | number, comparator: string} +type Filter = { by: string, value: string | number, comparator: string } function filtersToParams(filters: Filter[]) { - const filter_by : Filter['by'][] = [] - const filter_value : Filter['value'][] = [] - const filter_comparator : Filter['comparator'][] = [] + const filter_by: Filter['by'][] = [] + const filter_value: Filter['value'][] = [] + const filter_comparator: Filter['comparator'][] = [] filters.forEach(({by, value, comparator}) => { filter_by.push(by) @@ -330,7 +330,7 @@ function searchTasks() { taskSearchTimeout.value = null } - const { text, project: projectName, labels } = parsedQuery.value + const {text, project: projectName, labels} = parsedQuery.value const filters: Filter[] = [] @@ -361,13 +361,13 @@ function searchTasks() { } } - const params = { - s: text, - ...filtersToParams(filters), - } + const params = { + s: text, + ...filtersToParams(filters), + } taskSearchTimeout.value = setTimeout(async () => { - const r = await taskService.getAll({}, params) as DoAction[] + const r = await taskService.getAll({}, params) as DoAction[] foundTasks.value = r.map((t) => { t.type = ACTION_TYPE.TASK const project = projectStore.projects[t.projectId] @@ -396,10 +396,10 @@ function searchTeams() { clearTimeout(teamSearchTimeout.value) teamSearchTimeout.value = null } - const { assignees } = parsedQuery.value + const {assignees} = parsedQuery.value teamSearchTimeout.value = setTimeout(async () => { const teamSearchPromises = assignees.map((t) => - teamService.getAll({}, { s: t }), + teamService.getAll({}, {s: t}), ) const teamsResult = await Promise.all(teamSearchPromises) foundTeams.value = teamsResult.flat().map((team) => { @@ -422,21 +422,21 @@ async function doAction(type: ACTION_TYPE, item: DoAction) { closeQuickActions() await router.push({ name: 'project.index', - params: { projectId: (item as DoAction).id }, + params: {projectId: (item as DoAction).id}, }) break case ACTION_TYPE.TASK: closeQuickActions() await router.push({ name: 'task.detail', - params: { id: (item as DoAction).id }, + params: {id: (item as DoAction).id}, }) break case ACTION_TYPE.TEAM: closeQuickActions() await router.push({ name: 'teams.edit', - params: { id: (item as DoAction).id }, + params: {id: (item as DoAction).id}, }) break case ACTION_TYPE.CMD: @@ -470,8 +470,8 @@ async function newTask() { title: query.value, projectId: currentProject.value.id, }) - success({ message: t('task.createSuccess') }) - await router.push({ name: 'task.detail', params: { id: task.id } }) + success({message: t('task.createSuccess')}) + await router.push({name: 'task.detail', params: {id: task.id}}) } async function newProject() { @@ -481,17 +481,17 @@ async function newProject() { await projectStore.createProject(new ProjectModel({ title: query.value, })) - success({ message: t('project.create.createdSuccess')}) + success({message: t('project.create.createdSuccess')}) } async function newTeam() { - const newTeam = new TeamModel({ name: query.value }) + const newTeam = new TeamModel({name: query.value}) const team = await teamService.create(newTeam) await router.push({ name: 'teams.edit', - params: { id: team.id }, + params: {id: team.id}, }) - success({ message: t('team.create.success') }) + success({message: t('team.create.success')}) } type BaseButtonInstance = InstanceType @@ -502,7 +502,7 @@ function setResultRefs(el: Element | ComponentPublicInstance | null, index: numb resultRefs.value[index] = [] } - resultRefs.value[index][key] = el as (BaseButtonInstance | null) + resultRefs.value[index][key] = el as (BaseButtonInstance | null) } function select(parentIndex: number, index: number) { @@ -547,7 +547,7 @@ function reset() { \ No newline at end of file diff --git a/src/components/tasks/partials/quick-add-magic.vue b/src/components/tasks/partials/quick-add-magic.vue index 30818a0ff..9595fb178 100644 --- a/src/components/tasks/partials/quick-add-magic.vue +++ b/src/components/tasks/partials/quick-add-magic.vue @@ -108,7 +108,7 @@ const visible = ref(false) const mode = computed(() => authStore.settings.frontendSettings.quickAddMagicMode) defineProps<{ - highlightHintIcon: boolean, + highlightHintIcon?: boolean, }>() const prefixes = computed(() => PREFIXES[mode.value]) From 442d0342a90093cbc1c7f778bd744d7e8a436a87 Mon Sep 17 00:00:00 2001 From: kolaente Date: Tue, 29 Aug 2023 10:08:47 +0200 Subject: [PATCH 08/13] fix(quick actions): project search --- src/components/quick-actions/quick-actions.vue | 15 +++++---------- src/stores/projects.ts | 3 ++- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/components/quick-actions/quick-actions.vue b/src/components/quick-actions/quick-actions.vue index d70ca7d0e..1648d81db 100644 --- a/src/components/quick-actions/quick-actions.vue +++ b/src/components/quick-actions/quick-actions.vue @@ -143,18 +143,13 @@ const foundProjects = computed(() => { searchMode.value === SEARCH_MODE.PROJECTS || text === '' ) { - return [] + const history = getHistory() + return history.map((p) => projectStore.projects[p.id]) + .filter(p => Boolean(p)) } - const history = getHistory() - const allProjects = [ - ...new Set([ - ...history.map((p) => projectStore.projects[p.id]), - ...projectStore.searchProject(project), - ]), - ] - - return allProjects.filter(p => Boolean(p)) + return projectStore.searchProject(project ?? text) + .filter(p => Boolean(p)) }) // FIXME: use fuzzysearch diff --git a/src/stores/projects.ts b/src/stores/projects.ts index b3ce6d889..a18e14956 100644 --- a/src/stores/projects.ts +++ b/src/stores/projects.ts @@ -19,7 +19,7 @@ import {success} from '@/message' import {useBaseStore} from '@/stores/base' import {getSavedFilterIdFromProjectId} from '@/services/savedFilter' -const {remove, search, update} = createNewIndexer('projects', ['title', 'description']) +const {add, remove, search, update} = createNewIndexer('projects', ['title', 'description']) export interface ProjectState { [id: IProject['id']]: IProject @@ -174,6 +174,7 @@ export const useProjectStore = defineStore('project', () => { const loadedProjects = await projectService.getAll({}, {is_archived: true}) as IProject[] projects.value = {} setProjects(loadedProjects) + loadedProjects.forEach(p => add(p)) return loadedProjects } finally { From 99d8fbdfa7023cc6c88fa9d4cbec0d0c53e2a386 Mon Sep 17 00:00:00 2001 From: kolaente Date: Tue, 29 Aug 2023 11:11:37 +0200 Subject: [PATCH 09/13] feat(quick actions): show tasks for a label when selecting it --- .../quick-actions/quick-actions.vue | 25 +++++++++++++++++++ src/i18n/lang/en.json | 1 + 2 files changed, 26 insertions(+) diff --git a/src/components/quick-actions/quick-actions.vue b/src/components/quick-actions/quick-actions.vue index 1648d81db..4ffee13d5 100644 --- a/src/components/quick-actions/quick-actions.vue +++ b/src/components/quick-actions/quick-actions.vue @@ -83,6 +83,7 @@ import {success} from '@/message' import type {ITeam} from '@/modelTypes/ITeam' import type {ITask} from '@/modelTypes/ITask' import type {IProject} from '@/modelTypes/IProject' +import type {ILabel} from '@/modelTypes/ILabel' const {t} = useI18n({useScope: 'global'}) const router = useRouter() @@ -100,6 +101,7 @@ enum ACTION_TYPE { TASK = 'task', PROJECT = 'project', TEAM = 'team', + LABELS = 'labels', } enum COMMAND_TYPE { @@ -152,6 +154,19 @@ const foundProjects = computed(() => { .filter(p => Boolean(p)) }) +const foundLabels = computed(() => { + const {labels, text} = parsedQuery.value + if (text === '' && labels.length === 0) { + return [] + } + + if (labels.length > 0) { + return labelStore.filterLabelsByQuery([], labels[0]) + } + + return labelStore.filterLabelsByQuery([], text) +}) + // FIXME: use fuzzysearch const foundCommands = computed(() => availableCmds.value.filter((a) => a.title.toLowerCase().includes(query.value.toLowerCase()), @@ -180,6 +195,11 @@ const results = computed(() => { title: t('quickActions.tasks'), items: foundTasks.value, }, + { + type: ACTION_TYPE.LABELS, + title: t('quickActions.labels'), + items: foundLabels.value, + }, { type: ACTION_TYPE.TEAM, title: t('quickActions.teams'), @@ -447,6 +467,11 @@ async function doAction(type: ACTION_TYPE, item: DoAction) { selectedCmd.value = item as DoAction searchInput.value?.focus() break + case ACTION_TYPE.LABELS: + query.value = '*'+item.title + searchInput.value?.focus() + searchTasks() + break } } diff --git a/src/i18n/lang/en.json b/src/i18n/lang/en.json index bd87f8f1a..be6bf4ed6 100644 --- a/src/i18n/lang/en.json +++ b/src/i18n/lang/en.json @@ -905,6 +905,7 @@ "tasks": "Tasks", "projects": "Projects", "teams": "Teams", + "labels": "Labels", "newProject": "Enter the title of the new project…", "newTask": "Enter the title of the new task…", "newTeam": "Enter the name of the new team…", From d57e1909c4bd1997b790a5a32b2920398b781f9c Mon Sep 17 00:00:00 2001 From: kolaente Date: Tue, 29 Aug 2023 12:33:43 +0200 Subject: [PATCH 10/13] feat(quick actions): show labels as labels and tasks with all of their details --- .../quick-actions/quick-actions.vue | 29 +-- src/components/tasks/partials/label.vue | 25 +++ src/components/tasks/partials/labels.vue | 18 +- .../partials/singleTaskInlineReadonly.vue | 196 ++++++++++++++++++ 4 files changed, 244 insertions(+), 24 deletions(-) create mode 100644 src/components/tasks/partials/label.vue create mode 100644 src/components/tasks/partials/singleTaskInlineReadonly.vue diff --git a/src/components/quick-actions/quick-actions.vue b/src/components/quick-actions/quick-actions.vue index 4ffee13d5..480d31f99 100644 --- a/src/components/quick-actions/quick-actions.vue +++ b/src/components/quick-actions/quick-actions.vue @@ -44,10 +44,18 @@ @keyup.prevent.enter="doAction(r.type, i)" @keyup.prevent.esc="searchInput?.focus()" > - - {{ i.identifier }} - - {{ i.title }} + + + @@ -69,6 +77,8 @@ import ProjectModel from '@/models/project' import BaseButton from '@/components/base/BaseButton.vue' import QuickAddMagic from '@/components/tasks/partials/quick-add-magic.vue' +import XLabel from '@/components/tasks/partials/label.vue' +import SingleTaskInlineReadonly from '@/components/tasks/partials/singleTaskInlineReadonly.vue' import {useBaseStore} from '@/stores/base' import {useProjectStore} from '@/stores/projects' @@ -83,7 +93,6 @@ import {success} from '@/message' import type {ITeam} from '@/modelTypes/ITeam' import type {ITask} from '@/modelTypes/ITask' import type {IProject} from '@/modelTypes/IProject' -import type {ILabel} from '@/modelTypes/ILabel' const {t} = useI18n({useScope: 'global'}) const router = useRouter() @@ -159,11 +168,11 @@ const foundLabels = computed(() => { if (text === '' && labels.length === 0) { return [] } - + if (labels.length > 0) { return labelStore.filterLabelsByQuery([], labels[0]) } - + return labelStore.filterLabelsByQuery([], text) }) @@ -393,10 +402,6 @@ function searchTasks() { const r = await taskService.getAll({}, params) as DoAction[] foundTasks.value = r.map((t) => { t.type = ACTION_TYPE.TASK - const project = projectStore.projects[t.projectId] - if (project !== null) { - t.title = `${t.title} (${project.title})` - } return t }) }, 150) @@ -468,7 +473,7 @@ async function doAction(type: ACTION_TYPE, item: DoAction) { searchInput.value?.focus() break case ACTION_TYPE.LABELS: - query.value = '*'+item.title + query.value = '*' + item.title searchInput.value?.focus() searchTasks() break diff --git a/src/components/tasks/partials/label.vue b/src/components/tasks/partials/label.vue new file mode 100644 index 000000000..d8f515a0e --- /dev/null +++ b/src/components/tasks/partials/label.vue @@ -0,0 +1,25 @@ + + + + + \ No newline at end of file diff --git a/src/components/tasks/partials/labels.vue b/src/components/tasks/partials/labels.vue index 8727695a9..e80d06798 100644 --- a/src/components/tasks/partials/labels.vue +++ b/src/components/tasks/partials/labels.vue @@ -1,12 +1,10 @@ @@ -14,6 +12,8 @@ import type {PropType} from 'vue' import type {ILabel} from '@/modelTypes/ILabel' +import XLabel from '@/components/tasks/partials/label.vue' + defineProps({ labels: { type: Array as PropType, @@ -26,10 +26,4 @@ defineProps({ .label-wrapper { display: inline; } - -.tag { - & + & { - margin-left: 0.5rem; - } -} \ No newline at end of file diff --git a/src/components/tasks/partials/singleTaskInlineReadonly.vue b/src/components/tasks/partials/singleTaskInlineReadonly.vue new file mode 100644 index 000000000..6c16f1b09 --- /dev/null +++ b/src/components/tasks/partials/singleTaskInlineReadonly.vue @@ -0,0 +1,196 @@ + + + + + From 4e6b99544ecd08199bfb046b60c4786372974d86 Mon Sep 17 00:00:00 2001 From: kolaente Date: Tue, 29 Aug 2023 12:38:59 +0200 Subject: [PATCH 11/13] fix(quick actions): don't show projects when searching for labels or tasks --- .../quick-actions/quick-actions.vue | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/components/quick-actions/quick-actions.vue b/src/components/quick-actions/quick-actions.vue index 480d31f99..8a948767c 100644 --- a/src/components/quick-actions/quick-actions.vue +++ b/src/components/quick-actions/quick-actions.vue @@ -48,7 +48,7 @@