@storyshelf/core 0.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/README.md +127 -0
- package/dist/adapter/auth.d.mts +50 -0
- package/dist/adapter/auth.mjs +10 -0
- package/dist/adapter/auth.mjs.map +1 -0
- package/dist/adapter/capture-runner.d.mts +70 -0
- package/dist/adapter/capture-runner.mjs +4 -0
- package/dist/adapter/database.d.mts +43 -0
- package/dist/adapter/database.mjs +4 -0
- package/dist/adapter/git-host/helpers.d.mts +12 -0
- package/dist/adapter/git-host/helpers.mjs +29 -0
- package/dist/adapter/git-host/helpers.mjs.map +1 -0
- package/dist/adapter/git-host.d.mts +46 -0
- package/dist/adapter/git-host.mjs +4 -0
- package/dist/adapter/storage.d.mts +22 -0
- package/dist/adapter/storage.mjs +4 -0
- package/dist/adapters/capture-queue.d.mts +49 -0
- package/dist/adapters/metadata.d.mts +24 -0
- package/dist/adapters/webhook-events.mjs +39 -0
- package/dist/adapters/webhook-events.mjs.map +1 -0
- package/dist/capture/adapter.d.mts +29 -0
- package/dist/capture/adapter.mjs +13 -0
- package/dist/capture/adapter.mjs.map +1 -0
- package/dist/capture/orchestrator.d.mts +23 -0
- package/dist/capture/orchestrator.mjs +103 -0
- package/dist/capture/orchestrator.mjs.map +1 -0
- package/dist/capture/pipeline.d.mts +41 -0
- package/dist/capture/pipeline.mjs +119 -0
- package/dist/capture/pipeline.mjs.map +1 -0
- package/dist/capture/queue.d.mts +35 -0
- package/dist/capture/queue.mjs +96 -0
- package/dist/capture/queue.mjs.map +1 -0
- package/dist/capture/status-fanout.mjs +66 -0
- package/dist/capture/status-fanout.mjs.map +1 -0
- package/dist/capture/storybook.d.mts +14 -0
- package/dist/capture/storybook.mjs +40 -0
- package/dist/capture/storybook.mjs.map +1 -0
- package/dist/config.d.mts +68 -0
- package/dist/config.mjs +69 -0
- package/dist/config.mjs.map +1 -0
- package/dist/ddl.d.mts +7 -0
- package/dist/ddl.mjs +155 -0
- package/dist/ddl.mjs.map +1 -0
- package/dist/diff/engine.d.mts +8 -0
- package/dist/diff/engine.mjs +79 -0
- package/dist/diff/engine.mjs.map +1 -0
- package/dist/diff/options.d.mts +40 -0
- package/dist/diff/options.mjs +15 -0
- package/dist/diff/options.mjs.map +1 -0
- package/dist/index.d.mts +48 -0
- package/dist/index.mjs +327 -0
- package/dist/index.mjs.map +1 -0
- package/dist/logger.d.mts +39 -0
- package/dist/logger.mjs +35 -0
- package/dist/logger.mjs.map +1 -0
- package/dist/middleware/csrf.mjs +39 -0
- package/dist/middleware/csrf.mjs.map +1 -0
- package/dist/middleware/rate-limit.mjs +38 -0
- package/dist/middleware/rate-limit.mjs.map +1 -0
- package/dist/models/baseline.d.mts +20 -0
- package/dist/models/baseline.mjs +89 -0
- package/dist/models/baseline.mjs.map +1 -0
- package/dist/models/build.d.mts +35 -0
- package/dist/models/build.mjs +77 -0
- package/dist/models/build.mjs.map +1 -0
- package/dist/models/comment.d.mts +20 -0
- package/dist/models/comment.mjs +42 -0
- package/dist/models/comment.mjs.map +1 -0
- package/dist/models/label.d.mts +43 -0
- package/dist/models/label.mjs +107 -0
- package/dist/models/label.mjs.map +1 -0
- package/dist/models/member.d.mts +27 -0
- package/dist/models/member.mjs +54 -0
- package/dist/models/member.mjs.map +1 -0
- package/dist/models/project.d.mts +42 -0
- package/dist/models/project.mjs +78 -0
- package/dist/models/project.mjs.map +1 -0
- package/dist/models/snapshot.d.mts +46 -0
- package/dist/models/snapshot.mjs +75 -0
- package/dist/models/snapshot.mjs.map +1 -0
- package/dist/models/status-config.mjs +61 -0
- package/dist/models/status-config.mjs.map +1 -0
- package/dist/models/token.d.mts +33 -0
- package/dist/models/token.mjs +60 -0
- package/dist/models/token.mjs.map +1 -0
- package/dist/models/webhook.d.mts +37 -0
- package/dist/models/webhook.mjs +67 -0
- package/dist/models/webhook.mjs.map +1 -0
- package/dist/pages/build-detail.mjs +333 -0
- package/dist/pages/build-detail.mjs.map +1 -0
- package/dist/pages/build-diff.mjs +437 -0
- package/dist/pages/build-diff.mjs.map +1 -0
- package/dist/pages/compute-jobs.mjs +196 -0
- package/dist/pages/compute-jobs.mjs.map +1 -0
- package/dist/pages/login.mjs +77 -0
- package/dist/pages/login.mjs.map +1 -0
- package/dist/pages/project-builds.mjs +228 -0
- package/dist/pages/project-builds.mjs.map +1 -0
- package/dist/pages/project-create.mjs +168 -0
- package/dist/pages/project-create.mjs.map +1 -0
- package/dist/pages/project-settings.mjs +111 -0
- package/dist/pages/project-settings.mjs.map +1 -0
- package/dist/pages/projects.mjs +178 -0
- package/dist/pages/projects.mjs.map +1 -0
- package/dist/pages/root.mjs +90 -0
- package/dist/pages/root.mjs.map +1 -0
- package/dist/pages/settings-general.mjs +191 -0
- package/dist/pages/settings-general.mjs.map +1 -0
- package/dist/pages/settings-labels.mjs +149 -0
- package/dist/pages/settings-labels.mjs.map +1 -0
- package/dist/pages/settings-members.mjs +124 -0
- package/dist/pages/settings-members.mjs.map +1 -0
- package/dist/pages/settings-status.mjs +150 -0
- package/dist/pages/settings-status.mjs.map +1 -0
- package/dist/pages/settings-tokens.mjs +95 -0
- package/dist/pages/settings-tokens.mjs.map +1 -0
- package/dist/pages/settings-webhooks.mjs +149 -0
- package/dist/pages/settings-webhooks.mjs.map +1 -0
- package/dist/retention/purge.d.mts +28 -0
- package/dist/retention/purge.mjs +66 -0
- package/dist/retention/purge.mjs.map +1 -0
- package/dist/routers/admin.mjs +41 -0
- package/dist/routers/admin.mjs.map +1 -0
- package/dist/routers/assets.mjs +24 -0
- package/dist/routers/assets.mjs.map +1 -0
- package/dist/routers/auth.mjs +77 -0
- package/dist/routers/auth.mjs.map +1 -0
- package/dist/routers/builds.handlers.mjs +87 -0
- package/dist/routers/builds.handlers.mjs.map +1 -0
- package/dist/routers/builds.mjs +162 -0
- package/dist/routers/builds.mjs.map +1 -0
- package/dist/routers/comments.mjs +89 -0
- package/dist/routers/comments.mjs.map +1 -0
- package/dist/routers/helpers.mjs +76 -0
- package/dist/routers/helpers.mjs.map +1 -0
- package/dist/routers/htmx.mjs +18 -0
- package/dist/routers/htmx.mjs.map +1 -0
- package/dist/routers/labels.mjs +77 -0
- package/dist/routers/labels.mjs.map +1 -0
- package/dist/routers/media.mjs +54 -0
- package/dist/routers/media.mjs.map +1 -0
- package/dist/routers/members.mjs +101 -0
- package/dist/routers/members.mjs.map +1 -0
- package/dist/routers/projects.mjs +121 -0
- package/dist/routers/projects.mjs.map +1 -0
- package/dist/routers/schemas.mjs +188 -0
- package/dist/routers/schemas.mjs.map +1 -0
- package/dist/routers/settings.mjs +235 -0
- package/dist/routers/settings.mjs.map +1 -0
- package/dist/routers/snapshots.mjs +143 -0
- package/dist/routers/snapshots.mjs.map +1 -0
- package/dist/routers/status-configs.mjs +100 -0
- package/dist/routers/status-configs.mjs.map +1 -0
- package/dist/routers/tokens.mjs +80 -0
- package/dist/routers/tokens.mjs.map +1 -0
- package/dist/routers/ui.mjs +142 -0
- package/dist/routers/ui.mjs.map +1 -0
- package/dist/routers/webhooks.mjs +89 -0
- package/dist/routers/webhooks.mjs.map +1 -0
- package/dist/schema.d.mts +4372 -0
- package/dist/schema.mjs +158 -0
- package/dist/schema.mjs.map +1 -0
- package/dist/store.mjs +18 -0
- package/dist/store.mjs.map +1 -0
- package/dist/types.d.mts +18 -0
- package/dist/types.mjs +49 -0
- package/dist/types.mjs.map +1 -0
- package/dist/ui/components.mjs +127 -0
- package/dist/ui/components.mjs.map +1 -0
- package/dist/ui/document.d.mts +8 -0
- package/dist/ui/document.mjs +338 -0
- package/dist/ui/document.mjs.map +1 -0
- package/dist/ui/styles.mjs +173 -0
- package/dist/ui/styles.mjs.map +1 -0
- package/dist/ui/theme.mjs +42 -0
- package/dist/ui/theme.mjs.map +1 -0
- package/dist/urls.d.mts +19 -0
- package/dist/urls.mjs +23 -0
- package/dist/urls.mjs.map +1 -0
- package/dist/utils/encrypt.mjs +49 -0
- package/dist/utils/encrypt.mjs.map +1 -0
- package/dist/utils/hash.mjs +22 -0
- package/dist/utils/hash.mjs.map +1 -0
- package/dist/utils/paths.d.mts +11 -0
- package/dist/utils/paths.mjs +23 -0
- package/dist/utils/paths.mjs.map +1 -0
- package/dist/utils/ulid.d.mts +8 -0
- package/dist/utils/ulid.mjs +41 -0
- package/dist/utils/ulid.mjs.map +1 -0
- package/package.json +162 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { jsx, jsxs } from "hono/jsx/jsx-runtime";
|
|
5
|
+
//#region src/pages/settings-general.tsx
|
|
6
|
+
function renderSettingsGeneral(project, formState, isAdmin) {
|
|
7
|
+
const errors = formState?.errors ?? {};
|
|
8
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
9
|
+
class: "grid",
|
|
10
|
+
style: "max-width: 720px;",
|
|
11
|
+
children: [
|
|
12
|
+
formState?.globalError ? /* @__PURE__ */ jsx("div", {
|
|
13
|
+
class: "alert alert--danger",
|
|
14
|
+
role: "alert",
|
|
15
|
+
children: formState.globalError
|
|
16
|
+
}) : null,
|
|
17
|
+
/* @__PURE__ */ jsxs("div", {
|
|
18
|
+
class: "card card--padded",
|
|
19
|
+
children: [/* @__PURE__ */ jsx("h2", {
|
|
20
|
+
style: "margin:0 0 .5rem;",
|
|
21
|
+
children: "General"
|
|
22
|
+
}), /* @__PURE__ */ jsxs("form", {
|
|
23
|
+
method: "post",
|
|
24
|
+
action: `/projects/${project.slug}/settings`,
|
|
25
|
+
"hx-post": `/projects/${project.slug}/settings`,
|
|
26
|
+
"hx-target": "body",
|
|
27
|
+
"hx-swap": "outerHTML",
|
|
28
|
+
children: [
|
|
29
|
+
/* @__PURE__ */ jsxs("div", {
|
|
30
|
+
class: "field",
|
|
31
|
+
children: [
|
|
32
|
+
/* @__PURE__ */ jsx("label", {
|
|
33
|
+
class: "field__label",
|
|
34
|
+
for: "name",
|
|
35
|
+
children: "Name"
|
|
36
|
+
}),
|
|
37
|
+
/* @__PURE__ */ jsx("input", {
|
|
38
|
+
class: `field__input ${errors["name"] ? "field__input--error" : ""}`,
|
|
39
|
+
id: "name",
|
|
40
|
+
name: "name",
|
|
41
|
+
value: project.name
|
|
42
|
+
}),
|
|
43
|
+
errors["name"] ? /* @__PURE__ */ jsx("p", {
|
|
44
|
+
class: "field__error",
|
|
45
|
+
role: "alert",
|
|
46
|
+
children: errors["name"]
|
|
47
|
+
}) : null
|
|
48
|
+
]
|
|
49
|
+
}),
|
|
50
|
+
/* @__PURE__ */ jsxs("div", {
|
|
51
|
+
class: "field",
|
|
52
|
+
children: [/* @__PURE__ */ jsx("label", {
|
|
53
|
+
class: "field__label",
|
|
54
|
+
for: "gitRepository",
|
|
55
|
+
children: "Git repository"
|
|
56
|
+
}), /* @__PURE__ */ jsx("input", {
|
|
57
|
+
class: "field__input",
|
|
58
|
+
id: "gitRepository",
|
|
59
|
+
name: "gitRepository",
|
|
60
|
+
value: project.gitRepository ?? "",
|
|
61
|
+
placeholder: "owner/repo"
|
|
62
|
+
})]
|
|
63
|
+
}),
|
|
64
|
+
/* @__PURE__ */ jsxs("div", {
|
|
65
|
+
class: "field",
|
|
66
|
+
children: [/* @__PURE__ */ jsx("label", {
|
|
67
|
+
class: "field__label",
|
|
68
|
+
for: "gitDefaultBranch",
|
|
69
|
+
children: "Default branch"
|
|
70
|
+
}), /* @__PURE__ */ jsx("input", {
|
|
71
|
+
class: "field__input",
|
|
72
|
+
id: "gitDefaultBranch",
|
|
73
|
+
name: "gitDefaultBranch",
|
|
74
|
+
value: project.gitDefaultBranch
|
|
75
|
+
})]
|
|
76
|
+
}),
|
|
77
|
+
/* @__PURE__ */ jsxs("div", {
|
|
78
|
+
class: "grid grid--2",
|
|
79
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
80
|
+
class: "field",
|
|
81
|
+
children: [
|
|
82
|
+
/* @__PURE__ */ jsx("label", {
|
|
83
|
+
class: "field__label",
|
|
84
|
+
for: "pixelThreshold",
|
|
85
|
+
children: "Pixel threshold"
|
|
86
|
+
}),
|
|
87
|
+
/* @__PURE__ */ jsx("input", {
|
|
88
|
+
class: "field__input",
|
|
89
|
+
id: "pixelThreshold",
|
|
90
|
+
name: "pixelThreshold",
|
|
91
|
+
type: "number",
|
|
92
|
+
step: "0.01",
|
|
93
|
+
min: "0",
|
|
94
|
+
max: "1",
|
|
95
|
+
value: String(project.pixelThreshold)
|
|
96
|
+
}),
|
|
97
|
+
/* @__PURE__ */ jsx("p", {
|
|
98
|
+
class: "field__hint",
|
|
99
|
+
children: "Per-pixel color distance 0–1"
|
|
100
|
+
})
|
|
101
|
+
]
|
|
102
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
103
|
+
class: "field",
|
|
104
|
+
children: [
|
|
105
|
+
/* @__PURE__ */ jsx("label", {
|
|
106
|
+
class: "field__label",
|
|
107
|
+
for: "maxDiffRatio",
|
|
108
|
+
children: "Max diff ratio"
|
|
109
|
+
}),
|
|
110
|
+
/* @__PURE__ */ jsx("input", {
|
|
111
|
+
class: "field__input",
|
|
112
|
+
id: "maxDiffRatio",
|
|
113
|
+
name: "maxDiffRatio",
|
|
114
|
+
type: "number",
|
|
115
|
+
step: "0.001",
|
|
116
|
+
min: "0",
|
|
117
|
+
max: "1",
|
|
118
|
+
value: String(project.maxDiffRatio)
|
|
119
|
+
}),
|
|
120
|
+
/* @__PURE__ */ jsx("p", {
|
|
121
|
+
class: "field__hint",
|
|
122
|
+
children: "Allowed diff ratio 0–1"
|
|
123
|
+
})
|
|
124
|
+
]
|
|
125
|
+
})]
|
|
126
|
+
}),
|
|
127
|
+
/* @__PURE__ */ jsxs("div", {
|
|
128
|
+
class: "field",
|
|
129
|
+
children: [
|
|
130
|
+
/* @__PURE__ */ jsx("label", {
|
|
131
|
+
class: "field__label",
|
|
132
|
+
for: "publicBranchRegex",
|
|
133
|
+
children: "Public branch regex"
|
|
134
|
+
}),
|
|
135
|
+
/* @__PURE__ */ jsx("input", {
|
|
136
|
+
class: "field__input",
|
|
137
|
+
id: "publicBranchRegex",
|
|
138
|
+
name: "publicBranchRegex",
|
|
139
|
+
value: project.publicBranchRegex ?? "",
|
|
140
|
+
placeholder: "^main$"
|
|
141
|
+
}),
|
|
142
|
+
/* @__PURE__ */ jsx("p", {
|
|
143
|
+
class: "field__hint",
|
|
144
|
+
children: "Branches matching this regex are publicly viewable."
|
|
145
|
+
})
|
|
146
|
+
]
|
|
147
|
+
}),
|
|
148
|
+
isAdmin ? /* @__PURE__ */ jsx("button", {
|
|
149
|
+
class: "btn btn--primary",
|
|
150
|
+
type: "submit",
|
|
151
|
+
children: "Save changes"
|
|
152
|
+
}) : /* @__PURE__ */ jsx("p", {
|
|
153
|
+
class: "field__hint",
|
|
154
|
+
children: "You need admin access to edit settings."
|
|
155
|
+
})
|
|
156
|
+
]
|
|
157
|
+
})]
|
|
158
|
+
}),
|
|
159
|
+
isAdmin ? /* @__PURE__ */ jsxs("div", {
|
|
160
|
+
class: "card card--padded",
|
|
161
|
+
style: "border-color: var(--status-rejected);",
|
|
162
|
+
children: [
|
|
163
|
+
/* @__PURE__ */ jsx("h3", {
|
|
164
|
+
style: "margin:0 0 .4rem; color: var(--status-rejected);",
|
|
165
|
+
children: "Danger zone"
|
|
166
|
+
}),
|
|
167
|
+
/* @__PURE__ */ jsx("p", {
|
|
168
|
+
class: "field__hint",
|
|
169
|
+
children: "Deleting a project removes all builds, snapshots, baselines and tokens. This cannot be undone."
|
|
170
|
+
}),
|
|
171
|
+
/* @__PURE__ */ jsx("form", {
|
|
172
|
+
method: "post",
|
|
173
|
+
action: `/projects/${project.slug}/delete`,
|
|
174
|
+
"hx-post": `/projects/${project.slug}/delete`,
|
|
175
|
+
"hx-target": "body",
|
|
176
|
+
"hx-confirm": "Delete this project? This cannot be undone.",
|
|
177
|
+
children: /* @__PURE__ */ jsx("button", {
|
|
178
|
+
class: "btn btn--danger",
|
|
179
|
+
type: "submit",
|
|
180
|
+
children: "Delete project"
|
|
181
|
+
})
|
|
182
|
+
})
|
|
183
|
+
]
|
|
184
|
+
}) : null
|
|
185
|
+
]
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
//#endregion
|
|
189
|
+
export { renderSettingsGeneral };
|
|
190
|
+
|
|
191
|
+
//# sourceMappingURL=settings-general.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings-general.mjs","names":[],"sources":["../../src/pages/settings-general.tsx"],"sourcesContent":["import type { Project } from \"../schema.ts\";\n\nexport interface SettingsFormState {\n errors?: Record<string, string>;\n globalError?: string;\n}\n\nexport function renderSettingsGeneral(project: Project, formState: SettingsFormState | undefined, isAdmin: boolean): unknown {\n const errors = formState?.errors ?? {};\n return (\n <div class=\"grid\" style=\"max-width: 720px;\">\n {formState?.globalError ? (\n <div class=\"alert alert--danger\" role=\"alert\">\n {formState.globalError}\n </div>\n ) : null}\n <div class=\"card card--padded\">\n <h2 style=\"margin:0 0 .5rem;\">General</h2>\n <form\n method=\"post\"\n action={`/projects/${project.slug}/settings`}\n hx-post={`/projects/${project.slug}/settings`}\n hx-target=\"body\"\n hx-swap=\"outerHTML\"\n >\n <div class=\"field\">\n <label class=\"field__label\" for=\"name\">\n Name\n </label>\n <input class={`field__input ${errors[\"name\"] ? \"field__input--error\" : \"\"}`} id=\"name\" name=\"name\" value={project.name} />\n {errors[\"name\"] ? (\n <p class=\"field__error\" role=\"alert\">\n {errors[\"name\"]}\n </p>\n ) : null}\n </div>\n <div class=\"field\">\n <label class=\"field__label\" for=\"gitRepository\">\n Git repository\n </label>\n <input class=\"field__input\" id=\"gitRepository\" name=\"gitRepository\" value={project.gitRepository ?? \"\"} placeholder=\"owner/repo\" />\n </div>\n <div class=\"field\">\n <label class=\"field__label\" for=\"gitDefaultBranch\">\n Default branch\n </label>\n <input class=\"field__input\" id=\"gitDefaultBranch\" name=\"gitDefaultBranch\" value={project.gitDefaultBranch} />\n </div>\n <div class=\"grid grid--2\">\n <div class=\"field\">\n <label class=\"field__label\" for=\"pixelThreshold\">\n Pixel threshold\n </label>\n <input class=\"field__input\" id=\"pixelThreshold\" name=\"pixelThreshold\" type=\"number\" step=\"0.01\" min=\"0\" max=\"1\" value={String(project.pixelThreshold)} />\n <p class=\"field__hint\">Per-pixel color distance 0–1</p>\n </div>\n <div class=\"field\">\n <label class=\"field__label\" for=\"maxDiffRatio\">\n Max diff ratio\n </label>\n <input class=\"field__input\" id=\"maxDiffRatio\" name=\"maxDiffRatio\" type=\"number\" step=\"0.001\" min=\"0\" max=\"1\" value={String(project.maxDiffRatio)} />\n <p class=\"field__hint\">Allowed diff ratio 0–1</p>\n </div>\n </div>\n <div class=\"field\">\n <label class=\"field__label\" for=\"publicBranchRegex\">\n Public branch regex\n </label>\n <input class=\"field__input\" id=\"publicBranchRegex\" name=\"publicBranchRegex\" value={project.publicBranchRegex ?? \"\"} placeholder=\"^main$\" />\n <p class=\"field__hint\">Branches matching this regex are publicly viewable.</p>\n </div>\n {isAdmin ? (\n <button class=\"btn btn--primary\" type=\"submit\">\n Save changes\n </button>\n ) : (\n <p class=\"field__hint\">You need admin access to edit settings.</p>\n )}\n </form>\n </div>\n\n {isAdmin ? (\n <div class=\"card card--padded\" style=\"border-color: var(--status-rejected);\">\n <h3 style=\"margin:0 0 .4rem; color: var(--status-rejected);\">Danger zone</h3>\n <p class=\"field__hint\">Deleting a project removes all builds, snapshots, baselines and tokens. This cannot be undone.</p>\n <form\n method=\"post\"\n action={`/projects/${project.slug}/delete`}\n hx-post={`/projects/${project.slug}/delete`}\n hx-target=\"body\"\n hx-confirm=\"Delete this project? This cannot be undone.\"\n >\n <button class=\"btn btn--danger\" type=\"submit\">\n Delete project\n </button>\n </form>\n </div>\n ) : null}\n </div>\n );\n}"],"mappings":"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"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { Badge } from "../ui/components.mjs";
|
|
5
|
+
import { jsx, jsxs } from "hono/jsx/jsx-runtime";
|
|
6
|
+
//#region src/pages/settings-labels.tsx
|
|
7
|
+
function renderSettingsLabels(project, labelTypes, isAdmin) {
|
|
8
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
9
|
+
class: "grid",
|
|
10
|
+
style: "max-width: 880px;",
|
|
11
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
12
|
+
class: "card card--padded",
|
|
13
|
+
children: [
|
|
14
|
+
/* @__PURE__ */ jsx("h2", {
|
|
15
|
+
style: "margin:0 0 .3rem;",
|
|
16
|
+
children: "Label types"
|
|
17
|
+
}),
|
|
18
|
+
/* @__PURE__ */ jsx("p", {
|
|
19
|
+
class: "field__hint",
|
|
20
|
+
children: "Labels attach typed values to builds (e.g. pr=123, jira=ABC-123). Values link out via the template."
|
|
21
|
+
}),
|
|
22
|
+
/* @__PURE__ */ jsx("div", {
|
|
23
|
+
class: "table-wrap",
|
|
24
|
+
style: "margin-top:.75rem;",
|
|
25
|
+
children: /* @__PURE__ */ jsxs("table", { children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
26
|
+
/* @__PURE__ */ jsx("th", { children: "Key" }),
|
|
27
|
+
/* @__PURE__ */ jsx("th", { children: "Name" }),
|
|
28
|
+
/* @__PURE__ */ jsx("th", { children: "Template" }),
|
|
29
|
+
/* @__PURE__ */ jsx("th", {})
|
|
30
|
+
] }) }), /* @__PURE__ */ jsx("tbody", { children: labelTypes.map((labelType) => /* @__PURE__ */ jsxs("tr", { children: [
|
|
31
|
+
/* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx(Badge, {
|
|
32
|
+
tone: "neutral",
|
|
33
|
+
children: labelType.key
|
|
34
|
+
}) }),
|
|
35
|
+
/* @__PURE__ */ jsx("td", { children: labelType.name }),
|
|
36
|
+
/* @__PURE__ */ jsx("td", {
|
|
37
|
+
style: "max-width:32ch; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;",
|
|
38
|
+
children: labelType.linkTemplate ?? "—"
|
|
39
|
+
}),
|
|
40
|
+
/* @__PURE__ */ jsx("td", { children: isAdmin && labelType.key !== "persistent" && labelType.key !== "branch" ? /* @__PURE__ */ jsx("form", {
|
|
41
|
+
method: "post",
|
|
42
|
+
action: `/projects/${project.slug}/settings/labels/${labelType.key}/delete`,
|
|
43
|
+
"hx-post": `/projects/${project.slug}/settings/labels/${labelType.key}/delete`,
|
|
44
|
+
"hx-target": "body",
|
|
45
|
+
children: /* @__PURE__ */ jsx("button", {
|
|
46
|
+
class: "btn btn--ghost",
|
|
47
|
+
type: "submit",
|
|
48
|
+
"aria-label": `Delete ${labelType.key}`,
|
|
49
|
+
children: "Delete"
|
|
50
|
+
})
|
|
51
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
52
|
+
class: "field__hint",
|
|
53
|
+
children: "built-in"
|
|
54
|
+
}) })
|
|
55
|
+
] }, labelType.id)) })] })
|
|
56
|
+
}),
|
|
57
|
+
labelTypes.length === 0 ? /* @__PURE__ */ jsx("p", {
|
|
58
|
+
class: "field__hint",
|
|
59
|
+
style: "margin-top:.5rem;",
|
|
60
|
+
children: "No label types configured."
|
|
61
|
+
}) : null
|
|
62
|
+
]
|
|
63
|
+
}), isAdmin ? /* @__PURE__ */ jsxs("div", {
|
|
64
|
+
class: "card card--padded",
|
|
65
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
66
|
+
style: "margin:0 0 .5rem;",
|
|
67
|
+
children: "Create label type"
|
|
68
|
+
}), /* @__PURE__ */ jsxs("form", {
|
|
69
|
+
method: "post",
|
|
70
|
+
action: `/projects/${project.slug}/settings/labels`,
|
|
71
|
+
"hx-post": `/projects/${project.slug}/settings/labels`,
|
|
72
|
+
"hx-target": "body",
|
|
73
|
+
children: [
|
|
74
|
+
/* @__PURE__ */ jsxs("div", {
|
|
75
|
+
class: "grid grid--2",
|
|
76
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
77
|
+
class: "field",
|
|
78
|
+
children: [
|
|
79
|
+
/* @__PURE__ */ jsx("label", {
|
|
80
|
+
class: "field__label",
|
|
81
|
+
for: "key",
|
|
82
|
+
children: "Key"
|
|
83
|
+
}),
|
|
84
|
+
/* @__PURE__ */ jsx("input", {
|
|
85
|
+
class: "field__input",
|
|
86
|
+
id: "key",
|
|
87
|
+
name: "key",
|
|
88
|
+
required: true,
|
|
89
|
+
placeholder: "jira",
|
|
90
|
+
pattern: "^[a-z0-9_-]+$"
|
|
91
|
+
}),
|
|
92
|
+
/* @__PURE__ */ jsx("p", {
|
|
93
|
+
class: "field__hint",
|
|
94
|
+
children: "Lowercase, no spaces."
|
|
95
|
+
})
|
|
96
|
+
]
|
|
97
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
98
|
+
class: "field",
|
|
99
|
+
children: [/* @__PURE__ */ jsx("label", {
|
|
100
|
+
class: "field__label",
|
|
101
|
+
for: "labelName",
|
|
102
|
+
children: "Name"
|
|
103
|
+
}), /* @__PURE__ */ jsx("input", {
|
|
104
|
+
class: "field__input",
|
|
105
|
+
id: "labelName",
|
|
106
|
+
name: "labelName",
|
|
107
|
+
required: true,
|
|
108
|
+
placeholder: "Jira issue"
|
|
109
|
+
})]
|
|
110
|
+
})]
|
|
111
|
+
}),
|
|
112
|
+
/* @__PURE__ */ jsxs("div", {
|
|
113
|
+
class: "field",
|
|
114
|
+
children: [
|
|
115
|
+
/* @__PURE__ */ jsx("label", {
|
|
116
|
+
class: "field__label",
|
|
117
|
+
for: "linkTemplate",
|
|
118
|
+
children: "Link template"
|
|
119
|
+
}),
|
|
120
|
+
/* @__PURE__ */ jsx("input", {
|
|
121
|
+
class: "field__input",
|
|
122
|
+
id: "linkTemplate",
|
|
123
|
+
name: "linkTemplate",
|
|
124
|
+
placeholder: "https://jira.example.com/browse/{value}"
|
|
125
|
+
}),
|
|
126
|
+
/* @__PURE__ */ jsxs("p", {
|
|
127
|
+
class: "field__hint",
|
|
128
|
+
children: [
|
|
129
|
+
"Use ",
|
|
130
|
+
"{value}",
|
|
131
|
+
" placeholder. Optional."
|
|
132
|
+
]
|
|
133
|
+
})
|
|
134
|
+
]
|
|
135
|
+
}),
|
|
136
|
+
/* @__PURE__ */ jsx("button", {
|
|
137
|
+
class: "btn btn--primary",
|
|
138
|
+
type: "submit",
|
|
139
|
+
children: "Add label type"
|
|
140
|
+
})
|
|
141
|
+
]
|
|
142
|
+
})]
|
|
143
|
+
}) : null]
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
//#endregion
|
|
147
|
+
export { renderSettingsLabels };
|
|
148
|
+
|
|
149
|
+
//# sourceMappingURL=settings-labels.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings-labels.mjs","names":[],"sources":["../../src/pages/settings-labels.tsx"],"sourcesContent":["import type { LabelType, Project } from \"../schema.ts\";\nimport { Badge } from \"../ui/components.tsx\";\n\nexport function renderSettingsLabels(project: Project, labelTypes: LabelType[], isAdmin: boolean): unknown {\n return (\n <div class=\"grid\" style=\"max-width: 880px;\">\n <div class=\"card card--padded\">\n <h2 style=\"margin:0 0 .3rem;\">Label types</h2>\n <p class=\"field__hint\">Labels attach typed values to builds (e.g. pr=123, jira=ABC-123). Values link out via the template.</p>\n <div class=\"table-wrap\" style=\"margin-top:.75rem;\">\n <table>\n <thead>\n <tr>\n <th>Key</th>\n <th>Name</th>\n <th>Template</th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n {labelTypes.map(\n // eslint-disable-next-line promise-function-async -- JSX.Element includes Promise<HtmlEscapedString>\n (labelType) => (\n <tr key={labelType.id}>\n <td>\n <Badge tone=\"neutral\">{labelType.key}</Badge>\n </td>\n <td>{labelType.name}</td>\n <td style=\"max-width:32ch; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;\">{labelType.linkTemplate ?? \"—\"}</td>\n <td>\n {isAdmin && labelType.key !== \"persistent\" && labelType.key !== \"branch\" ? (\n <form method=\"post\" action={`/projects/${project.slug}/settings/labels/${labelType.key}/delete`} hx-post={`/projects/${project.slug}/settings/labels/${labelType.key}/delete`} hx-target=\"body\">\n <button class=\"btn btn--ghost\" type=\"submit\" aria-label={`Delete ${labelType.key}`}>\n Delete\n </button>\n </form>\n ) : (\n <span class=\"field__hint\">built-in</span>\n )}\n </td>\n </tr>\n ),\n )}\n </tbody>\n </table>\n </div>\n {labelTypes.length === 0 ? <p class=\"field__hint\" style=\"margin-top:.5rem;\">No label types configured.</p> : null}\n </div>\n\n {isAdmin ? (\n <div class=\"card card--padded\">\n <h3 style=\"margin:0 0 .5rem;\">Create label type</h3>\n <form method=\"post\" action={`/projects/${project.slug}/settings/labels`} hx-post={`/projects/${project.slug}/settings/labels`} hx-target=\"body\">\n <div class=\"grid grid--2\">\n <div class=\"field\">\n <label class=\"field__label\" for=\"key\">\n Key\n </label>\n <input class=\"field__input\" id=\"key\" name=\"key\" required placeholder=\"jira\" pattern=\"^[a-z0-9_-]+$\" />\n <p class=\"field__hint\">Lowercase, no spaces.</p>\n </div>\n <div class=\"field\">\n <label class=\"field__label\" for=\"labelName\">\n Name\n </label>\n <input class=\"field__input\" id=\"labelName\" name=\"labelName\" required placeholder=\"Jira issue\" />\n </div>\n </div>\n <div class=\"field\">\n <label class=\"field__label\" for=\"linkTemplate\">\n Link template\n </label>\n <input class=\"field__input\" id=\"linkTemplate\" name=\"linkTemplate\" placeholder=\"https://jira.example.com/browse/{value}\" />\n <p class=\"field__hint\">\n Use {\"{value}\"} placeholder. Optional.\n </p>\n </div>\n <button class=\"btn btn--primary\" type=\"submit\">\n Add label type\n </button>\n </form>\n </div>\n ) : null}\n </div>\n );\n}"],"mappings":";;;;;;AAGA,SAAgB,qBAAqB,SAAkB,YAAyB,SAA2B;CACzG,OACE,qBAAC,OAAD;EAAK,OAAM;EAAO,OAAM;EAAxB,UAAA,CACE,qBAAC,OAAD;GAAK,OAAM;GAAX,UAAA;IACE,oBAAC,MAAD;KAAI,OAAM;KAAoB,UAAA;IAAe,CAAA;IAC7C,oBAAC,KAAD;KAAG,OAAM;KAAc,UAAA;IAAsG,CAAA;IAC7H,oBAAC,OAAD;KAAK,OAAM;KAAa,OAAM;KAC5B,UAAA,qBAAC,SAAD,EAAA,UAAA,CACE,oBAAC,SAAD,EAAA,UACE,qBAAC,MAAD,EAAA,UAAA;MACE,oBAAC,MAAD,EAAA,UAAI,MAAO,CAAA;MACX,oBAAC,MAAD,EAAA,UAAI,OAAQ,CAAA;MACZ,oBAAC,MAAD,EAAA,UAAI,WAAY,CAAA;MAChB,oBAAC,MAAD,CAAQ,CAAA;KACN,EAAA,CAAA,EACC,CAAA,GACP,oBAAC,SAAD,EAAA,UACG,WAAW,KAET,cACC,qBAAC,MAAD,EAAA,UAAA;MACE,oBAAC,MAAD,EAAA,UACE,oBAAC,OAAD;OAAO,MAAK;OAAW,UAAA,UAAU;MAAW,CAAA,EAC1C,CAAA;MACJ,oBAAC,MAAD,EAAA,UAAK,UAAU,KAAS,CAAA;MACxB,oBAAC,MAAD;OAAI,OAAM;OAAgF,UAAA,UAAU,gBAAgB;MAAQ,CAAA;MAC5H,oBAAC,MAAD,EAAA,UACG,WAAW,UAAU,QAAQ,gBAAgB,UAAU,QAAQ,WAC9D,oBAAC,QAAD;OAAM,QAAO;OAAO,QAAQ,aAAa,QAAQ,KAAK,mBAAmB,UAAU,IAAI;OAAU,WAAS,aAAa,QAAQ,KAAK,mBAAmB,UAAU,IAAI;OAAU,aAAU;OACvL,UAAA,oBAAC,UAAD;QAAQ,OAAM;QAAiB,MAAK;QAAS,cAAY,UAAU,UAAU;QAAO,UAAA;OAE5E,CAAA;MACJ,CAAA,IAEN,oBAAC,QAAD;OAAM,OAAM;OAAc,UAAA;MAAc,CAAA,EAExC,CAAA;KACF,EAAA,GAjBK,UAAU,EAiBf,CAER,EACK,CAAA,CACF,EAAA,CAAA;IACJ,CAAA;IACJ,WAAW,WAAW,IAAI,oBAAC,KAAD;KAAG,OAAM;KAAc,OAAM;KAAoB,UAAA;IAA6B,CAAA,IAAI;GAC1G;EAEJ,CAAA,GAAA,UACC,qBAAC,OAAD;GAAK,OAAM;GAAX,UAAA,CACE,oBAAC,MAAD;IAAI,OAAM;IAAoB,UAAA;GAAqB,CAAA,GACnD,qBAAC,QAAD;IAAM,QAAO;IAAO,QAAQ,aAAa,QAAQ,KAAK;IAAmB,WAAS,aAAa,QAAQ,KAAK;IAAmB,aAAU;IAAzI,UAAA;KACE,qBAAC,OAAD;MAAK,OAAM;MAAX,UAAA,CACE,qBAAC,OAAD;OAAK,OAAM;OAAX,UAAA;QACE,oBAAC,SAAD;SAAO,OAAM;SAAe,KAAI;SAAM,UAAA;QAE/B,CAAA;QACP,oBAAC,SAAD;SAAO,OAAM;SAAe,IAAG;SAAM,MAAK;SAAM,UAAA;SAAS,aAAY;SAAO,SAAQ;QAAiB,CAAA;QACrG,oBAAC,KAAD;SAAG,OAAM;SAAc,UAAA;QAAwB,CAAA;OAC5C;MACL,CAAA,GAAA,qBAAC,OAAD;OAAK,OAAM;OAAX,UAAA,CACE,oBAAC,SAAD;QAAO,OAAM;QAAe,KAAI;QAAY,UAAA;OAErC,CAAA,GACP,oBAAC,SAAD;QAAO,OAAM;QAAe,IAAG;QAAY,MAAK;QAAY,UAAA;QAAS,aAAY;OAAc,CAAA,CAC5F;MACF,CAAA,CAAA;;KACL,qBAAC,OAAD;MAAK,OAAM;MAAX,UAAA;OACE,oBAAC,SAAD;QAAO,OAAM;QAAe,KAAI;QAAe,UAAA;OAExC,CAAA;OACP,oBAAC,SAAD;QAAO,OAAM;QAAe,IAAG;QAAe,MAAK;QAAe,aAAY;OAA2C,CAAA;OACzH,qBAAC,KAAD;QAAG,OAAM;QAAT,UAAA;SAAuB;SAChB;SAAU;QACd;;MACA;;KACL,oBAAC,UAAD;MAAQ,OAAM;MAAmB,MAAK;MAAS,UAAA;KAEvC,CAAA;IACJ;GACH,CAAA,CAAA;EACH,CAAA,IAAA,IACD;;AAET"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { Badge } from "../ui/components.mjs";
|
|
5
|
+
import { jsx, jsxs } from "hono/jsx/jsx-runtime";
|
|
6
|
+
//#region src/pages/settings-members.tsx
|
|
7
|
+
function renderSettingsMembers(project, members, isAdmin) {
|
|
8
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
9
|
+
class: "grid",
|
|
10
|
+
style: "max-width: 880px;",
|
|
11
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
12
|
+
class: "card card--padded",
|
|
13
|
+
children: [
|
|
14
|
+
/* @__PURE__ */ jsx("h2", {
|
|
15
|
+
style: "margin:0 0 .3rem;",
|
|
16
|
+
children: "Members"
|
|
17
|
+
}),
|
|
18
|
+
/* @__PURE__ */ jsx("p", {
|
|
19
|
+
class: "field__hint",
|
|
20
|
+
children: "Project members and their roles. Site admins have implicit admin access."
|
|
21
|
+
}),
|
|
22
|
+
/* @__PURE__ */ jsx("div", {
|
|
23
|
+
class: "table-wrap",
|
|
24
|
+
style: "margin-top:.75rem;",
|
|
25
|
+
children: /* @__PURE__ */ jsxs("table", { children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
26
|
+
/* @__PURE__ */ jsx("th", { children: "User" }),
|
|
27
|
+
/* @__PURE__ */ jsx("th", { children: "Role" }),
|
|
28
|
+
/* @__PURE__ */ jsx("th", { children: "Since" }),
|
|
29
|
+
/* @__PURE__ */ jsx("th", {})
|
|
30
|
+
] }) }), /* @__PURE__ */ jsx("tbody", { children: members.map((member) => /* @__PURE__ */ jsxs("tr", { children: [
|
|
31
|
+
/* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx("code", { children: member.userId }) }),
|
|
32
|
+
/* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx(Badge, {
|
|
33
|
+
tone: member.role === "admin" ? "danger" : member.role === "viewer" ? "neutral" : "info",
|
|
34
|
+
children: member.role
|
|
35
|
+
}) }),
|
|
36
|
+
/* @__PURE__ */ jsx("td", { children: new Date(member.createdAt).toLocaleDateString() }),
|
|
37
|
+
/* @__PURE__ */ jsx("td", { children: isAdmin ? /* @__PURE__ */ jsx("form", {
|
|
38
|
+
method: "post",
|
|
39
|
+
action: `/projects/${project.slug}/settings/members/${member.userId}/remove`,
|
|
40
|
+
"hx-post": `/projects/${project.slug}/settings/members/${member.userId}/remove`,
|
|
41
|
+
"hx-target": "body",
|
|
42
|
+
children: /* @__PURE__ */ jsx("button", {
|
|
43
|
+
class: "btn btn--ghost",
|
|
44
|
+
type: "submit",
|
|
45
|
+
children: "Remove"
|
|
46
|
+
})
|
|
47
|
+
}) : null })
|
|
48
|
+
] }, member.id)) })] })
|
|
49
|
+
}),
|
|
50
|
+
members.length === 0 ? /* @__PURE__ */ jsx("p", {
|
|
51
|
+
class: "field__hint",
|
|
52
|
+
style: "margin-top:.5rem;",
|
|
53
|
+
children: "No members yet."
|
|
54
|
+
}) : null
|
|
55
|
+
]
|
|
56
|
+
}), isAdmin ? /* @__PURE__ */ jsxs("div", {
|
|
57
|
+
class: "card card--padded",
|
|
58
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
59
|
+
style: "margin:0 0 .5rem;",
|
|
60
|
+
children: "Add member"
|
|
61
|
+
}), /* @__PURE__ */ jsxs("form", {
|
|
62
|
+
method: "post",
|
|
63
|
+
action: `/projects/${project.slug}/settings/members`,
|
|
64
|
+
"hx-post": `/projects/${project.slug}/settings/members`,
|
|
65
|
+
"hx-target": "body",
|
|
66
|
+
children: [
|
|
67
|
+
/* @__PURE__ */ jsxs("div", {
|
|
68
|
+
class: "field",
|
|
69
|
+
children: [/* @__PURE__ */ jsx("label", {
|
|
70
|
+
class: "field__label",
|
|
71
|
+
for: "userId",
|
|
72
|
+
children: "User ID"
|
|
73
|
+
}), /* @__PURE__ */ jsx("input", {
|
|
74
|
+
class: "field__input",
|
|
75
|
+
id: "userId",
|
|
76
|
+
name: "userId",
|
|
77
|
+
required: true,
|
|
78
|
+
placeholder: "user_..."
|
|
79
|
+
})]
|
|
80
|
+
}),
|
|
81
|
+
/* @__PURE__ */ jsxs("div", {
|
|
82
|
+
class: "field",
|
|
83
|
+
children: [/* @__PURE__ */ jsx("label", {
|
|
84
|
+
class: "field__label",
|
|
85
|
+
for: "role",
|
|
86
|
+
children: "Role"
|
|
87
|
+
}), /* @__PURE__ */ jsxs("select", {
|
|
88
|
+
class: "field__input",
|
|
89
|
+
id: "role",
|
|
90
|
+
name: "role",
|
|
91
|
+
children: [
|
|
92
|
+
/* @__PURE__ */ jsx("option", {
|
|
93
|
+
value: "viewer",
|
|
94
|
+
children: "viewer"
|
|
95
|
+
}),
|
|
96
|
+
/* @__PURE__ */ jsx("option", {
|
|
97
|
+
value: "developer",
|
|
98
|
+
children: "developer"
|
|
99
|
+
}),
|
|
100
|
+
/* @__PURE__ */ jsx("option", {
|
|
101
|
+
value: "approver",
|
|
102
|
+
children: "approver"
|
|
103
|
+
}),
|
|
104
|
+
/* @__PURE__ */ jsx("option", {
|
|
105
|
+
value: "admin",
|
|
106
|
+
children: "admin"
|
|
107
|
+
})
|
|
108
|
+
]
|
|
109
|
+
})]
|
|
110
|
+
}),
|
|
111
|
+
/* @__PURE__ */ jsx("button", {
|
|
112
|
+
class: "btn btn--primary",
|
|
113
|
+
type: "submit",
|
|
114
|
+
children: "Add member"
|
|
115
|
+
})
|
|
116
|
+
]
|
|
117
|
+
})]
|
|
118
|
+
}) : null]
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
//#endregion
|
|
122
|
+
export { renderSettingsMembers };
|
|
123
|
+
|
|
124
|
+
//# sourceMappingURL=settings-members.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings-members.mjs","names":[],"sources":["../../src/pages/settings-members.tsx"],"sourcesContent":["import type { Project } from \"../schema.ts\";\nimport { Badge } from \"../ui/components.tsx\";\n\nexport interface SettingsMember {\n id: string;\n projectId: string;\n userId: string;\n role: string;\n createdAt: string;\n}\n\nexport function renderSettingsMembers(project: Project, members: SettingsMember[], isAdmin: boolean): unknown {\n return (\n <div class=\"grid\" style=\"max-width: 880px;\">\n <div class=\"card card--padded\">\n <h2 style=\"margin:0 0 .3rem;\">Members</h2>\n <p class=\"field__hint\">Project members and their roles. Site admins have implicit admin access.</p>\n <div class=\"table-wrap\" style=\"margin-top:.75rem;\">\n <table>\n <thead>\n <tr>\n <th>User</th>\n <th>Role</th>\n <th>Since</th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n {members.map(\n // eslint-disable-next-line promise-function-async -- JSX.Element includes Promise<HtmlEscapedString>\n (member) => (\n <tr key={member.id}>\n <td>\n <code>{member.userId}</code>\n </td>\n <td>\n <Badge tone={member.role === \"admin\" ? \"danger\" : member.role === \"viewer\" ? \"neutral\" : \"info\"}>{member.role}</Badge>\n </td>\n <td>{new Date(member.createdAt).toLocaleDateString()}</td>\n <td>\n {isAdmin ? (\n <form method=\"post\" action={`/projects/${project.slug}/settings/members/${member.userId}/remove`} hx-post={`/projects/${project.slug}/settings/members/${member.userId}/remove`} hx-target=\"body\">\n <button class=\"btn btn--ghost\" type=\"submit\">\n Remove\n </button>\n </form>\n ) : null}\n </td>\n </tr>\n ),\n )}\n </tbody>\n </table>\n </div>\n {members.length === 0 ? <p class=\"field__hint\" style=\"margin-top:.5rem;\">No members yet.</p> : null}\n </div>\n\n {isAdmin ? (\n <div class=\"card card--padded\">\n <h3 style=\"margin:0 0 .5rem;\">Add member</h3>\n <form method=\"post\" action={`/projects/${project.slug}/settings/members`} hx-post={`/projects/${project.slug}/settings/members`} hx-target=\"body\">\n <div class=\"field\">\n <label class=\"field__label\" for=\"userId\">\n User ID\n </label>\n <input class=\"field__input\" id=\"userId\" name=\"userId\" required placeholder=\"user_...\" />\n </div>\n <div class=\"field\">\n <label class=\"field__label\" for=\"role\">\n Role\n </label>\n <select class=\"field__input\" id=\"role\" name=\"role\">\n <option value=\"viewer\">viewer</option>\n <option value=\"developer\">developer</option>\n <option value=\"approver\">approver</option>\n <option value=\"admin\">admin</option>\n </select>\n </div>\n <button class=\"btn btn--primary\" type=\"submit\">\n Add member\n </button>\n </form>\n </div>\n ) : null}\n </div>\n );\n}"],"mappings":"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"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { Badge, Field, SelectField, TextareaField } from "../ui/components.mjs";
|
|
5
|
+
import { jsx, jsxs } from "hono/jsx/jsx-runtime";
|
|
6
|
+
//#region src/pages/settings-status.tsx
|
|
7
|
+
function providerOptions(providers) {
|
|
8
|
+
return providers.map((provider) => ({
|
|
9
|
+
value: provider.metadata.kind,
|
|
10
|
+
label: provider.metadata.name
|
|
11
|
+
}));
|
|
12
|
+
}
|
|
13
|
+
const StatusConfigRow = ({ config, provider, project, isAdmin }) => {
|
|
14
|
+
const rendered = JSON.stringify(config.config);
|
|
15
|
+
return /* @__PURE__ */ jsxs("tr", { children: [
|
|
16
|
+
/* @__PURE__ */ jsx("td", { children: provider?.metadata.name ?? config.provider }),
|
|
17
|
+
/* @__PURE__ */ jsx("td", {
|
|
18
|
+
style: "max-width:32ch; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;",
|
|
19
|
+
title: rendered,
|
|
20
|
+
children: /* @__PURE__ */ jsx("code", { children: rendered })
|
|
21
|
+
}),
|
|
22
|
+
/* @__PURE__ */ jsx("td", { children: config.hasToken ? /* @__PURE__ */ jsx(Badge, {
|
|
23
|
+
tone: "success",
|
|
24
|
+
children: "configured"
|
|
25
|
+
}) : /* @__PURE__ */ jsx(Badge, {
|
|
26
|
+
tone: "danger",
|
|
27
|
+
children: "missing"
|
|
28
|
+
}) }),
|
|
29
|
+
/* @__PURE__ */ jsx("td", { children: new Date(config.createdAt).toLocaleDateString() }),
|
|
30
|
+
/* @__PURE__ */ jsx("td", { children: isAdmin ? /* @__PURE__ */ jsx("form", {
|
|
31
|
+
method: "post",
|
|
32
|
+
action: `/projects/${project.slug}/settings/status/${config.id}/delete`,
|
|
33
|
+
"hx-post": `/projects/${project.slug}/settings/status/${config.id}/delete`,
|
|
34
|
+
"hx-target": "body",
|
|
35
|
+
children: /* @__PURE__ */ jsx("button", {
|
|
36
|
+
class: "btn btn--ghost",
|
|
37
|
+
type: "submit",
|
|
38
|
+
children: "Delete"
|
|
39
|
+
})
|
|
40
|
+
}) : null })
|
|
41
|
+
] }, config.id);
|
|
42
|
+
};
|
|
43
|
+
const StatusCreateCard = ({ project, providers, formState }) => {
|
|
44
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
45
|
+
class: "card card--padded",
|
|
46
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
47
|
+
style: "margin:0 0 .5rem;",
|
|
48
|
+
children: "Add git provider"
|
|
49
|
+
}), /* @__PURE__ */ jsxs("form", {
|
|
50
|
+
method: "post",
|
|
51
|
+
action: `/projects/${project.slug}/settings/status`,
|
|
52
|
+
"hx-post": `/projects/${project.slug}/settings/status`,
|
|
53
|
+
"hx-target": "body",
|
|
54
|
+
children: [
|
|
55
|
+
/* @__PURE__ */ jsx(SelectField, {
|
|
56
|
+
label: "Provider",
|
|
57
|
+
name: "provider",
|
|
58
|
+
options: providerOptions(providers),
|
|
59
|
+
hint: "Integration that posts commit statuses for this project."
|
|
60
|
+
}),
|
|
61
|
+
/* @__PURE__ */ jsx(Field, {
|
|
62
|
+
label: "Token",
|
|
63
|
+
name: "token",
|
|
64
|
+
type: "password",
|
|
65
|
+
required: true,
|
|
66
|
+
placeholder: "ghp_…",
|
|
67
|
+
error: formState?.errors?.["token"],
|
|
68
|
+
hint: "Scoped token for the provider (e.g. a GitHub PAT with repo:status)."
|
|
69
|
+
}),
|
|
70
|
+
/* @__PURE__ */ jsx(TextareaField, {
|
|
71
|
+
label: "Config",
|
|
72
|
+
name: "config",
|
|
73
|
+
rows: 6,
|
|
74
|
+
placeholder: "{\"owner\":\"my-org\",\"repo\":\"my-repo\"}",
|
|
75
|
+
error: formState?.errors?.["config"],
|
|
76
|
+
hint: "JSON configuration for the provider. See the provider documentation for its fields."
|
|
77
|
+
}),
|
|
78
|
+
/* @__PURE__ */ jsx("button", {
|
|
79
|
+
class: "btn btn--primary",
|
|
80
|
+
type: "submit",
|
|
81
|
+
children: "Add git provider"
|
|
82
|
+
})
|
|
83
|
+
]
|
|
84
|
+
})]
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
function renderCreateSection(project, providers, formState) {
|
|
88
|
+
if (providers.length === 0) return /* @__PURE__ */ jsx("p", {
|
|
89
|
+
class: "field__hint",
|
|
90
|
+
children: "No git providers registered on this server."
|
|
91
|
+
});
|
|
92
|
+
return /* @__PURE__ */ jsx(StatusCreateCard, {
|
|
93
|
+
project,
|
|
94
|
+
providers,
|
|
95
|
+
formState
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
function renderSettingsStatus(project, statusConfigs, providers, isAdmin, formState) {
|
|
99
|
+
const byProvider = new Map(providers.map((provider) => [provider.metadata.kind, provider]));
|
|
100
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
101
|
+
class: "grid",
|
|
102
|
+
style: "max-width: 880px;",
|
|
103
|
+
children: [
|
|
104
|
+
formState?.globalError ? /* @__PURE__ */ jsx("div", {
|
|
105
|
+
class: "alert alert--danger",
|
|
106
|
+
role: "alert",
|
|
107
|
+
children: formState.globalError
|
|
108
|
+
}) : null,
|
|
109
|
+
/* @__PURE__ */ jsxs("div", {
|
|
110
|
+
class: "card card--padded",
|
|
111
|
+
children: [
|
|
112
|
+
/* @__PURE__ */ jsx("h2", {
|
|
113
|
+
style: "margin:0 0 .3rem;",
|
|
114
|
+
children: "Git status"
|
|
115
|
+
}),
|
|
116
|
+
/* @__PURE__ */ jsx("p", {
|
|
117
|
+
class: "field__hint",
|
|
118
|
+
children: "Post commit statuses to a git provider so visual tests show up in your PR checks. Status is reported for each configured provider: pending while capturing, success on approval, failure on rejection or capture errors."
|
|
119
|
+
}),
|
|
120
|
+
/* @__PURE__ */ jsx("div", {
|
|
121
|
+
class: "table-wrap",
|
|
122
|
+
style: "margin-top:.75rem;",
|
|
123
|
+
children: /* @__PURE__ */ jsxs("table", { children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
124
|
+
/* @__PURE__ */ jsx("th", { children: "Provider" }),
|
|
125
|
+
/* @__PURE__ */ jsx("th", { children: "Config" }),
|
|
126
|
+
/* @__PURE__ */ jsx("th", { children: "Token" }),
|
|
127
|
+
/* @__PURE__ */ jsx("th", { children: "Created" }),
|
|
128
|
+
/* @__PURE__ */ jsx("th", {})
|
|
129
|
+
] }) }), /* @__PURE__ */ jsx("tbody", { children: statusConfigs.map((config) => /* @__PURE__ */ jsx(StatusConfigRow, {
|
|
130
|
+
config,
|
|
131
|
+
provider: byProvider.get(config.provider),
|
|
132
|
+
project,
|
|
133
|
+
isAdmin
|
|
134
|
+
}, config.id)) })] })
|
|
135
|
+
}),
|
|
136
|
+
statusConfigs.length === 0 ? /* @__PURE__ */ jsx("p", {
|
|
137
|
+
class: "field__hint",
|
|
138
|
+
style: "margin-top:.5rem;",
|
|
139
|
+
children: "No git providers configured for this project."
|
|
140
|
+
}) : null
|
|
141
|
+
]
|
|
142
|
+
}),
|
|
143
|
+
isAdmin ? renderCreateSection(project, providers, formState) : null
|
|
144
|
+
]
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
//#endregion
|
|
148
|
+
export { renderSettingsStatus };
|
|
149
|
+
|
|
150
|
+
//# sourceMappingURL=settings-status.mjs.map
|