@sanity/ailf-studio 0.1.25 → 0.1.27
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/dist/index.d.ts +41 -16
- package/dist/index.js +276 -58
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -7,22 +7,24 @@ import { DocumentRef } from './document-ref.js';
|
|
|
7
7
|
* actions/GraduateToNativeAction.tsx
|
|
8
8
|
*
|
|
9
9
|
* Sanity Studio document action that "graduates" a mirrored task to
|
|
10
|
-
* a native task by
|
|
10
|
+
* a native (Studio-owned) task by changing the `ownership` field from
|
|
11
|
+
* "repo" to "studio".
|
|
11
12
|
*
|
|
12
|
-
* This is a one-way
|
|
13
|
+
* This is a one-way operation. Once graduated:
|
|
13
14
|
* - The task becomes fully editable in Studio
|
|
14
|
-
* - Future pipeline mirror syncs will
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* - Future pipeline mirror syncs will skip this document (the mirror
|
|
16
|
+
* step checks `ownership` and skips documents with `ownership: "studio"`)
|
|
17
|
+
* - The `origin` field is preserved as provenance — you can always
|
|
18
|
+
* see where the task originally came from
|
|
18
19
|
* - The task's _id is unchanged — it keeps the mirror prefix
|
|
19
20
|
* (ailf.task.mirror.*) but that's just an ID string, not a
|
|
20
21
|
* behavioral marker
|
|
21
22
|
*
|
|
22
|
-
* The action only appears on ailf.task documents that have
|
|
23
|
-
*
|
|
23
|
+
* The action only appears on ailf.task documents that have
|
|
24
|
+
* `ownership: "repo"` (i.e., active mirrors). Native tasks and
|
|
25
|
+
* already-graduated tasks never see it.
|
|
24
26
|
*
|
|
25
|
-
* @see docs/exec-plans/
|
|
27
|
+
* @see docs/exec-plans/task-lifecycle/phase-1-ownership.md
|
|
26
28
|
*/
|
|
27
29
|
|
|
28
30
|
declare const GraduateToNativeAction: DocumentActionComponent;
|
|
@@ -75,15 +77,29 @@ declare function ReleasePicker(props: StringInputProps): react_jsx_runtime.JSX.E
|
|
|
75
77
|
/**
|
|
76
78
|
* components/MirrorBanner.tsx
|
|
77
79
|
*
|
|
78
|
-
* Informational banner shown at the top of
|
|
79
|
-
*
|
|
80
|
-
* to the source file on GitHub.
|
|
80
|
+
* Informational banner shown at the top of task documents that have
|
|
81
|
+
* origin provenance (both active mirrors and graduated tasks).
|
|
81
82
|
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
83
|
+
* For active mirrors (`ownership: "repo"`): communicates that the task
|
|
84
|
+
* is managed in an external repo and links to the source file on GitHub.
|
|
84
85
|
*
|
|
85
|
-
*
|
|
86
|
+
* For graduated tasks (`ownership: "studio"` with origin): shows
|
|
87
|
+
* provenance info about where the task originally came from.
|
|
88
|
+
*
|
|
89
|
+
* Paired with `SyncStatusBadge` to show sync freshness for active mirrors.
|
|
90
|
+
*
|
|
91
|
+
* @see docs/exec-plans/task-lifecycle/phase-1-ownership.md
|
|
86
92
|
*/
|
|
93
|
+
interface GitAuthorInfo {
|
|
94
|
+
gitName?: string;
|
|
95
|
+
gitEmail?: string;
|
|
96
|
+
githubUsername?: string;
|
|
97
|
+
}
|
|
98
|
+
interface GraduatedByInfo {
|
|
99
|
+
sanityId?: string;
|
|
100
|
+
name?: string;
|
|
101
|
+
email?: string;
|
|
102
|
+
}
|
|
87
103
|
interface MirrorBannerProps {
|
|
88
104
|
origin: {
|
|
89
105
|
repo?: string;
|
|
@@ -93,9 +109,15 @@ interface MirrorBannerProps {
|
|
|
93
109
|
branch?: string;
|
|
94
110
|
commitSha?: string;
|
|
95
111
|
lastSyncedAt?: string;
|
|
112
|
+
author?: GitAuthorInfo;
|
|
113
|
+
lastEditor?: GitAuthorInfo;
|
|
114
|
+
graduatedAt?: string;
|
|
115
|
+
graduatedBy?: GraduatedByInfo;
|
|
96
116
|
};
|
|
117
|
+
/** Task ownership — "repo" for active mirrors, "studio" for graduated */
|
|
118
|
+
ownership?: string;
|
|
97
119
|
}
|
|
98
|
-
declare function MirrorBanner({ origin }: MirrorBannerProps): react_jsx_runtime.JSX.Element;
|
|
120
|
+
declare function MirrorBanner({ origin, ownership }: MirrorBannerProps): react_jsx_runtime.JSX.Element;
|
|
99
121
|
|
|
100
122
|
/**
|
|
101
123
|
* components/SyncStatusBadge.tsx
|
|
@@ -468,6 +490,8 @@ declare const taskSchema: {
|
|
|
468
490
|
description: string;
|
|
469
491
|
id: string;
|
|
470
492
|
origin: string;
|
|
493
|
+
ownership: string;
|
|
494
|
+
status: string;
|
|
471
495
|
}, Record<string, unknown>> | undefined;
|
|
472
496
|
};
|
|
473
497
|
|
|
@@ -551,6 +575,7 @@ interface ComparisonData {
|
|
|
551
575
|
generatedAt: string;
|
|
552
576
|
improved: string[];
|
|
553
577
|
noiseThreshold: number;
|
|
578
|
+
notEvaluated: string[];
|
|
554
579
|
regressed: string[];
|
|
555
580
|
unchanged: string[];
|
|
556
581
|
}
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { definePlugin } from "sanity";
|
|
|
5
5
|
import { EditIcon } from "@sanity/icons";
|
|
6
6
|
import { Box, Stack, Text } from "@sanity/ui";
|
|
7
7
|
import { useCallback, useState } from "react";
|
|
8
|
-
import { useClient } from "sanity";
|
|
8
|
+
import { useClient, useCurrentUser } from "sanity";
|
|
9
9
|
|
|
10
10
|
// src/lib/constants.ts
|
|
11
11
|
var API_VERSION = "2026-03-11";
|
|
@@ -15,6 +15,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
15
15
|
var GraduateToNativeAction = (props) => {
|
|
16
16
|
const { id, type, draft, published, onComplete } = props;
|
|
17
17
|
const client = useClient({ apiVersion: API_VERSION });
|
|
18
|
+
const currentUser = useCurrentUser();
|
|
18
19
|
const [isConfirming, setIsConfirming] = useState(false);
|
|
19
20
|
const doc = draft ?? published;
|
|
20
21
|
const origin = doc?.origin;
|
|
@@ -23,17 +24,35 @@ var GraduateToNativeAction = (props) => {
|
|
|
23
24
|
const handleGraduate = useCallback(async () => {
|
|
24
25
|
try {
|
|
25
26
|
const publishedId = id.replace(/^drafts\./, "");
|
|
26
|
-
|
|
27
|
+
const graduationPatch = {
|
|
28
|
+
ownership: "studio",
|
|
29
|
+
"origin.graduatedAt": (/* @__PURE__ */ new Date()).toISOString(),
|
|
30
|
+
"origin.graduatedBy": {
|
|
31
|
+
sanityId: currentUser?.id ?? "unknown",
|
|
32
|
+
name: currentUser?.name ?? "unknown",
|
|
33
|
+
email: currentUser?.email ?? "unknown"
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
await client.patch(publishedId).set(graduationPatch).commit();
|
|
27
37
|
if (draft) {
|
|
28
|
-
await client.patch(`drafts.${publishedId}`).
|
|
38
|
+
await client.patch(`drafts.${publishedId}`).set(graduationPatch).commit().catch(() => {
|
|
29
39
|
});
|
|
30
40
|
}
|
|
31
41
|
onComplete();
|
|
32
42
|
} catch (err) {
|
|
33
43
|
console.error("Failed to graduate task:", err);
|
|
34
44
|
}
|
|
35
|
-
}, [
|
|
36
|
-
|
|
45
|
+
}, [
|
|
46
|
+
client,
|
|
47
|
+
currentUser?.email,
|
|
48
|
+
currentUser?.id,
|
|
49
|
+
currentUser?.name,
|
|
50
|
+
draft,
|
|
51
|
+
id,
|
|
52
|
+
onComplete
|
|
53
|
+
]);
|
|
54
|
+
const ownership = doc?.ownership;
|
|
55
|
+
if (type !== "ailf.task" || ownership !== "repo") return null;
|
|
37
56
|
return {
|
|
38
57
|
dialog: isConfirming ? {
|
|
39
58
|
type: "confirm",
|
|
@@ -44,8 +63,8 @@ var GraduateToNativeAction = (props) => {
|
|
|
44
63
|
/* @__PURE__ */ jsx("strong", { children: repoDisplay }),
|
|
45
64
|
" and make it fully editable in Studio."
|
|
46
65
|
] }),
|
|
47
|
-
/* @__PURE__ */ jsx(Text, { weight: "semibold", children: "\u26A0\uFE0F This is a one-way operation. The task will no longer sync from the repo
|
|
48
|
-
repoUrl && /* @__PURE__ */ jsxs(Text, { size: 1, muted: true, children: [
|
|
66
|
+
/* @__PURE__ */ jsx(Text, { weight: "semibold", children: "\u26A0\uFE0F This is a one-way operation. The task will no longer sync from the repo \u2014 future mirror syncs will not overwrite your edits. The task will continue to run in evaluations. Source repo provenance is preserved for reference." }),
|
|
67
|
+
repoUrl && origin && /* @__PURE__ */ jsxs(Text, { size: 1, muted: true, children: [
|
|
49
68
|
"Current source:",
|
|
50
69
|
" ",
|
|
51
70
|
/* @__PURE__ */ jsx("a", { href: repoUrl, target: "_blank", rel: "noopener noreferrer", children: origin.path }),
|
|
@@ -62,7 +81,7 @@ var GraduateToNativeAction = (props) => {
|
|
|
62
81
|
icon: EditIcon,
|
|
63
82
|
label: "Graduate to native task",
|
|
64
83
|
onHandle: () => setIsConfirming(true),
|
|
65
|
-
title: "
|
|
84
|
+
title: "Transfer ownership to Studio so this task becomes fully editable. Source repo provenance is preserved.",
|
|
66
85
|
tone: "caution"
|
|
67
86
|
};
|
|
68
87
|
};
|
|
@@ -74,7 +93,7 @@ import { useToast } from "@sanity/ui";
|
|
|
74
93
|
import { useCallback as useCallback2, useEffect, useRef, useState as useState2 } from "react";
|
|
75
94
|
import {
|
|
76
95
|
useClient as useClient2,
|
|
77
|
-
useCurrentUser,
|
|
96
|
+
useCurrentUser as useCurrentUser2,
|
|
78
97
|
useDataset,
|
|
79
98
|
useProjectId
|
|
80
99
|
} from "sanity";
|
|
@@ -184,7 +203,7 @@ var RunTaskEvaluationAction = (props) => {
|
|
|
184
203
|
const client = useClient2({ apiVersion: API_VERSION });
|
|
185
204
|
const dataset = useDataset();
|
|
186
205
|
const projectId = useProjectId();
|
|
187
|
-
const currentUser =
|
|
206
|
+
const currentUser = useCurrentUser2();
|
|
188
207
|
const toast = useToast();
|
|
189
208
|
const [state, setState] = useState2({ status: "idle" });
|
|
190
209
|
const requestedAtRef = useRef(null);
|
|
@@ -1537,6 +1556,13 @@ var reportSchema = defineType4({
|
|
|
1537
1556
|
title: "Unchanged Areas",
|
|
1538
1557
|
type: "array"
|
|
1539
1558
|
}),
|
|
1559
|
+
defineField4({
|
|
1560
|
+
name: "notEvaluated",
|
|
1561
|
+
of: [{ type: "string" }],
|
|
1562
|
+
title: "Not Evaluated Areas",
|
|
1563
|
+
description: "Areas present in only one of the two runs (e.g., auto-scoped release eval vs full baseline).",
|
|
1564
|
+
type: "array"
|
|
1565
|
+
}),
|
|
1540
1566
|
defineField4({
|
|
1541
1567
|
name: "noiseThreshold",
|
|
1542
1568
|
title: "Noise Threshold",
|
|
@@ -1872,6 +1898,7 @@ function CanonicalDocPreview(props) {
|
|
|
1872
1898
|
|
|
1873
1899
|
// src/components/OriginInput.tsx
|
|
1874
1900
|
import { Stack as Stack5 } from "@sanity/ui";
|
|
1901
|
+
import { useFormValue } from "sanity";
|
|
1875
1902
|
|
|
1876
1903
|
// src/components/MirrorBanner.tsx
|
|
1877
1904
|
import { LinkIcon } from "@sanity/icons";
|
|
@@ -1918,32 +1945,45 @@ function SyncStatusBadge({
|
|
|
1918
1945
|
}
|
|
1919
1946
|
|
|
1920
1947
|
// src/components/MirrorBanner.tsx
|
|
1921
|
-
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1922
|
-
function
|
|
1948
|
+
import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1949
|
+
function formatAuthor(author) {
|
|
1950
|
+
if (!author) return null;
|
|
1951
|
+
const parts = [];
|
|
1952
|
+
if (author.gitName) parts.push(author.gitName);
|
|
1953
|
+
if (author.githubUsername) parts.push(`(${author.githubUsername})`);
|
|
1954
|
+
if (parts.length === 0 && author.gitEmail) parts.push(author.gitEmail);
|
|
1955
|
+
return parts.length > 0 ? parts.join(" ") : null;
|
|
1956
|
+
}
|
|
1957
|
+
function MirrorBanner({ origin, ownership }) {
|
|
1923
1958
|
const { repo, path, branch, commitSha, lastSyncedAt } = origin;
|
|
1959
|
+
const isGraduated = ownership === "studio";
|
|
1924
1960
|
const repoUrl = repo && path && branch ? `https://github.com/${repo}/blob/${branch}/${path}` : null;
|
|
1925
1961
|
const repoDisplay = repo ?? "an external repository";
|
|
1962
|
+
const repoLink = repoUrl ? /* @__PURE__ */ jsx6(
|
|
1963
|
+
"a",
|
|
1964
|
+
{
|
|
1965
|
+
href: repoUrl,
|
|
1966
|
+
target: "_blank",
|
|
1967
|
+
rel: "noopener noreferrer",
|
|
1968
|
+
style: { fontWeight: 600 },
|
|
1969
|
+
children: repoDisplay
|
|
1970
|
+
}
|
|
1971
|
+
) : /* @__PURE__ */ jsx6("strong", { children: repoDisplay });
|
|
1926
1972
|
return /* @__PURE__ */ jsx6(Card3, { padding: 3, radius: 2, tone: "transparent", border: true, children: /* @__PURE__ */ jsxs6(Stack4, { space: 3, children: [
|
|
1927
1973
|
/* @__PURE__ */ jsxs6(Flex4, { align: "center", gap: 2, children: [
|
|
1928
1974
|
/* @__PURE__ */ jsx6(Text6, { size: 2, children: /* @__PURE__ */ jsx6(LinkIcon, {}) }),
|
|
1929
|
-
/* @__PURE__ */
|
|
1930
|
-
"This task
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
target: "_blank",
|
|
1937
|
-
rel: "noopener noreferrer",
|
|
1938
|
-
style: { fontWeight: 600 },
|
|
1939
|
-
children: repoDisplay
|
|
1940
|
-
}
|
|
1941
|
-
) : /* @__PURE__ */ jsx6("strong", { children: repoDisplay }),
|
|
1975
|
+
/* @__PURE__ */ jsx6(Text6, { size: 2, children: isGraduated ? /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
1976
|
+
"This task was originally mirrored from ",
|
|
1977
|
+
repoLink,
|
|
1978
|
+
" and has been graduated to Studio ownership."
|
|
1979
|
+
] }) : /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
1980
|
+
"This task is managed in ",
|
|
1981
|
+
repoLink,
|
|
1942
1982
|
". Edit it there to make changes."
|
|
1943
|
-
] })
|
|
1983
|
+
] }) })
|
|
1944
1984
|
] }),
|
|
1945
1985
|
/* @__PURE__ */ jsxs6(Flex4, { align: "center", gap: 2, wrap: "wrap", children: [
|
|
1946
|
-
lastSyncedAt && /* @__PURE__ */ jsx6(
|
|
1986
|
+
!isGraduated && lastSyncedAt && /* @__PURE__ */ jsx6(
|
|
1947
1987
|
SyncStatusBadge,
|
|
1948
1988
|
{
|
|
1949
1989
|
lastSyncedAt,
|
|
@@ -1956,6 +1996,19 @@ function MirrorBanner({ origin }) {
|
|
|
1956
1996
|
commitSha ? ` @ ${commitSha.slice(0, 7)}` : ""
|
|
1957
1997
|
] }),
|
|
1958
1998
|
path && /* @__PURE__ */ jsx6(Text6, { size: 1, muted: true, children: path })
|
|
1999
|
+
] }),
|
|
2000
|
+
isGraduated && origin.graduatedBy?.name && /* @__PURE__ */ jsxs6(Text6, { size: 1, muted: true, children: [
|
|
2001
|
+
"Graduated by ",
|
|
2002
|
+
origin.graduatedBy.name,
|
|
2003
|
+
origin.graduatedAt && ` \xB7 ${new Date(origin.graduatedAt).toLocaleDateString()}`
|
|
2004
|
+
] }),
|
|
2005
|
+
!isGraduated && formatAuthor(origin.lastEditor) && /* @__PURE__ */ jsxs6(Text6, { size: 1, muted: true, children: [
|
|
2006
|
+
"Last edited by ",
|
|
2007
|
+
formatAuthor(origin.lastEditor)
|
|
2008
|
+
] }),
|
|
2009
|
+
isGraduated && formatAuthor(origin.author) && /* @__PURE__ */ jsxs6(Text6, { size: 1, muted: true, children: [
|
|
2010
|
+
"Originally authored by ",
|
|
2011
|
+
formatAuthor(origin.author)
|
|
1959
2012
|
] })
|
|
1960
2013
|
] }) });
|
|
1961
2014
|
}
|
|
@@ -1965,17 +2018,25 @@ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
|
1965
2018
|
function OriginInput(props) {
|
|
1966
2019
|
const value = props.value;
|
|
1967
2020
|
if (!value) return props.renderDefault(props);
|
|
2021
|
+
const str = (key) => typeof value[key] === "string" ? value[key] : void 0;
|
|
2022
|
+
const obj = (key) => value[key] !== null && typeof value[key] === "object" ? value[key] : void 0;
|
|
1968
2023
|
const origin = {
|
|
1969
|
-
repo:
|
|
1970
|
-
repoOwner:
|
|
1971
|
-
repoName:
|
|
1972
|
-
path:
|
|
1973
|
-
branch:
|
|
1974
|
-
commitSha:
|
|
1975
|
-
lastSyncedAt:
|
|
2024
|
+
repo: str("repo"),
|
|
2025
|
+
repoOwner: str("repoOwner"),
|
|
2026
|
+
repoName: str("repoName"),
|
|
2027
|
+
path: str("path"),
|
|
2028
|
+
branch: str("branch"),
|
|
2029
|
+
commitSha: str("commitSha"),
|
|
2030
|
+
lastSyncedAt: str("lastSyncedAt"),
|
|
2031
|
+
author: obj("author"),
|
|
2032
|
+
lastEditor: obj("lastEditor"),
|
|
2033
|
+
graduatedAt: str("graduatedAt"),
|
|
2034
|
+
graduatedBy: obj("graduatedBy")
|
|
1976
2035
|
};
|
|
2036
|
+
const ownershipValue = useFormValue(["ownership"]);
|
|
2037
|
+
const ownership = typeof ownershipValue === "string" ? ownershipValue : void 0;
|
|
1977
2038
|
return /* @__PURE__ */ jsxs7(Stack5, { space: 3, children: [
|
|
1978
|
-
/* @__PURE__ */ jsx7(MirrorBanner, { origin }),
|
|
2039
|
+
/* @__PURE__ */ jsx7(MirrorBanner, { origin, ownership }),
|
|
1979
2040
|
props.renderDefault(props)
|
|
1980
2041
|
] });
|
|
1981
2042
|
}
|
|
@@ -2147,6 +2208,57 @@ var taskSchema = defineType5({
|
|
|
2147
2208
|
validation: (rule) => rule.required()
|
|
2148
2209
|
}),
|
|
2149
2210
|
// -----------------------------------------------------------------------
|
|
2211
|
+
// Ownership — who is the source of truth for this task
|
|
2212
|
+
//
|
|
2213
|
+
// "studio" tasks are fully editable in Studio. "repo" tasks are managed
|
|
2214
|
+
// in an external repository and read-only in Studio. Mirrored tasks are
|
|
2215
|
+
// set to "repo" by the pipeline; graduation changes this to "studio".
|
|
2216
|
+
//
|
|
2217
|
+
// Absent = "studio" for backwards compatibility with existing native tasks.
|
|
2218
|
+
// -----------------------------------------------------------------------
|
|
2219
|
+
defineField5({
|
|
2220
|
+
description: 'Who is the source of truth for this task. "studio" tasks are fully editable here. "repo" tasks are managed in an external repository and read-only in Studio.',
|
|
2221
|
+
group: ["optional", "all-fields"],
|
|
2222
|
+
hidden: true,
|
|
2223
|
+
// Managed by system actions, not manually edited
|
|
2224
|
+
initialValue: "studio",
|
|
2225
|
+
name: "ownership",
|
|
2226
|
+
options: {
|
|
2227
|
+
list: [
|
|
2228
|
+
{ title: "Studio", value: "studio" },
|
|
2229
|
+
{ title: "Repository", value: "repo" }
|
|
2230
|
+
]
|
|
2231
|
+
},
|
|
2232
|
+
title: "Ownership",
|
|
2233
|
+
type: "string"
|
|
2234
|
+
}),
|
|
2235
|
+
// -----------------------------------------------------------------------
|
|
2236
|
+
// Status — task lifecycle state
|
|
2237
|
+
//
|
|
2238
|
+
// Active tasks run in evaluations and appear in default list views.
|
|
2239
|
+
// Exploratory tasks are excluded from production evals (for testing).
|
|
2240
|
+
// Archived tasks are retired, hidden from default views, and preserved
|
|
2241
|
+
// for historical report references.
|
|
2242
|
+
// -----------------------------------------------------------------------
|
|
2243
|
+
defineField5({
|
|
2244
|
+
description: "Task lifecycle status. Active tasks run in evaluations. Draft tasks are work-in-progress, excluded from production evals. Paused tasks are temporarily suspended. Archived tasks are retired and excluded from evaluations.",
|
|
2245
|
+
group: ["main", "all-fields"],
|
|
2246
|
+
initialValue: "active",
|
|
2247
|
+
name: "status",
|
|
2248
|
+
options: {
|
|
2249
|
+
direction: "horizontal",
|
|
2250
|
+
layout: "radio",
|
|
2251
|
+
list: [
|
|
2252
|
+
{ title: "Active", value: "active" },
|
|
2253
|
+
{ title: "Draft", value: "draft" },
|
|
2254
|
+
{ title: "Paused", value: "paused" },
|
|
2255
|
+
{ title: "Archived", value: "archived" }
|
|
2256
|
+
]
|
|
2257
|
+
},
|
|
2258
|
+
title: "Status",
|
|
2259
|
+
type: "string"
|
|
2260
|
+
}),
|
|
2261
|
+
// -----------------------------------------------------------------------
|
|
2150
2262
|
// Task prompt
|
|
2151
2263
|
// -----------------------------------------------------------------------
|
|
2152
2264
|
defineField5({
|
|
@@ -2679,6 +2791,95 @@ var taskSchema = defineType5({
|
|
|
2679
2791
|
readOnly: true,
|
|
2680
2792
|
title: "Last Synced At",
|
|
2681
2793
|
type: "datetime"
|
|
2794
|
+
}),
|
|
2795
|
+
// --- Authorship tracking (Phase 4: Task Lifecycle) ---
|
|
2796
|
+
defineField5({
|
|
2797
|
+
description: "Who originally created this task in the source repo. Set on first mirror, never overwritten on subsequent syncs.",
|
|
2798
|
+
fields: [
|
|
2799
|
+
defineField5({
|
|
2800
|
+
name: "gitName",
|
|
2801
|
+
readOnly: true,
|
|
2802
|
+
title: "Git Name",
|
|
2803
|
+
type: "string"
|
|
2804
|
+
}),
|
|
2805
|
+
defineField5({
|
|
2806
|
+
name: "gitEmail",
|
|
2807
|
+
readOnly: true,
|
|
2808
|
+
title: "Git Email",
|
|
2809
|
+
type: "string"
|
|
2810
|
+
}),
|
|
2811
|
+
defineField5({
|
|
2812
|
+
name: "githubUsername",
|
|
2813
|
+
readOnly: true,
|
|
2814
|
+
title: "GitHub Username",
|
|
2815
|
+
type: "string"
|
|
2816
|
+
})
|
|
2817
|
+
],
|
|
2818
|
+
name: "author",
|
|
2819
|
+
readOnly: true,
|
|
2820
|
+
title: "Original Author",
|
|
2821
|
+
type: "object"
|
|
2822
|
+
}),
|
|
2823
|
+
defineField5({
|
|
2824
|
+
description: "Who last modified this task in the source repo. Updated on every content-changing mirror sync.",
|
|
2825
|
+
fields: [
|
|
2826
|
+
defineField5({
|
|
2827
|
+
name: "gitName",
|
|
2828
|
+
readOnly: true,
|
|
2829
|
+
title: "Git Name",
|
|
2830
|
+
type: "string"
|
|
2831
|
+
}),
|
|
2832
|
+
defineField5({
|
|
2833
|
+
name: "gitEmail",
|
|
2834
|
+
readOnly: true,
|
|
2835
|
+
title: "Git Email",
|
|
2836
|
+
type: "string"
|
|
2837
|
+
}),
|
|
2838
|
+
defineField5({
|
|
2839
|
+
name: "githubUsername",
|
|
2840
|
+
readOnly: true,
|
|
2841
|
+
title: "GitHub Username",
|
|
2842
|
+
type: "string"
|
|
2843
|
+
})
|
|
2844
|
+
],
|
|
2845
|
+
name: "lastEditor",
|
|
2846
|
+
readOnly: true,
|
|
2847
|
+
title: "Last Editor",
|
|
2848
|
+
type: "object"
|
|
2849
|
+
}),
|
|
2850
|
+
defineField5({
|
|
2851
|
+
description: "When this task was graduated to Studio ownership",
|
|
2852
|
+
name: "graduatedAt",
|
|
2853
|
+
readOnly: true,
|
|
2854
|
+
title: "Graduated At",
|
|
2855
|
+
type: "datetime"
|
|
2856
|
+
}),
|
|
2857
|
+
defineField5({
|
|
2858
|
+
description: "Who graduated this task from repo to Studio ownership",
|
|
2859
|
+
fields: [
|
|
2860
|
+
defineField5({
|
|
2861
|
+
name: "sanityId",
|
|
2862
|
+
readOnly: true,
|
|
2863
|
+
title: "Sanity User ID",
|
|
2864
|
+
type: "string"
|
|
2865
|
+
}),
|
|
2866
|
+
defineField5({
|
|
2867
|
+
name: "name",
|
|
2868
|
+
readOnly: true,
|
|
2869
|
+
title: "Name",
|
|
2870
|
+
type: "string"
|
|
2871
|
+
}),
|
|
2872
|
+
defineField5({
|
|
2873
|
+
name: "email",
|
|
2874
|
+
readOnly: true,
|
|
2875
|
+
title: "Email",
|
|
2876
|
+
type: "string"
|
|
2877
|
+
})
|
|
2878
|
+
],
|
|
2879
|
+
name: "graduatedBy",
|
|
2880
|
+
readOnly: true,
|
|
2881
|
+
title: "Graduated By",
|
|
2882
|
+
type: "object"
|
|
2682
2883
|
})
|
|
2683
2884
|
],
|
|
2684
2885
|
components: {
|
|
@@ -2697,9 +2898,16 @@ var taskSchema = defineType5({
|
|
|
2697
2898
|
],
|
|
2698
2899
|
name: "ailf.task",
|
|
2699
2900
|
preview: {
|
|
2700
|
-
prepare({
|
|
2901
|
+
prepare({
|
|
2902
|
+
area,
|
|
2903
|
+
description,
|
|
2904
|
+
id,
|
|
2905
|
+
origin,
|
|
2906
|
+
ownership,
|
|
2907
|
+
status
|
|
2908
|
+
}) {
|
|
2701
2909
|
const taskId = id !== null && typeof id === "object" && "current" in id ? id.current : void 0;
|
|
2702
|
-
const isMirror = origin !== null && typeof origin === "object" && "repo" in origin;
|
|
2910
|
+
const isMirror = ownership === "repo" || !ownership && origin !== null && typeof origin === "object" && "repo" in origin;
|
|
2703
2911
|
const areaId = area !== null && typeof area === "object" && "current" in area ? area.current : void 0;
|
|
2704
2912
|
const prefix = isMirror ? "\u{1F517} " : "";
|
|
2705
2913
|
const areaStr = typeof areaId === "string" ? `[${areaId}] ` : "";
|
|
@@ -2717,22 +2925,32 @@ var taskSchema = defineType5({
|
|
|
2717
2925
|
syncInfo = ` \xB7 ${icon} ${ageLabel}`;
|
|
2718
2926
|
}
|
|
2719
2927
|
}
|
|
2928
|
+
const statusIcon = status === "archived" ? "\u{1F4E6} " : status === "draft" ? "\u{1F9EA} " : status === "paused" ? "\u23F8\uFE0F " : "";
|
|
2720
2929
|
return {
|
|
2721
2930
|
subtitle: `${areaStr}${typeof taskId === "string" ? taskId : ""}${syncInfo}`,
|
|
2722
|
-
title: `${prefix}${typeof description === "string" ? description : "Task"}`
|
|
2931
|
+
title: `${prefix}${statusIcon}${typeof description === "string" ? description : "Task"}`
|
|
2723
2932
|
};
|
|
2724
2933
|
},
|
|
2725
2934
|
select: {
|
|
2726
2935
|
area: "featureArea.areaId",
|
|
2727
2936
|
description: "description",
|
|
2728
2937
|
id: "id",
|
|
2729
|
-
origin: "origin"
|
|
2938
|
+
origin: "origin",
|
|
2939
|
+
ownership: "ownership",
|
|
2940
|
+
status: "status"
|
|
2730
2941
|
}
|
|
2731
2942
|
},
|
|
2732
|
-
// Document-level read-only when
|
|
2733
|
-
// Native tasks (
|
|
2734
|
-
// are read-only because the source of truth is the repo.
|
|
2735
|
-
|
|
2943
|
+
// Document-level read-only when owned by a repo.
|
|
2944
|
+
// Native tasks (ownership: "studio" or absent) are fully editable;
|
|
2945
|
+
// repo-owned tasks are read-only because the source of truth is the repo.
|
|
2946
|
+
// Falls back to checking origin for legacy mirrored tasks that don't
|
|
2947
|
+
// have the ownership field yet (pre-migration).
|
|
2948
|
+
readOnly: ({ document: document2 }) => {
|
|
2949
|
+
const doc = document2;
|
|
2950
|
+
if (doc?.ownership === "repo") return true;
|
|
2951
|
+
if (doc?.ownership === "studio" || doc?.ownership) return false;
|
|
2952
|
+
return !!doc?.origin;
|
|
2953
|
+
},
|
|
2736
2954
|
title: "AILF Task",
|
|
2737
2955
|
type: "document"
|
|
2738
2956
|
});
|
|
@@ -3272,7 +3490,7 @@ function LoadingState({ message = "Loading\u2026" }) {
|
|
|
3272
3490
|
}
|
|
3273
3491
|
|
|
3274
3492
|
// src/components/ComparisonView.tsx
|
|
3275
|
-
import { Fragment as
|
|
3493
|
+
import { Fragment as Fragment4, jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
3276
3494
|
function ComparisonView() {
|
|
3277
3495
|
const client = useClient3({ apiVersion: API_VERSION });
|
|
3278
3496
|
const [baselineId, setBaselineId] = useState3(null);
|
|
@@ -3370,7 +3588,7 @@ function ComparisonView() {
|
|
|
3370
3588
|
] }),
|
|
3371
3589
|
hasBoth && loading && /* @__PURE__ */ jsx12(LoadingState, { message: "Loading comparison\u2026" }),
|
|
3372
3590
|
hasBoth && !loading && !hasData && /* @__PURE__ */ jsx12(Card6, { padding: 4, tone: "caution", children: /* @__PURE__ */ jsx12(Text11, { size: 2, children: "Report not found." }) }),
|
|
3373
|
-
hasBoth && !loading && hasData && /* @__PURE__ */ jsxs10(
|
|
3591
|
+
hasBoth && !loading && hasData && /* @__PURE__ */ jsxs10(Fragment4, { children: [
|
|
3374
3592
|
/* @__PURE__ */ jsx12(
|
|
3375
3593
|
AreaComparisonTable,
|
|
3376
3594
|
{
|
|
@@ -3817,7 +4035,7 @@ function formatCardDate(iso) {
|
|
|
3817
4035
|
}
|
|
3818
4036
|
|
|
3819
4037
|
// src/components/report-table/ReportTable.tsx
|
|
3820
|
-
import { Fragment as
|
|
4038
|
+
import { Fragment as Fragment5, jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3821
4039
|
function GitBranchIcon({ style }) {
|
|
3822
4040
|
return /* @__PURE__ */ jsxs12(
|
|
3823
4041
|
"svg",
|
|
@@ -3862,7 +4080,7 @@ function ReportTable({
|
|
|
3862
4080
|
onSortChange
|
|
3863
4081
|
}) {
|
|
3864
4082
|
const { ref, tier } = useContainerWidth();
|
|
3865
|
-
return /* @__PURE__ */ jsxs12(
|
|
4083
|
+
return /* @__PURE__ */ jsxs12(Fragment5, { children: [
|
|
3866
4084
|
/* @__PURE__ */ jsx15("style", { children: TABLE_HOVER_STYLES }),
|
|
3867
4085
|
/* @__PURE__ */ jsxs12("div", { ref, children: [
|
|
3868
4086
|
/* @__PURE__ */ jsxs12(
|
|
@@ -3895,7 +4113,7 @@ function ReportTable({
|
|
|
3895
4113
|
onClick: () => onSortChange("score")
|
|
3896
4114
|
}
|
|
3897
4115
|
),
|
|
3898
|
-
tier === "full" && /* @__PURE__ */ jsxs12(
|
|
4116
|
+
tier === "full" && /* @__PURE__ */ jsxs12(Fragment5, { children: [
|
|
3899
4117
|
/* @__PURE__ */ jsx15(ColHeader, { label: "Mode" }),
|
|
3900
4118
|
/* @__PURE__ */ jsx15(ColHeader, { label: "Trigger" }),
|
|
3901
4119
|
/* @__PURE__ */ jsx15(
|
|
@@ -4423,7 +4641,7 @@ import {
|
|
|
4423
4641
|
// src/components/primitives/StatCard.tsx
|
|
4424
4642
|
import { HelpCircleIcon as HelpCircleIcon4 } from "@sanity/icons";
|
|
4425
4643
|
import { Box as Box8, Card as Card8, Stack as Stack11, Text as Text15, Tooltip as Tooltip3 } from "@sanity/ui";
|
|
4426
|
-
import { Fragment as
|
|
4644
|
+
import { Fragment as Fragment6, jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
4427
4645
|
function StatCard({
|
|
4428
4646
|
label,
|
|
4429
4647
|
value,
|
|
@@ -4434,7 +4652,7 @@ function StatCard({
|
|
|
4434
4652
|
return /* @__PURE__ */ jsx17(Card8, { padding: 3, radius: 2, shadow: 1, tone, children: /* @__PURE__ */ jsxs14(Stack11, { space: 2, children: [
|
|
4435
4653
|
/* @__PURE__ */ jsxs14(Text15, { muted: true, size: 2, children: [
|
|
4436
4654
|
label,
|
|
4437
|
-
tooltip && /* @__PURE__ */ jsxs14(
|
|
4655
|
+
tooltip && /* @__PURE__ */ jsxs14(Fragment6, { children: [
|
|
4438
4656
|
" ",
|
|
4439
4657
|
/* @__PURE__ */ jsx17(
|
|
4440
4658
|
Tooltip3,
|
|
@@ -5106,10 +5324,10 @@ import { HelpCircleIcon as HelpCircleIcon6 } from "@sanity/icons";
|
|
|
5106
5324
|
import { Badge as Badge8, Box as Box11, Card as Card14, Flex as Flex14, Stack as Stack16, Text as Text21, Tooltip as Tooltip6 } from "@sanity/ui";
|
|
5107
5325
|
|
|
5108
5326
|
// src/components/primitives/InlineCode.tsx
|
|
5109
|
-
import { Fragment as
|
|
5327
|
+
import { Fragment as Fragment7, jsx as jsx23 } from "react/jsx-runtime";
|
|
5110
5328
|
function InlineCode({ text }) {
|
|
5111
5329
|
const parts = text.split(/`([^`]+)`/);
|
|
5112
|
-
return /* @__PURE__ */ jsx23(
|
|
5330
|
+
return /* @__PURE__ */ jsx23(Fragment7, { children: parts.map(
|
|
5113
5331
|
(part, i) => i % 2 === 1 ? /* @__PURE__ */ jsx23(
|
|
5114
5332
|
"code",
|
|
5115
5333
|
{
|
|
@@ -5882,7 +6100,7 @@ function DownloadReportAction({
|
|
|
5882
6100
|
import { PlayIcon as PlayIcon2 } from "@sanity/icons";
|
|
5883
6101
|
import { MenuItem as MenuItem6, useToast as useToast6 } from "@sanity/ui";
|
|
5884
6102
|
import { useCallback as useCallback16, useState as useState11 } from "react";
|
|
5885
|
-
import { useClient as useClient8, useCurrentUser as
|
|
6103
|
+
import { useClient as useClient8, useCurrentUser as useCurrentUser3 } from "sanity";
|
|
5886
6104
|
|
|
5887
6105
|
// src/lib/eval-scope.ts
|
|
5888
6106
|
function extractEvalScope(provenance) {
|
|
@@ -5934,7 +6152,7 @@ function RerunEvaluationAction({
|
|
|
5934
6152
|
reportId
|
|
5935
6153
|
}) {
|
|
5936
6154
|
const client = useClient8({ apiVersion: API_VERSION });
|
|
5937
|
-
const currentUser =
|
|
6155
|
+
const currentUser = useCurrentUser3();
|
|
5938
6156
|
const toast = useToast6();
|
|
5939
6157
|
const [requesting, setRequesting] = useState11(false);
|
|
5940
6158
|
const handleClick = useCallback16(async () => {
|
|
@@ -5976,7 +6194,7 @@ function RerunEvaluationAction({
|
|
|
5976
6194
|
}
|
|
5977
6195
|
|
|
5978
6196
|
// src/components/report-detail/report-actions/ReportActions.tsx
|
|
5979
|
-
import { Fragment as
|
|
6197
|
+
import { Fragment as Fragment8, jsx as jsx35, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
5980
6198
|
function ReportActions({
|
|
5981
6199
|
documentId,
|
|
5982
6200
|
onDeleted,
|
|
@@ -6032,7 +6250,7 @@ function ReportActions({
|
|
|
6032
6250
|
setDeleting(false);
|
|
6033
6251
|
}
|
|
6034
6252
|
}, [client, documentId, onDeleted, toast]);
|
|
6035
|
-
return /* @__PURE__ */ jsxs24(
|
|
6253
|
+
return /* @__PURE__ */ jsxs24(Fragment8, { children: [
|
|
6036
6254
|
/* @__PURE__ */ jsxs24(Flex18, { children: [
|
|
6037
6255
|
/* @__PURE__ */ jsx35(
|
|
6038
6256
|
Button3,
|
|
@@ -6812,7 +7030,7 @@ import { useCallback as useCallback21, useEffect as useEffect9, useRef as useRef
|
|
|
6812
7030
|
import {
|
|
6813
7031
|
getReleaseIdFromReleaseDocumentId as getReleaseIdFromReleaseDocumentId3,
|
|
6814
7032
|
useClient as useClient12,
|
|
6815
|
-
useCurrentUser as
|
|
7033
|
+
useCurrentUser as useCurrentUser4,
|
|
6816
7034
|
useDataset as useDataset2,
|
|
6817
7035
|
useProjectId as useProjectId2
|
|
6818
7036
|
} from "sanity";
|
|
@@ -6837,7 +7055,7 @@ function createRunEvaluationAction(options = {}) {
|
|
|
6837
7055
|
const client = useClient12({ apiVersion: API_VERSION2 });
|
|
6838
7056
|
const dataset = useDataset2();
|
|
6839
7057
|
const projectId = useProjectId2();
|
|
6840
|
-
const currentUser =
|
|
7058
|
+
const currentUser = useCurrentUser4();
|
|
6841
7059
|
const toast = useToast8();
|
|
6842
7060
|
const [state, setState] = useState15({ status: "loading" });
|
|
6843
7061
|
const requestedAtRef = useRef4(null);
|