@agent-native/core 0.114.11 → 0.114.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +12 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/application-state/index.ts +3 -0
- package/corpus/core/src/application-state/script-helpers.ts +12 -1
- package/corpus/core/src/application-state/store.ts +216 -15
- package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +89 -1
- package/corpus/core/src/db/client.ts +44 -1
- package/corpus/templates/clips/changelog/2026-07-21-live-dictation-text-now-appears-above-the-desktop-recording-.md +6 -0
- package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +14 -3
- package/corpus/templates/clips/desktop/src/overlays/flow-bar.tsx +25 -0
- package/corpus/templates/clips/desktop/src/styles.css +20 -0
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +3 -4
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +11 -4
- package/corpus/templates/design/AGENTS.md +7 -3
- package/corpus/templates/design/actions/begin-node-rewrite-request.ts +78 -0
- package/corpus/templates/design/actions/cancel-node-rewrite-request.ts +17 -7
- package/corpus/templates/design/actions/propose-node-rewrite.ts +26 -18
- package/corpus/templates/design/actions/resolve-node-rewrite.ts +67 -19
- package/corpus/templates/design/app/components/visual-editor/NodeRewriteProposal.tsx +1 -4
- package/corpus/templates/design/app/components/visual-editor/ReviewCanvasPins.tsx +2 -6
- package/corpus/templates/design/shared/node-rewrite.ts +32 -0
- package/corpus/templates/forms/app/components/layout/Sidebar.tsx +6 -3
- package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +11 -18
- package/corpus/templates/forms/app/pages/FormsListPage.tsx +9 -5
- package/corpus/templates/slides/app/context/DeckContext.tsx +18 -0
- package/corpus/templates/slides/changelog/2026-07-21-decks-list-now-refreshes-when-you-switch-organizations.md +6 -0
- package/corpus/templates/tasks/app/components/custom-fields/FieldCreateBar.tsx +13 -19
- package/corpus/templates/tasks/app/components/custom-fields/FieldListRow.tsx +27 -22
- package/corpus/templates/tasks/app/components/custom-fields/FieldsList.tsx +26 -22
- package/corpus/templates/tasks/app/components/custom-fields/FieldsListSkeleton.tsx +4 -1
- package/corpus/templates/tasks/app/components/custom-fields/FieldsPage.tsx +4 -2
- package/corpus/templates/tasks/app/components/custom-fields/editor/FieldEditorSidebar.tsx +12 -3
- package/corpus/templates/tasks/app/components/custom-fields/editor/FieldTitleSection.tsx +6 -3
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/CurrencyConfigControl.tsx +5 -2
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/NumberConfigControl.tsx +5 -2
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/PercentConfigControl.tsx +4 -1
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/SelectConfigControl.tsx +17 -7
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/select-colors.ts +37 -9
- package/corpus/templates/tasks/app/components/custom-fields/field-types.ts +23 -0
- package/corpus/templates/tasks/app/components/inbox/InboxList.tsx +24 -16
- package/corpus/templates/tasks/app/components/inbox/InboxListPage.tsx +5 -3
- package/corpus/templates/tasks/app/components/inbox/InboxListRow.tsx +7 -5
- package/corpus/templates/tasks/app/components/layout/Header.tsx +10 -10
- package/corpus/templates/tasks/app/components/layout/Layout.tsx +11 -7
- package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +17 -10
- package/corpus/templates/tasks/app/components/shared/AddListItemInput.tsx +14 -8
- package/corpus/templates/tasks/app/components/shared/AlertDialog.tsx +6 -2
- package/corpus/templates/tasks/app/components/shared/BulkDeleteDialog.tsx +13 -6
- package/corpus/templates/tasks/app/components/shared/ChipSelect.tsx +12 -5
- package/corpus/templates/tasks/app/components/shared/DeleteItemDialog.tsx +6 -6
- package/corpus/templates/tasks/app/components/shared/ListViewHeader.tsx +3 -1
- package/corpus/templates/tasks/app/components/shared/SidePanel.tsx +5 -2
- package/corpus/templates/tasks/app/components/shared/list/ListRowDragHandle.tsx +3 -1
- package/corpus/templates/tasks/app/components/shared/selection/ListSelectionBar.tsx +46 -20
- package/corpus/templates/tasks/app/components/shared/selection/ListSelectionHeaderToggle.tsx +3 -1
- package/corpus/templates/tasks/app/components/shared/selection/ListSelectionToolbar.tsx +10 -6
- package/corpus/templates/tasks/app/components/tasks/TaskList.tsx +24 -13
- package/corpus/templates/tasks/app/components/tasks/TaskListHeaderRow.tsx +4 -1
- package/corpus/templates/tasks/app/components/tasks/TaskListPage.tsx +5 -3
- package/corpus/templates/tasks/app/components/tasks/TaskListRow.tsx +15 -6
- package/corpus/templates/tasks/app/components/tasks/fields/TaskFieldsSidebar.tsx +11 -6
- package/corpus/templates/tasks/app/components/tasks/fields/TaskTitleSection.tsx +8 -3
- package/corpus/templates/tasks/app/components/tasks/fields/controls/RichTextValueControl.tsx +12 -6
- package/corpus/templates/tasks/app/components/tasks/fields/controls/SingleSelectValueControl.tsx +6 -1
- package/corpus/templates/tasks/app/i18n/en-US.ts +209 -0
- package/corpus/templates/tasks/app/i18n/index.ts +34 -0
- package/corpus/templates/tasks/app/root.tsx +34 -2
- package/corpus/templates/tasks/app/routes/extensions.$id.tsx +2 -1
- package/corpus/templates/tasks/app/routes/extensions._index.tsx +2 -1
- package/corpus/templates/tasks/app/routes/fields.tsx +2 -1
- package/corpus/templates/tasks/app/routes/inbox.tsx +2 -1
- package/corpus/templates/tasks/app/routes/tasks.tsx +2 -1
- package/corpus/templates/tasks/app/routes/team.tsx +6 -3
- package/corpus/templates/tasks/changelog/2026-07-20-tasks-is-now-available-in-10-additional-languages.md +6 -0
- package/dist/application-state/index.d.ts +2 -2
- package/dist/application-state/index.d.ts.map +1 -1
- package/dist/application-state/index.js +2 -2
- package/dist/application-state/index.js.map +1 -1
- package/dist/application-state/script-helpers.d.ts +3 -1
- package/dist/application-state/script-helpers.d.ts.map +1 -1
- package/dist/application-state/script-helpers.js +7 -1
- package/dist/application-state/script-helpers.js.map +1 -1
- package/dist/application-state/store.d.ts +7 -1
- package/dist/application-state/store.d.ts.map +1 -1
- package/dist/application-state/store.js +143 -17
- package/dist/application-state/store.js.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.js +65 -1
- package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/db/client.d.ts +7 -0
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +39 -1
- package/dist/db/client.js.map +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/package.json +1 -1
- package/src/application-state/index.ts +3 -0
- package/src/application-state/script-helpers.ts +12 -1
- package/src/application-state/store.ts +216 -15
- package/src/client/extensions/EmbeddedExtension.tsx +89 -1
- package/src/db/client.ts +44 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
1
2
|
import { type ReactNode } from "react";
|
|
2
3
|
|
|
3
4
|
import {
|
|
@@ -20,19 +21,18 @@ export function DeleteItemDialog({
|
|
|
20
21
|
pending,
|
|
21
22
|
onConfirm,
|
|
22
23
|
}: DeleteItemDialogProps) {
|
|
24
|
+
const t = useT();
|
|
23
25
|
return (
|
|
24
26
|
<AlertDialog
|
|
25
27
|
open={open}
|
|
26
28
|
onOpenChange={onOpenChange}
|
|
27
29
|
pending={pending}
|
|
28
|
-
title={
|
|
30
|
+
title={t("dialogs.deleteEntityTitle", { entity: entityLabel })}
|
|
29
31
|
description={
|
|
30
32
|
description ??
|
|
31
|
-
(itemTitle
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
`This removes the ${entityLabel} permanently.`
|
|
35
|
-
))
|
|
33
|
+
(itemTitle
|
|
34
|
+
? t("dialogs.deleteItemDescriptionWithTitle", { title: itemTitle })
|
|
35
|
+
: t("dialogs.deleteItemDescription", { entity: entityLabel }))
|
|
36
36
|
}
|
|
37
37
|
onConfirm={onConfirm}
|
|
38
38
|
/>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AgentToggleButton } from "@agent-native/core/client/agent-chat";
|
|
2
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
2
3
|
|
|
3
4
|
import { PageHeader } from "@/components/shared/PageHeader";
|
|
4
5
|
import { ListSelectionHeaderToggle } from "@/components/shared/selection/ListSelectionHeaderToggle";
|
|
@@ -29,6 +30,7 @@ export function ListViewHeader<T extends { id: string }>({
|
|
|
29
30
|
onIncludeDoneChange,
|
|
30
31
|
showAgentToggle = false,
|
|
31
32
|
}: ListViewHeaderProps<T>) {
|
|
33
|
+
const t = useT();
|
|
32
34
|
const showIncludeDone =
|
|
33
35
|
includeDone !== undefined && onIncludeDoneChange !== undefined;
|
|
34
36
|
const hasActions =
|
|
@@ -62,7 +64,7 @@ export function ListViewHeader<T extends { id: string }>({
|
|
|
62
64
|
htmlFor="include-done"
|
|
63
65
|
className="text-sm whitespace-nowrap"
|
|
64
66
|
>
|
|
65
|
-
|
|
67
|
+
{t("common.showAll")}
|
|
66
68
|
</Label>
|
|
67
69
|
</div>
|
|
68
70
|
) : null}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
1
2
|
import { IconX } from "@tabler/icons-react";
|
|
2
3
|
import { useEffect, useState, type ReactNode } from "react";
|
|
3
4
|
|
|
@@ -32,7 +33,7 @@ export function SidePanel({
|
|
|
32
33
|
className,
|
|
33
34
|
title,
|
|
34
35
|
subtitle,
|
|
35
|
-
closeLabel
|
|
36
|
+
closeLabel,
|
|
36
37
|
onClose,
|
|
37
38
|
}: {
|
|
38
39
|
children: ReactNode;
|
|
@@ -42,6 +43,8 @@ export function SidePanel({
|
|
|
42
43
|
closeLabel?: string;
|
|
43
44
|
onClose?: () => void;
|
|
44
45
|
}) {
|
|
46
|
+
const t = useT();
|
|
47
|
+
const resolvedCloseLabel = closeLabel ?? t("common.closePanel");
|
|
45
48
|
const width = useAgentSidebarWidth();
|
|
46
49
|
|
|
47
50
|
useEffect(() => {
|
|
@@ -85,7 +88,7 @@ export function SidePanel({
|
|
|
85
88
|
variant="ghost"
|
|
86
89
|
size="icon"
|
|
87
90
|
onClick={onClose}
|
|
88
|
-
aria-label={
|
|
91
|
+
aria-label={resolvedCloseLabel}
|
|
89
92
|
className="size-8"
|
|
90
93
|
>
|
|
91
94
|
<IconX className="size-4" />
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
1
2
|
import { IconGripVertical } from "@tabler/icons-react";
|
|
2
3
|
|
|
3
4
|
import type {
|
|
@@ -19,6 +20,7 @@ export function ListRowDragHandle({
|
|
|
19
20
|
displayTitle,
|
|
20
21
|
disabled = false,
|
|
21
22
|
}: ListRowDragHandleProps) {
|
|
23
|
+
const t = useT();
|
|
22
24
|
const { dragHandleProps, isDragging } = rowDrag;
|
|
23
25
|
const { selectionMode } = rowSelection;
|
|
24
26
|
|
|
@@ -29,7 +31,7 @@ export function ListRowDragHandle({
|
|
|
29
31
|
type="button"
|
|
30
32
|
{...dragHandleProps}
|
|
31
33
|
disabled={disabled}
|
|
32
|
-
aria-label={
|
|
34
|
+
aria-label={t("common.reorderAriaLabel", { title: displayTitle })}
|
|
33
35
|
onClick={(event) => {
|
|
34
36
|
if (selectionMode) {
|
|
35
37
|
event.stopPropagation();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
1
2
|
import { IconCircleCheck, IconCircle } from "@tabler/icons-react";
|
|
2
3
|
import { toast } from "sonner";
|
|
3
4
|
|
|
@@ -26,6 +27,7 @@ export function ListSelectionBar<
|
|
|
26
27
|
toolbarBusy,
|
|
27
28
|
onOpenBulkDelete,
|
|
28
29
|
}: ListSelectionBarProps<T>) {
|
|
30
|
+
const t = useT();
|
|
29
31
|
const bulkUpdateTasks = useBulkUpdateTasks();
|
|
30
32
|
const bulkMarkInboxItemsReady = useBulkMarkInboxItemsReady();
|
|
31
33
|
|
|
@@ -35,8 +37,6 @@ export function ListSelectionBar<
|
|
|
35
37
|
const allVisibleSelected =
|
|
36
38
|
items.length > 0 && items.every((item) => selectedIdSet.has(item.id));
|
|
37
39
|
|
|
38
|
-
const entityLabel = promotedToTask ? "task" : "item";
|
|
39
|
-
|
|
40
40
|
async function markSelectedReady() {
|
|
41
41
|
if (selectedCount === 0) return;
|
|
42
42
|
|
|
@@ -45,11 +45,13 @@ export function ListSelectionBar<
|
|
|
45
45
|
inboxItemIds: selectedItems.map((item) => item.id),
|
|
46
46
|
});
|
|
47
47
|
toast.success(
|
|
48
|
-
|
|
48
|
+
selectedCount === 1
|
|
49
|
+
? t("selection.markedReadyOne", { count: selectedCount })
|
|
50
|
+
: t("selection.markedReadyOther", { count: selectedCount }),
|
|
49
51
|
);
|
|
50
52
|
selection.actions.clearSelection();
|
|
51
53
|
} catch {
|
|
52
|
-
toast.error("
|
|
54
|
+
toast.error(t("selection.couldNotMarkReady"));
|
|
53
55
|
}
|
|
54
56
|
}
|
|
55
57
|
|
|
@@ -59,8 +61,8 @@ export function ListSelectionBar<
|
|
|
59
61
|
if (applicableTasks.length === 0) {
|
|
60
62
|
toast.info(
|
|
61
63
|
done
|
|
62
|
-
? "
|
|
63
|
-
: "
|
|
64
|
+
? t("selection.allTasksAlreadyComplete")
|
|
65
|
+
: t("selection.allTasksAlreadyIncomplete"),
|
|
64
66
|
);
|
|
65
67
|
return;
|
|
66
68
|
}
|
|
@@ -70,19 +72,33 @@ export function ListSelectionBar<
|
|
|
70
72
|
try {
|
|
71
73
|
await bulkUpdateTasks.mutateAsync({ taskIds, done });
|
|
72
74
|
|
|
73
|
-
const
|
|
75
|
+
const unit =
|
|
76
|
+
applicableTasks.length === 1
|
|
77
|
+
? t("tasks.entitySingular")
|
|
78
|
+
: t("tasks.entityPlural");
|
|
74
79
|
toast.success(
|
|
75
80
|
done
|
|
76
81
|
? skippedCount > 0
|
|
77
|
-
?
|
|
78
|
-
|
|
82
|
+
? t("selection.markedDoneWithSkipped", {
|
|
83
|
+
count: applicableTasks.length,
|
|
84
|
+
unit,
|
|
85
|
+
skipped: skippedCount,
|
|
86
|
+
})
|
|
87
|
+
: t("selection.markedDone", { count: applicableTasks.length, unit })
|
|
79
88
|
: skippedCount > 0
|
|
80
|
-
?
|
|
81
|
-
|
|
89
|
+
? t("selection.markedNotDoneWithSkipped", {
|
|
90
|
+
count: applicableTasks.length,
|
|
91
|
+
unit,
|
|
92
|
+
skipped: skippedCount,
|
|
93
|
+
})
|
|
94
|
+
: t("selection.markedNotDone", {
|
|
95
|
+
count: applicableTasks.length,
|
|
96
|
+
unit,
|
|
97
|
+
}),
|
|
82
98
|
);
|
|
83
99
|
selection.actions.clearSelection();
|
|
84
100
|
} catch {
|
|
85
|
-
toast.error("
|
|
101
|
+
toast.error(t("selection.couldNotUpdateTasks"));
|
|
86
102
|
}
|
|
87
103
|
}
|
|
88
104
|
|
|
@@ -101,9 +117,15 @@ export function ListSelectionBar<
|
|
|
101
117
|
return (
|
|
102
118
|
<ListSelectionToolbar
|
|
103
119
|
ariaLabel={
|
|
104
|
-
promotedToTask
|
|
120
|
+
promotedToTask
|
|
121
|
+
? t("selection.taskSelectionActionsAriaLabel")
|
|
122
|
+
: t("selection.inboxSelectionActionsAriaLabel")
|
|
123
|
+
}
|
|
124
|
+
emptySelectionHint={
|
|
125
|
+
promotedToTask
|
|
126
|
+
? t("selection.tapToSelectTasks")
|
|
127
|
+
: t("selection.tapToSelectItems")
|
|
105
128
|
}
|
|
106
|
-
emptySelectionHint={`Tap ${entityLabel}s to select them.`}
|
|
107
129
|
visibleCount={items.length}
|
|
108
130
|
selectedCount={selectedCount}
|
|
109
131
|
allVisibleSelected={allVisibleSelected}
|
|
@@ -120,11 +142,13 @@ export function ListSelectionBar<
|
|
|
120
142
|
disabled={
|
|
121
143
|
selectedCount === 0 || toolbarDisabled || allSelectedComplete
|
|
122
144
|
}
|
|
123
|
-
aria-label="
|
|
145
|
+
aria-label={t("selection.markComplete")}
|
|
124
146
|
onClick={() => void markSelectedDone(true)}
|
|
125
147
|
>
|
|
126
148
|
<IconCircleCheck className="h-3.5 w-3.5" />
|
|
127
|
-
<span className="hidden sm:inline">
|
|
149
|
+
<span className="hidden sm:inline">
|
|
150
|
+
{t("selection.completeLabel")}
|
|
151
|
+
</span>
|
|
128
152
|
</Button>
|
|
129
153
|
<Button
|
|
130
154
|
variant="ghost"
|
|
@@ -133,11 +157,13 @@ export function ListSelectionBar<
|
|
|
133
157
|
disabled={
|
|
134
158
|
selectedCount === 0 || toolbarDisabled || allSelectedIncomplete
|
|
135
159
|
}
|
|
136
|
-
aria-label="
|
|
160
|
+
aria-label={t("selection.markIncomplete")}
|
|
137
161
|
onClick={() => void markSelectedDone(false)}
|
|
138
162
|
>
|
|
139
163
|
<IconCircle className="h-3.5 w-3.5" />
|
|
140
|
-
<span className="hidden sm:inline">
|
|
164
|
+
<span className="hidden sm:inline">
|
|
165
|
+
{t("selection.incompleteLabel")}
|
|
166
|
+
</span>
|
|
141
167
|
</Button>
|
|
142
168
|
</>
|
|
143
169
|
) : (
|
|
@@ -146,11 +172,11 @@ export function ListSelectionBar<
|
|
|
146
172
|
size="sm"
|
|
147
173
|
className="h-8 shrink-0 gap-1 px-2 text-xs"
|
|
148
174
|
disabled={selectedCount === 0 || toolbarDisabled}
|
|
149
|
-
aria-label="
|
|
175
|
+
aria-label={t("common.markReady")}
|
|
150
176
|
onClick={() => void markSelectedReady()}
|
|
151
177
|
>
|
|
152
178
|
<IconCircleCheck className="h-3.5 w-3.5" />
|
|
153
|
-
<span className="hidden sm:inline">
|
|
179
|
+
<span className="hidden sm:inline">{t("common.markReady")}</span>
|
|
154
180
|
</Button>
|
|
155
181
|
)}
|
|
156
182
|
</ListSelectionToolbar>
|
package/corpus/templates/tasks/app/components/shared/selection/ListSelectionHeaderToggle.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
1
2
|
import { IconChecks } from "@tabler/icons-react";
|
|
2
3
|
|
|
3
4
|
import { Button } from "@/components/ui/button";
|
|
@@ -13,6 +14,7 @@ export function ListSelectionHeaderToggle({
|
|
|
13
14
|
disabled,
|
|
14
15
|
onSelectionModeChange,
|
|
15
16
|
}: ListSelectionHeaderToggleProps) {
|
|
17
|
+
const t = useT();
|
|
16
18
|
return (
|
|
17
19
|
<Button
|
|
18
20
|
variant={selectionMode ? "secondary" : "ghost"}
|
|
@@ -22,7 +24,7 @@ export function ListSelectionHeaderToggle({
|
|
|
22
24
|
onClick={() => onSelectionModeChange(!selectionMode)}
|
|
23
25
|
>
|
|
24
26
|
<IconChecks className="h-3.5 w-3.5" />
|
|
25
|
-
{selectionMode ? "
|
|
27
|
+
{selectionMode ? t("selection.doneSelecting") : t("selection.select")}
|
|
26
28
|
</Button>
|
|
27
29
|
);
|
|
28
30
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
1
2
|
import { IconTrash, IconX } from "@tabler/icons-react";
|
|
2
3
|
import { type ReactNode } from "react";
|
|
3
4
|
|
|
@@ -27,12 +28,13 @@ export function ListSelectionToolbar({
|
|
|
27
28
|
onOpenBulkDelete,
|
|
28
29
|
children,
|
|
29
30
|
}: ListSelectionToolbarProps) {
|
|
31
|
+
const t = useT();
|
|
30
32
|
const statusText =
|
|
31
33
|
selectedCount === 0
|
|
32
34
|
? emptySelectionHint
|
|
33
35
|
: selectedCount > 1
|
|
34
|
-
?
|
|
35
|
-
:
|
|
36
|
+
? t("selection.selectedCountReorder", { count: selectedCount })
|
|
37
|
+
: t("selection.selectedCount", { count: selectedCount });
|
|
36
38
|
|
|
37
39
|
return (
|
|
38
40
|
<div
|
|
@@ -51,7 +53,9 @@ export function ListSelectionToolbar({
|
|
|
51
53
|
disabled={toolbarDisabled || visibleCount === 0}
|
|
52
54
|
onClick={selectionActions.selectAll}
|
|
53
55
|
>
|
|
54
|
-
{allVisibleSelected
|
|
56
|
+
{allVisibleSelected
|
|
57
|
+
? t("selection.clearAll")
|
|
58
|
+
: t("selection.selectAll")}
|
|
55
59
|
</Button>
|
|
56
60
|
{children}
|
|
57
61
|
<Button
|
|
@@ -59,11 +63,11 @@ export function ListSelectionToolbar({
|
|
|
59
63
|
size="sm"
|
|
60
64
|
className="h-8 shrink-0 gap-1 px-2 text-xs text-destructive hover:text-destructive"
|
|
61
65
|
disabled={selectedCount === 0 || toolbarDisabled}
|
|
62
|
-
aria-label="
|
|
66
|
+
aria-label={t("common.delete")}
|
|
63
67
|
onClick={onOpenBulkDelete}
|
|
64
68
|
>
|
|
65
69
|
<IconTrash className="h-3.5 w-3.5" />
|
|
66
|
-
<span className="hidden sm:inline">
|
|
70
|
+
<span className="hidden sm:inline">{t("common.delete")}</span>
|
|
67
71
|
</Button>
|
|
68
72
|
<Button
|
|
69
73
|
variant="ghost"
|
|
@@ -71,7 +75,7 @@ export function ListSelectionToolbar({
|
|
|
71
75
|
className="h-8 w-8 shrink-0"
|
|
72
76
|
disabled={toolbarDisabled}
|
|
73
77
|
onClick={selectionActions.clearSelection}
|
|
74
|
-
aria-label="
|
|
78
|
+
aria-label={t("selection.exitSelectionMode")}
|
|
75
79
|
>
|
|
76
80
|
<IconX className="h-3.5 w-3.5" />
|
|
77
81
|
</Button>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { focusAgentChat } from "@agent-native/core/client/agent-chat";
|
|
2
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
2
3
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
3
4
|
import { toast } from "sonner";
|
|
4
5
|
|
|
@@ -41,19 +42,20 @@ function NoTasksMessage({
|
|
|
41
42
|
}: {
|
|
42
43
|
hasHiddenCompletedTasks: boolean;
|
|
43
44
|
}) {
|
|
45
|
+
const t = useT();
|
|
44
46
|
if (hasHiddenCompletedTasks) {
|
|
45
47
|
return (
|
|
46
48
|
<ListEmptyState
|
|
47
|
-
heading="
|
|
48
|
-
description="
|
|
49
|
+
heading={t("tasks.allCompleteHeading")}
|
|
50
|
+
description={t("tasks.allCompleteDescription")}
|
|
49
51
|
/>
|
|
50
52
|
);
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
return (
|
|
54
56
|
<ListEmptyState
|
|
55
|
-
heading="
|
|
56
|
-
description="
|
|
57
|
+
heading={t("tasks.emptyHeading")}
|
|
58
|
+
description={t("tasks.emptyDescription")}
|
|
57
59
|
/>
|
|
58
60
|
);
|
|
59
61
|
}
|
|
@@ -67,6 +69,7 @@ export function TaskList({
|
|
|
67
69
|
activeTaskId,
|
|
68
70
|
setActiveTaskId,
|
|
69
71
|
}: TaskListProps) {
|
|
72
|
+
const t = useT();
|
|
70
73
|
const createTask = useCreateTask();
|
|
71
74
|
const updateTask = useUpdateTask();
|
|
72
75
|
const deleteTask = useDeleteTask();
|
|
@@ -162,12 +165,18 @@ export function TaskList({
|
|
|
162
165
|
try {
|
|
163
166
|
await handleBulkDelete(ids);
|
|
164
167
|
toast.success(
|
|
165
|
-
|
|
168
|
+
t("dialogs.deletedCount", {
|
|
169
|
+
count: ids.length,
|
|
170
|
+
entity:
|
|
171
|
+
ids.length === 1
|
|
172
|
+
? t("tasks.entitySingular")
|
|
173
|
+
: t("tasks.entityPlural"),
|
|
174
|
+
}),
|
|
166
175
|
);
|
|
167
176
|
selection.actions.clearSelection();
|
|
168
177
|
setBulkDeleteOpen(false);
|
|
169
178
|
} catch {
|
|
170
|
-
toast.error("
|
|
179
|
+
toast.error(t("tasks.bulkDeleteError"));
|
|
171
180
|
}
|
|
172
181
|
}
|
|
173
182
|
|
|
@@ -176,8 +185,8 @@ export function TaskList({
|
|
|
176
185
|
<div className="flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden">
|
|
177
186
|
<div className="flex min-h-0 flex-col gap-6 overflow-hidden">
|
|
178
187
|
<ListViewHeader
|
|
179
|
-
title="
|
|
180
|
-
description="
|
|
188
|
+
title={t("tasks.pageTitle")}
|
|
189
|
+
description={t("tasks.pageDescription")}
|
|
181
190
|
isPending={isPending}
|
|
182
191
|
showSelectToggle={hasTasks}
|
|
183
192
|
selection={selection}
|
|
@@ -215,7 +224,9 @@ export function TaskList({
|
|
|
215
224
|
|
|
216
225
|
<div
|
|
217
226
|
aria-label={
|
|
218
|
-
isPending || tasks.length === 0
|
|
227
|
+
isPending || tasks.length === 0
|
|
228
|
+
? t("tasks.listAriaLabel")
|
|
229
|
+
: undefined
|
|
219
230
|
}
|
|
220
231
|
className="min-h-0 flex-1 overflow-y-auto overscroll-contain pr-1 outline-none"
|
|
221
232
|
>
|
|
@@ -229,7 +240,7 @@ export function TaskList({
|
|
|
229
240
|
<List
|
|
230
241
|
items={orderedTasks}
|
|
231
242
|
selection={selection}
|
|
232
|
-
ariaLabel="
|
|
243
|
+
ariaLabel={t("tasks.listAriaLabel")}
|
|
233
244
|
onReorder={handleReorder}
|
|
234
245
|
renderItem={({ item, sortable }) => (
|
|
235
246
|
<TaskListRow
|
|
@@ -300,7 +311,7 @@ export function TaskList({
|
|
|
300
311
|
onOpenChange={(open) => {
|
|
301
312
|
if (!open) setPendingDeleteId(null);
|
|
302
313
|
}}
|
|
303
|
-
entityLabel="
|
|
314
|
+
entityLabel={t("tasks.entitySingular")}
|
|
304
315
|
itemTitle={pendingDeleteTask?.title ?? null}
|
|
305
316
|
pending={deleteTask.isPending}
|
|
306
317
|
onConfirm={async () => {
|
|
@@ -315,8 +326,8 @@ export function TaskList({
|
|
|
315
326
|
open={bulkDeleteOpen}
|
|
316
327
|
onOpenChange={setBulkDeleteOpen}
|
|
317
328
|
selectedItems={selection.state.selectedItems}
|
|
318
|
-
entitySingular="
|
|
319
|
-
entityPlural="tasks"
|
|
329
|
+
entitySingular={t("tasks.entitySingular")}
|
|
330
|
+
entityPlural={t("tasks.entityPlural")}
|
|
320
331
|
pending={bulkDeleteTasks.isPending}
|
|
321
332
|
onConfirm={() => void confirmBulkDelete()}
|
|
322
333
|
/>
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
2
|
+
|
|
1
3
|
import type { TaskFieldValue } from "@/hooks/use-custom-fields";
|
|
2
4
|
import type { TaskWithFields } from "@/hooks/use-tasks";
|
|
3
5
|
import {
|
|
@@ -34,11 +36,12 @@ export function TaskListHeaderRow({
|
|
|
34
36
|
}: {
|
|
35
37
|
task: TaskWithFields | undefined;
|
|
36
38
|
}) {
|
|
39
|
+
const t = useT();
|
|
37
40
|
return (
|
|
38
41
|
<div className="hidden items-center gap-3 px-3 mb-2 text-xs font-medium text-muted-foreground md:flex">
|
|
39
42
|
<div className="size-8 shrink-0" />
|
|
40
43
|
<div className="size-4 shrink-0" />
|
|
41
|
-
<div className="min-w-0 flex-1 px-3">
|
|
44
|
+
<div className="min-w-0 flex-1 px-3">{t("tasks.taskColumnHeader")}</div>
|
|
42
45
|
<TaskListFieldStripHeader fields={task?.fields} />
|
|
43
46
|
<div className="size-8 shrink-0" />
|
|
44
47
|
</div>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
1
2
|
import {
|
|
2
3
|
INCLUDE_DONE_QUERY_VALUE,
|
|
3
4
|
parseIncludeDoneParam,
|
|
@@ -11,6 +12,7 @@ import { TaskList } from "@/components/tasks/TaskList";
|
|
|
11
12
|
import { useTasks } from "@/hooks/use-tasks";
|
|
12
13
|
|
|
13
14
|
export function TaskListPage() {
|
|
15
|
+
const t = useT();
|
|
14
16
|
const [searchParams, setSearchParams] = useSearchParams();
|
|
15
17
|
const includeDone = parseIncludeDoneParam(searchParams.get("includeDone"));
|
|
16
18
|
const activeTaskId = searchParams.get("task");
|
|
@@ -84,8 +86,8 @@ export function TaskListPage() {
|
|
|
84
86
|
{isError ? (
|
|
85
87
|
<>
|
|
86
88
|
<ListViewHeader
|
|
87
|
-
title="
|
|
88
|
-
description="
|
|
89
|
+
title={t("tasks.pageTitle")}
|
|
90
|
+
description={t("tasks.pageDescription")}
|
|
89
91
|
isPending={false}
|
|
90
92
|
showSelectToggle={false}
|
|
91
93
|
selection={null}
|
|
@@ -96,7 +98,7 @@ export function TaskListPage() {
|
|
|
96
98
|
/>
|
|
97
99
|
<ListErrorMessage
|
|
98
100
|
error={error}
|
|
99
|
-
fallbackMessage="
|
|
101
|
+
fallbackMessage={t("tasks.loadError")}
|
|
100
102
|
/>
|
|
101
103
|
</>
|
|
102
104
|
) : (
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
1
2
|
import { IconChecks, IconTrash } from "@tabler/icons-react";
|
|
2
3
|
import { useState } from "react";
|
|
3
4
|
|
|
@@ -55,6 +56,7 @@ export function TaskListRow({
|
|
|
55
56
|
onBeginExit,
|
|
56
57
|
onExitAfterComplete,
|
|
57
58
|
}: TaskListRowProps) {
|
|
59
|
+
const t = useT();
|
|
58
60
|
const selected = selection.state.selectedItems.some(
|
|
59
61
|
(entry) => entry.id === item.id,
|
|
60
62
|
);
|
|
@@ -122,7 +124,11 @@ export function TaskListRow({
|
|
|
122
124
|
onClick={
|
|
123
125
|
rowSelection.selectionMode ? rowSelection.selectRow : undefined
|
|
124
126
|
}
|
|
125
|
-
aria-label={
|
|
127
|
+
aria-label={
|
|
128
|
+
displayDone
|
|
129
|
+
? t("tasks.markIncompleteAriaLabel", { title: displayTitle })
|
|
130
|
+
: t("tasks.markCompleteAriaLabel", { title: displayTitle })
|
|
131
|
+
}
|
|
126
132
|
/>
|
|
127
133
|
|
|
128
134
|
<div className="min-w-0 flex-1">
|
|
@@ -133,7 +139,7 @@ export function TaskListRow({
|
|
|
133
139
|
value={item.title}
|
|
134
140
|
onSave={onUpdateTitle}
|
|
135
141
|
onDisplayTitleChange={setDisplayTitle}
|
|
136
|
-
ariaLabel="
|
|
142
|
+
ariaLabel={t("common.editTitleAriaLabel")}
|
|
137
143
|
disabled={busy}
|
|
138
144
|
titleDragProps={rowDrag.titleDragProps}
|
|
139
145
|
displayDone={displayDone}
|
|
@@ -149,7 +155,9 @@ export function TaskListRow({
|
|
|
149
155
|
</div>
|
|
150
156
|
|
|
151
157
|
<RowActionsMenu
|
|
152
|
-
ariaLabel={
|
|
158
|
+
ariaLabel={t("common.rowActionsAriaLabel", {
|
|
159
|
+
title: displayTitle,
|
|
160
|
+
})}
|
|
153
161
|
disabled={busy || rowSelection.selectionMode}
|
|
154
162
|
>
|
|
155
163
|
<DropdownMenuItem
|
|
@@ -157,14 +165,14 @@ export function TaskListRow({
|
|
|
157
165
|
onSelect={() => selection.actions.startSelection(item.id)}
|
|
158
166
|
>
|
|
159
167
|
<IconChecks className="size-4" />
|
|
160
|
-
|
|
168
|
+
{t("selection.select")}
|
|
161
169
|
</DropdownMenuItem>
|
|
162
170
|
<DropdownMenuItem
|
|
163
171
|
className="gap-2 text-destructive focus:bg-destructive focus:text-destructive-foreground"
|
|
164
172
|
onSelect={onRequestDelete}
|
|
165
173
|
>
|
|
166
174
|
<IconTrash className="size-4" />
|
|
167
|
-
|
|
175
|
+
{t("common.delete")}
|
|
168
176
|
</DropdownMenuItem>
|
|
169
177
|
</RowActionsMenu>
|
|
170
178
|
</>
|
|
@@ -203,6 +211,7 @@ function TaskListRowFieldBadges({ fields }: { fields?: TaskFieldValue[] }) {
|
|
|
203
211
|
}
|
|
204
212
|
|
|
205
213
|
function TaskListRowFieldStrip({ fields }: { fields?: TaskFieldValue[] }) {
|
|
214
|
+
const t = useT();
|
|
206
215
|
const { fieldIds } = useVisibleTaskFieldIds();
|
|
207
216
|
const items = taskCardDisplayFields(fieldIds, fields);
|
|
208
217
|
const columnCount = Math.min(fieldIds.length, TASK_CARD_FIELD_LIMIT);
|
|
@@ -213,7 +222,7 @@ function TaskListRowFieldStrip({ fields }: { fields?: TaskFieldValue[] }) {
|
|
|
213
222
|
style={{
|
|
214
223
|
gridTemplateColumns: `repeat(${columnCount}, minmax(6.5rem, 8rem))`,
|
|
215
224
|
}}
|
|
216
|
-
aria-label="
|
|
225
|
+
aria-label={t("tasks.visibleTaskFieldsAriaLabel")}
|
|
217
226
|
>
|
|
218
227
|
{items.map((item) => (
|
|
219
228
|
<div
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
1
2
|
import { useCallback } from "react";
|
|
2
3
|
import { toast } from "sonner";
|
|
3
4
|
|
|
@@ -16,13 +17,14 @@ export function TaskFieldsSidebar({
|
|
|
16
17
|
task: TaskWithFields | null;
|
|
17
18
|
onClose: () => void;
|
|
18
19
|
}) {
|
|
20
|
+
const t = useT();
|
|
19
21
|
if (!task) return null;
|
|
20
22
|
|
|
21
23
|
return (
|
|
22
24
|
<SidePanel
|
|
23
|
-
title="
|
|
24
|
-
subtitle="
|
|
25
|
-
closeLabel="
|
|
25
|
+
title={t("taskFields.panelTitle")}
|
|
26
|
+
subtitle={t("taskFields.panelSubtitle")}
|
|
27
|
+
closeLabel={t("taskFields.closeLabel")}
|
|
26
28
|
onClose={onClose}
|
|
27
29
|
>
|
|
28
30
|
<TaskFieldsSidebarPanel task={task} />
|
|
@@ -31,6 +33,7 @@ export function TaskFieldsSidebar({
|
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
function TaskFieldsSidebarPanel({ task }: { task: TaskWithFields }) {
|
|
36
|
+
const t = useT();
|
|
34
37
|
const fields = task.fields ?? [];
|
|
35
38
|
const updateTask = useUpdateTask();
|
|
36
39
|
|
|
@@ -42,10 +45,12 @@ function TaskFieldsSidebarPanel({ task }: { task: TaskWithFields }) {
|
|
|
42
45
|
void updateTask
|
|
43
46
|
.mutateAsync({ taskId: task.id, ...payload })
|
|
44
47
|
.catch((caught) => {
|
|
45
|
-
toast.error(
|
|
48
|
+
toast.error(
|
|
49
|
+
(caught as Error)?.message ?? t("taskFields.updateError"),
|
|
50
|
+
);
|
|
46
51
|
});
|
|
47
52
|
},
|
|
48
|
-
[task.id, updateTask],
|
|
53
|
+
[task.id, updateTask, t],
|
|
49
54
|
);
|
|
50
55
|
|
|
51
56
|
return (
|
|
@@ -57,7 +62,7 @@ function TaskFieldsSidebarPanel({ task }: { task: TaskWithFields }) {
|
|
|
57
62
|
|
|
58
63
|
{fields.length === 0 ? (
|
|
59
64
|
<div className="m-3 rounded-lg border border-dashed border-border p-6 text-center text-[13px] text-muted-foreground">
|
|
60
|
-
|
|
65
|
+
{t("taskFields.noFieldsDefined")}
|
|
61
66
|
</div>
|
|
62
67
|
) : (
|
|
63
68
|
fields.map((field) => (
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
2
|
+
|
|
1
3
|
import { Input } from "@/components/ui/input";
|
|
2
4
|
import { Label } from "@/components/ui/label";
|
|
3
5
|
|
|
@@ -8,18 +10,21 @@ export function TaskTitleSection({
|
|
|
8
10
|
title: string;
|
|
9
11
|
onChange: (title: string) => void;
|
|
10
12
|
}) {
|
|
13
|
+
const t = useT();
|
|
11
14
|
return (
|
|
12
15
|
<section className="grid gap-2 border-b border-border/70 px-3 py-3">
|
|
13
16
|
<div className="flex min-w-0 items-center justify-between gap-2">
|
|
14
17
|
<Label className="min-w-0 truncate text-[13px] font-medium">
|
|
15
|
-
|
|
18
|
+
{t("taskFields.titleLabel")}
|
|
16
19
|
</Label>
|
|
17
|
-
<span className="shrink-0 text-[11px] text-muted-foreground">
|
|
20
|
+
<span className="shrink-0 text-[11px] text-muted-foreground">
|
|
21
|
+
{t("taskFields.taskBadge")}
|
|
22
|
+
</span>
|
|
18
23
|
</div>
|
|
19
24
|
<Input
|
|
20
25
|
value={title}
|
|
21
26
|
onChange={(event) => onChange(event.currentTarget.value)}
|
|
22
|
-
aria-label="
|
|
27
|
+
aria-label={t("taskFields.editTaskTitleAriaLabel")}
|
|
23
28
|
className="h-9 text-[13px]"
|
|
24
29
|
/>
|
|
25
30
|
</section>
|