@shivaedev/work-board 0.17.0 → 0.17.1
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/CHANGELOG.md +14 -0
- package/README.md +4 -4
- package/assets/react.css +1 -1
- package/assets/react.js +34 -33
- package/dist/browser/responses/cardContext.d.ts +8 -1
- package/dist/browser/responses/cardContext.d.ts.map +1 -1
- package/dist/browser/responses/cardContext.js +14 -6
- package/dist/browser/responses/cardContext.js.map +1 -1
- package/dist/browser/views/schema.d.ts +11 -0
- package/dist/browser/views/schema.d.ts.map +1 -1
- package/dist/browser/views/schema.js +1 -0
- package/dist/browser/views/schema.js.map +1 -1
- package/dist/client/formStatus.d.ts +1 -1
- package/dist/client/formStatus.d.ts.map +1 -1
- package/dist/client/formStatus.js +2 -2
- package/dist/client/formStatus.js.map +1 -1
- package/dist/client/react/AnswerContext.d.ts.map +1 -1
- package/dist/client/react/AnswerContext.js +5 -2
- package/dist/client/react/AnswerContext.js.map +1 -1
- package/dist/client/react/AnswerForm.d.ts.map +1 -1
- package/dist/client/react/AnswerForm.js +6 -2
- package/dist/client/react/AnswerForm.js.map +1 -1
- package/dist/client/react/AnswerMarkdown.d.ts +6 -0
- package/dist/client/react/AnswerMarkdown.d.ts.map +1 -0
- package/dist/client/react/AnswerMarkdown.js +7 -0
- package/dist/client/react/AnswerMarkdown.js.map +1 -0
- package/dist/client/react/AnswerMore.d.ts.map +1 -1
- package/dist/client/react/AnswerMore.js +2 -1
- package/dist/client/react/AnswerMore.js.map +1 -1
- package/dist/client/react/AnswerPanel.d.ts.map +1 -1
- package/dist/client/react/AnswerPanel.js +3 -2
- package/dist/client/react/AnswerPanel.js.map +1 -1
- package/dist/client/react/AnswerPrompts.d.ts.map +1 -1
- package/dist/client/react/AnswerPrompts.js +16 -10
- package/dist/client/react/AnswerPrompts.js.map +1 -1
- package/dist/client/react/BoardShell.js +1 -1
- package/dist/client/react/BoardShell.js.map +1 -1
- package/dist/client/react/DocumentMain.d.ts.map +1 -1
- package/dist/client/react/DocumentMain.js +1 -1
- package/dist/client/react/DocumentMain.js.map +1 -1
- package/dist/client/react/GoalPage.js +1 -1
- package/dist/client/react/GoalPage.js.map +1 -1
- package/dist/client/react/GoalProgressHeader.js +1 -1
- package/dist/client/react/GoalProgressHeader.js.map +1 -1
- package/dist/client/react/LibraryMain.d.ts.map +1 -1
- package/dist/client/react/LibraryMain.js +1 -1
- package/dist/client/react/LibraryMain.js.map +1 -1
- package/dist/client/react/LibraryPage.js +1 -1
- package/dist/client/react/LibraryPage.js.map +1 -1
- package/dist/client/react/ProjectionMain.d.ts.map +1 -1
- package/dist/client/react/ProjectionMain.js +1 -1
- package/dist/client/react/ProjectionMain.js.map +1 -1
- package/dist/client/react/PromptOption.d.ts.map +1 -1
- package/dist/client/react/PromptOption.js +7 -5
- package/dist/client/react/PromptOption.js.map +1 -1
- package/dist/client/react/RemainingMain.d.ts.map +1 -1
- package/dist/client/react/RemainingMain.js +1 -1
- package/dist/client/react/RemainingMain.js.map +1 -1
- package/dist/client/react/ResponseHistory.d.ts.map +1 -1
- package/dist/client/react/ResponseHistory.js +11 -5
- package/dist/client/react/ResponseHistory.js.map +1 -1
- package/dist/client/react/SystemMain.d.ts.map +1 -1
- package/dist/client/react/SystemMain.js +1 -1
- package/dist/client/react/SystemMain.js.map +1 -1
- package/dist/client/react/TodayNeeds.d.ts +5 -0
- package/dist/client/react/TodayNeeds.d.ts.map +1 -1
- package/dist/client/react/TodayNeeds.js +6 -3
- package/dist/client/react/TodayNeeds.js.map +1 -1
- package/dist/client/react/TodayOptionButton.d.ts +15 -0
- package/dist/client/react/TodayOptionButton.d.ts.map +1 -0
- package/dist/client/react/TodayOptionButton.js +10 -0
- package/dist/client/react/TodayOptionButton.js.map +1 -0
- package/dist/client/react/TodayOptions.d.ts.map +1 -1
- package/dist/client/react/TodayOptions.js +11 -9
- package/dist/client/react/TodayOptions.js.map +1 -1
- package/dist/client/react/TodayPage.d.ts.map +1 -1
- package/dist/client/react/TodayPage.js +7 -4
- package/dist/client/react/TodayPage.js.map +1 -1
- package/dist/client/react/activeRead.js +1 -1
- package/dist/client/react/activeRead.js.map +1 -1
- package/dist/client/react/loadBoardPage.d.ts.map +1 -1
- package/dist/client/react/loadBoardPage.js +1 -1
- package/dist/client/react/loadBoardPage.js.map +1 -1
- package/dist/client/react/loadProjection.d.ts.map +1 -1
- package/dist/client/react/loadProjection.js +1 -1
- package/dist/client/react/loadProjection.js.map +1 -1
- package/dist/client/react/loadRemaining.d.ts +201 -201
- package/dist/client/react/loadRemaining.d.ts.map +1 -1
- package/dist/client/react/loadRemaining.js +1 -1
- package/dist/client/react/loadRemaining.js.map +1 -1
- package/dist/client/react/pageQueries.js +1 -1
- package/dist/client/react/pageQueries.js.map +1 -1
- package/dist/client/react/resolvedDocumentFailure.d.ts.map +1 -0
- package/dist/client/react/resolvedDocumentFailure.js.map +1 -0
- package/dist/client/react/routeQuery.d.ts.map +1 -0
- package/dist/client/react/routeQuery.js.map +1 -0
- package/dist/client/react/useResponseForm.d.ts.map +1 -1
- package/dist/client/react/useResponseForm.js +2 -2
- package/dist/client/react/useResponseForm.js.map +1 -1
- package/dist/client/responses/summary.d.ts +1 -0
- package/dist/client/responses/summary.d.ts.map +1 -1
- package/dist/client/responses/summary.js +12 -1
- package/dist/client/responses/summary.js.map +1 -1
- package/dist/rpc/contract.d.ts +33 -0
- package/dist/rpc/contract.d.ts.map +1 -1
- package/dist/server/attention/inbox.d.ts +13 -2
- package/dist/server/attention/inbox.d.ts.map +1 -1
- package/dist/server/attention/inbox.js +44 -27
- package/dist/server/attention/inbox.js.map +1 -1
- package/dist/server/attention/managedRequestReceipt.d.ts +10 -0
- package/dist/server/attention/managedRequestReceipt.d.ts.map +1 -1
- package/dist/server/attention/managedRequestReceipt.js +29 -10
- package/dist/server/attention/managedRequestReceipt.js.map +1 -1
- package/dist/server/attention/projection.d.ts.map +1 -1
- package/dist/server/attention/projection.js +2 -1
- package/dist/server/attention/projection.js.map +1 -1
- package/dist/server/attention/requestInbox.d.ts +3 -3
- package/dist/server/attention/requestInbox.js +2 -2
- package/dist/server/attention/requestInbox.js.map +1 -1
- package/dist/server/attention/requests.d.ts +1 -0
- package/dist/server/attention/requests.d.ts.map +1 -1
- package/dist/server/attention/requests.js +7 -3
- package/dist/server/attention/requests.js.map +1 -1
- package/dist/server/mcp/client.d.ts +874 -863
- package/dist/server/mcp/client.d.ts.map +1 -1
- package/dist/server/mcp/queries.d.ts +33 -0
- package/dist/server/mcp/queries.d.ts.map +1 -1
- package/dist/server/packageInfo.d.ts +1 -1
- package/dist/server/packageInfo.js +1 -1
- package/dist/server/views/projectionQueries.d.ts +11 -0
- package/dist/server/views/projectionQueries.d.ts.map +1 -1
- package/docs/delivery/README.md +2 -2
- package/package.json +4 -4
- package/src/browser/responses/cardContext.ts +15 -6
- package/src/browser/views/schema.ts +1 -0
- package/src/client/formStatus.ts +2 -2
- package/src/client/react/AnswerContext.tsx +9 -4
- package/src/client/react/AnswerForm.tsx +25 -6
- package/src/client/react/AnswerMarkdown.tsx +15 -0
- package/src/client/react/AnswerMore.tsx +58 -46
- package/src/client/react/AnswerPanel.tsx +14 -8
- package/src/client/react/AnswerPrompts.tsx +33 -18
- package/src/client/react/BoardShell.tsx +1 -1
- package/src/client/react/DocumentMain.tsx +1 -1
- package/src/client/react/GoalPage.tsx +1 -1
- package/src/client/react/GoalProgressHeader.tsx +1 -1
- package/src/client/react/LibraryMain.tsx +1 -1
- package/src/client/react/LibraryPage.tsx +1 -1
- package/src/client/react/ProjectionMain.tsx +1 -1
- package/src/client/react/PromptOption.tsx +39 -24
- package/src/client/react/RemainingMain.tsx +1 -1
- package/src/client/react/ResponseHistory.tsx +53 -14
- package/src/client/react/SystemMain.tsx +1 -1
- package/src/client/react/TodayNeeds.tsx +21 -6
- package/src/client/react/TodayOptionButton.tsx +37 -0
- package/src/client/react/TodayOptions.tsx +36 -28
- package/src/client/react/TodayPage.tsx +18 -3
- package/src/client/react/activeRead.ts +1 -1
- package/src/client/react/entry.css +0 -6
- package/src/client/react/loadBoardPage.ts +1 -1
- package/src/client/react/loadProjection.ts +1 -1
- package/src/client/react/loadRemaining.ts +1 -1
- package/src/client/react/pageQueries.ts +1 -1
- package/src/client/react/useResponseForm.ts +4 -2
- package/src/client/responses/summary.ts +13 -1
- package/src/server/attention/inbox.ts +51 -27
- package/src/server/attention/managedRequestReceipt.ts +41 -10
- package/src/server/attention/projection.ts +5 -2
- package/src/server/attention/requestInbox.ts +2 -2
- package/src/server/attention/requests.ts +7 -2
- package/src/server/packageInfo.ts +1 -1
- package/dist/client/page/resolvedDocumentFailure.d.ts.map +0 -1
- package/dist/client/page/resolvedDocumentFailure.js.map +0 -1
- package/dist/client/page/routeQuery.d.ts.map +0 -1
- package/dist/client/page/routeQuery.js.map +0 -1
- /package/dist/client/{page → react}/resolvedDocumentFailure.d.ts +0 -0
- /package/dist/client/{page → react}/resolvedDocumentFailure.js +0 -0
- /package/dist/client/{page → react}/routeQuery.d.ts +0 -0
- /package/dist/client/{page → react}/routeQuery.js +0 -0
- /package/src/client/{page → react}/resolvedDocumentFailure.ts +0 -0
- /package/src/client/{page → react}/routeQuery.ts +0 -0
|
@@ -4,7 +4,6 @@ import type * as AtomRegistry from "effect/reactivity/AtomRegistry";
|
|
|
4
4
|
import { useCallback, useContext, useEffect, useState } from "react";
|
|
5
5
|
import { useQuery } from "@shivaedev/effect-react/result-state.ts";
|
|
6
6
|
import type { BrowserClient } from "#client/client.ts";
|
|
7
|
-
import { navigationQuery } from "#client/page/routeQuery.ts";
|
|
8
7
|
import { AgeTicker } from "./Age.tsx";
|
|
9
8
|
import { FleetMain } from "./FleetMain.tsx";
|
|
10
9
|
import { FormContext } from "./FormContext.ts";
|
|
@@ -15,6 +14,7 @@ import { emptyMainLocation, type MainLocation } from "./mainLocation.ts";
|
|
|
15
14
|
import { PhoneNavigation } from "./PhoneNavigation.tsx";
|
|
16
15
|
import { ReadingLibrary } from "./ReadingLibrary.tsx";
|
|
17
16
|
import { ReadingReadyContext, readingReady } from "./ReadingReadyContext.ts";
|
|
17
|
+
import { navigationQuery } from "./routeQuery.ts";
|
|
18
18
|
import { SearchDialog } from "./SearchDialog.tsx";
|
|
19
19
|
import { SessionContext } from "./SessionContext.ts";
|
|
20
20
|
import type { ShellApi } from "./ShellApi.ts";
|
|
@@ -2,11 +2,11 @@ import { Cause, Option } from "effect";
|
|
|
2
2
|
import { useEffect, useState } from "react";
|
|
3
3
|
import { useQuery } from "@shivaedev/effect-react/result-state.ts";
|
|
4
4
|
import type { Document } from "#browser/document/schema.ts";
|
|
5
|
-
import { documentQuery } from "#client/page/routeQuery.ts";
|
|
6
5
|
import { DocumentPage } from "./DocumentPage.tsx";
|
|
7
6
|
import type { MainLocation } from "./mainLocation.ts";
|
|
8
7
|
import { ProjectionMain } from "./ProjectionMain.tsx";
|
|
9
8
|
import { RemainingMain } from "./RemainingMain.tsx";
|
|
9
|
+
import { documentQuery } from "./routeQuery.ts";
|
|
10
10
|
import type { ShellApi } from "./ShellApi.ts";
|
|
11
11
|
import { shellIds } from "./shellIds.ts";
|
|
12
12
|
import { useDocumentPage } from "./useDocumentPage.ts";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Option } from "effect";
|
|
2
2
|
import { useQuery } from "@shivaedev/effect-react/result-state.ts";
|
|
3
3
|
import type { Document } from "#browser/document/schema.ts";
|
|
4
|
-
import { routeQueryOptions } from "#client/page/routeQuery.ts";
|
|
5
4
|
import { GoalCriteria } from "./GoalCriteria.tsx";
|
|
6
5
|
import { GoalWorkTable } from "./GoalWorkTable.tsx";
|
|
7
6
|
import { targetsGoal } from "./goalWork.ts";
|
|
7
|
+
import { routeQueryOptions } from "./routeQuery.ts";
|
|
8
8
|
import type { ShellApi } from "./ShellApi.ts";
|
|
9
9
|
|
|
10
10
|
export function GoalPage({ api, document }: { readonly api: ShellApi; readonly document: Document }) {
|
|
@@ -2,8 +2,8 @@ import { Option } from "effect";
|
|
|
2
2
|
import { useId } from "react";
|
|
3
3
|
import { useQuery } from "@shivaedev/effect-react/result-state.ts";
|
|
4
4
|
import type { Document } from "#browser/document/schema.ts";
|
|
5
|
-
import { routeQueryOptions } from "#client/page/routeQuery.ts";
|
|
6
5
|
import { GoalProgressSummary } from "./GoalProgressSummary.tsx";
|
|
6
|
+
import { routeQueryOptions } from "./routeQuery.ts";
|
|
7
7
|
import type { ShellApi } from "./ShellApi.ts";
|
|
8
8
|
|
|
9
9
|
export function GoalProgressHeader({ api, document }: { readonly api: ShellApi; readonly document: Document }) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { routeQueryOptions } from "#client/page/routeQuery.ts";
|
|
2
1
|
import { LibraryPage } from "./LibraryPage.tsx";
|
|
3
2
|
import type { MainLocation } from "./mainLocation.ts";
|
|
4
3
|
import { ProjectionFrame } from "./ProjectionFrame.tsx";
|
|
4
|
+
import { routeQueryOptions } from "./routeQuery.ts";
|
|
5
5
|
import type { ShellApi } from "./ShellApi.ts";
|
|
6
6
|
export function LibraryMain({
|
|
7
7
|
api,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Option } from "effect";
|
|
2
2
|
import { useState } from "react";
|
|
3
3
|
import { useQuery } from "@shivaedev/effect-react/result-state.ts";
|
|
4
|
-
import { routeQueryOptions } from "#client/page/routeQuery.ts";
|
|
5
4
|
import { LibraryContents } from "./LibraryContents.tsx";
|
|
5
|
+
import { routeQueryOptions } from "./routeQuery.ts";
|
|
6
6
|
import type { ShellApi } from "./ShellApi.ts";
|
|
7
7
|
|
|
8
8
|
export function LibraryPage({ api, url = "/_board/library" }: { readonly api: ShellApi; readonly url?: string }) {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { documentSourceId } from "#client/document/layout.ts";
|
|
2
|
-
import { routeQueryOptions } from "#client/page/routeQuery.ts";
|
|
3
2
|
import { HomeBoard } from "./HomeBoard.tsx";
|
|
4
3
|
import type { MainLocation } from "./mainLocation.ts";
|
|
5
4
|
import { ProjectionFrame } from "./ProjectionFrame.tsx";
|
|
6
5
|
import type { ProjectionRoute } from "./projectionRoute.ts";
|
|
6
|
+
import { routeQueryOptions } from "./routeQuery.ts";
|
|
7
7
|
import type { ShellApi } from "./ShellApi.ts";
|
|
8
8
|
import { TodayPage } from "./TodayPage.tsx";
|
|
9
9
|
import { WorkPage } from "./WorkPage.tsx";
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { useId } from "react";
|
|
2
2
|
import type { Document } from "#browser/document/schema.ts";
|
|
3
|
-
import {
|
|
3
|
+
import { optionText } from "#browser/responses/cardContext.ts";
|
|
4
4
|
import type { Prompt } from "#browser/responses/Prompt.ts";
|
|
5
|
-
import {
|
|
5
|
+
import { Badge } from "#client/react/components/ui/Badge.tsx";
|
|
6
|
+
import { cn } from "#client/react/lib/cn.ts";
|
|
7
|
+
|
|
6
8
|
export function PromptOption({
|
|
7
9
|
document,
|
|
8
10
|
prompt,
|
|
@@ -20,37 +22,50 @@ export function PromptOption({
|
|
|
20
22
|
}) {
|
|
21
23
|
const source = document.metadata.options?.[choice];
|
|
22
24
|
const id = useId();
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
data-option-source={option.source}
|
|
27
|
-
hidden
|
|
28
|
-
id={id}
|
|
29
|
-
name={`choice-${prompt.id}`}
|
|
30
|
-
onChange={(event) => choose(option.id, event.currentTarget.checked)}
|
|
31
|
-
onInput={(event) => choose(option.id, event.currentTarget.checked)}
|
|
32
|
-
type={prompt.mode === "one" ? "radio" : "checkbox"}
|
|
33
|
-
value={option.id}
|
|
34
|
-
/>
|
|
35
|
-
);
|
|
36
|
-
const label = source?.label ?? optionLabel(option.id, option.source, document.requests.find((request) => request.open)?.preview?.reason ?? "");
|
|
25
|
+
const authored = optionText(option.id, option.source, document.requests.find((request) => request.open)?.preview?.reason ?? "");
|
|
26
|
+
const label = source?.label ?? authored.label;
|
|
27
|
+
const description = source?.description ?? authored.description;
|
|
37
28
|
return (
|
|
38
29
|
<div>
|
|
39
|
-
|
|
30
|
+
<input
|
|
31
|
+
checked={checked}
|
|
32
|
+
data-option-source={option.source}
|
|
33
|
+
hidden
|
|
34
|
+
id={id}
|
|
35
|
+
name={`choice-${prompt.id}`}
|
|
36
|
+
onChange={(event) => choose(option.id, event.currentTarget.checked)}
|
|
37
|
+
onInput={(event) => choose(option.id, event.currentTarget.checked)}
|
|
38
|
+
type={prompt.mode === "one" ? "radio" : "checkbox"}
|
|
39
|
+
value={option.id}
|
|
40
|
+
/>
|
|
40
41
|
<button
|
|
41
42
|
aria-pressed={checked}
|
|
42
|
-
className=
|
|
43
|
+
className={cn(
|
|
44
|
+
"question-choice flex w-full items-start gap-3 rounded-lg border bg-background px-4 py-3 text-left transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
45
|
+
checked && "border-primary bg-accent",
|
|
46
|
+
)}
|
|
43
47
|
data-choice={option.id}
|
|
44
48
|
onClick={() => choose(option.id, prompt.mode !== "many" || !checked)}
|
|
45
49
|
type="button"
|
|
46
50
|
>
|
|
47
|
-
<
|
|
48
|
-
|
|
49
|
-
{
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
<span
|
|
52
|
+
aria-hidden="true"
|
|
53
|
+
className={cn(
|
|
54
|
+
"mt-0.5 grid size-4 shrink-0 place-items-center border border-muted-foreground",
|
|
55
|
+
prompt.mode === "many" ? "rounded-sm" : "rounded-full",
|
|
56
|
+
checked && "border-primary",
|
|
57
|
+
)}
|
|
58
|
+
>
|
|
59
|
+
{checked ? <span className={cn("size-2 bg-primary", prompt.mode === "many" ? "rounded-[1px]" : "rounded-full")} /> : null}
|
|
60
|
+
</span>
|
|
61
|
+
<span className="grid gap-1">
|
|
62
|
+
<strong className="flex flex-wrap items-center gap-2 font-medium text-sm">
|
|
63
|
+
{label}
|
|
64
|
+
{label === document.metadata.recommended && <Badge variant="outline">Recommended</Badge>}
|
|
65
|
+
</strong>
|
|
66
|
+
{Boolean(description) && <small className="text-muted-foreground text-sm">{description}</small>}
|
|
67
|
+
</span>
|
|
52
68
|
</button>
|
|
53
|
-
{source === undefined && <ResponseMarkdown file={document.file} source={option.source.replace(/^#{1,6}\s+.+$/mu, "")} />}
|
|
54
69
|
</div>
|
|
55
70
|
);
|
|
56
71
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { routeQueryOptions } from "#client/page/routeQuery.ts";
|
|
2
1
|
import { GoalsPage } from "./GoalsPage.tsx";
|
|
3
2
|
import { HandoffPage } from "./HandoffPage.tsx";
|
|
4
3
|
import { LibraryMain } from "./LibraryMain.tsx";
|
|
@@ -6,6 +5,7 @@ import type { MainLocation } from "./mainLocation.ts";
|
|
|
6
5
|
import { ProjectionFrame } from "./ProjectionFrame.tsx";
|
|
7
6
|
import { ResultPage } from "./ResultPage.tsx";
|
|
8
7
|
import type { RemainingRoute } from "./remainingRoute.ts";
|
|
8
|
+
import { routeQueryOptions } from "./routeQuery.ts";
|
|
9
9
|
import type { ShellApi } from "./ShellApi.ts";
|
|
10
10
|
import { StartPage } from "./StartPage.tsx";
|
|
11
11
|
import { SystemMain } from "./SystemMain.tsx";
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import type { DocumentRequest } from "#browser/document/schema.ts";
|
|
2
|
-
import {
|
|
2
|
+
import type { RecordedResponse } from "#browser/responses/schema.ts";
|
|
3
|
+
import { chosenLabels } from "#client/responses/summary.ts";
|
|
4
|
+
import { Age } from "./Age.tsx";
|
|
5
|
+
import { AnswerMarkdown } from "./AnswerMarkdown.tsx";
|
|
3
6
|
import { shellIds } from "./shellIds.ts";
|
|
7
|
+
|
|
8
|
+
const KINDS = { "answer": "answered", "clarify": "asked back", "not_now": "said not now" } as const;
|
|
9
|
+
|
|
4
10
|
export function ResponseHistory({
|
|
5
11
|
request,
|
|
6
12
|
id = shellIds.responseHistory,
|
|
@@ -11,34 +17,67 @@ export function ResponseHistory({
|
|
|
11
17
|
const records = request?.responses ?? [];
|
|
12
18
|
const preview = request?.preview;
|
|
13
19
|
return (
|
|
14
|
-
<section id={id}>
|
|
15
|
-
<h2>Recorded responses</h2>
|
|
20
|
+
<section className="space-y-3 border-t pt-4" id={id}>
|
|
21
|
+
<h2 className="font-medium text-sm">Recorded responses</h2>
|
|
16
22
|
{records.length === 0 ? (
|
|
17
|
-
<p>No response is recorded
|
|
23
|
+
<p className="text-muted-foreground text-sm">No response is recorded yet.</p>
|
|
18
24
|
) : (
|
|
19
|
-
records.map((record) =>
|
|
25
|
+
records.map((record) => (
|
|
26
|
+
<ResponseEntry current={record.response.question === preview?.id} key={record.id} record={record} request={request} />
|
|
27
|
+
))
|
|
20
28
|
)}
|
|
21
29
|
</section>
|
|
22
30
|
);
|
|
23
31
|
}
|
|
24
|
-
function ResponseEntry({
|
|
32
|
+
function ResponseEntry({
|
|
33
|
+
record,
|
|
34
|
+
current,
|
|
35
|
+
request,
|
|
36
|
+
}: {
|
|
37
|
+
readonly record: RecordedResponse;
|
|
38
|
+
readonly current: boolean;
|
|
39
|
+
readonly request: DocumentRequest | undefined;
|
|
40
|
+
}) {
|
|
41
|
+
const answers = record.response.answers;
|
|
42
|
+
const chosen = chosenLabels(request?.prompts ?? [], answers);
|
|
43
|
+
const notes = (answers ?? []).map((answer) => answer.text.trim()).filter(Boolean);
|
|
25
44
|
return (
|
|
26
|
-
<article id={record.id}>
|
|
27
|
-
<h3>
|
|
28
|
-
<a href={`/responses/${record.id}.md`}>
|
|
29
|
-
{record.response.author}
|
|
45
|
+
<article className="space-y-2 rounded-lg bg-muted/50 px-4 py-3 text-sm" id={record.id}>
|
|
46
|
+
<h3 className="flex flex-wrap items-baseline gap-x-1.5 font-normal">
|
|
47
|
+
<a className="font-medium underline-offset-4 hover:underline" href={`/responses/${record.id}.md`}>
|
|
48
|
+
{record.response.author}
|
|
30
49
|
</a>
|
|
50
|
+
<span className="text-muted-foreground">{KINDS[record.response.type]}</span>
|
|
51
|
+
<Age modified={record.response.recordedAt} short />
|
|
31
52
|
</h3>
|
|
32
|
-
|
|
53
|
+
{answers === undefined ? (
|
|
54
|
+
<AnswerMarkdown file={`responses/${record.id}.md`} source={record.body} />
|
|
55
|
+
) : (
|
|
56
|
+
<>
|
|
57
|
+
<p>
|
|
58
|
+
<span className="text-muted-foreground">Chose </span>
|
|
59
|
+
<strong className="font-medium">{chosen || "no listed option"}</strong>
|
|
60
|
+
</p>
|
|
61
|
+
{notes.map((note) => (
|
|
62
|
+
<p className="whitespace-pre-wrap" key={note}>
|
|
63
|
+
{note}
|
|
64
|
+
</p>
|
|
65
|
+
))}
|
|
66
|
+
<details className="text-muted-foreground text-xs">
|
|
67
|
+
<summary className="cursor-pointer select-none">Full response</summary>
|
|
68
|
+
<AnswerMarkdown className="mt-2 text-foreground text-sm" file={`responses/${record.id}.md`} source={record.body} />
|
|
69
|
+
</details>
|
|
70
|
+
</>
|
|
71
|
+
)}
|
|
72
|
+
<p className="text-muted-foreground text-xs" title={record.response.reviewedRevision}>
|
|
33
73
|
{current ? "This reviewed revision" : "Earlier reviewed context — does not approve the current source"} ·{" "}
|
|
34
|
-
<code>{record.response.reviewedRevision}</code>
|
|
74
|
+
<code>{record.response.reviewedRevision.slice(0, 12)}</code>
|
|
35
75
|
</p>
|
|
36
76
|
{Boolean(record.response.supersedes) && (
|
|
37
|
-
<p>
|
|
77
|
+
<p className="text-muted-foreground text-xs">
|
|
38
78
|
Explicitly supersedes <a href={`/responses/${record.response.supersedes}.md`}>{record.response.supersedes}</a>.
|
|
39
79
|
</p>
|
|
40
80
|
)}
|
|
41
|
-
<ResponseMarkdown file={`responses/${record.id}.md`} source={record.body} />
|
|
42
81
|
</article>
|
|
43
82
|
);
|
|
44
83
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useContext } from "react";
|
|
2
|
-
import { routeQueryOptions } from "#client/page/routeQuery.ts";
|
|
3
2
|
import type { MainLocation } from "./mainLocation.ts";
|
|
4
3
|
import { ProjectionFrame } from "./ProjectionFrame.tsx";
|
|
4
|
+
import { routeQueryOptions } from "./routeQuery.ts";
|
|
5
5
|
import { SessionContext } from "./SessionContext.ts";
|
|
6
6
|
import type { ShellApi } from "./ShellApi.ts";
|
|
7
7
|
import { SystemPage } from "./SystemPage.tsx";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
1
2
|
import type { InboxProjection } from "#browser/views/schema.ts";
|
|
2
3
|
import { StatusChip } from "#client/react/components/ui/StatusChip.tsx";
|
|
3
4
|
import { Age } from "./Age.tsx";
|
|
@@ -13,7 +14,9 @@ export function TodayNeeds({ api, data }: { readonly api: ShellApi; readonly dat
|
|
|
13
14
|
<ul aria-label="Needs you" className="m-0 list-none divide-y rounded-lg border border-border p-0">
|
|
14
15
|
{data.you.map((item) => (
|
|
15
16
|
<li className="h-12 max-h-12" data-attention-id={item.id} key={`${item.file}:${item.href}`}>
|
|
16
|
-
<TodayRow
|
|
17
|
+
<TodayRow item={item} status="needs-you">
|
|
18
|
+
<TodayOptions api={api} item={item} />
|
|
19
|
+
</TodayRow>
|
|
17
20
|
</li>
|
|
18
21
|
))}
|
|
19
22
|
</ul>
|
|
@@ -22,13 +25,25 @@ export function TodayNeeds({ api, data }: { readonly api: ShellApi; readonly dat
|
|
|
22
25
|
);
|
|
23
26
|
}
|
|
24
27
|
|
|
25
|
-
function
|
|
28
|
+
export function TodayLater({ items }: { readonly items: readonly Item[] }) {
|
|
26
29
|
return (
|
|
27
|
-
<
|
|
30
|
+
<ul aria-label="Later" className="m-0 list-none divide-y rounded-lg border border-border p-0">
|
|
31
|
+
{items.map((item) => (
|
|
32
|
+
<li className="h-12 max-h-12" key={item.file}>
|
|
33
|
+
<TodayRow item={item} status="deferred" />
|
|
34
|
+
</li>
|
|
35
|
+
))}
|
|
36
|
+
</ul>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function TodayRow({ children, item, status }: { readonly children?: ReactNode; readonly item: Item; readonly status: "deferred" | "needs-you" }) {
|
|
41
|
+
return (
|
|
42
|
+
<div className="today-row flex h-full min-w-0 items-center gap-2 px-2" data-attention-row={status === "needs-you" ? "" : undefined}>
|
|
28
43
|
<StatusChip
|
|
29
|
-
aria-label="Needs you"
|
|
44
|
+
aria-label={status === "needs-you" ? "Needs you" : "Deferred"}
|
|
30
45
|
className="shrink-0 max-sm:size-6 max-sm:justify-center max-sm:gap-0 max-sm:px-1 max-sm:text-[0px] max-sm:[&_svg]:shrink-0"
|
|
31
|
-
status=
|
|
46
|
+
status={status}
|
|
32
47
|
/>
|
|
33
48
|
<div className="min-w-0 flex-1">
|
|
34
49
|
<div className="flex min-w-0 items-baseline gap-2">
|
|
@@ -48,7 +63,7 @@ function TodayRow({ api, item }: { readonly api: ShellApi; readonly item: Item }
|
|
|
48
63
|
<span className="shrink-0 text-[10px] text-muted-foreground tabular-nums">
|
|
49
64
|
{item.modified === undefined ? "Age ?" : <Age modified={item.modified} short />}
|
|
50
65
|
</span>
|
|
51
|
-
|
|
66
|
+
{children}
|
|
52
67
|
</div>
|
|
53
68
|
);
|
|
54
69
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { optionText } from "#browser/responses/cardContext.ts";
|
|
2
|
+
import { Button } from "#client/react/components/ui/Button.tsx";
|
|
3
|
+
|
|
4
|
+
export function TodayOptionButton({
|
|
5
|
+
disabled,
|
|
6
|
+
onChoose,
|
|
7
|
+
option,
|
|
8
|
+
reason,
|
|
9
|
+
recommended,
|
|
10
|
+
source,
|
|
11
|
+
}: {
|
|
12
|
+
readonly disabled: boolean;
|
|
13
|
+
readonly onChoose: () => void;
|
|
14
|
+
readonly option: { readonly id: string; readonly source: string };
|
|
15
|
+
readonly reason: string;
|
|
16
|
+
readonly recommended: string | undefined;
|
|
17
|
+
readonly source: { readonly label: string; readonly description: string } | undefined;
|
|
18
|
+
}) {
|
|
19
|
+
const authored = optionText(option.id, option.source, reason);
|
|
20
|
+
const text = source?.label ?? authored.label;
|
|
21
|
+
const description = source?.description ?? authored.description;
|
|
22
|
+
return (
|
|
23
|
+
<Button
|
|
24
|
+
className="h-auto w-full flex-col items-start gap-0.5 whitespace-normal px-3 py-2 text-left"
|
|
25
|
+
disabled={disabled}
|
|
26
|
+
onClick={onChoose}
|
|
27
|
+
size="sm"
|
|
28
|
+
variant="outline"
|
|
29
|
+
>
|
|
30
|
+
<span>
|
|
31
|
+
{text}
|
|
32
|
+
{recommended === text ? " · Recommended" : null}
|
|
33
|
+
</span>
|
|
34
|
+
{description ? <span className="font-normal text-muted-foreground text-xs">{description}</span> : null}
|
|
35
|
+
</Button>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
@@ -4,18 +4,20 @@ import { useContext, useMemo, useState } from "react";
|
|
|
4
4
|
import { useAction, useQuery } from "@shivaedev/effect-react/result-state.ts";
|
|
5
5
|
import type { Document, DocumentRequest } from "#browser/document/schema.ts";
|
|
6
6
|
import { answerBody } from "#browser/responses/answerBody.ts";
|
|
7
|
-
import {
|
|
7
|
+
import { promptHeading } from "#browser/responses/cardContext.ts";
|
|
8
|
+
import { reasonMarkdown } from "#browser/responses/reasonMarkdown.ts";
|
|
8
9
|
import type { InboxProjection } from "#browser/views/schema.ts";
|
|
9
|
-
import { documentQuery, navigationQuery, routeQueryOptions } from "#client/page/routeQuery.ts";
|
|
10
|
-
import { Button } from "#client/react/components/ui/Button.tsx";
|
|
11
10
|
import { Popover } from "#client/react/components/ui/Popover.tsx";
|
|
12
11
|
import { authorLabel } from "#client/responses/authorLabel.ts";
|
|
12
|
+
import { chosenLabels } from "#client/responses/summary.ts";
|
|
13
13
|
import { saveFailure } from "#client/saveFailure.ts";
|
|
14
14
|
import { fileUrl } from "#files/url.ts";
|
|
15
15
|
import { responseUrl } from "#responses/url.ts";
|
|
16
16
|
import { createResponse } from "./createResponse.ts";
|
|
17
17
|
import { useFormClient } from "./FormContext.ts";
|
|
18
|
+
import { documentQuery, navigationQuery, routeQueryOptions } from "./routeQuery.ts";
|
|
18
19
|
import type { ShellApi } from "./ShellApi.ts";
|
|
20
|
+
import { TodayOptionButton } from "./TodayOptionButton.tsx";
|
|
19
21
|
|
|
20
22
|
export function TodayOptions({ api, item }: { readonly api: ShellApi; readonly item: InboxProjection["you"][number] }) {
|
|
21
23
|
const query = useQuery(documentQuery(api, fileUrl(item.file)), { keepPreviousData: true });
|
|
@@ -28,11 +30,11 @@ export function TodayOptions({ api, item }: { readonly api: ShellApi; readonly i
|
|
|
28
30
|
&& !request.promptUnavailable
|
|
29
31
|
&& request.prompts?.length === 1
|
|
30
32
|
&& request.prompts[0]?.mode === "one" ? (
|
|
31
|
-
<Popover label={`Answer ${item.title}`} trigger="Answer" triggerClassName="h-8 w-auto px-1 text-xs">
|
|
32
|
-
<a className="mb-3 block text-xs" href={item.href}>
|
|
33
|
-
Open full question
|
|
34
|
-
</a>
|
|
33
|
+
<Popover className="w-80" label={`Answer ${item.title}`} trigger="Answer" triggerClassName="h-8 w-auto px-1 text-xs">
|
|
35
34
|
<InlineOptions api={api} document={data} key={request.preview.reviewedRevision} request={request} />
|
|
35
|
+
<a className="mt-3 block border-t px-2 pt-2 text-muted-foreground text-xs hover:text-foreground" href={item.href}>
|
|
36
|
+
Open the full question with its context →
|
|
37
|
+
</a>
|
|
36
38
|
</Popover>
|
|
37
39
|
) : (
|
|
38
40
|
<a aria-label={`Answer ${item.title}`} className="shrink-0 text-xs" href={item.href}>
|
|
@@ -78,7 +80,9 @@ function InlineOptions({ api, document: data, request }: { readonly api: ShellAp
|
|
|
78
80
|
const action = useAction(actionAtom);
|
|
79
81
|
const failure = Option.getOrUndefined(Option.flatMap(action.cause, Cause.findErrorOption));
|
|
80
82
|
const saved = Option.getOrUndefined(action.data);
|
|
81
|
-
let status = saved
|
|
83
|
+
let status = saved
|
|
84
|
+
? `Saved: your answer “${chosenLabels(request.prompts ?? [], saved.answers)}” is recorded. The agent reads it the next time it checks.`
|
|
85
|
+
: "";
|
|
82
86
|
if (failure) {
|
|
83
87
|
status = typeof failure === "string" ? failure : saveFailure(failure, "response").text;
|
|
84
88
|
}
|
|
@@ -86,33 +90,37 @@ function InlineOptions({ api, document: data, request }: { readonly api: ShellAp
|
|
|
86
90
|
status = "Pending: registering reviewed context, then recording response…";
|
|
87
91
|
}
|
|
88
92
|
const prompt = request.prompts?.[0];
|
|
93
|
+
const reason = reasonMarkdown(request.preview?.reason ?? "").split("\n")[0];
|
|
89
94
|
return (
|
|
90
|
-
<fieldset aria-label={`Options for ${data.identity}`} className="m-0 min-w-0 space-y-
|
|
91
|
-
<
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
);
|
|
106
|
-
})}
|
|
95
|
+
<fieldset aria-label={`Options for ${data.identity}`} className="m-0 min-w-0 space-y-3 border-0 px-2 pb-1">
|
|
96
|
+
{Boolean(reason) && <p className="m-0 font-medium text-sm">{reason}</p>}
|
|
97
|
+
{prompt ? <p className="m-0 text-muted-foreground text-xs">{promptHeading(prompt.source).title ?? "Choose one option."}</p> : null}
|
|
98
|
+
<div className="grid gap-2">
|
|
99
|
+
{prompt?.options.map((option, index) => (
|
|
100
|
+
<TodayOptionButton
|
|
101
|
+
disabled={!(data.writable && author.trim()) || action.pending || Boolean(saved)}
|
|
102
|
+
key={option.id}
|
|
103
|
+
onChoose={() => action.dispatch(option.id)}
|
|
104
|
+
option={option}
|
|
105
|
+
reason={request.preview?.reason ?? ""}
|
|
106
|
+
recommended={data.metadata.recommended}
|
|
107
|
+
source={data.metadata.options?.[index]}
|
|
108
|
+
/>
|
|
109
|
+
))}
|
|
107
110
|
</div>
|
|
108
111
|
<details className="text-muted-foreground text-xs">
|
|
109
112
|
<summary className="cursor-pointer">Answer as {author || "…"}</summary>
|
|
110
|
-
<label>
|
|
113
|
+
<label className="mt-2 flex items-center gap-2">
|
|
111
114
|
Local author label{" "}
|
|
112
|
-
<input
|
|
115
|
+
<input
|
|
116
|
+
className="rounded border bg-background px-2 py-1"
|
|
117
|
+
maxLength={200}
|
|
118
|
+
onChange={(event) => setAuthor(event.currentTarget.value)}
|
|
119
|
+
value={author}
|
|
120
|
+
/>
|
|
113
121
|
</label>
|
|
114
122
|
</details>
|
|
115
|
-
{!data.writable && <p className="m-0 text-muted-foreground text-xs">
|
|
123
|
+
{!data.writable && <p className="m-0 text-muted-foreground text-xs">This Board is read-only. Start it with --responses to record answers.</p>}
|
|
116
124
|
{Boolean(status) && (
|
|
117
125
|
<p className="m-0 text-xs" role="status">
|
|
118
126
|
{status}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { Option } from "effect";
|
|
2
2
|
import { useQuery } from "@shivaedev/effect-react/result-state.ts";
|
|
3
3
|
import type { InboxProjection } from "#browser/views/schema.ts";
|
|
4
|
-
import { navigationQuery, routeQueryOptions } from "#client/page/routeQuery.ts";
|
|
5
4
|
import { fileUrl } from "#files/url.ts";
|
|
6
5
|
import { inProgressItems } from "./inProgressItems.ts";
|
|
6
|
+
import { navigationQuery, routeQueryOptions } from "./routeQuery.ts";
|
|
7
7
|
import type { ShellApi } from "./ShellApi.ts";
|
|
8
8
|
import { TodayGoals } from "./TodayGoals.tsx";
|
|
9
|
-
import { TodayNeeds } from "./TodayNeeds.tsx";
|
|
9
|
+
import { TodayLater, TodayNeeds } from "./TodayNeeds.tsx";
|
|
10
10
|
import { TodayProgress } from "./TodayProgress.tsx";
|
|
11
11
|
|
|
12
|
-
const todayIds = { goals: "today-goals", needs: "needs-you", progress: "in-progress" };
|
|
12
|
+
const todayIds = { goals: "today-goals", later: "later", needs: "needs-you", progress: "in-progress" };
|
|
13
13
|
|
|
14
14
|
export function TodayPage({ api, data }: { readonly api: ShellApi; readonly data: InboxProjection }) {
|
|
15
15
|
const query = useQuery(api.goals.query(undefined, routeQueryOptions), { keepPreviousData: true });
|
|
@@ -43,6 +43,7 @@ export function TodayPage({ api, data }: { readonly api: ShellApi; readonly data
|
|
|
43
43
|
<h2 className="mt-0 mb-3 font-semibold text-lg">In progress</h2>
|
|
44
44
|
<TodayProgress data={fleet} failed={Option.isSome(fleetQuery.cause)} />
|
|
45
45
|
</section>
|
|
46
|
+
{data.complete && data.later.length > 0 && <Later items={data.later} />}
|
|
46
47
|
</div>
|
|
47
48
|
<section className="min-w-0" id={todayIds.goals}>
|
|
48
49
|
<h2 className="mt-0 mb-3 font-semibold text-lg">Goals</h2>
|
|
@@ -67,3 +68,17 @@ function NeedsYou({ api, data }: { readonly api: ShellApi; readonly data: InboxP
|
|
|
67
68
|
</section>
|
|
68
69
|
);
|
|
69
70
|
}
|
|
71
|
+
|
|
72
|
+
function Later({ items }: { readonly items: InboxProjection["later"] }) {
|
|
73
|
+
return (
|
|
74
|
+
<section className="min-w-0" id={todayIds.later}>
|
|
75
|
+
<details>
|
|
76
|
+
<summary className="mb-3 cursor-pointer">
|
|
77
|
+
<h2 className="m-0 inline font-semibold text-lg">Later</h2>
|
|
78
|
+
<span className="ml-2 text-muted-foreground text-sm tabular-nums">{items.length}</span>
|
|
79
|
+
</summary>
|
|
80
|
+
<TodayLater items={items} />
|
|
81
|
+
</details>
|
|
82
|
+
</section>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Cause } from "effect";
|
|
2
2
|
import * as Atom from "effect/reactivity/Atom";
|
|
3
|
-
import { resolvedDocumentFailure } from "#client/page/resolvedDocumentFailure.ts";
|
|
4
3
|
import { pageQueries } from "./pageQueries.ts";
|
|
4
|
+
import { resolvedDocumentFailure } from "./resolvedDocumentFailure.ts";
|
|
5
5
|
import type { ShellApi } from "./ShellApi.ts";
|
|
6
6
|
|
|
7
7
|
function health(value: { readonly _tag: string; readonly waiting: boolean; readonly cause?: Cause.Cause<unknown> }) {
|
|
@@ -2,13 +2,13 @@ import { isRedirect, type LoaderFnContext, redirect } from "@tanstack/react-rout
|
|
|
2
2
|
import { Predicate } from "effect";
|
|
3
3
|
import type * as AtomRegistry from "effect/reactivity/AtomRegistry";
|
|
4
4
|
import { loadQuery } from "@shivaedev/effect-react/router.ts";
|
|
5
|
-
import { documentQuery, navigationQuery } from "#client/page/routeQuery.ts";
|
|
6
5
|
import type { ShellOptions } from "./BoardShell.tsx";
|
|
7
6
|
import { documentRoute } from "./documentRoute.ts";
|
|
8
7
|
import { loadProjection } from "./loadProjection.ts";
|
|
9
8
|
import { loadRemaining } from "./loadRemaining.ts";
|
|
10
9
|
import { projectionRoute } from "./projectionRoute.ts";
|
|
11
10
|
import { remainingRoute } from "./remainingRoute.ts";
|
|
11
|
+
import { documentQuery, navigationQuery } from "./routeQuery.ts";
|
|
12
12
|
|
|
13
13
|
export type RouterShell = ShellOptions & { readonly registry: AtomRegistry.AtomRegistry };
|
|
14
14
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type * as AtomRegistry from "effect/reactivity/AtomRegistry";
|
|
2
2
|
import { loadQuery } from "@shivaedev/effect-react/router.ts";
|
|
3
|
-
import { routeQueryOptions } from "#client/page/routeQuery.ts";
|
|
4
3
|
import { pageQueries } from "./pageQueries.ts";
|
|
5
4
|
import type { ProjectionRoute } from "./projectionRoute.ts";
|
|
5
|
+
import { routeQueryOptions } from "./routeQuery.ts";
|
|
6
6
|
import type { ShellApi } from "./ShellApi.ts";
|
|
7
7
|
export function loadProjection(
|
|
8
8
|
registry: AtomRegistry.AtomRegistry,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type * as AtomRegistry from "effect/reactivity/AtomRegistry";
|
|
2
2
|
import { loadQuery } from "@shivaedev/effect-react/router.ts";
|
|
3
|
-
import { routeQueryOptions } from "#client/page/routeQuery.ts";
|
|
4
3
|
import type { RemainingRoute } from "./remainingRoute.ts";
|
|
4
|
+
import { routeQueryOptions } from "./routeQuery.ts";
|
|
5
5
|
import type { ShellApi } from "./ShellApi.ts";
|
|
6
6
|
export function loadRemaining(
|
|
7
7
|
registry: AtomRegistry.AtomRegistry,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type * as AsyncResult from "effect/reactivity/AsyncResult";
|
|
2
2
|
import type * as Atom from "effect/reactivity/Atom";
|
|
3
|
-
import { routeQueryOptions } from "
|
|
3
|
+
import { routeQueryOptions } from "./routeQuery.ts";
|
|
4
4
|
import type { ShellApi } from "./ShellApi.ts";
|
|
5
5
|
|
|
6
6
|
export function pageQueries(api: ShellApi, kind: string, url: string): readonly Atom.Atom<AsyncResult.AsyncResult<unknown, unknown>>[] {
|
|
@@ -11,7 +11,7 @@ import { authorLabel } from "#client/responses/authorLabel.ts";
|
|
|
11
11
|
import { type ResponseInput, responseFormSchema } from "#client/responses/formSchema.ts";
|
|
12
12
|
import { responsePreview } from "#client/responses/preview.ts";
|
|
13
13
|
import { retainContext } from "#client/responses/retainContext.ts";
|
|
14
|
-
import { responseFeedback, responseSummary } from "#client/responses/summary.ts";
|
|
14
|
+
import { chosenLabels, responseFeedback, responseSummary } from "#client/responses/summary.ts";
|
|
15
15
|
import { sourceChanged } from "#client/sourceChanged.ts";
|
|
16
16
|
import { createResponse } from "./createResponse.ts";
|
|
17
17
|
import { useFormClient } from "./FormContext.ts";
|
|
@@ -116,7 +116,9 @@ export function useResponseForm(source: QuestionPreview, prompts: readonly Promp
|
|
|
116
116
|
setInteraction("cleared");
|
|
117
117
|
}
|
|
118
118
|
const previewed = preview !== undefined && same && Equal.equals(preview, values);
|
|
119
|
-
const { outcome, text: status } = formStatus(created, interaction, "response", (saved) =>
|
|
119
|
+
const { outcome, text: status } = formStatus(created, interaction, "response", (saved) =>
|
|
120
|
+
responseSaved(saved.id, created.dirty, chosenLabels(prompts, saved.answers)),
|
|
121
|
+
);
|
|
120
122
|
const summary = responseSummary(values, prompts, answers(values), attempted);
|
|
121
123
|
return {
|
|
122
124
|
answers: answers(values),
|