@agent-native/core 0.114.12 → 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 +6 -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/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/collab/routes.d.ts +1 -1
- package/dist/collab/struct-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/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/db/client.ts +44 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
1
2
|
import { useEffect, useState } from "react";
|
|
2
3
|
import { toast } from "sonner";
|
|
3
4
|
|
|
@@ -34,6 +35,7 @@ export function InboxList({
|
|
|
34
35
|
isPending,
|
|
35
36
|
selectedInboxItemId,
|
|
36
37
|
}: InboxListProps) {
|
|
38
|
+
const t = useT();
|
|
37
39
|
const createInboxItem = useCreateInboxItem();
|
|
38
40
|
const updateInboxItem = useUpdateInboxItem();
|
|
39
41
|
const deleteInboxItem = useDeleteInboxItem();
|
|
@@ -78,20 +80,26 @@ export function InboxList({
|
|
|
78
80
|
try {
|
|
79
81
|
await handleBulkDelete(ids);
|
|
80
82
|
toast.success(
|
|
81
|
-
|
|
83
|
+
t("dialogs.deletedCount", {
|
|
84
|
+
count: ids.length,
|
|
85
|
+
entity:
|
|
86
|
+
ids.length === 1
|
|
87
|
+
? t("inbox.entitySingular")
|
|
88
|
+
: t("inbox.entityPlural"),
|
|
89
|
+
}),
|
|
82
90
|
);
|
|
83
91
|
selection.actions.clearSelection();
|
|
84
92
|
setBulkDeleteOpen(false);
|
|
85
93
|
} catch {
|
|
86
|
-
toast.error("
|
|
94
|
+
toast.error(t("inbox.bulkDeleteError"));
|
|
87
95
|
}
|
|
88
96
|
}
|
|
89
97
|
|
|
90
98
|
return (
|
|
91
99
|
<>
|
|
92
100
|
<ListViewHeader
|
|
93
|
-
title="
|
|
94
|
-
description="
|
|
101
|
+
title={t("inbox.pageTitle")}
|
|
102
|
+
description={t("inbox.pageDescription")}
|
|
95
103
|
isPending={isPending}
|
|
96
104
|
showSelectToggle={items.length > 0}
|
|
97
105
|
selection={selection}
|
|
@@ -112,29 +120,29 @@ export function InboxList({
|
|
|
112
120
|
<AddListItemInput
|
|
113
121
|
disabled={createInboxItem.isPending}
|
|
114
122
|
onCreate={(title) => createInboxItem.mutateAsync({ title })}
|
|
115
|
-
placeholder="
|
|
116
|
-
buttonLabel="
|
|
117
|
-
inputAriaLabel="
|
|
118
|
-
errorMessage="
|
|
123
|
+
placeholder={t("inbox.addPlaceholder")}
|
|
124
|
+
buttonLabel={t("inbox.addButtonLabel")}
|
|
125
|
+
inputAriaLabel={t("inbox.addInputAriaLabel")}
|
|
126
|
+
errorMessage={t("inbox.addErrorMessage")}
|
|
119
127
|
/>
|
|
120
128
|
)}
|
|
121
129
|
</div>
|
|
122
130
|
|
|
123
131
|
{isPending ? (
|
|
124
132
|
<div
|
|
125
|
-
aria-label="
|
|
133
|
+
aria-label={t("inbox.listAriaLabel")}
|
|
126
134
|
className="min-h-0 flex-1 overflow-y-auto overscroll-contain pr-1 outline-none"
|
|
127
135
|
>
|
|
128
136
|
<ListSkeletonRows />
|
|
129
137
|
</div>
|
|
130
138
|
) : items.length === 0 ? (
|
|
131
139
|
<div
|
|
132
|
-
aria-label="
|
|
140
|
+
aria-label={t("inbox.listAriaLabel")}
|
|
133
141
|
className="min-h-0 flex-1 overflow-y-auto overscroll-contain pr-1 outline-none"
|
|
134
142
|
>
|
|
135
143
|
<ListEmptyState
|
|
136
|
-
heading="
|
|
137
|
-
description="
|
|
144
|
+
heading={t("inbox.emptyHeading")}
|
|
145
|
+
description={t("inbox.emptyDescription")}
|
|
138
146
|
/>
|
|
139
147
|
</div>
|
|
140
148
|
) : (
|
|
@@ -142,7 +150,7 @@ export function InboxList({
|
|
|
142
150
|
<List
|
|
143
151
|
items={items}
|
|
144
152
|
selection={selection}
|
|
145
|
-
ariaLabel="
|
|
153
|
+
ariaLabel={t("inbox.listAriaLabel")}
|
|
146
154
|
listClassName="flex flex-col gap-3 pb-6"
|
|
147
155
|
onReorder={handleReorder}
|
|
148
156
|
renderItem={({ item, sortable }) => (
|
|
@@ -194,7 +202,7 @@ export function InboxList({
|
|
|
194
202
|
onOpenChange={(open) => {
|
|
195
203
|
if (!open) setPendingDeleteId(null);
|
|
196
204
|
}}
|
|
197
|
-
entityLabel="inbox
|
|
205
|
+
entityLabel={t("inbox.entitySingular")}
|
|
198
206
|
itemTitle={pendingDeleteItem?.title ?? null}
|
|
199
207
|
pending={deleteInboxItem.isPending}
|
|
200
208
|
onConfirm={async () => {
|
|
@@ -211,8 +219,8 @@ export function InboxList({
|
|
|
211
219
|
open={bulkDeleteOpen}
|
|
212
220
|
onOpenChange={setBulkDeleteOpen}
|
|
213
221
|
selectedItems={selection.state.selectedItems}
|
|
214
|
-
entitySingular="inbox
|
|
215
|
-
entityPlural="inbox
|
|
222
|
+
entitySingular={t("inbox.entitySingular")}
|
|
223
|
+
entityPlural={t("inbox.entityPlural")}
|
|
216
224
|
pending={bulkDeleteInboxItems.isPending}
|
|
217
225
|
onConfirm={() => void confirmBulkDelete()}
|
|
218
226
|
/>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
1
2
|
import { useSearchParams } from "react-router";
|
|
2
3
|
|
|
3
4
|
import { InboxList } from "@/components/inbox/InboxList";
|
|
@@ -6,6 +7,7 @@ import { ListViewHeader } from "@/components/shared/ListViewHeader";
|
|
|
6
7
|
import { useInboxItems } from "@/hooks/use-inbox-items";
|
|
7
8
|
|
|
8
9
|
export function InboxListPage() {
|
|
10
|
+
const t = useT();
|
|
9
11
|
const [searchParams] = useSearchParams();
|
|
10
12
|
const selectedInboxItemId = searchParams.get("inboxItem");
|
|
11
13
|
const { items: serverItems, isPending, isError, error } = useInboxItems();
|
|
@@ -15,8 +17,8 @@ export function InboxListPage() {
|
|
|
15
17
|
{isError ? (
|
|
16
18
|
<>
|
|
17
19
|
<ListViewHeader
|
|
18
|
-
title="
|
|
19
|
-
description="
|
|
20
|
+
title={t("inbox.pageTitle")}
|
|
21
|
+
description={t("inbox.pageDescription")}
|
|
20
22
|
isPending={false}
|
|
21
23
|
showSelectToggle={false}
|
|
22
24
|
selection={null}
|
|
@@ -24,7 +26,7 @@ export function InboxListPage() {
|
|
|
24
26
|
/>
|
|
25
27
|
<ListErrorMessage
|
|
26
28
|
error={error}
|
|
27
|
-
fallbackMessage="
|
|
29
|
+
fallbackMessage={t("inbox.loadError")}
|
|
28
30
|
/>
|
|
29
31
|
</>
|
|
30
32
|
) : (
|
|
@@ -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
|
|
|
@@ -33,6 +34,7 @@ export function InboxListRow({
|
|
|
33
34
|
onRequestDelete,
|
|
34
35
|
onMarkReady,
|
|
35
36
|
}: InboxListRowProps) {
|
|
37
|
+
const t = useT();
|
|
36
38
|
const [displayTitle, setDisplayTitle] = useState(item.title);
|
|
37
39
|
const [markReadyPending, setMarkReadyPending] = useState(false);
|
|
38
40
|
const busy = markReadyPending;
|
|
@@ -79,7 +81,7 @@ export function InboxListRow({
|
|
|
79
81
|
value={item.title}
|
|
80
82
|
onSave={onUpdateTitle}
|
|
81
83
|
onDisplayTitleChange={setDisplayTitle}
|
|
82
|
-
ariaLabel="
|
|
84
|
+
ariaLabel={t("common.editTitleAriaLabel")}
|
|
83
85
|
disabled={busy}
|
|
84
86
|
titleDragProps={rowDrag.titleDragProps}
|
|
85
87
|
/>
|
|
@@ -93,11 +95,11 @@ export function InboxListRow({
|
|
|
93
95
|
disabled={busy || rowSelection.selectionMode}
|
|
94
96
|
onClick={() => void handleMarkReady()}
|
|
95
97
|
>
|
|
96
|
-
|
|
98
|
+
{t("common.markReady")}
|
|
97
99
|
</Button>
|
|
98
100
|
|
|
99
101
|
<RowActionsMenu
|
|
100
|
-
ariaLabel={
|
|
102
|
+
ariaLabel={t("common.rowActionsAriaLabel", { title: displayTitle })}
|
|
101
103
|
disabled={busy || rowSelection.selectionMode}
|
|
102
104
|
>
|
|
103
105
|
<DropdownMenuItem
|
|
@@ -105,14 +107,14 @@ export function InboxListRow({
|
|
|
105
107
|
onSelect={() => selection.actions.startSelection(item.id)}
|
|
106
108
|
>
|
|
107
109
|
<IconChecks className="size-4" />
|
|
108
|
-
|
|
110
|
+
{t("selection.select")}
|
|
109
111
|
</DropdownMenuItem>
|
|
110
112
|
<DropdownMenuItem
|
|
111
113
|
className="gap-2 text-destructive focus:bg-destructive focus:text-destructive-foreground"
|
|
112
114
|
onSelect={onRequestDelete}
|
|
113
115
|
>
|
|
114
116
|
<IconTrash className="size-4" />
|
|
115
|
-
|
|
117
|
+
{t("common.delete")}
|
|
116
118
|
</DropdownMenuItem>
|
|
117
119
|
</RowActionsMenu>
|
|
118
120
|
</>
|
|
@@ -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
|
import { IconMenu2 } from "@tabler/icons-react";
|
|
3
4
|
import { useLocation } from "react-router";
|
|
4
5
|
|
|
@@ -6,15 +7,13 @@ import { APP_TITLE } from "@/lib/app-config";
|
|
|
6
7
|
|
|
7
8
|
import { useHeaderTitle, useHeaderActions } from "./HeaderActions";
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
"/tasks": "Tasks",
|
|
11
|
-
"/settings": "Settings",
|
|
12
|
-
"/team": "Team",
|
|
13
|
-
};
|
|
10
|
+
type Translate = ReturnType<typeof useT>;
|
|
14
11
|
|
|
15
|
-
function resolveTitle(pathname: string): string {
|
|
16
|
-
if (
|
|
17
|
-
if (pathname
|
|
12
|
+
function resolveTitle(t: Translate, pathname: string): string {
|
|
13
|
+
if (pathname === "/tasks") return t("header.pageTasks");
|
|
14
|
+
if (pathname === "/settings") return t("header.pageSettings");
|
|
15
|
+
if (pathname === "/team") return t("header.pageTeam");
|
|
16
|
+
if (pathname.startsWith("/extensions")) return t("header.pageExtensions");
|
|
18
17
|
return APP_TITLE;
|
|
19
18
|
}
|
|
20
19
|
|
|
@@ -23,6 +22,7 @@ interface HeaderProps {
|
|
|
23
22
|
}
|
|
24
23
|
|
|
25
24
|
export function Header({ onOpenMobileSidebar }: HeaderProps) {
|
|
25
|
+
const t = useT();
|
|
26
26
|
const location = useLocation();
|
|
27
27
|
const title = useHeaderTitle();
|
|
28
28
|
const actions = useHeaderActions();
|
|
@@ -33,7 +33,7 @@ export function Header({ onOpenMobileSidebar }: HeaderProps) {
|
|
|
33
33
|
<button
|
|
34
34
|
type="button"
|
|
35
35
|
onClick={onOpenMobileSidebar}
|
|
36
|
-
aria-label="
|
|
36
|
+
aria-label={t("header.openNavigation")}
|
|
37
37
|
className="flex h-9 w-9 cursor-pointer items-center justify-center rounded-md text-muted-foreground hover:text-foreground hover:bg-accent md:hidden"
|
|
38
38
|
>
|
|
39
39
|
<IconMenu2 className="h-4 w-4" />
|
|
@@ -42,7 +42,7 @@ export function Header({ onOpenMobileSidebar }: HeaderProps) {
|
|
|
42
42
|
<div className="flex items-center gap-3 flex-1 min-w-0">
|
|
43
43
|
{title ?? (
|
|
44
44
|
<h1 className="text-lg font-semibold tracking-tight truncate">
|
|
45
|
-
{resolveTitle(location.pathname)}
|
|
45
|
+
{resolveTitle(t, location.pathname)}
|
|
46
46
|
</h1>
|
|
47
47
|
)}
|
|
48
48
|
</div>
|
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
AgentSidebar,
|
|
3
3
|
focusAgentChat,
|
|
4
4
|
} from "@agent-native/core/client/agent-chat";
|
|
5
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
5
6
|
import { IconMenu2 } from "@tabler/icons-react";
|
|
6
7
|
import { useState, useEffect } from "react";
|
|
7
8
|
import { useLocation } from "react-router";
|
|
@@ -35,6 +36,7 @@ function routeOwnsToolbar(pathname: string): boolean {
|
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
export function Layout({ children }: LayoutProps) {
|
|
39
|
+
const t = useT();
|
|
38
40
|
const location = useLocation();
|
|
39
41
|
const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
|
|
40
42
|
const [sidebarCollapsed, setSidebarCollapsed] = useState(true);
|
|
@@ -71,7 +73,7 @@ export function Layout({ children }: LayoutProps) {
|
|
|
71
73
|
<button
|
|
72
74
|
type="button"
|
|
73
75
|
onClick={() => setMobileSidebarOpen(true)}
|
|
74
|
-
aria-label="
|
|
76
|
+
aria-label={t("header.openNavigation")}
|
|
75
77
|
className="flex h-9 w-9 cursor-pointer items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground"
|
|
76
78
|
>
|
|
77
79
|
<IconMenu2 className="h-4 w-4" />
|
|
@@ -97,9 +99,11 @@ export function Layout({ children }: LayoutProps) {
|
|
|
97
99
|
</div>
|
|
98
100
|
<Sheet open={mobileSidebarOpen} onOpenChange={setMobileSidebarOpen}>
|
|
99
101
|
<SheetContent side="left" className="p-0 w-[260px]">
|
|
100
|
-
<SheetTitle className="sr-only">
|
|
102
|
+
<SheetTitle className="sr-only">
|
|
103
|
+
{t("sidebar.navigationTitle")}
|
|
104
|
+
</SheetTitle>
|
|
101
105
|
<SheetDescription className="sr-only">
|
|
102
|
-
|
|
106
|
+
{t("sidebar.navigationDescription")}
|
|
103
107
|
</SheetDescription>
|
|
104
108
|
<Sidebar collapsed={false} collapsible={false} />
|
|
105
109
|
</SheetContent>
|
|
@@ -110,12 +114,12 @@ export function Layout({ children }: LayoutProps) {
|
|
|
110
114
|
storageKey="tasks"
|
|
111
115
|
browserTabId={TAB_ID}
|
|
112
116
|
onFullscreenRequest={() => focusAgentChat()}
|
|
113
|
-
emptyStateText="
|
|
117
|
+
emptyStateText={t("agent.emptyState")}
|
|
114
118
|
dynamicSuggestions={false}
|
|
115
119
|
suggestions={[
|
|
116
|
-
"
|
|
117
|
-
"
|
|
118
|
-
"
|
|
120
|
+
t("agent.suggestionCalendar"),
|
|
121
|
+
t("agent.suggestionPrioritize"),
|
|
122
|
+
t("agent.suggestionCleanHouse"),
|
|
119
123
|
]}
|
|
120
124
|
>
|
|
121
125
|
{contentFrame}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { appPath } from "@agent-native/core/client/api-path";
|
|
2
2
|
import { ExtensionsSidebarSection } from "@agent-native/core/client/extensions";
|
|
3
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
3
4
|
import { OrgSwitcher } from "@agent-native/core/client/org";
|
|
4
5
|
import { FeedbackButton } from "@agent-native/core/client/ui";
|
|
5
6
|
import {
|
|
@@ -19,10 +20,10 @@ import {
|
|
|
19
20
|
import { APP_TITLE } from "@/lib/app-config";
|
|
20
21
|
import { cn } from "@/lib/utils";
|
|
21
22
|
|
|
22
|
-
const
|
|
23
|
-
{ icon: IconInbox,
|
|
24
|
-
{ icon: IconCheckbox,
|
|
25
|
-
{ icon: IconForms,
|
|
23
|
+
const NAV_ITEMS = [
|
|
24
|
+
{ icon: IconInbox, labelKey: "sidebar.navInbox", href: "/inbox" },
|
|
25
|
+
{ icon: IconCheckbox, labelKey: "sidebar.navTasks", href: "/tasks" },
|
|
26
|
+
{ icon: IconForms, labelKey: "sidebar.navFields", href: "/fields" },
|
|
26
27
|
];
|
|
27
28
|
|
|
28
29
|
interface SidebarProps {
|
|
@@ -36,6 +37,7 @@ export function Sidebar({
|
|
|
36
37
|
collapsible = true,
|
|
37
38
|
onCollapsedChange,
|
|
38
39
|
}: SidebarProps) {
|
|
40
|
+
const t = useT();
|
|
39
41
|
const location = useLocation();
|
|
40
42
|
const ToggleIcon = collapsed
|
|
41
43
|
? IconLayoutSidebarLeftExpand
|
|
@@ -64,13 +66,17 @@ export function Sidebar({
|
|
|
64
66
|
"flex shrink-0 items-center justify-center rounded-md text-sidebar-foreground/65 transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
65
67
|
collapsed ? "size-8" : "size-7",
|
|
66
68
|
)}
|
|
67
|
-
aria-label={
|
|
69
|
+
aria-label={
|
|
70
|
+
collapsed
|
|
71
|
+
? t("sidebar.expandSidebar")
|
|
72
|
+
: t("sidebar.collapseSidebar")
|
|
73
|
+
}
|
|
68
74
|
>
|
|
69
75
|
<ToggleIcon className="size-4" />
|
|
70
76
|
</button>
|
|
71
77
|
</TooltipTrigger>
|
|
72
78
|
<TooltipContent side="right">
|
|
73
|
-
{collapsed ? "
|
|
79
|
+
{collapsed ? t("sidebar.expandSidebar") : t("sidebar.collapseSidebar")}
|
|
74
80
|
</TooltipContent>
|
|
75
81
|
</Tooltip>
|
|
76
82
|
) : null;
|
|
@@ -124,26 +130,27 @@ export function Sidebar({
|
|
|
124
130
|
)}
|
|
125
131
|
>
|
|
126
132
|
<div className={cn("grid", collapsed ? "gap-0" : "gap-1")}>
|
|
127
|
-
{
|
|
133
|
+
{NAV_ITEMS.map((item) => {
|
|
128
134
|
const Icon = item.icon;
|
|
129
135
|
const isActive = location.pathname.startsWith(item.href);
|
|
136
|
+
const label = t(item.labelKey);
|
|
130
137
|
const link = (
|
|
131
138
|
<Link
|
|
132
139
|
to={item.href}
|
|
133
140
|
className={navClass({ isActive })}
|
|
134
141
|
aria-current={isActive ? "page" : undefined}
|
|
135
|
-
aria-label={collapsed ?
|
|
142
|
+
aria-label={collapsed ? label : undefined}
|
|
136
143
|
>
|
|
137
144
|
<Icon className="size-4 shrink-0" />
|
|
138
145
|
<span className={collapsed ? "sr-only" : "truncate"}>
|
|
139
|
-
{
|
|
146
|
+
{label}
|
|
140
147
|
</span>
|
|
141
148
|
</Link>
|
|
142
149
|
);
|
|
143
150
|
return collapsed ? (
|
|
144
151
|
<Tooltip key={item.href}>
|
|
145
152
|
<TooltipTrigger asChild>{link}</TooltipTrigger>
|
|
146
|
-
<TooltipContent side="right">{
|
|
153
|
+
<TooltipContent side="right">{label}</TooltipContent>
|
|
147
154
|
</Tooltip>
|
|
148
155
|
) : (
|
|
149
156
|
<div key={item.href}>{link}</div>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
1
2
|
import { useRef, useState, type FormEvent } from "react";
|
|
2
3
|
import { toast } from "sonner";
|
|
3
4
|
|
|
@@ -16,11 +17,16 @@ interface AddListItemInputProps {
|
|
|
16
17
|
export function AddListItemInput({
|
|
17
18
|
disabled = false,
|
|
18
19
|
onCreate,
|
|
19
|
-
placeholder
|
|
20
|
-
buttonLabel
|
|
21
|
-
inputAriaLabel
|
|
22
|
-
errorMessage
|
|
20
|
+
placeholder,
|
|
21
|
+
buttonLabel,
|
|
22
|
+
inputAriaLabel,
|
|
23
|
+
errorMessage,
|
|
23
24
|
}: AddListItemInputProps) {
|
|
25
|
+
const t = useT();
|
|
26
|
+
const resolvedPlaceholder = placeholder ?? t("tasks.addPlaceholder");
|
|
27
|
+
const resolvedButtonLabel = buttonLabel ?? t("tasks.addButtonLabel");
|
|
28
|
+
const resolvedInputAriaLabel = inputAriaLabel ?? t("tasks.addInputAriaLabel");
|
|
29
|
+
const resolvedErrorMessage = errorMessage ?? t("tasks.addErrorMessage");
|
|
24
30
|
const [title, setTitle] = useState("");
|
|
25
31
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
26
32
|
|
|
@@ -32,7 +38,7 @@ export function AddListItemInput({
|
|
|
32
38
|
void onCreate(trimmed)
|
|
33
39
|
.catch(() => {
|
|
34
40
|
setTitle(trimmed);
|
|
35
|
-
toast.error(
|
|
41
|
+
toast.error(resolvedErrorMessage);
|
|
36
42
|
})
|
|
37
43
|
.finally(() => {
|
|
38
44
|
inputRef.current?.focus();
|
|
@@ -45,12 +51,12 @@ export function AddListItemInput({
|
|
|
45
51
|
ref={inputRef}
|
|
46
52
|
value={title}
|
|
47
53
|
onChange={(event) => setTitle(event.target.value)}
|
|
48
|
-
placeholder={
|
|
49
|
-
aria-label={
|
|
54
|
+
placeholder={resolvedPlaceholder}
|
|
55
|
+
aria-label={resolvedInputAriaLabel}
|
|
50
56
|
disabled={disabled}
|
|
51
57
|
/>
|
|
52
58
|
<Button type="submit" disabled={disabled || !title.trim()}>
|
|
53
|
-
{
|
|
59
|
+
{resolvedButtonLabel}
|
|
54
60
|
</Button>
|
|
55
61
|
</form>
|
|
56
62
|
);
|
|
@@ -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 {
|
|
@@ -28,6 +29,7 @@ export function AlertDialog({
|
|
|
28
29
|
pending = false,
|
|
29
30
|
onConfirm,
|
|
30
31
|
}: AlertDialogProps) {
|
|
32
|
+
const t = useT();
|
|
31
33
|
return (
|
|
32
34
|
<AlertDialogRoot open={open} onOpenChange={onOpenChange}>
|
|
33
35
|
<AlertDialogContent>
|
|
@@ -38,13 +40,15 @@ export function AlertDialog({
|
|
|
38
40
|
</AlertDialogDescription>
|
|
39
41
|
</AlertDialogHeader>
|
|
40
42
|
<AlertDialogFooter>
|
|
41
|
-
<AlertDialogCancel disabled={pending}>
|
|
43
|
+
<AlertDialogCancel disabled={pending}>
|
|
44
|
+
{t("common.cancel")}
|
|
45
|
+
</AlertDialogCancel>
|
|
42
46
|
<AlertDialogAction
|
|
43
47
|
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
|
44
48
|
disabled={pending}
|
|
45
49
|
onClick={() => void onConfirm()}
|
|
46
50
|
>
|
|
47
|
-
|
|
51
|
+
{t("common.delete")}
|
|
48
52
|
</AlertDialogAction>
|
|
49
53
|
</AlertDialogFooter>
|
|
50
54
|
</AlertDialogContent>
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
2
|
+
|
|
1
3
|
import {
|
|
2
4
|
AlertDialog,
|
|
3
5
|
type AlertDialogProps,
|
|
@@ -19,16 +21,18 @@ function BulkDeleteDialogDescription({
|
|
|
19
21
|
BulkDeleteDialogProps,
|
|
20
22
|
"selectedItems" | "entitySingular" | "entityPlural"
|
|
21
23
|
>) {
|
|
24
|
+
const t = useT();
|
|
22
25
|
const selectedCount = selectedItems.length;
|
|
23
26
|
|
|
24
27
|
return (
|
|
25
28
|
<div className="space-y-2 text-sm text-muted-foreground">
|
|
26
29
|
<p>
|
|
27
|
-
This permanently removes{" "}
|
|
28
30
|
{selectedCount === 1
|
|
29
|
-
?
|
|
30
|
-
:
|
|
31
|
-
|
|
31
|
+
? t("dialogs.bulkDeleteDescriptionOne", { entity: entitySingular })
|
|
32
|
+
: t("dialogs.bulkDeleteDescriptionOther", {
|
|
33
|
+
count: selectedCount,
|
|
34
|
+
entity: entityPlural,
|
|
35
|
+
})}
|
|
32
36
|
</p>
|
|
33
37
|
{selectedItems.length > 0 ? (
|
|
34
38
|
<ul className="list-disc space-y-1 pl-5 text-foreground">
|
|
@@ -39,7 +43,7 @@ function BulkDeleteDialogDescription({
|
|
|
39
43
|
))}
|
|
40
44
|
{selectedItems.length > 5 ? (
|
|
41
45
|
<li className="text-muted-foreground">
|
|
42
|
-
|
|
46
|
+
{t("dialogs.andMore", { count: selectedItems.length - 5 })}
|
|
43
47
|
</li>
|
|
44
48
|
) : null}
|
|
45
49
|
</ul>
|
|
@@ -57,12 +61,15 @@ export function BulkDeleteDialog({
|
|
|
57
61
|
pending,
|
|
58
62
|
onConfirm,
|
|
59
63
|
}: BulkDeleteDialogProps) {
|
|
64
|
+
const t = useT();
|
|
60
65
|
return (
|
|
61
66
|
<AlertDialog
|
|
62
67
|
open={open}
|
|
63
68
|
onOpenChange={onOpenChange}
|
|
64
69
|
pending={pending}
|
|
65
|
-
title={
|
|
70
|
+
title={t("dialogs.deleteEntityTitle", {
|
|
71
|
+
entity: selectedItems.length === 1 ? entitySingular : entityPlural,
|
|
72
|
+
})}
|
|
66
73
|
description={
|
|
67
74
|
<BulkDeleteDialogDescription
|
|
68
75
|
selectedItems={selectedItems}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
1
2
|
import {
|
|
2
3
|
closestCenter,
|
|
3
4
|
DndContext,
|
|
@@ -56,6 +57,7 @@ function ChipSelectChip({
|
|
|
56
57
|
sortable: boolean;
|
|
57
58
|
onRemove: () => void;
|
|
58
59
|
}) {
|
|
60
|
+
const t = useT();
|
|
59
61
|
const {
|
|
60
62
|
attributes,
|
|
61
63
|
listeners,
|
|
@@ -89,7 +91,7 @@ function ChipSelectChip({
|
|
|
89
91
|
variant="ghost"
|
|
90
92
|
size="icon"
|
|
91
93
|
disabled={disabled}
|
|
92
|
-
aria-label={
|
|
94
|
+
aria-label={t("common.removeAriaLabel", { label: option.label })}
|
|
93
95
|
onPointerDown={(event) => event.stopPropagation()}
|
|
94
96
|
onClick={(event) => {
|
|
95
97
|
event.stopPropagation();
|
|
@@ -110,10 +112,13 @@ export function ChipSelect({
|
|
|
110
112
|
onSelectedIdsChange,
|
|
111
113
|
disabled = false,
|
|
112
114
|
limit,
|
|
113
|
-
addButtonLabel
|
|
114
|
-
emptyLabel
|
|
115
|
+
addButtonLabel,
|
|
116
|
+
emptyLabel,
|
|
115
117
|
sortable = true,
|
|
116
118
|
}: ChipSelectProps) {
|
|
119
|
+
const t = useT();
|
|
120
|
+
const resolvedAddButtonLabel = addButtonLabel ?? t("common.add");
|
|
121
|
+
const resolvedEmptyLabel = emptyLabel ?? t("common.noneSelected");
|
|
117
122
|
const optionsById = useMemo(
|
|
118
123
|
() => new Map(options.map((option) => [option.id, option])),
|
|
119
124
|
[options],
|
|
@@ -192,7 +197,9 @@ export function ChipSelect({
|
|
|
192
197
|
</div>
|
|
193
198
|
<div className="flex min-w-0 flex-wrap items-center gap-2">
|
|
194
199
|
{selectedOptions.length === 0 ? (
|
|
195
|
-
<span className="text-sm text-muted-foreground">
|
|
200
|
+
<span className="text-sm text-muted-foreground">
|
|
201
|
+
{resolvedEmptyLabel}
|
|
202
|
+
</span>
|
|
196
203
|
) : sortable ? (
|
|
197
204
|
<DndContext
|
|
198
205
|
sensors={sensors}
|
|
@@ -218,7 +225,7 @@ export function ChipSelect({
|
|
|
218
225
|
disabled={disabled || availableOptions.length === 0 || atLimit}
|
|
219
226
|
className="h-8 gap-1.5 px-2"
|
|
220
227
|
>
|
|
221
|
-
{
|
|
228
|
+
{resolvedAddButtonLabel}
|
|
222
229
|
<IconChevronDown className="size-4" />
|
|
223
230
|
</Button>
|
|
224
231
|
</DropdownMenuTrigger>
|
|
@@ -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" />
|