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}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { useState } 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";
|
||||
|
||||
@@ -53,9 +53,7 @@ function OptionsEditor({ options, onChange }: OptionsEditorProps) {
|
||||
}
|
||||
|
||||
function updateOption(idx: number, field: "value" | "label", val: string) {
|
||||
const next = options.map((o, i) =>
|
||||
i === idx ? { ...o, [field]: val } : o,
|
||||
);
|
||||
const next = options.map((o, i) => (i === idx ? { ...o, [field]: val } : o));
|
||||
onChange(next);
|
||||
}
|
||||
|
||||
@@ -111,8 +109,7 @@ interface FieldRowProps {
|
||||
function FieldRow({ field, onChange, onDelete }: FieldRowProps) {
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
|
||||
const needsOptions =
|
||||
field.type === FieldType.SELECT || field.type === FieldType.MULTI_SELECT;
|
||||
const needsOptions = field.type === FieldType.SELECT || field.type === FieldType.MULTI_SELECT;
|
||||
|
||||
function update<K extends keyof BlueprintFieldDefinition>(
|
||||
key: K,
|
||||
@@ -126,9 +123,7 @@ function FieldRow({ field, onChange, onDelete }: FieldRowProps) {
|
||||
{/* Main row */}
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
{/* Drag handle placeholder */}
|
||||
<span className="text-gray-300 cursor-grab select-none text-lg leading-none">
|
||||
☰
|
||||
</span>
|
||||
<span className="text-gray-300 cursor-grab select-none text-lg leading-none">☰</span>
|
||||
|
||||
{/* Key */}
|
||||
<input
|
||||
@@ -158,7 +153,7 @@ function FieldRow({ field, onChange, onDelete }: FieldRowProps) {
|
||||
// Clear options when switching away from select types
|
||||
const clearedOptions =
|
||||
t === FieldType.SELECT || t === FieldType.MULTI_SELECT
|
||||
? field.options ?? []
|
||||
? (field.options ?? [])
|
||||
: undefined;
|
||||
onChange({ ...field, type: t, options: clearedOptions } as BlueprintFieldDefinition);
|
||||
}}
|
||||
@@ -218,29 +213,21 @@ function FieldRow({ field, onChange, onDelete }: FieldRowProps) {
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="text-xs text-gray-500 font-medium">
|
||||
Placeholder
|
||||
</label>
|
||||
<label className="text-xs text-gray-500 font-medium">Placeholder</label>
|
||||
<input
|
||||
type="text"
|
||||
value={field.placeholder ?? ""}
|
||||
onChange={(e) =>
|
||||
update("placeholder", e.target.value || undefined)
|
||||
}
|
||||
onChange={(e) => update("placeholder", e.target.value || undefined)}
|
||||
placeholder="Placeholder text"
|
||||
className="app-input"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="text-xs text-gray-500 font-medium">
|
||||
Description
|
||||
</label>
|
||||
<label className="text-xs text-gray-500 font-medium">Description</label>
|
||||
<input
|
||||
type="text"
|
||||
value={field.description ?? ""}
|
||||
onChange={(e) =>
|
||||
update("description", e.target.value || undefined)
|
||||
}
|
||||
onChange={(e) => update("description", e.target.value || undefined)}
|
||||
placeholder="Helper text"
|
||||
className="app-input"
|
||||
/>
|
||||
@@ -311,9 +298,8 @@ export function BlueprintFieldEditor({
|
||||
const utils = trpc.useUtils();
|
||||
|
||||
const [activeTab, setActiveTab] = useState<"fields" | "presets">(initialTab);
|
||||
const [fields, setFields] = useState<BlueprintFieldDefinition[]>(
|
||||
() =>
|
||||
[...initialFieldDefs].sort((a, b) => a.order - b.order),
|
||||
const [fields, setFields] = useState<BlueprintFieldDefinition[]>(() =>
|
||||
[...initialFieldDefs].sort((a, b) => a.order - b.order),
|
||||
);
|
||||
const [saveError, setSaveError] = useState<string | null>(null);
|
||||
const [presetSaveError, setPresetSaveError] = useState<string | null>(null);
|
||||
@@ -327,17 +313,11 @@ export function BlueprintFieldEditor({
|
||||
}
|
||||
|
||||
function removeField(idx: number) {
|
||||
setFields((prev) =>
|
||||
prev
|
||||
.filter((_, i) => i !== idx)
|
||||
.map((f, i) => ({ ...f, order: i })),
|
||||
);
|
||||
setFields((prev) => prev.filter((_, i) => i !== idx).map((f, i) => ({ ...f, order: i })));
|
||||
}
|
||||
|
||||
function updateField(idx: number, updated: BlueprintFieldDefinition) {
|
||||
setFields((prev) =>
|
||||
prev.map((f, i) => (i === idx ? updated : f)),
|
||||
);
|
||||
setFields((prev) => prev.map((f, i) => (i === idx ? updated : f)));
|
||||
}
|
||||
|
||||
function handleSave() {
|
||||
@@ -375,8 +355,7 @@ export function BlueprintFieldEditor({
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between px-6 py-4 border-b border-gray-200">
|
||||
<h2 className="text-lg font-semibold text-gray-900">
|
||||
Edit Fields:{" "}
|
||||
<span className="text-gray-600 font-normal">{blueprintName}</span>
|
||||
Edit Fields: <span className="text-gray-600 font-normal">{blueprintName}</span>
|
||||
</h2>
|
||||
<button
|
||||
type="button"
|
||||
@@ -461,7 +440,8 @@ export function BlueprintFieldEditor({
|
||||
) : (
|
||||
<div className="px-6 py-4">
|
||||
<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}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import type { FormEvent } from "react";
|
||||
import type { BlueprintTarget } from "@capakraken/shared";
|
||||
import type { BlueprintFieldDefinition } from "@capakraken/shared";
|
||||
import type { BlueprintTarget } from "@nexus/shared";
|
||||
import type { BlueprintFieldDefinition } from "@nexus/shared";
|
||||
import { trpc } from "~/lib/trpc/client.js";
|
||||
import { BlueprintFieldCatalog } from "./BlueprintFieldCatalog.js";
|
||||
import { useSelection } from "~/hooks/useSelection.js";
|
||||
@@ -637,7 +637,7 @@ export function BlueprintsClient() {
|
||||
}
|
||||
initialRolePresets={
|
||||
Array.isArray(editingBlueprint.rolePresets)
|
||||
? (editingBlueprint.rolePresets as import("@capakraken/shared").StaffingRequirement[])
|
||||
? (editingBlueprint.rolePresets as import("@nexus/shared").StaffingRequirement[])
|
||||
: []
|
||||
}
|
||||
initialTab={editingTab}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { FieldType } from "@capakraken/shared";
|
||||
import type { FieldOption } from "@capakraken/shared";
|
||||
import { FieldType } from "@nexus/shared";
|
||||
import type { FieldOption } from "@nexus/shared";
|
||||
import type { CatalogField } from "~/lib/blueprint-field-catalog.js";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -234,9 +234,7 @@ function DefaultValueInput({
|
||||
<input
|
||||
type="number"
|
||||
value={value != null ? String(value) : ""}
|
||||
onChange={(e) =>
|
||||
onChange(e.target.value === "" ? undefined : Number(e.target.value))
|
||||
}
|
||||
onChange={(e) => onChange(e.target.value === "" ? undefined : Number(e.target.value))}
|
||||
placeholder="No default"
|
||||
className="app-input"
|
||||
/>
|
||||
@@ -247,9 +245,7 @@ function DefaultValueInput({
|
||||
<input
|
||||
type="date"
|
||||
value={typeof value === "string" ? value : ""}
|
||||
onChange={(e) =>
|
||||
onChange(e.target.value === "" ? undefined : e.target.value)
|
||||
}
|
||||
onChange={(e) => onChange(e.target.value === "" ? undefined : e.target.value)}
|
||||
className="app-input"
|
||||
/>
|
||||
);
|
||||
@@ -258,9 +254,7 @@ function DefaultValueInput({
|
||||
return (
|
||||
<select
|
||||
value={typeof value === "string" ? value : ""}
|
||||
onChange={(e) =>
|
||||
onChange(e.target.value === "" ? undefined : e.target.value)
|
||||
}
|
||||
onChange={(e) => onChange(e.target.value === "" ? undefined : e.target.value)}
|
||||
className="app-input"
|
||||
>
|
||||
<option value="">No default</option>
|
||||
@@ -286,9 +280,7 @@ function DefaultValueInput({
|
||||
<input
|
||||
type="url"
|
||||
value={typeof value === "string" ? value : ""}
|
||||
onChange={(e) =>
|
||||
onChange(e.target.value === "" ? undefined : e.target.value)
|
||||
}
|
||||
onChange={(e) => onChange(e.target.value === "" ? undefined : e.target.value)}
|
||||
placeholder="https://..."
|
||||
className="app-input"
|
||||
/>
|
||||
@@ -299,9 +291,7 @@ function DefaultValueInput({
|
||||
<input
|
||||
type="email"
|
||||
value={typeof value === "string" ? value : ""}
|
||||
onChange={(e) =>
|
||||
onChange(e.target.value === "" ? undefined : e.target.value)
|
||||
}
|
||||
onChange={(e) => onChange(e.target.value === "" ? undefined : e.target.value)}
|
||||
placeholder="name@example.com"
|
||||
className="app-input"
|
||||
/>
|
||||
@@ -311,9 +301,7 @@ function DefaultValueInput({
|
||||
return (
|
||||
<textarea
|
||||
value={typeof value === "string" ? value : ""}
|
||||
onChange={(e) =>
|
||||
onChange(e.target.value === "" ? undefined : e.target.value)
|
||||
}
|
||||
onChange={(e) => onChange(e.target.value === "" ? undefined : e.target.value)}
|
||||
placeholder="No default"
|
||||
className="app-input resize-none"
|
||||
rows={2}
|
||||
@@ -325,9 +313,7 @@ function DefaultValueInput({
|
||||
<input
|
||||
type="text"
|
||||
value={typeof value === "string" ? value : ""}
|
||||
onChange={(e) =>
|
||||
onChange(e.target.value === "" ? undefined : e.target.value)
|
||||
}
|
||||
onChange={(e) => onChange(e.target.value === "" ? undefined : e.target.value)}
|
||||
placeholder="No default"
|
||||
className="app-input"
|
||||
/>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import type { StaffingRequirement } from "@capakraken/shared";
|
||||
import type { StaffingRequirement } from "@nexus/shared";
|
||||
import { uuid } from "~/lib/uuid.js";
|
||||
|
||||
function makeEmptyPreset(): StaffingRequirement {
|
||||
|
||||
Reference in New Issue
Block a user