@sanity/ailf-studio 2.0.2 → 2.1.0
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 +63 -12
- package/dist/index.js +477 -14
- package/package.json +5 -2
package/dist/index.d.ts
CHANGED
|
@@ -100,9 +100,9 @@ declare const RunTaskEvaluationAction: DocumentActionComponent;
|
|
|
100
100
|
/**
|
|
101
101
|
* structure.ts
|
|
102
102
|
*
|
|
103
|
-
* Structure helpers for
|
|
104
|
-
*
|
|
105
|
-
*
|
|
103
|
+
* Structure helpers for AILF document types. Exposes filtered list views so
|
|
104
|
+
* editors see only the documents they care about by default, with diagnostic
|
|
105
|
+
* sub-lists that surface routing/ownership gaps.
|
|
106
106
|
*
|
|
107
107
|
* ## Usage
|
|
108
108
|
*
|
|
@@ -118,10 +118,13 @@ declare const RunTaskEvaluationAction: DocumentActionComponent;
|
|
|
118
118
|
* })
|
|
119
119
|
* ```
|
|
120
120
|
*
|
|
121
|
-
* `ailfStructure` renders
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
121
|
+
* `ailfStructure` renders filtered entries for `ailf.task`, `ailf.team`,
|
|
122
|
+
* `ailf.featureArea`, and `ailf.report` in place of their default Studio
|
|
123
|
+
* list items, plus a top-level diagnostic for teams whose channel events
|
|
124
|
+
* reference unknown event-type strings. Other document types are preserved
|
|
125
|
+
* at their Studio default via `S.documentTypeListItems().filter(...)`.
|
|
126
|
+
* Consumers who already maintain a custom structure can splice individual
|
|
127
|
+
* helpers in via the per-type exports.
|
|
125
128
|
*/
|
|
126
129
|
|
|
127
130
|
/**
|
|
@@ -131,9 +134,10 @@ declare const RunTaskEvaluationAction: DocumentActionComponent;
|
|
|
131
134
|
*/
|
|
132
135
|
declare function ailfTaskStructureItem(S: StructureBuilder): ReturnType<StructureBuilder["listItem"]>;
|
|
133
136
|
/**
|
|
134
|
-
* Full structure resolver that replaces the default
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
+
* Full structure resolver that replaces the default entries for
|
|
138
|
+
* `ailf.task`, `ailf.team`, `ailf.featureArea`, and `ailf.report` with
|
|
139
|
+
* filtered AILF views, exposes a top-level unknown-events diagnostic,
|
|
140
|
+
* and keeps every other document type list item at its Studio default.
|
|
137
141
|
*/
|
|
138
142
|
declare const ailfStructure: StructureResolver;
|
|
139
143
|
|
|
@@ -388,7 +392,7 @@ declare const scoreTimelineQuery: string;
|
|
|
388
392
|
*
|
|
389
393
|
* Used by: ReportDetail view
|
|
390
394
|
*/
|
|
391
|
-
declare const reportDetailQuery = "\n *[_type == \"ailf.report\" && reportId == $reportId][0] {\n _id,\n reportId,\n completedAt,\n durationMs,\n tag,\n title,\n provenance,\n summary,\n \"comparison\": comparison {\n areas,\n deltas,\n generatedAt,\n improved,\n mismatched,\n noiseThreshold,\n noiseThresholdEmpirical,\n notEvaluated,\n regressed,\n unchanged\n }\n }\n";
|
|
395
|
+
declare const reportDetailQuery = "\n *[_type == \"ailf.report\" && reportId == $reportId][0] {\n _id,\n reportId,\n completedAt,\n durationMs,\n tag,\n title,\n provenance,\n \"teamDoc\": *[_type == \"ailf.team\" && slug.current == ^.provenance.owner.team][0]{\n _id,\n displayName,\n status\n },\n summary,\n \"comparison\": comparison {\n areas,\n deltas,\n generatedAt,\n improved,\n mismatched,\n noiseThreshold,\n noiseThresholdEmpirical,\n notEvaluated,\n regressed,\n unchanged\n }\n }\n";
|
|
392
396
|
/**
|
|
393
397
|
* Find all reports that evaluated a specific Sanity document or perspective.
|
|
394
398
|
*
|
|
@@ -606,6 +610,35 @@ declare const taskSchema: {
|
|
|
606
610
|
}, Record<string, unknown>> | undefined;
|
|
607
611
|
};
|
|
608
612
|
|
|
613
|
+
/**
|
|
614
|
+
* schema/team.ts
|
|
615
|
+
*
|
|
616
|
+
* Sanity document schema for `ailf.team` — a team that owns feature areas,
|
|
617
|
+
* repos, or task tags, and the notification channels used to route events
|
|
618
|
+
* to its members.
|
|
619
|
+
*
|
|
620
|
+
* The team entity is the routing target for the AILF notification system.
|
|
621
|
+
* A team owns members (people, identified by email / Sanity user id /
|
|
622
|
+
* GitHub username) and zero-or-more notification channels (Slack, email,
|
|
623
|
+
* webhook). Each channel carries a `scope` that says which events the
|
|
624
|
+
* channel cares about: the team's own areas/repos, all events, or a
|
|
625
|
+
* specific list of areas/repos/tags.
|
|
626
|
+
*
|
|
627
|
+
* Soft enums (member role, event type) are seeded from `@sanity/ailf-shared`
|
|
628
|
+
* but not closed — teams can introduce custom roles/events without a code
|
|
629
|
+
* change. The `options.list` provides suggestions; Sanity's `string` field
|
|
630
|
+
* doesn't enforce the list as a closed enum.
|
|
631
|
+
*/
|
|
632
|
+
declare const teamSchema: {
|
|
633
|
+
type: "document";
|
|
634
|
+
name: "ailf.team";
|
|
635
|
+
} & Omit<sanity.DocumentDefinition, "preview"> & {
|
|
636
|
+
preview?: sanity.PreviewConfig<{
|
|
637
|
+
displayName: string;
|
|
638
|
+
slug: string;
|
|
639
|
+
}, Record<string, unknown>> | undefined;
|
|
640
|
+
};
|
|
641
|
+
|
|
609
642
|
/**
|
|
610
643
|
* schema/webhook-config.ts
|
|
611
644
|
*
|
|
@@ -812,6 +845,20 @@ interface ProvenanceData {
|
|
|
812
845
|
workflow?: string;
|
|
813
846
|
};
|
|
814
847
|
}
|
|
848
|
+
/**
|
|
849
|
+
* Resolved `ailf.team` document referenced by `provenance.owner.team`.
|
|
850
|
+
*
|
|
851
|
+
* Projected as a peer of `ownerTeam`/`provenance` in `latestReportsQuery`
|
|
852
|
+
* and `reportDetailQuery` so the dashboard can render the team's
|
|
853
|
+
* displayName and detect archived/missing teams without a second
|
|
854
|
+
* roundtrip. `null` when no team doc matches the owner slug (legacy
|
|
855
|
+
* reports, or a team that has not yet been seeded).
|
|
856
|
+
*/
|
|
857
|
+
interface TeamDocRef {
|
|
858
|
+
_id: string;
|
|
859
|
+
displayName: string;
|
|
860
|
+
status: "active" | "archived";
|
|
861
|
+
}
|
|
815
862
|
/** Shape returned by reportDetailQuery */
|
|
816
863
|
interface ReportDetail {
|
|
817
864
|
_id: string;
|
|
@@ -822,6 +869,8 @@ interface ReportDetail {
|
|
|
822
869
|
reportId: string;
|
|
823
870
|
summary: SummaryData;
|
|
824
871
|
tag: null | string;
|
|
872
|
+
/** Resolved owner team document (T10) — null when no `ailf.team` doc matches. */
|
|
873
|
+
teamDoc?: TeamDocRef | null;
|
|
825
874
|
title: null | string;
|
|
826
875
|
}
|
|
827
876
|
/** Shape returned by latestReportsQuery */
|
|
@@ -871,6 +920,8 @@ interface ReportListItem {
|
|
|
871
920
|
scores: ScoreItem[];
|
|
872
921
|
source: string;
|
|
873
922
|
tag: null | string;
|
|
923
|
+
/** Resolved owner team document (T10) — null when no `ailf.team` doc matches. */
|
|
924
|
+
teamDoc?: TeamDocRef | null;
|
|
874
925
|
title: null | string;
|
|
875
926
|
/** Target document slugs (when evaluated with --changed-docs) */
|
|
876
927
|
targetDocuments?: null | string[];
|
|
@@ -1179,4 +1230,4 @@ interface AilfPluginOptions {
|
|
|
1179
1230
|
*/
|
|
1180
1231
|
declare const ailfPlugin: sanity.Plugin<void | AilfPluginOptions>;
|
|
1181
1232
|
|
|
1182
|
-
export { type AilfPluginOptions, ArchiveTaskAction, AssertionInput, CanonicalDocInput, type ComparisonData, type ContentImpactItem, GraduateToNativeAction, HelpDrawer, HelpProvider, MirrorBanner, type PerModelData, type ProvenanceData, ReleasePicker, type ReportDetail, type ReportListItem, RestoreTaskAction, type RunEvaluationActionOptions, RunTaskEvaluationAction, type ScoreItem, type SummaryData, SyncStatusBadge, type TimelineDataPoint, ailfPlugin, ailfStructure, ailfTaskStructureItem, ailfTool, articleSearchQuery, comparisonPairQuery, contentImpactQuery, createRunEvaluationAction, deriveHelpTopic, distinctAreasQuery, distinctModesQuery, distinctPerspectivesQuery, distinctSourcesQuery, distinctTargetDocumentsQuery, distinctTriggersQuery, evalRequestSchema, featureAreaSchema, findTopic, latestReportsQuery, recentDocumentEvalsQuery, referenceSolutionSchema, reportDetailQuery, reportSchema, scoreTimelineQuery, searchTopics, taskSchema, useHelp, webhookConfigSchema };
|
|
1233
|
+
export { type AilfPluginOptions, ArchiveTaskAction, AssertionInput, CanonicalDocInput, type ComparisonData, type ContentImpactItem, GraduateToNativeAction, HelpDrawer, HelpProvider, MirrorBanner, type PerModelData, type ProvenanceData, ReleasePicker, type ReportDetail, type ReportListItem, RestoreTaskAction, type RunEvaluationActionOptions, RunTaskEvaluationAction, type ScoreItem, type SummaryData, SyncStatusBadge, type TimelineDataPoint, ailfPlugin, ailfStructure, ailfTaskStructureItem, ailfTool, articleSearchQuery, comparisonPairQuery, contentImpactQuery, createRunEvaluationAction, deriveHelpTopic, distinctAreasQuery, distinctModesQuery, distinctPerspectivesQuery, distinctSourcesQuery, distinctTargetDocumentsQuery, distinctTriggersQuery, evalRequestSchema, featureAreaSchema, findTopic, latestReportsQuery, recentDocumentEvalsQuery, referenceSolutionSchema, reportDetailQuery, reportSchema, scoreTimelineQuery, searchTopics, taskSchema, teamSchema, useHelp, webhookConfigSchema };
|
package/dist/index.js
CHANGED
|
@@ -191,6 +191,17 @@ import {
|
|
|
191
191
|
useProjectId
|
|
192
192
|
} from "sanity";
|
|
193
193
|
|
|
194
|
+
// ../shared/dist/event-types.js
|
|
195
|
+
var KNOWN_EVENT_TYPES = [
|
|
196
|
+
"eval.failed",
|
|
197
|
+
"eval.completed",
|
|
198
|
+
"eval.threshold-breached",
|
|
199
|
+
"eval.score-regressed",
|
|
200
|
+
"task.created",
|
|
201
|
+
"task.archived",
|
|
202
|
+
"area.unowned-tasks"
|
|
203
|
+
];
|
|
204
|
+
|
|
194
205
|
// ../shared/dist/feature-flags.js
|
|
195
206
|
var FEATURE_FLAGS = {
|
|
196
207
|
showFailureModes: {
|
|
@@ -692,7 +703,7 @@ Click into any report for the full breakdown: per-area scores, diagnostics, and
|
|
|
692
703
|
{
|
|
693
704
|
"id": "weaknesses-recommendations",
|
|
694
705
|
"title": "Weaknesses & Recommendations",
|
|
695
|
-
"body": "## Understanding weaknesses\n\nThe Issues sub-tab in Diagnostics lists every area or dimension that scored\nbelow threshold. Each weakness entry shows:\n\n- **The feature area** \u2014 Which product feature is affected (e.g., GROQ,\n Functions, Webhooks).\n- **The bottleneck dimension** \u2014 Which scoring dimension is dragging the area\n down: task completion, code correctness, or doc coverage.\n- **The score** \u2014 How far below threshold the dimension scored.\n\n## Gap analysis recommendations\n\nWhen an evaluation runs with gap analysis enabled, the dashboard shows\n**prioritized recommendations** \u2014 specific actions ranked by estimated impact.\n\nEach recommendation includes:\n\n- **Failure mode** \u2014 The type of doc problem identified:\n - `missing-docs` \u2014 The functionality isn't documented at all.\n - `incorrect-docs` \u2014 The docs contain factual errors.\n - `outdated-docs` \u2014 The docs describe an old API version or pattern.\n - `poor-structure` \u2014 The docs exist but are hard to find or understand.\n- **Estimated lift** \u2014 How many score points fixing this gap would add. Based on\n raising the bottleneck dimension to the median of non-bottleneck dimensions.\n Conservative estimate \u2014 actual improvement may be higher.\n- **Confidence** \u2014 How sure the analysis is about this diagnosis (high, medium,\n or low).\n- **Affected tasks** \u2014 Which specific evaluation tasks exposed this gap.\n\n## Low-scoring judgments\n\nBelow the recommendations, you'll find the **grader's explanations** for tests\nthat scored below 70. These are the raw assessments from the grading model\nexplaining exactly what went wrong \u2014 missing API calls, incorrect patterns,\nhallucinated features, etc.\n\nEach judgment shows the task, the dimension, the score, and the grader's natural\nlanguage reason. These are the most granular diagnostic signal available and\noften point directly to the doc section that needs fixing.",
|
|
706
|
+
"body": "## Understanding weaknesses\n\nThe Issues sub-tab in Diagnostics lists every area or dimension that scored\nbelow threshold. Each weakness entry shows:\n\n- **The feature area** \u2014 Which product feature is affected (e.g., GROQ,\n Functions, Webhooks).\n- **The bottleneck dimension** \u2014 Which scoring dimension is dragging the area\n down: task completion, code correctness, or doc coverage.\n- **The score** \u2014 How far below threshold the dimension scored.\n\n## Gap analysis recommendations\n\nWhen an evaluation runs with gap analysis enabled, the dashboard shows\n**prioritized recommendations** \u2014 specific actions ranked by estimated impact.\n\nEach recommendation includes:\n\n- **Failure mode** \u2014 The type of doc problem identified:\n - `missing-docs` \u2014 The functionality isn't documented at all.\n - `incorrect-docs` \u2014 The docs contain factual errors.\n - `outdated-docs` \u2014 The docs describe an old API version or pattern.\n - `poor-structure` \u2014 The docs exist but are hard to find or understand.\n- **Estimated lift** \u2014 How many score points fixing this gap would add. Based on\n raising the bottleneck dimension to the median of non-bottleneck dimensions.\n Conservative estimate \u2014 actual improvement may be higher.\n- **Confidence** \u2014 How sure the analysis is about this diagnosis (high, medium,\n or low).\n- **Affected tasks** \u2014 Which specific evaluation tasks exposed this gap.\n\n## Diagnosis cards\n\nEvery published report now carries a **diagnosis artifact** \u2014 a set of cards\nproduced by the post-pipeline hook (`ailf interpret`). The Studio diagnosis\npanel renders these cards directly; the dashboard's Recommendations and\nFailure-modes panels migrate to the same source in a follow-up.\n\nThe hook runs by default for every pipeline invocation. To opt out for a single\nrun, pass `--no-summary`; to opt out in CI, set `AILF_INTERPRET_ON_RUN=0` in the\nworkflow env block; to opt out project-wide, set `summary.onRun: never` in\n`.ailf/config.yaml`.\n\n## Low-scoring judgments\n\nBelow the recommendations, you'll find the **grader's explanations** for tests\nthat scored below 70. These are the raw assessments from the grading model\nexplaining exactly what went wrong \u2014 missing API calls, incorrect patterns,\nhallucinated features, etc.\n\nEach judgment shows the task, the dimension, the score, and the grader's natural\nlanguage reason. These are the most granular diagnostic signal available and\noften point directly to the doc section that needs fixing.",
|
|
696
707
|
"source": "docs/help/weaknesses-recommendations.md",
|
|
697
708
|
"related": [
|
|
698
709
|
"interpreting-diagnostics",
|
|
@@ -732,6 +743,9 @@ Click into any report for the full breakdown: per-area scores, diagnostics, and
|
|
|
732
743
|
}
|
|
733
744
|
];
|
|
734
745
|
|
|
746
|
+
// ../shared/dist/member-roles.js
|
|
747
|
+
var KNOWN_MEMBER_ROLES = ["lead", "member", "oncall"];
|
|
748
|
+
|
|
735
749
|
// ../shared/dist/score-grades.js
|
|
736
750
|
var GRADE_BOUNDARIES = {
|
|
737
751
|
good: 80,
|
|
@@ -1142,6 +1156,14 @@ var evalRequestSchema = defineType({
|
|
|
1142
1156
|
type: "string",
|
|
1143
1157
|
validation: (rule) => rule.required()
|
|
1144
1158
|
}),
|
|
1159
|
+
defineField({
|
|
1160
|
+
description: "ailf.job document id this request was dispatched to. Set by the webhook handler when GHA dispatch succeeds; the pipeline orchestrator reads it back to patch this doc on job terminal state.",
|
|
1161
|
+
group: ["optional", "all-fields"],
|
|
1162
|
+
name: "jobId",
|
|
1163
|
+
readOnly: true,
|
|
1164
|
+
title: "Job ID",
|
|
1165
|
+
type: "string"
|
|
1166
|
+
}),
|
|
1145
1167
|
defineField({
|
|
1146
1168
|
description: "Links to the resulting ailf.report document's reportId",
|
|
1147
1169
|
group: ["optional", "all-fields"],
|
|
@@ -1252,6 +1274,14 @@ var featureAreaSchema = defineType2({
|
|
|
1252
1274
|
of: [{ type: "string" }],
|
|
1253
1275
|
title: "Tags",
|
|
1254
1276
|
type: "array"
|
|
1277
|
+
}),
|
|
1278
|
+
defineField2({
|
|
1279
|
+
description: "Primary team responsible for this area. Optional; unowned areas surface in a triage view.",
|
|
1280
|
+
group: ["optional", "all-fields"],
|
|
1281
|
+
name: "team",
|
|
1282
|
+
title: "Owning Team",
|
|
1283
|
+
to: [{ type: "ailf.team" }],
|
|
1284
|
+
type: "reference"
|
|
1255
1285
|
})
|
|
1256
1286
|
],
|
|
1257
1287
|
name: "ailf.featureArea",
|
|
@@ -4004,16 +4034,381 @@ var taskSchema = defineType5({
|
|
|
4004
4034
|
type: "document"
|
|
4005
4035
|
});
|
|
4006
4036
|
|
|
4007
|
-
// src/schema/
|
|
4008
|
-
import {
|
|
4009
|
-
|
|
4037
|
+
// src/schema/team.ts
|
|
4038
|
+
import {
|
|
4039
|
+
ALL_FIELDS_GROUP as ALL_FIELDS_GROUP6,
|
|
4040
|
+
defineArrayMember,
|
|
4041
|
+
defineField as defineField6,
|
|
4042
|
+
defineType as defineType6
|
|
4043
|
+
} from "sanity";
|
|
4044
|
+
var EVENT_TYPE_SUGGESTIONS = KNOWN_EVENT_TYPES.map((value) => ({
|
|
4045
|
+
title: value,
|
|
4046
|
+
value
|
|
4047
|
+
}));
|
|
4048
|
+
var MEMBER_ROLE_SUGGESTIONS = KNOWN_MEMBER_ROLES.map((value) => ({
|
|
4049
|
+
title: value,
|
|
4050
|
+
value
|
|
4051
|
+
}));
|
|
4052
|
+
var SCOPE_TYPES = [
|
|
4053
|
+
{ title: "Owned (areas + repos)", value: "owned" },
|
|
4054
|
+
{ title: "All events", value: "all" },
|
|
4055
|
+
{ title: "Specific areas", value: "areas" },
|
|
4056
|
+
{ title: "Specific repos", value: "repos" },
|
|
4057
|
+
{ title: "Specific tags", value: "tags" }
|
|
4058
|
+
];
|
|
4059
|
+
var channelScopeField = defineField6({
|
|
4060
|
+
description: "Which events this channel cares about. 'Owned' uses the team's own areas + repos. 'All' receives every event. The remaining variants scope to a specific list of areas, repos, or tags.",
|
|
4061
|
+
fields: [
|
|
4062
|
+
defineField6({
|
|
4063
|
+
description: "Scope discriminator",
|
|
4064
|
+
name: "type",
|
|
4065
|
+
options: {
|
|
4066
|
+
layout: "radio",
|
|
4067
|
+
list: [...SCOPE_TYPES]
|
|
4068
|
+
},
|
|
4069
|
+
title: "Scope Type",
|
|
4070
|
+
type: "string",
|
|
4071
|
+
validation: (rule) => rule.required()
|
|
4072
|
+
}),
|
|
4073
|
+
defineField6({
|
|
4074
|
+
description: "Feature areas this channel listens to",
|
|
4075
|
+
hidden: ({ parent }) => parent?.type !== "areas",
|
|
4076
|
+
name: "areas",
|
|
4077
|
+
of: [
|
|
4078
|
+
defineArrayMember({
|
|
4079
|
+
to: [{ type: "ailf.featureArea" }],
|
|
4080
|
+
type: "reference"
|
|
4081
|
+
})
|
|
4082
|
+
],
|
|
4083
|
+
title: "Areas",
|
|
4084
|
+
type: "array"
|
|
4085
|
+
}),
|
|
4086
|
+
defineField6({
|
|
4087
|
+
description: "Repository identifiers this channel listens to",
|
|
4088
|
+
hidden: ({ parent }) => parent?.type !== "repos",
|
|
4089
|
+
name: "repos",
|
|
4090
|
+
of: [defineArrayMember({ type: "string" })],
|
|
4091
|
+
title: "Repos",
|
|
4092
|
+
type: "array"
|
|
4093
|
+
}),
|
|
4094
|
+
defineField6({
|
|
4095
|
+
description: "Task tags this channel listens to",
|
|
4096
|
+
hidden: ({ parent }) => parent?.type !== "tags",
|
|
4097
|
+
name: "tags",
|
|
4098
|
+
of: [defineArrayMember({ type: "string" })],
|
|
4099
|
+
title: "Tags",
|
|
4100
|
+
type: "array"
|
|
4101
|
+
})
|
|
4102
|
+
],
|
|
4103
|
+
initialValue: { type: "owned" },
|
|
4104
|
+
name: "scope",
|
|
4105
|
+
title: "Scope",
|
|
4106
|
+
type: "object"
|
|
4107
|
+
});
|
|
4108
|
+
var channelPurposeField = defineField6({
|
|
4109
|
+
description: "Short human-readable label describing what this channel is used for (e.g. 'GROQ on-call', 'Visual editing weekly digest').",
|
|
4110
|
+
name: "purpose",
|
|
4111
|
+
title: "Purpose",
|
|
4112
|
+
type: "string"
|
|
4113
|
+
});
|
|
4114
|
+
var channelEventsField = defineField6({
|
|
4115
|
+
description: "Event types this channel receives. Suggestions come from the known event-type registry, but custom strings are accepted.",
|
|
4116
|
+
name: "events",
|
|
4117
|
+
of: [defineArrayMember({ type: "string" })],
|
|
4118
|
+
options: {
|
|
4119
|
+
layout: "tags",
|
|
4120
|
+
list: EVENT_TYPE_SUGGESTIONS
|
|
4121
|
+
},
|
|
4122
|
+
title: "Events",
|
|
4123
|
+
type: "array"
|
|
4124
|
+
});
|
|
4125
|
+
var teamMemberMember = defineArrayMember({
|
|
4126
|
+
fields: [
|
|
4127
|
+
defineField6({
|
|
4128
|
+
description: "Email address (preferred routing identity)",
|
|
4129
|
+
name: "email",
|
|
4130
|
+
title: "Email",
|
|
4131
|
+
type: "string",
|
|
4132
|
+
validation: (rule) => rule.email()
|
|
4133
|
+
}),
|
|
4134
|
+
defineField6({
|
|
4135
|
+
description: "Sanity user id (for Studio mentions / permissions)",
|
|
4136
|
+
name: "sanityUserId",
|
|
4137
|
+
title: "Sanity User ID",
|
|
4138
|
+
type: "string"
|
|
4139
|
+
}),
|
|
4140
|
+
defineField6({
|
|
4141
|
+
description: "GitHub username (for PR review routing)",
|
|
4142
|
+
name: "githubUsername",
|
|
4143
|
+
title: "GitHub Username",
|
|
4144
|
+
type: "string"
|
|
4145
|
+
}),
|
|
4146
|
+
defineField6({
|
|
4147
|
+
description: "Human-readable display name",
|
|
4148
|
+
name: "displayName",
|
|
4149
|
+
title: "Display Name",
|
|
4150
|
+
type: "string"
|
|
4151
|
+
}),
|
|
4152
|
+
defineField6({
|
|
4153
|
+
description: "Role within the team. Suggestions come from the known member-role registry, but custom roles are accepted.",
|
|
4154
|
+
name: "role",
|
|
4155
|
+
options: {
|
|
4156
|
+
list: [...MEMBER_ROLE_SUGGESTIONS]
|
|
4157
|
+
},
|
|
4158
|
+
title: "Role",
|
|
4159
|
+
type: "string"
|
|
4160
|
+
}),
|
|
4161
|
+
defineField6({
|
|
4162
|
+
description: "When this member's identity was last verified",
|
|
4163
|
+
name: "lastVerifiedAt",
|
|
4164
|
+
title: "Last Verified At",
|
|
4165
|
+
type: "datetime"
|
|
4166
|
+
})
|
|
4167
|
+
],
|
|
4168
|
+
name: "teamMember",
|
|
4169
|
+
preview: {
|
|
4170
|
+
prepare({
|
|
4171
|
+
displayName,
|
|
4172
|
+
email,
|
|
4173
|
+
githubUsername,
|
|
4174
|
+
role
|
|
4175
|
+
}) {
|
|
4176
|
+
const name = typeof displayName === "string" && displayName ? displayName : typeof email === "string" && email ? email : typeof githubUsername === "string" && githubUsername ? githubUsername : "(unnamed member)";
|
|
4177
|
+
const handle = typeof email === "string" && email ? email : typeof githubUsername === "string" && githubUsername ? `@${githubUsername}` : "";
|
|
4178
|
+
const subtitle = [typeof role === "string" ? role : "", handle].filter(Boolean).join(" \xB7 ");
|
|
4179
|
+
return { subtitle, title: name };
|
|
4180
|
+
},
|
|
4181
|
+
select: {
|
|
4182
|
+
displayName: "displayName",
|
|
4183
|
+
email: "email",
|
|
4184
|
+
githubUsername: "githubUsername",
|
|
4185
|
+
role: "role"
|
|
4186
|
+
}
|
|
4187
|
+
},
|
|
4188
|
+
title: "Team Member",
|
|
4189
|
+
type: "object",
|
|
4190
|
+
validation: (rule) => rule.custom((m) => {
|
|
4191
|
+
const member = m;
|
|
4192
|
+
if (!member) return true;
|
|
4193
|
+
const hasIdentity = typeof member.email === "string" && member.email.length > 0 || typeof member.sanityUserId === "string" && member.sanityUserId.length > 0 || typeof member.githubUsername === "string" && member.githubUsername.length > 0;
|
|
4194
|
+
return hasIdentity || "At least one of email, Sanity user id, or GitHub username is required";
|
|
4195
|
+
})
|
|
4196
|
+
});
|
|
4197
|
+
var slackChannelMember = defineArrayMember({
|
|
4198
|
+
fields: [
|
|
4199
|
+
defineField6({
|
|
4200
|
+
description: "Slack channel id (e.g. 'C01ABCDEF'). Must start with 'C' and contain only uppercase letters and digits.",
|
|
4201
|
+
name: "channelId",
|
|
4202
|
+
title: "Channel ID",
|
|
4203
|
+
type: "string",
|
|
4204
|
+
validation: (rule) => rule.required().custom((value) => {
|
|
4205
|
+
if (typeof value !== "string") return "Channel id is required";
|
|
4206
|
+
if (!/^C[A-Z0-9]+$/.test(value)) {
|
|
4207
|
+
return "Must start with 'C' followed by uppercase letters and digits";
|
|
4208
|
+
}
|
|
4209
|
+
return true;
|
|
4210
|
+
})
|
|
4211
|
+
}),
|
|
4212
|
+
defineField6({
|
|
4213
|
+
description: "Human-readable channel name (e.g. '#groq-oncall')",
|
|
4214
|
+
name: "channelName",
|
|
4215
|
+
title: "Channel Name",
|
|
4216
|
+
type: "string"
|
|
4217
|
+
}),
|
|
4218
|
+
channelPurposeField,
|
|
4219
|
+
channelEventsField,
|
|
4220
|
+
channelScopeField
|
|
4221
|
+
],
|
|
4222
|
+
name: "slackChannel",
|
|
4223
|
+
preview: {
|
|
4224
|
+
prepare({ channelId, channelName, purpose }) {
|
|
4225
|
+
const name = typeof channelName === "string" && channelName ? channelName : typeof channelId === "string" ? channelId : "(slack)";
|
|
4226
|
+
return {
|
|
4227
|
+
subtitle: typeof purpose === "string" && purpose ? purpose : "Slack channel",
|
|
4228
|
+
title: name
|
|
4229
|
+
};
|
|
4230
|
+
},
|
|
4231
|
+
select: {
|
|
4232
|
+
channelId: "channelId",
|
|
4233
|
+
channelName: "channelName",
|
|
4234
|
+
purpose: "purpose"
|
|
4235
|
+
}
|
|
4236
|
+
},
|
|
4237
|
+
title: "Slack Channel",
|
|
4238
|
+
type: "object"
|
|
4239
|
+
});
|
|
4240
|
+
var emailChannelMember = defineArrayMember({
|
|
4241
|
+
fields: [
|
|
4242
|
+
defineField6({
|
|
4243
|
+
description: "Email addresses that receive notifications on this channel",
|
|
4244
|
+
name: "addresses",
|
|
4245
|
+
of: [defineArrayMember({ type: "string" })],
|
|
4246
|
+
title: "Addresses",
|
|
4247
|
+
type: "array",
|
|
4248
|
+
validation: (rule) => rule.min(1)
|
|
4249
|
+
}),
|
|
4250
|
+
channelPurposeField,
|
|
4251
|
+
channelEventsField,
|
|
4252
|
+
channelScopeField
|
|
4253
|
+
],
|
|
4254
|
+
name: "emailChannel",
|
|
4255
|
+
preview: {
|
|
4256
|
+
prepare({ addresses, purpose }) {
|
|
4257
|
+
const list = Array.isArray(addresses) ? addresses.filter((a) => typeof a === "string") : [];
|
|
4258
|
+
const first = list[0] ?? "(email)";
|
|
4259
|
+
const more = list.length > 1 ? ` (+${list.length - 1} more)` : "";
|
|
4260
|
+
return {
|
|
4261
|
+
subtitle: typeof purpose === "string" && purpose ? purpose : "Email channel",
|
|
4262
|
+
title: `${first}${more}`
|
|
4263
|
+
};
|
|
4264
|
+
},
|
|
4265
|
+
select: {
|
|
4266
|
+
addresses: "addresses",
|
|
4267
|
+
purpose: "purpose"
|
|
4268
|
+
}
|
|
4269
|
+
},
|
|
4270
|
+
title: "Email Channel",
|
|
4271
|
+
type: "object"
|
|
4272
|
+
});
|
|
4273
|
+
var webhookChannelMember = defineArrayMember({
|
|
4274
|
+
fields: [
|
|
4275
|
+
defineField6({
|
|
4276
|
+
description: "Logical webhook name resolved at dispatch time. Do not paste raw URLs \u2014 the actual URL is configured outside Studio so secrets stay out of the Content Lake.",
|
|
4277
|
+
name: "logicalName",
|
|
4278
|
+
title: "Logical Name",
|
|
4279
|
+
type: "string",
|
|
4280
|
+
validation: (rule) => rule.required()
|
|
4281
|
+
}),
|
|
4282
|
+
channelPurposeField,
|
|
4283
|
+
channelEventsField,
|
|
4284
|
+
channelScopeField
|
|
4285
|
+
],
|
|
4286
|
+
name: "webhookChannel",
|
|
4287
|
+
preview: {
|
|
4288
|
+
prepare({ logicalName, purpose }) {
|
|
4289
|
+
return {
|
|
4290
|
+
subtitle: typeof purpose === "string" && purpose ? purpose : "Webhook channel",
|
|
4291
|
+
title: typeof logicalName === "string" && logicalName ? logicalName : "(webhook)"
|
|
4292
|
+
};
|
|
4293
|
+
},
|
|
4294
|
+
select: {
|
|
4295
|
+
logicalName: "logicalName",
|
|
4296
|
+
purpose: "purpose"
|
|
4297
|
+
}
|
|
4298
|
+
},
|
|
4299
|
+
title: "Webhook Channel",
|
|
4300
|
+
type: "object"
|
|
4301
|
+
});
|
|
4302
|
+
var teamSchema = defineType6({
|
|
4010
4303
|
groups: [
|
|
4011
4304
|
{ name: "main", title: "Main", default: true },
|
|
4012
|
-
{ name: "
|
|
4305
|
+
{ name: "members", title: "Members" },
|
|
4306
|
+
{ name: "ownership", title: "Ownership" },
|
|
4307
|
+
{ name: "notifications", title: "Notifications" },
|
|
4013
4308
|
ALL_FIELDS_GROUP6
|
|
4014
4309
|
],
|
|
4015
4310
|
fields: [
|
|
4016
4311
|
defineField6({
|
|
4312
|
+
description: "Unique stable identifier (e.g. 'groq-team'). Lowercase alphanumeric with hyphens. Used for cross-document references and routing keys.",
|
|
4313
|
+
group: ["main", "all-fields"],
|
|
4314
|
+
name: "slug",
|
|
4315
|
+
options: {
|
|
4316
|
+
maxLength: 64,
|
|
4317
|
+
source: "displayName"
|
|
4318
|
+
},
|
|
4319
|
+
title: "Slug",
|
|
4320
|
+
type: "slug",
|
|
4321
|
+
validation: (rule) => rule.required().custom((slug) => {
|
|
4322
|
+
if (slug?.current && !/^[a-z0-9][a-z0-9-]*$/.test(slug.current)) {
|
|
4323
|
+
return "Must be lowercase alphanumeric with hyphens (e.g. 'groq-team')";
|
|
4324
|
+
}
|
|
4325
|
+
return true;
|
|
4326
|
+
})
|
|
4327
|
+
}),
|
|
4328
|
+
defineField6({
|
|
4329
|
+
description: "Human-readable team name (e.g. 'GROQ Platform')",
|
|
4330
|
+
group: ["main", "all-fields"],
|
|
4331
|
+
name: "displayName",
|
|
4332
|
+
title: "Display Name",
|
|
4333
|
+
type: "string",
|
|
4334
|
+
validation: (rule) => rule.required().min(1)
|
|
4335
|
+
}),
|
|
4336
|
+
defineField6({
|
|
4337
|
+
description: "What this team owns and how they prefer to be contacted",
|
|
4338
|
+
group: ["main", "all-fields"],
|
|
4339
|
+
name: "description",
|
|
4340
|
+
title: "Description",
|
|
4341
|
+
type: "string"
|
|
4342
|
+
}),
|
|
4343
|
+
defineField6({
|
|
4344
|
+
description: "Lifecycle status. Active teams receive routed notifications; archived teams are preserved for historical references but excluded from default routing.",
|
|
4345
|
+
group: ["main", "all-fields"],
|
|
4346
|
+
initialValue: "active",
|
|
4347
|
+
name: "status",
|
|
4348
|
+
options: {
|
|
4349
|
+
list: [
|
|
4350
|
+
{ title: "Active", value: "active" },
|
|
4351
|
+
{ title: "Archived", value: "archived" }
|
|
4352
|
+
]
|
|
4353
|
+
},
|
|
4354
|
+
title: "Status",
|
|
4355
|
+
type: "string",
|
|
4356
|
+
validation: (rule) => rule.required()
|
|
4357
|
+
}),
|
|
4358
|
+
defineField6({
|
|
4359
|
+
description: "People on this team. Each member needs at least one of email, Sanity user id, or GitHub username so the routing layer can resolve them to a real account.",
|
|
4360
|
+
group: ["members", "all-fields"],
|
|
4361
|
+
name: "members",
|
|
4362
|
+
of: [teamMemberMember],
|
|
4363
|
+
title: "Members",
|
|
4364
|
+
type: "array",
|
|
4365
|
+
validation: (rule) => rule.required().min(1)
|
|
4366
|
+
}),
|
|
4367
|
+
defineField6({
|
|
4368
|
+
description: "Repository identifiers this team owns (e.g. 'sanity-io/sanity'). Used by channel scope 'owned' and 'repos'.",
|
|
4369
|
+
group: ["ownership", "all-fields"],
|
|
4370
|
+
name: "repos",
|
|
4371
|
+
of: [defineArrayMember({ type: "string" })],
|
|
4372
|
+
title: "Repos",
|
|
4373
|
+
type: "array"
|
|
4374
|
+
}),
|
|
4375
|
+
defineField6({
|
|
4376
|
+
description: "Notification channels for this team. Each channel carries its own purpose, event subscriptions, and scope.",
|
|
4377
|
+
group: ["notifications", "all-fields"],
|
|
4378
|
+
name: "notifications",
|
|
4379
|
+
of: [slackChannelMember, emailChannelMember, webhookChannelMember],
|
|
4380
|
+
title: "Notification Channels",
|
|
4381
|
+
type: "array"
|
|
4382
|
+
})
|
|
4383
|
+
],
|
|
4384
|
+
name: "ailf.team",
|
|
4385
|
+
preview: {
|
|
4386
|
+
prepare({ displayName, slug }) {
|
|
4387
|
+
const slugCurrent = slug !== null && typeof slug === "object" && "current" in slug ? slug.current : void 0;
|
|
4388
|
+
return {
|
|
4389
|
+
subtitle: typeof slugCurrent === "string" ? slugCurrent : "",
|
|
4390
|
+
title: typeof displayName === "string" && displayName ? displayName : "Team"
|
|
4391
|
+
};
|
|
4392
|
+
},
|
|
4393
|
+
select: {
|
|
4394
|
+
displayName: "displayName",
|
|
4395
|
+
slug: "slug"
|
|
4396
|
+
}
|
|
4397
|
+
},
|
|
4398
|
+
title: "AILF Team",
|
|
4399
|
+
type: "document"
|
|
4400
|
+
});
|
|
4401
|
+
|
|
4402
|
+
// src/schema/webhook-config.ts
|
|
4403
|
+
import { ALL_FIELDS_GROUP as ALL_FIELDS_GROUP7, defineField as defineField7, defineType as defineType7 } from "sanity";
|
|
4404
|
+
var webhookConfigSchema = defineType7({
|
|
4405
|
+
groups: [
|
|
4406
|
+
{ name: "main", title: "Main", default: true },
|
|
4407
|
+
{ name: "optional", title: "Optional" },
|
|
4408
|
+
ALL_FIELDS_GROUP7
|
|
4409
|
+
],
|
|
4410
|
+
fields: [
|
|
4411
|
+
defineField7({
|
|
4017
4412
|
description: "When enabled, publishing articles will automatically trigger AI Literacy evaluations for affected feature areas.",
|
|
4018
4413
|
group: ["main", "all-fields"],
|
|
4019
4414
|
initialValue: false,
|
|
@@ -4021,7 +4416,7 @@ var webhookConfigSchema = defineType6({
|
|
|
4021
4416
|
title: "Evaluate on Publish",
|
|
4022
4417
|
type: "boolean"
|
|
4023
4418
|
}),
|
|
4024
|
-
|
|
4419
|
+
defineField7({
|
|
4025
4420
|
description: "Which evaluation mode to use for webhook-triggered evaluations.",
|
|
4026
4421
|
group: ["main", "all-fields"],
|
|
4027
4422
|
initialValue: "baseline",
|
|
@@ -4037,7 +4432,7 @@ var webhookConfigSchema = defineType6({
|
|
|
4037
4432
|
title: "Evaluation Mode",
|
|
4038
4433
|
type: "string"
|
|
4039
4434
|
}),
|
|
4040
|
-
|
|
4435
|
+
defineField7({
|
|
4041
4436
|
description: "Maximum evaluations per day. Prevents runaway costs from rapid editing.",
|
|
4042
4437
|
group: ["main", "all-fields"],
|
|
4043
4438
|
initialValue: 20,
|
|
@@ -4046,7 +4441,7 @@ var webhookConfigSchema = defineType6({
|
|
|
4046
4441
|
type: "number",
|
|
4047
4442
|
validation: (rule) => rule.min(1).max(100)
|
|
4048
4443
|
}),
|
|
4049
|
-
|
|
4444
|
+
defineField7({
|
|
4050
4445
|
description: "Seconds to wait after the last edit before dispatching. Coalesces rapid edits into a single evaluation.",
|
|
4051
4446
|
group: ["optional", "all-fields"],
|
|
4052
4447
|
initialValue: 300,
|
|
@@ -4055,7 +4450,7 @@ var webhookConfigSchema = defineType6({
|
|
|
4055
4450
|
type: "number",
|
|
4056
4451
|
validation: (rule) => rule.min(10).max(3600)
|
|
4057
4452
|
}),
|
|
4058
|
-
|
|
4453
|
+
defineField7({
|
|
4059
4454
|
description: "Specific feature areas to evaluate. Leave empty to evaluate all affected areas automatically.",
|
|
4060
4455
|
group: ["optional", "all-fields"],
|
|
4061
4456
|
name: "areas",
|
|
@@ -4063,7 +4458,7 @@ var webhookConfigSchema = defineType6({
|
|
|
4063
4458
|
title: "Area Filter",
|
|
4064
4459
|
type: "array"
|
|
4065
4460
|
}),
|
|
4066
|
-
|
|
4461
|
+
defineField7({
|
|
4067
4462
|
description: "Slack webhook URL for notifications about webhook-triggered evaluations.",
|
|
4068
4463
|
group: ["optional", "all-fields"],
|
|
4069
4464
|
name: "notifySlack",
|
|
@@ -4834,6 +5229,11 @@ var latestReportsQuery = (
|
|
|
4834
5229
|
"trigger": provenance.trigger.type,
|
|
4835
5230
|
"classification": provenance.classification,
|
|
4836
5231
|
"ownerTeam": provenance.owner.team,
|
|
5232
|
+
"teamDoc": *[_type == "ailf.team" && slug.current == ^.provenance.owner.team][0]{
|
|
5233
|
+
_id,
|
|
5234
|
+
displayName,
|
|
5235
|
+
status
|
|
5236
|
+
},
|
|
4837
5237
|
"ownerIndividual": provenance.owner.individual,
|
|
4838
5238
|
"executorType": provenance.executor.type,
|
|
4839
5239
|
"executorName": provenance.executor.name,
|
|
@@ -4916,6 +5316,11 @@ var reportDetailQuery = (
|
|
|
4916
5316
|
tag,
|
|
4917
5317
|
title,
|
|
4918
5318
|
provenance,
|
|
5319
|
+
"teamDoc": *[_type == "ailf.team" && slug.current == ^.provenance.owner.team][0]{
|
|
5320
|
+
_id,
|
|
5321
|
+
displayName,
|
|
5322
|
+
status
|
|
5323
|
+
},
|
|
4919
5324
|
summary,
|
|
4920
5325
|
"comparison": comparison {
|
|
4921
5326
|
areas,
|
|
@@ -15330,7 +15735,7 @@ function ailfTool(options = {}) {
|
|
|
15330
15735
|
}
|
|
15331
15736
|
|
|
15332
15737
|
// src/structure.ts
|
|
15333
|
-
import { ArchiveIcon as ArchiveIcon2, TaskIcon } from "@sanity/icons";
|
|
15738
|
+
import { ArchiveIcon as ArchiveIcon2, TaskIcon, WarningOutlineIcon as WarningOutlineIcon5 } from "@sanity/icons";
|
|
15334
15739
|
function ailfTaskStructureItem(S) {
|
|
15335
15740
|
return S.listItem().id("ailfTasks").title("AILF Tasks").icon(TaskIcon).child(
|
|
15336
15741
|
S.list().id("ailfTasksViews").title("AILF Tasks").items([
|
|
@@ -15353,12 +15758,68 @@ function ailfTaskStructureItem(S) {
|
|
|
15353
15758
|
])
|
|
15354
15759
|
);
|
|
15355
15760
|
}
|
|
15761
|
+
function ailfTeamsStructureItem(S) {
|
|
15762
|
+
return S.listItem().id("ailfTeams").title("Teams").child(
|
|
15763
|
+
S.list().id("ailfTeamsViews").title("Teams").items([
|
|
15764
|
+
S.listItem().id("activeTeams").title("Active teams").child(
|
|
15765
|
+
S.documentTypeList("ailf.team").id("ailfTeamsActive").title("Active teams").apiVersion(API_VERSION).filter('_type == "ailf.team" && status == "active"')
|
|
15766
|
+
),
|
|
15767
|
+
S.listItem().id("archivedTeams").title("Archived teams").icon(ArchiveIcon2).child(
|
|
15768
|
+
S.documentTypeList("ailf.team").id("ailfTeamsArchived").title("Archived teams").apiVersion(API_VERSION).filter('_type == "ailf.team" && status == "archived"')
|
|
15769
|
+
),
|
|
15770
|
+
S.divider(),
|
|
15771
|
+
S.listItem().id("allTeams").title("All teams").child(
|
|
15772
|
+
S.documentTypeList("ailf.team").id("ailfTeamsAll").title("All teams")
|
|
15773
|
+
)
|
|
15774
|
+
])
|
|
15775
|
+
);
|
|
15776
|
+
}
|
|
15777
|
+
function ailfAreasStructureItem(S) {
|
|
15778
|
+
return S.listItem().id("ailfAreas").title("Areas").child(
|
|
15779
|
+
S.list().id("ailfAreasViews").title("Areas").items([
|
|
15780
|
+
S.listItem().id("allAreas").title("All areas").child(
|
|
15781
|
+
S.documentTypeList("ailf.featureArea").id("ailfAreasAll").title("All areas")
|
|
15782
|
+
),
|
|
15783
|
+
S.divider(),
|
|
15784
|
+
S.listItem().id("unownedAreas").title("\u26A0 Unowned areas").icon(WarningOutlineIcon5).child(
|
|
15785
|
+
S.documentTypeList("ailf.featureArea").id("ailfAreasUnowned").title("\u26A0 Unowned areas").apiVersion(API_VERSION).filter('_type == "ailf.featureArea" && !defined(team)')
|
|
15786
|
+
)
|
|
15787
|
+
])
|
|
15788
|
+
);
|
|
15789
|
+
}
|
|
15790
|
+
function ailfReportsStructureItem(S) {
|
|
15791
|
+
return S.listItem().id("ailfReports").title("Reports").child(
|
|
15792
|
+
S.list().id("ailfReportsViews").title("Reports").items([
|
|
15793
|
+
S.listItem().id("allReports").title("All reports").child(
|
|
15794
|
+
S.documentTypeList("ailf.report").id("ailfReportsAll").title("All reports")
|
|
15795
|
+
),
|
|
15796
|
+
S.divider(),
|
|
15797
|
+
S.listItem().id("unresolvedTeamReports").title("\u26A0 Reports with unresolved team").icon(WarningOutlineIcon5).child(
|
|
15798
|
+
S.documentList().id("ailfReportsUnresolvedTeam").title("\u26A0 Reports with unresolved team").apiVersion(API_VERSION).filter(
|
|
15799
|
+
`_type == "ailf.report" && defined(provenance.owner.team) && provenance.owner.team != "unknown" && !(provenance.owner.team in *[_type == "ailf.team"].slug.current)`
|
|
15800
|
+
)
|
|
15801
|
+
)
|
|
15802
|
+
])
|
|
15803
|
+
);
|
|
15804
|
+
}
|
|
15805
|
+
function ailfChannelsWithUnknownEventsItem(S) {
|
|
15806
|
+
return S.listItem().id("ailfChannelsUnknownEvents").title("\u26A0 Channels with unknown events").icon(WarningOutlineIcon5).child(
|
|
15807
|
+
S.documentList().id("ailfChannelsUnknownEventsList").title("Teams whose channels reference unknown event types").apiVersion(API_VERSION).filter(
|
|
15808
|
+
`_type == "ailf.team" && count(notifications[count(events[!(@ in $known)]) > 0]) > 0`
|
|
15809
|
+
).params({ known: [...KNOWN_EVENT_TYPES] })
|
|
15810
|
+
);
|
|
15811
|
+
}
|
|
15356
15812
|
var ailfStructure = (S) => S.list().id("root").title("Content").items([
|
|
15357
15813
|
ailfTaskStructureItem(S),
|
|
15814
|
+
ailfTeamsStructureItem(S),
|
|
15815
|
+
ailfAreasStructureItem(S),
|
|
15816
|
+
ailfReportsStructureItem(S),
|
|
15817
|
+
ailfChannelsWithUnknownEventsItem(S),
|
|
15358
15818
|
S.divider(),
|
|
15359
|
-
...S.documentTypeListItems().filter(
|
|
15360
|
-
|
|
15361
|
-
|
|
15819
|
+
...S.documentTypeListItems().filter((listItem) => {
|
|
15820
|
+
const id = listItem.getId();
|
|
15821
|
+
return id !== "ailf.task" && id !== "ailf.team" && id !== "ailf.featureArea" && id !== "ailf.report";
|
|
15822
|
+
})
|
|
15362
15823
|
]);
|
|
15363
15824
|
|
|
15364
15825
|
// src/actions/RunEvaluationAction.tsx
|
|
@@ -15646,6 +16107,7 @@ var ailfPlugin = definePlugin((options) => ({
|
|
|
15646
16107
|
referenceSolutionSchema,
|
|
15647
16108
|
reportSchema,
|
|
15648
16109
|
taskSchema,
|
|
16110
|
+
teamSchema,
|
|
15649
16111
|
webhookConfigSchema
|
|
15650
16112
|
]
|
|
15651
16113
|
},
|
|
@@ -15689,6 +16151,7 @@ export {
|
|
|
15689
16151
|
scoreTimelineQuery,
|
|
15690
16152
|
searchTopics,
|
|
15691
16153
|
taskSchema,
|
|
16154
|
+
teamSchema,
|
|
15692
16155
|
useHelp,
|
|
15693
16156
|
webhookConfigSchema
|
|
15694
16157
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanity/ailf-studio",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "AI Literacy Framework — Sanity Studio dashboard plugin",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"@testing-library/dom": "^10.4.1",
|
|
46
46
|
"@testing-library/react": "^16.3.2",
|
|
47
47
|
"@types/react": "^19.0.0",
|
|
48
|
+
"groq-js": "^1.30.1",
|
|
48
49
|
"jsdom": "^29.0.2",
|
|
49
50
|
"react": "^19.0.0",
|
|
50
51
|
"sanity": "^5.14.0",
|
|
@@ -69,9 +70,11 @@
|
|
|
69
70
|
"scripts": {
|
|
70
71
|
"generate-hooks": "tsx scripts/generate-hooks.ts",
|
|
71
72
|
"migrate-to-private-dataset": "tsx scripts/migrate-to-private-dataset.ts",
|
|
73
|
+
"seed-teams": "tsx scripts/seed-teams.ts",
|
|
72
74
|
"build": "tsup",
|
|
73
75
|
"dev": "tsup --watch",
|
|
74
76
|
"test": "vitest run",
|
|
75
|
-
"test:watch": "vitest"
|
|
77
|
+
"test:watch": "vitest",
|
|
78
|
+
"bench": "vitest bench --run"
|
|
76
79
|
}
|
|
77
80
|
}
|