rename(phase 1): CapaKraken → Nexus across code, UI, docs, CI (#61)
CI / Architecture Guardrails (push) Successful in 2m38s
CI / Assistant Split Regression (push) Successful in 3m33s
CI / Typecheck (push) Successful in 3m51s
CI / Lint (push) Successful in 5m2s
CI / E2E Tests (push) Has been cancelled
CI / Fresh-Linux Docker Deploy (push) Has been cancelled
CI / Release Images (push) Has been cancelled
CI / Build (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Architecture Guardrails (push) Successful in 2m38s
CI / Assistant Split Regression (push) Successful in 3m33s
CI / Typecheck (push) Successful in 3m51s
CI / Lint (push) Successful in 5m2s
CI / E2E Tests (push) Has been cancelled
CI / Fresh-Linux Docker Deploy (push) Has been cancelled
CI / Release Images (push) Has been cancelled
CI / Build (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
rename(phase 1): CapaKraken → Nexus across code, UI, docs, CI (#61) Co-authored-by: Hartmut Nörenberg <hn@hartmut-noerenberg.com> Co-committed-by: Hartmut Nörenberg <hn@hartmut-noerenberg.com>
This commit was merged in pull request #61.
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useMemo, useCallback } from "react";
|
||||
import { FieldType } from "@capakraken/shared";
|
||||
import type { BlueprintFieldDefinition, FieldOption, StaffingRequirement } from "@capakraken/shared";
|
||||
import { FieldType } from "@nexus/shared";
|
||||
import type { BlueprintFieldDefinition, FieldOption, StaffingRequirement } from "@nexus/shared";
|
||||
import { trpc } from "~/lib/trpc/client.js";
|
||||
import { RolePresetsEditor } from "./RolePresetsEditor.js";
|
||||
import { FieldCard } from "./FieldCard.js";
|
||||
@@ -48,10 +48,7 @@ interface FieldState {
|
||||
// Helpers: Convert between FieldState and BlueprintFieldDefinition
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function fieldDefToState(
|
||||
def: BlueprintFieldDefinition,
|
||||
target: BlueprintTargetValue,
|
||||
): FieldState {
|
||||
function fieldDefToState(def: BlueprintFieldDefinition, target: BlueprintTargetValue): FieldState {
|
||||
const catalogField = findCatalogField(target, def.key);
|
||||
if (catalogField) {
|
||||
return {
|
||||
@@ -186,9 +183,7 @@ export function BlueprintFieldCatalog({
|
||||
// Build initial state from existing fieldDefs + catalog
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const [catalogOverrides, setCatalogOverrides] = useState<
|
||||
Record<string, FieldOverrides>
|
||||
>(() => {
|
||||
const [catalogOverrides, setCatalogOverrides] = useState<Record<string, FieldOverrides>>(() => {
|
||||
const map: Record<string, FieldOverrides> = {};
|
||||
// Start with all catalog fields disabled
|
||||
for (const cf of catalog) {
|
||||
@@ -269,21 +264,13 @@ export function BlueprintFieldCatalog({
|
||||
// Handlers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const handleCatalogFieldChange = useCallback(
|
||||
(key: string, overrides: FieldOverrides) => {
|
||||
setCatalogOverrides((prev) => ({ ...prev, [key]: overrides }));
|
||||
},
|
||||
[],
|
||||
);
|
||||
const handleCatalogFieldChange = useCallback((key: string, overrides: FieldOverrides) => {
|
||||
setCatalogOverrides((prev) => ({ ...prev, [key]: overrides }));
|
||||
}, []);
|
||||
|
||||
const handleCustomFieldChange = useCallback(
|
||||
(idx: number, overrides: FieldOverrides) => {
|
||||
setCustomFields((prev) =>
|
||||
prev.map((f, i) => (i === idx ? { ...f, overrides } : f)),
|
||||
);
|
||||
},
|
||||
[],
|
||||
);
|
||||
const handleCustomFieldChange = useCallback((idx: number, overrides: FieldOverrides) => {
|
||||
setCustomFields((prev) => prev.map((f, i) => (i === idx ? { ...f, overrides } : f)));
|
||||
}, []);
|
||||
|
||||
function removeCustomField(idx: number) {
|
||||
setCustomFields((prev) => prev.filter((_, i) => i !== idx));
|
||||
@@ -370,9 +357,7 @@ export function BlueprintFieldCatalog({
|
||||
// Collapsed categories
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const [collapsedCategories, setCollapsedCategories] = useState<Set<string>>(
|
||||
new Set(),
|
||||
);
|
||||
const [collapsedCategories, setCollapsedCategories] = useState<Set<string>>(new Set());
|
||||
|
||||
function toggleCategory(name: string) {
|
||||
setCollapsedCategories((prev) => {
|
||||
@@ -502,15 +487,16 @@ export function BlueprintFieldCatalog({
|
||||
{/* Field cards */}
|
||||
<div className="flex-1 overflow-y-auto px-4 py-4 space-y-6">
|
||||
{categories
|
||||
.filter(
|
||||
(cat) =>
|
||||
activeCategory === null ||
|
||||
activeCategory === cat.name,
|
||||
)
|
||||
.filter((cat) => activeCategory === null || activeCategory === cat.name)
|
||||
.map((cat) => {
|
||||
const fields = fieldsByCategory.get(cat.name) ?? [];
|
||||
if (fields.length === 0 && searchQuery.trim()) return null;
|
||||
if (fields.length === 0 && activeCategory !== null && activeCategory !== cat.name) return null;
|
||||
if (
|
||||
fields.length === 0 &&
|
||||
activeCategory !== null &&
|
||||
activeCategory !== cat.name
|
||||
)
|
||||
return null;
|
||||
|
||||
const isCollapsed = collapsedCategories.has(cat.name);
|
||||
|
||||
@@ -527,9 +513,7 @@ export function BlueprintFieldCatalog({
|
||||
<h3 className="text-sm font-semibold text-gray-700 dark:text-gray-300 uppercase tracking-wider">
|
||||
{cat.name}
|
||||
</h3>
|
||||
<span className="text-xs text-gray-400">
|
||||
{cat.description}
|
||||
</span>
|
||||
<span className="text-xs text-gray-400">{cat.description}</span>
|
||||
</button>
|
||||
{!isCollapsed && (
|
||||
<div className="grid grid-cols-1 gap-2">
|
||||
@@ -538,9 +522,7 @@ export function BlueprintFieldCatalog({
|
||||
key={field.key}
|
||||
field={field}
|
||||
overrides={catalogOverrides[field.key]!}
|
||||
onChange={(ov) =>
|
||||
handleCatalogFieldChange(field.key, ov)
|
||||
}
|
||||
onChange={(ov) => handleCatalogFieldChange(field.key, ov)}
|
||||
/>
|
||||
))}
|
||||
{fields.length === 0 && (
|
||||
@@ -555,8 +537,7 @@ export function BlueprintFieldCatalog({
|
||||
})}
|
||||
|
||||
{/* Custom Fields section */}
|
||||
{(activeCategory === null ||
|
||||
activeCategory === "Custom Fields") && (
|
||||
{(activeCategory === null || activeCategory === "Custom Fields") && (
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
@@ -564,9 +545,7 @@ export function BlueprintFieldCatalog({
|
||||
className="flex items-center gap-2 mb-3 w-full text-left group"
|
||||
>
|
||||
<span className="text-xs text-gray-400 transition-transform group-hover:text-gray-600">
|
||||
{collapsedCategories.has("Custom Fields")
|
||||
? "\u25B6"
|
||||
: "\u25BC"}
|
||||
{collapsedCategories.has("Custom Fields") ? "\u25B6" : "\u25BC"}
|
||||
</span>
|
||||
<h3 className="text-sm font-semibold text-gray-700 dark:text-gray-300 uppercase tracking-wider">
|
||||
Custom Fields
|
||||
@@ -585,8 +564,7 @@ export function BlueprintFieldCatalog({
|
||||
label: cf.custom.label,
|
||||
type: cf.custom.type,
|
||||
category: "Custom Fields",
|
||||
description:
|
||||
cf.overrides.description || "Custom field",
|
||||
description: cf.overrides.description || "Custom field",
|
||||
...(cf.custom.options.length > 0
|
||||
? { options: cf.custom.options }
|
||||
: {}),
|
||||
@@ -597,9 +575,7 @@ export function BlueprintFieldCatalog({
|
||||
<FieldCard
|
||||
field={pseudoCatalog}
|
||||
overrides={cf.overrides}
|
||||
onChange={(ov) =>
|
||||
handleCustomFieldChange(idx, ov)
|
||||
}
|
||||
onChange={(ov) => handleCustomFieldChange(idx, ov)}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
@@ -619,19 +595,13 @@ export function BlueprintFieldCatalog({
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-3">
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="text-xs font-medium text-gray-600">
|
||||
Key{" "}
|
||||
<span className="text-red-500">*</span>
|
||||
Key <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={customKey}
|
||||
onChange={(e) =>
|
||||
setCustomKey(
|
||||
e.target.value.replace(
|
||||
/[^a-zA-Z0-9_]/g,
|
||||
"",
|
||||
),
|
||||
)
|
||||
setCustomKey(e.target.value.replace(/[^a-zA-Z0-9_]/g, ""))
|
||||
}
|
||||
placeholder="field_key"
|
||||
className="app-input font-mono"
|
||||
@@ -639,30 +609,21 @@ export function BlueprintFieldCatalog({
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="text-xs font-medium text-gray-600">
|
||||
Label{" "}
|
||||
<span className="text-red-500">*</span>
|
||||
Label <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={customLabel}
|
||||
onChange={(e) =>
|
||||
setCustomLabel(e.target.value)
|
||||
}
|
||||
onChange={(e) => setCustomLabel(e.target.value)}
|
||||
placeholder="Display Label"
|
||||
className="app-input"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="text-xs font-medium text-gray-600">
|
||||
Type
|
||||
</label>
|
||||
<label className="text-xs font-medium text-gray-600">Type</label>
|
||||
<select
|
||||
value={customType}
|
||||
onChange={(e) =>
|
||||
setCustomType(
|
||||
e.target.value as FieldType,
|
||||
)
|
||||
}
|
||||
onChange={(e) => setCustomType(e.target.value as FieldType)}
|
||||
className="app-input"
|
||||
>
|
||||
{FIELD_TYPES.map((ft) => (
|
||||
@@ -677,9 +638,7 @@ export function BlueprintFieldCatalog({
|
||||
<button
|
||||
type="button"
|
||||
onClick={addCustomField}
|
||||
disabled={
|
||||
!customKey.trim() || !customLabel.trim()
|
||||
}
|
||||
disabled={!customKey.trim() || !customLabel.trim()}
|
||||
className={BTN_PRIMARY}
|
||||
>
|
||||
Add
|
||||
@@ -704,8 +663,7 @@ export function BlueprintFieldCatalog({
|
||||
onClick={() => setShowCustomForm(true)}
|
||||
className="flex items-center gap-1.5 text-sm text-brand-600 hover:text-brand-800 font-medium py-2"
|
||||
>
|
||||
<span className="text-lg leading-none">+</span>{" "}
|
||||
Add Custom Field
|
||||
<span className="text-lg leading-none">+</span> Add Custom Field
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
@@ -726,8 +684,7 @@ export function BlueprintFieldCatalog({
|
||||
{/* Footer */}
|
||||
<div className="flex items-center justify-between gap-3 px-6 py-4 border-t border-gray-200 dark:border-gray-700 shrink-0">
|
||||
<span className="text-xs text-gray-400">
|
||||
{enabledCount} field{enabledCount !== 1 ? "s" : ""} will be
|
||||
saved
|
||||
{enabledCount} field{enabledCount !== 1 ? "s" : ""} will be saved
|
||||
</span>
|
||||
<div className="flex items-center gap-3">
|
||||
<button type="button" onClick={onClose} className={BTN_SECONDARY}>
|
||||
@@ -747,8 +704,8 @@ export function BlueprintFieldCatalog({
|
||||
) : (
|
||||
<div className="px-6 py-4 overflow-y-auto">
|
||||
<p className="text-xs text-gray-500 mb-4">
|
||||
Role presets are auto-loaded in Step 3 of the Project Creation
|
||||
Wizard when this blueprint is selected.
|
||||
Role presets are auto-loaded in Step 3 of the Project Creation Wizard when this
|
||||
blueprint is selected.
|
||||
</p>
|
||||
<RolePresetsEditor
|
||||
initialPresets={initialRolePresets}
|
||||
|
||||
Reference in New Issue
Block a user