@sanity/ailf-studio 0.1.26 → 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 +40 -16
- package/dist/index.js +269 -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
|
|
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);
|
|
@@ -1879,6 +1898,7 @@ function CanonicalDocPreview(props) {
|
|
|
1879
1898
|
|
|
1880
1899
|
// src/components/OriginInput.tsx
|
|
1881
1900
|
import { Stack as Stack5 } from "@sanity/ui";
|
|
1901
|
+
import { useFormValue } from "sanity";
|
|
1882
1902
|
|
|
1883
1903
|
// src/components/MirrorBanner.tsx
|
|
1884
1904
|
import { LinkIcon } from "@sanity/icons";
|
|
@@ -1925,32 +1945,45 @@ function SyncStatusBadge({
|
|
|
1925
1945
|
}
|
|
1926
1946
|
|
|
1927
1947
|
// src/components/MirrorBanner.tsx
|
|
1928
|
-
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1929
|
-
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 }) {
|
|
1930
1958
|
const { repo, path, branch, commitSha, lastSyncedAt } = origin;
|
|
1959
|
+
const isGraduated = ownership === "studio";
|
|
1931
1960
|
const repoUrl = repo && path && branch ? `https://github.com/${repo}/blob/${branch}/${path}` : null;
|
|
1932
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 });
|
|
1933
1972
|
return /* @__PURE__ */ jsx6(Card3, { padding: 3, radius: 2, tone: "transparent", border: true, children: /* @__PURE__ */ jsxs6(Stack4, { space: 3, children: [
|
|
1934
1973
|
/* @__PURE__ */ jsxs6(Flex4, { align: "center", gap: 2, children: [
|
|
1935
1974
|
/* @__PURE__ */ jsx6(Text6, { size: 2, children: /* @__PURE__ */ jsx6(LinkIcon, {}) }),
|
|
1936
|
-
/* @__PURE__ */
|
|
1937
|
-
"This task
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
target: "_blank",
|
|
1944
|
-
rel: "noopener noreferrer",
|
|
1945
|
-
style: { fontWeight: 600 },
|
|
1946
|
-
children: repoDisplay
|
|
1947
|
-
}
|
|
1948
|
-
) : /* @__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,
|
|
1949
1982
|
". Edit it there to make changes."
|
|
1950
|
-
] })
|
|
1983
|
+
] }) })
|
|
1951
1984
|
] }),
|
|
1952
1985
|
/* @__PURE__ */ jsxs6(Flex4, { align: "center", gap: 2, wrap: "wrap", children: [
|
|
1953
|
-
lastSyncedAt && /* @__PURE__ */ jsx6(
|
|
1986
|
+
!isGraduated && lastSyncedAt && /* @__PURE__ */ jsx6(
|
|
1954
1987
|
SyncStatusBadge,
|
|
1955
1988
|
{
|
|
1956
1989
|
lastSyncedAt,
|
|
@@ -1963,6 +1996,19 @@ function MirrorBanner({ origin }) {
|
|
|
1963
1996
|
commitSha ? ` @ ${commitSha.slice(0, 7)}` : ""
|
|
1964
1997
|
] }),
|
|
1965
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)
|
|
1966
2012
|
] })
|
|
1967
2013
|
] }) });
|
|
1968
2014
|
}
|
|
@@ -1972,17 +2018,25 @@ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
|
1972
2018
|
function OriginInput(props) {
|
|
1973
2019
|
const value = props.value;
|
|
1974
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;
|
|
1975
2023
|
const origin = {
|
|
1976
|
-
repo:
|
|
1977
|
-
repoOwner:
|
|
1978
|
-
repoName:
|
|
1979
|
-
path:
|
|
1980
|
-
branch:
|
|
1981
|
-
commitSha:
|
|
1982
|
-
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")
|
|
1983
2035
|
};
|
|
2036
|
+
const ownershipValue = useFormValue(["ownership"]);
|
|
2037
|
+
const ownership = typeof ownershipValue === "string" ? ownershipValue : void 0;
|
|
1984
2038
|
return /* @__PURE__ */ jsxs7(Stack5, { space: 3, children: [
|
|
1985
|
-
/* @__PURE__ */ jsx7(MirrorBanner, { origin }),
|
|
2039
|
+
/* @__PURE__ */ jsx7(MirrorBanner, { origin, ownership }),
|
|
1986
2040
|
props.renderDefault(props)
|
|
1987
2041
|
] });
|
|
1988
2042
|
}
|
|
@@ -2154,6 +2208,57 @@ var taskSchema = defineType5({
|
|
|
2154
2208
|
validation: (rule) => rule.required()
|
|
2155
2209
|
}),
|
|
2156
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
|
+
// -----------------------------------------------------------------------
|
|
2157
2262
|
// Task prompt
|
|
2158
2263
|
// -----------------------------------------------------------------------
|
|
2159
2264
|
defineField5({
|
|
@@ -2686,6 +2791,95 @@ var taskSchema = defineType5({
|
|
|
2686
2791
|
readOnly: true,
|
|
2687
2792
|
title: "Last Synced At",
|
|
2688
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"
|
|
2689
2883
|
})
|
|
2690
2884
|
],
|
|
2691
2885
|
components: {
|
|
@@ -2704,9 +2898,16 @@ var taskSchema = defineType5({
|
|
|
2704
2898
|
],
|
|
2705
2899
|
name: "ailf.task",
|
|
2706
2900
|
preview: {
|
|
2707
|
-
prepare({
|
|
2901
|
+
prepare({
|
|
2902
|
+
area,
|
|
2903
|
+
description,
|
|
2904
|
+
id,
|
|
2905
|
+
origin,
|
|
2906
|
+
ownership,
|
|
2907
|
+
status
|
|
2908
|
+
}) {
|
|
2708
2909
|
const taskId = id !== null && typeof id === "object" && "current" in id ? id.current : void 0;
|
|
2709
|
-
const isMirror = origin !== null && typeof origin === "object" && "repo" in origin;
|
|
2910
|
+
const isMirror = ownership === "repo" || !ownership && origin !== null && typeof origin === "object" && "repo" in origin;
|
|
2710
2911
|
const areaId = area !== null && typeof area === "object" && "current" in area ? area.current : void 0;
|
|
2711
2912
|
const prefix = isMirror ? "\u{1F517} " : "";
|
|
2712
2913
|
const areaStr = typeof areaId === "string" ? `[${areaId}] ` : "";
|
|
@@ -2724,22 +2925,32 @@ var taskSchema = defineType5({
|
|
|
2724
2925
|
syncInfo = ` \xB7 ${icon} ${ageLabel}`;
|
|
2725
2926
|
}
|
|
2726
2927
|
}
|
|
2928
|
+
const statusIcon = status === "archived" ? "\u{1F4E6} " : status === "draft" ? "\u{1F9EA} " : status === "paused" ? "\u23F8\uFE0F " : "";
|
|
2727
2929
|
return {
|
|
2728
2930
|
subtitle: `${areaStr}${typeof taskId === "string" ? taskId : ""}${syncInfo}`,
|
|
2729
|
-
title: `${prefix}${typeof description === "string" ? description : "Task"}`
|
|
2931
|
+
title: `${prefix}${statusIcon}${typeof description === "string" ? description : "Task"}`
|
|
2730
2932
|
};
|
|
2731
2933
|
},
|
|
2732
2934
|
select: {
|
|
2733
2935
|
area: "featureArea.areaId",
|
|
2734
2936
|
description: "description",
|
|
2735
2937
|
id: "id",
|
|
2736
|
-
origin: "origin"
|
|
2938
|
+
origin: "origin",
|
|
2939
|
+
ownership: "ownership",
|
|
2940
|
+
status: "status"
|
|
2737
2941
|
}
|
|
2738
2942
|
},
|
|
2739
|
-
// Document-level read-only when
|
|
2740
|
-
// Native tasks (
|
|
2741
|
-
// are read-only because the source of truth is the repo.
|
|
2742
|
-
|
|
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
|
+
},
|
|
2743
2954
|
title: "AILF Task",
|
|
2744
2955
|
type: "document"
|
|
2745
2956
|
});
|
|
@@ -3279,7 +3490,7 @@ function LoadingState({ message = "Loading\u2026" }) {
|
|
|
3279
3490
|
}
|
|
3280
3491
|
|
|
3281
3492
|
// src/components/ComparisonView.tsx
|
|
3282
|
-
import { Fragment as
|
|
3493
|
+
import { Fragment as Fragment4, jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
3283
3494
|
function ComparisonView() {
|
|
3284
3495
|
const client = useClient3({ apiVersion: API_VERSION });
|
|
3285
3496
|
const [baselineId, setBaselineId] = useState3(null);
|
|
@@ -3377,7 +3588,7 @@ function ComparisonView() {
|
|
|
3377
3588
|
] }),
|
|
3378
3589
|
hasBoth && loading && /* @__PURE__ */ jsx12(LoadingState, { message: "Loading comparison\u2026" }),
|
|
3379
3590
|
hasBoth && !loading && !hasData && /* @__PURE__ */ jsx12(Card6, { padding: 4, tone: "caution", children: /* @__PURE__ */ jsx12(Text11, { size: 2, children: "Report not found." }) }),
|
|
3380
|
-
hasBoth && !loading && hasData && /* @__PURE__ */ jsxs10(
|
|
3591
|
+
hasBoth && !loading && hasData && /* @__PURE__ */ jsxs10(Fragment4, { children: [
|
|
3381
3592
|
/* @__PURE__ */ jsx12(
|
|
3382
3593
|
AreaComparisonTable,
|
|
3383
3594
|
{
|
|
@@ -3824,7 +4035,7 @@ function formatCardDate(iso) {
|
|
|
3824
4035
|
}
|
|
3825
4036
|
|
|
3826
4037
|
// src/components/report-table/ReportTable.tsx
|
|
3827
|
-
import { Fragment as
|
|
4038
|
+
import { Fragment as Fragment5, jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3828
4039
|
function GitBranchIcon({ style }) {
|
|
3829
4040
|
return /* @__PURE__ */ jsxs12(
|
|
3830
4041
|
"svg",
|
|
@@ -3869,7 +4080,7 @@ function ReportTable({
|
|
|
3869
4080
|
onSortChange
|
|
3870
4081
|
}) {
|
|
3871
4082
|
const { ref, tier } = useContainerWidth();
|
|
3872
|
-
return /* @__PURE__ */ jsxs12(
|
|
4083
|
+
return /* @__PURE__ */ jsxs12(Fragment5, { children: [
|
|
3873
4084
|
/* @__PURE__ */ jsx15("style", { children: TABLE_HOVER_STYLES }),
|
|
3874
4085
|
/* @__PURE__ */ jsxs12("div", { ref, children: [
|
|
3875
4086
|
/* @__PURE__ */ jsxs12(
|
|
@@ -3902,7 +4113,7 @@ function ReportTable({
|
|
|
3902
4113
|
onClick: () => onSortChange("score")
|
|
3903
4114
|
}
|
|
3904
4115
|
),
|
|
3905
|
-
tier === "full" && /* @__PURE__ */ jsxs12(
|
|
4116
|
+
tier === "full" && /* @__PURE__ */ jsxs12(Fragment5, { children: [
|
|
3906
4117
|
/* @__PURE__ */ jsx15(ColHeader, { label: "Mode" }),
|
|
3907
4118
|
/* @__PURE__ */ jsx15(ColHeader, { label: "Trigger" }),
|
|
3908
4119
|
/* @__PURE__ */ jsx15(
|
|
@@ -4430,7 +4641,7 @@ import {
|
|
|
4430
4641
|
// src/components/primitives/StatCard.tsx
|
|
4431
4642
|
import { HelpCircleIcon as HelpCircleIcon4 } from "@sanity/icons";
|
|
4432
4643
|
import { Box as Box8, Card as Card8, Stack as Stack11, Text as Text15, Tooltip as Tooltip3 } from "@sanity/ui";
|
|
4433
|
-
import { Fragment as
|
|
4644
|
+
import { Fragment as Fragment6, jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
4434
4645
|
function StatCard({
|
|
4435
4646
|
label,
|
|
4436
4647
|
value,
|
|
@@ -4441,7 +4652,7 @@ function StatCard({
|
|
|
4441
4652
|
return /* @__PURE__ */ jsx17(Card8, { padding: 3, radius: 2, shadow: 1, tone, children: /* @__PURE__ */ jsxs14(Stack11, { space: 2, children: [
|
|
4442
4653
|
/* @__PURE__ */ jsxs14(Text15, { muted: true, size: 2, children: [
|
|
4443
4654
|
label,
|
|
4444
|
-
tooltip && /* @__PURE__ */ jsxs14(
|
|
4655
|
+
tooltip && /* @__PURE__ */ jsxs14(Fragment6, { children: [
|
|
4445
4656
|
" ",
|
|
4446
4657
|
/* @__PURE__ */ jsx17(
|
|
4447
4658
|
Tooltip3,
|
|
@@ -5113,10 +5324,10 @@ import { HelpCircleIcon as HelpCircleIcon6 } from "@sanity/icons";
|
|
|
5113
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";
|
|
5114
5325
|
|
|
5115
5326
|
// src/components/primitives/InlineCode.tsx
|
|
5116
|
-
import { Fragment as
|
|
5327
|
+
import { Fragment as Fragment7, jsx as jsx23 } from "react/jsx-runtime";
|
|
5117
5328
|
function InlineCode({ text }) {
|
|
5118
5329
|
const parts = text.split(/`([^`]+)`/);
|
|
5119
|
-
return /* @__PURE__ */ jsx23(
|
|
5330
|
+
return /* @__PURE__ */ jsx23(Fragment7, { children: parts.map(
|
|
5120
5331
|
(part, i) => i % 2 === 1 ? /* @__PURE__ */ jsx23(
|
|
5121
5332
|
"code",
|
|
5122
5333
|
{
|
|
@@ -5889,7 +6100,7 @@ function DownloadReportAction({
|
|
|
5889
6100
|
import { PlayIcon as PlayIcon2 } from "@sanity/icons";
|
|
5890
6101
|
import { MenuItem as MenuItem6, useToast as useToast6 } from "@sanity/ui";
|
|
5891
6102
|
import { useCallback as useCallback16, useState as useState11 } from "react";
|
|
5892
|
-
import { useClient as useClient8, useCurrentUser as
|
|
6103
|
+
import { useClient as useClient8, useCurrentUser as useCurrentUser3 } from "sanity";
|
|
5893
6104
|
|
|
5894
6105
|
// src/lib/eval-scope.ts
|
|
5895
6106
|
function extractEvalScope(provenance) {
|
|
@@ -5941,7 +6152,7 @@ function RerunEvaluationAction({
|
|
|
5941
6152
|
reportId
|
|
5942
6153
|
}) {
|
|
5943
6154
|
const client = useClient8({ apiVersion: API_VERSION });
|
|
5944
|
-
const currentUser =
|
|
6155
|
+
const currentUser = useCurrentUser3();
|
|
5945
6156
|
const toast = useToast6();
|
|
5946
6157
|
const [requesting, setRequesting] = useState11(false);
|
|
5947
6158
|
const handleClick = useCallback16(async () => {
|
|
@@ -5983,7 +6194,7 @@ function RerunEvaluationAction({
|
|
|
5983
6194
|
}
|
|
5984
6195
|
|
|
5985
6196
|
// src/components/report-detail/report-actions/ReportActions.tsx
|
|
5986
|
-
import { Fragment as
|
|
6197
|
+
import { Fragment as Fragment8, jsx as jsx35, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
5987
6198
|
function ReportActions({
|
|
5988
6199
|
documentId,
|
|
5989
6200
|
onDeleted,
|
|
@@ -6039,7 +6250,7 @@ function ReportActions({
|
|
|
6039
6250
|
setDeleting(false);
|
|
6040
6251
|
}
|
|
6041
6252
|
}, [client, documentId, onDeleted, toast]);
|
|
6042
|
-
return /* @__PURE__ */ jsxs24(
|
|
6253
|
+
return /* @__PURE__ */ jsxs24(Fragment8, { children: [
|
|
6043
6254
|
/* @__PURE__ */ jsxs24(Flex18, { children: [
|
|
6044
6255
|
/* @__PURE__ */ jsx35(
|
|
6045
6256
|
Button3,
|
|
@@ -6819,7 +7030,7 @@ import { useCallback as useCallback21, useEffect as useEffect9, useRef as useRef
|
|
|
6819
7030
|
import {
|
|
6820
7031
|
getReleaseIdFromReleaseDocumentId as getReleaseIdFromReleaseDocumentId3,
|
|
6821
7032
|
useClient as useClient12,
|
|
6822
|
-
useCurrentUser as
|
|
7033
|
+
useCurrentUser as useCurrentUser4,
|
|
6823
7034
|
useDataset as useDataset2,
|
|
6824
7035
|
useProjectId as useProjectId2
|
|
6825
7036
|
} from "sanity";
|
|
@@ -6844,7 +7055,7 @@ function createRunEvaluationAction(options = {}) {
|
|
|
6844
7055
|
const client = useClient12({ apiVersion: API_VERSION2 });
|
|
6845
7056
|
const dataset = useDataset2();
|
|
6846
7057
|
const projectId = useProjectId2();
|
|
6847
|
-
const currentUser =
|
|
7058
|
+
const currentUser = useCurrentUser4();
|
|
6848
7059
|
const toast = useToast8();
|
|
6849
7060
|
const [state, setState] = useState15({ status: "loading" });
|
|
6850
7061
|
const requestedAtRef = useRef4(null);
|