diff --git a/src/components/quick-actions/quick-actions.vue b/src/components/quick-actions/quick-actions.vue
index a6a5d47ce..18b24963e 100644
--- a/src/components/quick-actions/quick-actions.vue
+++ b/src/components/quick-actions/quick-actions.vue
@@ -24,7 +24,7 @@
{{ hintText }}
-
+
@@ -44,7 +44,18 @@
@keyup.prevent.enter="doAction(r.type, i)"
@keyup.prevent.esc="searchInput?.focus()"
>
- {{ i.title }}
+
+
+
+
+
+
+
+ {{ i.title }}
+
@@ -66,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'
@@ -97,6 +110,7 @@ enum ACTION_TYPE {
TASK = 'task',
PROJECT = 'project',
TEAM = 'team',
+ LABELS = 'labels',
}
enum COMMAND_TYPE {
@@ -134,24 +148,38 @@ function closeQuickActions() {
}
const foundProjects = computed(() => {
- const { project } = parsedQuery.value
- if (
- searchMode.value === SEARCH_MODE.ALL ||
- searchMode.value === SEARCH_MODE.PROJECTS ||
- project === null
- ) {
+ const {project, text, labels, assignees} = parsedQuery.value
+
+ if (project !== null) {
+ return projectStore.searchProject(project ?? text)
+ .filter(p => Boolean(p))
+ }
+
+ if (labels.length > 0 || assignees.length > 0) {
return []
}
- const history = getHistory()
- const allProjects = [
- ...new Set([
- ...history.map((l) => projectStore.projects[l.id]),
- ...projectStore.searchProject(project),
- ]),
- ]
+ if (text === '') {
+ const history = getHistory()
+ return history.map((p) => projectStore.projects[p.id])
+ .filter(p => Boolean(p))
+ }
- return allProjects.filter(l => Boolean(l))
+ return projectStore.searchProject(project ?? text)
+ .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
@@ -172,15 +200,20 @@ const results = computed(() => {
title: t('quickActions.commands'),
items: foundCommands.value,
},
+ {
+ type: ACTION_TYPE.PROJECT,
+ title: t('quickActions.projects'),
+ items: foundProjects.value,
+ },
{
type: ACTION_TYPE.TASK,
title: t('quickActions.tasks'),
items: foundTasks.value,
},
{
- type: ACTION_TYPE.PROJECT,
- title: t('quickActions.projects'),
- items: foundProjects.value,
+ type: ACTION_TYPE.LABELS,
+ title: t('quickActions.labels'),
+ items: foundLabels.value,
},
{
type: ACTION_TYPE.TEAM,
@@ -190,7 +223,7 @@ const results = computed(() => {
].filter((i) => i.items.length > 0)
})
-const loading = computed(() =>
+const loading = computed(() =>
taskService.loading ||
projectStore.isLoading ||
teamService.loading,
@@ -262,10 +295,12 @@ 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
}
+
if (
assignees.length === 0 &&
project !== null &&
@@ -274,6 +309,7 @@ const searchMode = computed(() => {
) {
return SEARCH_MODE.PROJECTS
}
+
if (
assignees.length > 0 &&
project === null &&
@@ -282,6 +318,7 @@ const searchMode = computed(() => {
) {
return SEARCH_MODE.TEAMS
}
+
return SEARCH_MODE.ALL
})
@@ -292,12 +329,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)
@@ -315,7 +352,8 @@ function filtersToParams(filters: Filter[]) {
function searchTasks() {
if (
searchMode.value !== SEARCH_MODE.ALL &&
- searchMode.value !== SEARCH_MODE.TASKS
+ searchMode.value !== SEARCH_MODE.TASKS &&
+ searchMode.value !== SEARCH_MODE.PROJECTS
) {
foundTasks.value = []
return
@@ -330,7 +368,7 @@ function searchTasks() {
taskSearchTimeout.value = null
}
- const { text, project: projectName, labels } = parsedQuery.value
+ const {text, project: projectName, labels} = parsedQuery.value
const filters: Filter[] = []
@@ -349,8 +387,9 @@ function searchTasks() {
if (projectName !== null) {
const project = projectStore.findProjectByExactname(projectName)
+ console.log({project})
if (project !== null) {
- addFilter('projectId', project.id, 'equals')
+ addFilter('project_id', project.id, 'equals')
}
}
@@ -361,19 +400,16 @@ function searchTasks() {
}
}
- const params = {
- s: text,
- ...filtersToParams(filters),
- }
+ const params = {
+ s: text,
+ sort_by: 'done',
+ ...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]
- if (project !== null) {
- t.title = `${t.title} (${project.title})`
- }
return t
})
}, 150)
@@ -396,10 +432,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 +458,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:
@@ -444,6 +480,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
}
}
@@ -470,8 +511,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 +522,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 +543,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 +588,7 @@ function reset() {
\ No newline at end of file
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 @@
+
+
+
+
+ {{ label.title }}
+
+
+
+
\ 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 @@
-
- {{ label.title }}
-
+ />
@@ -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/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])
diff --git a/src/components/tasks/partials/singleTaskInlineReadonly.vue b/src/components/tasks/partials/singleTaskInlineReadonly.vue
new file mode 100644
index 000000000..b20c0a765
--- /dev/null
+++ b/src/components/tasks/partials/singleTaskInlineReadonly.vue
@@ -0,0 +1,192 @@
+
+
+
+
+
+ {{ project.title }}
+
+
+
+
+
+
+
+ {{ pt.title }},
+
+ ›
+
+ {{ task.title }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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…",
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 {