Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions frontend/src/lib/layout/DashboardCustomizationSidebar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
Briefcase,
Grip,
ListChecks,
PenLine,
Search,
} from '@lucide/svelte';
import {
Expand All @@ -34,6 +35,7 @@
Briefcase,
Grip,
ListChecks,
PenLine,
Search,
};

Expand Down
6 changes: 6 additions & 0 deletions frontend/src/lib/locales/ar/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ export default {
name: 'مسند إليّ',
description: 'العناصر المفتوحة المسندة إليك في جميع مساحات العمل',
},
createdByMe: {
name: 'أنشأتها',
description: 'العناصر المفتوحة التي أنشأتها في جميع مساحات العمل',
},
watchedItems: {
name: 'العناصر المراقبة',
description: 'العناصر التي تتابعها',
Expand Down Expand Up @@ -106,6 +110,8 @@ export default {
states: {
assignedLoadError: 'تعذر تحميل العناصر المسندة إليك',
assignedEmpty: 'لا يوجد شيء مسند إليك حالياً',
createdLoadError: 'تعذر تحميل العناصر التي أنشأتها',
createdEmpty: 'لم تنشئ أي عناصر مفتوحة',
personalTasksLoadError: 'تعذر تحميل مهامك الشخصية',
personalTasksEmpty: 'قائمة مهامك الشخصية فارغة',
supportMetricsLoadError: 'تعذر تحميل مقاييس الدعم',
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/lib/locales/de/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ export default {
name: 'Mir zugewiesen',
description: 'Ihnen zugewiesene offene Einträge aus allen Arbeitsbereichen',
},
createdByMe: {
name: 'Von mir erstellt',
description: 'Von Ihnen erstellte offene Einträge aus allen Arbeitsbereichen',
},
watchedItems: {
name: 'Beobachtete Einträge',
description: 'Einträge, denen Sie folgen',
Expand Down Expand Up @@ -106,6 +110,8 @@ export default {
states: {
assignedLoadError: 'Die Ihnen zugewiesenen Einträge konnten nicht geladen werden',
assignedEmpty: 'Ihnen ist derzeit nichts zugewiesen',
createdLoadError: 'Die von Ihnen erstellten Einträge konnten nicht geladen werden',
createdEmpty: 'Sie haben keine offenen Einträge erstellt',
personalTasksLoadError: 'Ihre persönlichen Aufgaben konnten nicht geladen werden',
personalTasksEmpty: 'Ihre persönliche Aufgabenliste ist leer',
supportMetricsLoadError: 'Support-Kennzahlen konnten nicht geladen werden',
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/lib/locales/en/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ export default {
name: 'Assigned to Me',
description: 'Open items assigned to you across all workspaces',
},
createdByMe: {
name: 'Created by Me',
description: 'Open items you created across all workspaces',
},
watchedItems: {
name: 'Watched Items',
description: 'Items you are following',
Expand Down Expand Up @@ -106,6 +110,8 @@ export default {
states: {
assignedLoadError: "Couldn't load your assigned items",
assignedEmpty: 'Nothing assigned to you right now',
createdLoadError: "Couldn't load the items you created",
createdEmpty: "You haven't created any open items",
storyPointsLoadError: "Couldn't load the story points summary",
storyPointsEmpty: 'No open story points assigned yet',
personalTasksLoadError: "Couldn't load your personal tasks",
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/lib/locales/es/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ export default {
name: 'Asignados a mí',
description: 'Elementos abiertos que tienes asignados en todos los espacios de trabajo',
},
createdByMe: {
name: 'Creados por mí',
description: 'Elementos abiertos que creaste en todos los espacios de trabajo',
},
watchedItems: {
name: 'Elementos observados',
description: 'Elementos que sigues',
Expand Down Expand Up @@ -106,6 +110,8 @@ export default {
states: {
assignedLoadError: 'No se pudieron cargar los elementos que tienes asignados',
assignedEmpty: 'No tienes nada asignado en este momento',
createdLoadError: 'No se pudieron cargar los elementos que creaste',
createdEmpty: 'No has creado ningún elemento abierto',
personalTasksLoadError: 'No se pudieron cargar tus tareas personales',
personalTasksEmpty: 'Tu lista personal de tareas está vacía',
supportMetricsLoadError: 'No se pudieron cargar las métricas de soporte',
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/lib/locales/fr/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ export default {
name: 'Mes éléments attribués',
description: 'Éléments ouverts qui vous sont attribués dans tous les espaces de travail',
},
createdByMe: {
name: 'Créés par moi',
description: 'Éléments ouverts que vous avez créés dans tous les espaces de travail',
},
watchedItems: {
name: 'Éléments suivis',
description: 'Éléments que vous suivez',
Expand Down Expand Up @@ -106,6 +110,8 @@ export default {
states: {
assignedLoadError: 'Impossible de charger les éléments qui vous sont attribués',
assignedEmpty: 'Rien ne vous est attribué pour le moment',
createdLoadError: 'Impossible de charger les éléments que vous avez créés',
createdEmpty: "Vous n'avez créé aucun élément ouvert",
personalTasksLoadError: 'Impossible de charger vos tâches personnelles',
personalTasksEmpty: 'Votre liste de tâches personnelles est vide',
supportMetricsLoadError: 'Impossible de charger les métriques d’assistance',
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/lib/locales/ko/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ export default {
"name": "내 담당 작업",
"description": "전체 워크스페이스에서 나에게 배정된 미완료 작업"
},
"createdByMe": {
"name": "내가 만든 작업",
"description": "전체 워크스페이스에서 내가 만든 미완료 작업"
},
"watchedItems": {
"name": "관찰 중인 작업",
"description": "내가 지켜보는 작업"
Expand Down Expand Up @@ -107,6 +111,8 @@ export default {
"states": {
"assignedLoadError": "내 담당 작업을 불러오지 못했습니다",
"assignedEmpty": "현재 나에게 배정된 작업이 없습니다",
"createdLoadError": "내가 만든 작업을 불러오지 못했습니다",
"createdEmpty": "내가 만든 미완료 작업이 없습니다",
"storyPointsLoadError": "스토리 포인트 요약을 불러오지 못했습니다",
"storyPointsEmpty": "아직 배정된 미완료 스토리 포인트가 없습니다",
"personalTasksLoadError": "개인 작업을 불러오지 못했습니다",
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/lib/locales/pt-BR/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ export default {
name: 'Atribuídos a mim',
description: 'Itens abertos atribuídos a você em todos os espaços de trabalho',
},
createdByMe: {
name: 'Criados por mim',
description: 'Itens abertos criados por você em todos os espaços de trabalho',
},
watchedItems: {
name: 'Itens observados',
description: 'Itens que você acompanha',
Expand Down Expand Up @@ -106,6 +110,8 @@ export default {
states: {
assignedLoadError: 'Não foi possível carregar os itens atribuídos a você',
assignedEmpty: 'Nada foi atribuído a você no momento',
createdLoadError: 'Não foi possível carregar os itens criados por você',
createdEmpty: 'Você não criou nenhum item em aberto',
personalTasksLoadError: 'Não foi possível carregar suas tarefas pessoais',
personalTasksEmpty: 'Sua lista pessoal de tarefas está vazia',
supportMetricsLoadError: 'Não foi possível carregar as métricas de suporte',
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/lib/locales/ru/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ export default {
name: 'Назначено мне',
description: 'Открытые элементы, назначенные вам во всех рабочих пространствах',
},
createdByMe: {
name: 'Созданные мной',
description: 'Открытые элементы, созданные вами, во всех рабочих пространствах',
},
watchedItems: {
name: 'Отслеживаемые элементы',
description: 'Элементы, за которыми вы следите',
Expand Down Expand Up @@ -106,6 +110,8 @@ export default {
states: {
assignedLoadError: 'Не удалось загрузить назначенные вам элементы',
assignedEmpty: 'Сейчас вам ничего не назначено',
createdLoadError: 'Не удалось загрузить созданные вами элементы',
createdEmpty: 'У вас нет открытых элементов, созданных вами',
storyPointsLoadError: 'Не удалось загрузить сводку стори-поинтов',
storyPointsEmpty: 'Открытых стори-поинтов пока не назначено',
personalTasksLoadError: 'Не удалось загрузить личные задачи',
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/lib/locales/zh-CN/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ export default {
name: '分配给我的',
description: '所有工作区中分配给你的未完成事项',
},
createdByMe: {
name: '我创建的',
description: '所有工作区中你创建的未完成事项',
},
watchedItems: {
name: '关注的事项',
description: '你正在关注的事项',
Expand Down Expand Up @@ -106,6 +110,8 @@ export default {
states: {
assignedLoadError: '无法加载分配给你的事项',
assignedEmpty: '目前没有分配给你的事项',
createdLoadError: '无法加载你创建的事项',
createdEmpty: '你没有创建任何未完成的事项',
personalTasksLoadError: '无法加载你的个人任务',
personalTasksEmpty: '你的个人待办列表为空',
supportMetricsLoadError: '无法加载支持指标',
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/lib/pages/Homepage.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import WatchedItemsWidget from '../widgets/dashboard/WatchedItemsWidget.svelte';
import RecentWorkspacesWidget from '../widgets/dashboard/RecentWorkspacesWidget.svelte';
import AssignedToMeWidget from '../widgets/dashboard/AssignedToMeWidget.svelte';
import CreatedByMeWidget from '../widgets/dashboard/CreatedByMeWidget.svelte';
import PersonalTasksWidget from '../widgets/dashboard/PersonalTasksWidget.svelte';
import SupportOverviewWidget from '../widgets/SupportOverviewWidget.svelte';
import SavedSearchWidget from '../widgets/dashboard/SavedSearchWidget.svelte';
Expand Down Expand Up @@ -524,6 +525,8 @@
<RecentWorkspacesWidget />
{:else if widget.type === 'assigned-to-me'}
<AssignedToMeWidget config={widget.config ?? {}} />
{:else if widget.type === 'created-by-me'}
<CreatedByMeWidget config={widget.config ?? {}} />
{:else if widget.type === 'personal-tasks'}
<PersonalTasksWidget config={widget.config ?? {}} />
{:else if widget.type === 'support-overview'}
Expand Down
16 changes: 15 additions & 1 deletion frontend/src/lib/services/dashboardWidgetRegistry.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,15 @@ export const dashboardWidgetRegistry = [
defaultWidth: 6,
minWidth: 3,
},
{
type: 'created-by-me',
nameKey: 'dashboard.widgetCatalog.createdByMe.name',
descriptionKey: 'dashboard.widgetCatalog.createdByMe.description',
category: dashboardWidgetCategories.WORK,
icon: 'PenLine',
defaultWidth: 6,
minWidth: 3,
},
{
type: 'watched-items',
nameKey: 'dashboard.widgetCatalog.watchedItems.name',
Expand Down Expand Up @@ -201,7 +210,11 @@ export function buildDefaultDashboardLayout() {
'default-your-activity',
'default-whats-new',
]),
section('default-work', 1, ['default-personal-tasks', 'default-assigned-to-me']),
section('default-work', 1, [
'default-personal-tasks',
'default-assigned-to-me',
'default-created-by-me',
]),
section('default-workspaces', 2, ['default-recent-workspaces', 'default-quick-access']),
];

Expand All @@ -220,6 +233,7 @@ export function buildDefaultDashboardLayout() {
widget('default-whats-new', 'whats-new', 'default-your-day', 2),
widget('default-personal-tasks', 'personal-tasks', 'default-work', 0, 6),
widget('default-assigned-to-me', 'assigned-to-me', 'default-work', 1, 6),
widget('default-created-by-me', 'created-by-me', 'default-work', 2, 6),
widget('default-recent-workspaces', 'recent-workspaces', 'default-workspaces', 0),
widget('default-quick-access', 'quick-access', 'default-workspaces', 1),
];
Expand Down
72 changes: 72 additions & 0 deletions frontend/src/lib/widgets/dashboard/CreatedByMeWidget.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<script>
import { PenLine } from '@lucide/svelte';
import { authStore } from '../../stores';
import { t } from '../../stores/i18n.svelte.js';
import { api } from '../../api.js';
import DashboardTaskList from './DashboardTaskList.svelte';
import {
createdByMeQuery,
normalizeTaskResponse,
openTask,
resolveRowCount,
resolveDensity,
rowCountToLimit,
} from './taskWidgetState.js';
let { config = {} } = $props();
let tasks = $state([]);
let loading = $state(false);
let errored = $state(false);
let lastUserId = null;
let lastLoadKey = null;
let version = 0;
const currentUserId = $derived($authStore?.currentUser?.id ?? null);
const rowCount = $derived(resolveRowCount(config, 12));
const density = $derived(resolveDensity(config));
const fetchLimit = $derived(rowCountToLimit(rowCount));
const loadKey = $derived(`${currentUserId}:${rowCount}`);
$effect(() => {
if (currentUserId && (currentUserId !== lastUserId || loadKey !== lastLoadKey)) {
lastUserId = currentUserId;
lastLoadKey = loadKey;
load();
} else if (!currentUserId && lastUserId !== null) {
lastUserId = null;
lastLoadKey = null;
tasks = [];
}
});
async function load() {
const v = ++version;
loading = true;
errored = false;
try {
const response = await api.items.getAll(createdByMeQuery(currentUserId, fetchLimit));
if (v !== version) return;
tasks = normalizeTaskResponse(response, rowCount);
} catch (err) {
if (v !== version) return;
if (err?.name === 'AbortError') return;
console.error('Failed to load created items:', err);
errored = true;
tasks = [];
} finally {
if (v === version) loading = false;
}
}
</script>
<DashboardTaskList
{loading}
{errored}
{tasks}
icon={PenLine}
errorMessage={t('dashboard.states.createdLoadError')}
emptyMessage={t('dashboard.states.createdEmpty')}
{density}
{openTask}
/>
21 changes: 20 additions & 1 deletion frontend/src/lib/widgets/dashboard/taskWidgetState.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ export const DEFAULT_DONE_RANGE_DAYS = 7;
/**
* Widget types that support the row-count / density controls.
*/
export const ROW_COUNT_WIDGETS = new Set(['assigned-to-me', 'personal-tasks', 'saved-search']);
export const ROW_COUNT_WIDGETS = new Set([
'assigned-to-me',
'created-by-me',
'personal-tasks',
'saved-search',
]);

/**
* Row count options offered in the widget menu.
Expand Down Expand Up @@ -95,6 +100,20 @@ export function assignedToMeQuery(userId, limit = 30) {
};
}

/**
* Query params for "items I created and not yet completed", newest first.
* Counterpart to assignedToMeQuery for the created-by-me widget.
* @param {number|string} userId
* @param {number} [limit]
*/
export function createdByMeQuery(userId, limit = 30) {
return {
ql: `creator_id = ${userId} AND status_completed = false`,
limit,
order_by: 'updated_at',
};
}

/**
* @param {unknown} response
* @param {number | 'all'} [maxItems]
Expand Down
1 change: 1 addition & 0 deletions internal/handlers/user_dashboard_layout.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ var validDashboardWidgetTypes = map[string]bool{
"watched-items": true,
"recent-workspaces": true,
"assigned-to-me": true,
"created-by-me": true,
"personal-tasks": true,
"saved-search": true,
"support-overview": true,
Expand Down
Loading