Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2097,6 +2097,7 @@ export function Applications({
configurationDirty = false,
configurationSaved = false,
onEditTemplates,
onTemplateEditingChange,
}: {
session: Session | null;
draft: CommonConfiguration | null;
Expand All @@ -2105,6 +2106,7 @@ export function Applications({
configurationDirty?: boolean;
configurationSaved?: boolean;
onEditTemplates?: () => void;
onTemplateEditingChange?: (editing: boolean) => void;
}) {
const [versions, setVersions] = useState<PublishedProjectTemplate[]>([]);
const [instances, setInstances] = useState<ApplicationInstance[]>([]);
Expand Down Expand Up @@ -2163,6 +2165,9 @@ export function Applications({
>([]);
const [platformRevision, setPlatformRevision] = useState("");
const [activeTab, setActiveTab] = useState<string | null>(null);
useEffect(() => {
onTemplateEditingChange?.(activeTab === null || activeTab === "drafts");
}, [activeTab, onTemplateEditingChange]);
const [appliedPlatformsEnabled, setAppliedPlatformsEnabled] = useState(false);
const [appliedPlatforms, setAppliedPlatforms] = useState<
z.infer<typeof appliedPlatformsSchema>["platforms"]
Expand Down Expand Up @@ -2397,8 +2402,11 @@ export function Applications({
if (!session)
return (
<section>
<h2>{t("Anmeldung erforderlich")}</h2>
<h2>
{t(templateEditor ? "Template-Entwürfe" : "Anmeldung erforderlich")}
</h2>
<p>{t("Bitte melde dich für Application Landing Zones an.")}</p>
{templateEditor}
</section>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,11 @@ import {
import { useState } from "react";
import { t } from "../i18n";
import type { EditorStep } from "../navigation";
import type { Session } from "./Account";
import { useObservabilityCatalogue } from "./CloudCatalogues";
import { ComponentPicker } from "./ComponentPicker";
import { FederatedIdentityEditor } from "./FederatedIdentityEditor";
import { labelFor } from "./feature-labels";
import { NetworkEditor } from "./NetworkEditor";
import { ProjectTemplates } from "./ProjectTemplates";
import { projectTemplateSummary } from "./project-template-summary";
import { StructuredField } from "./StructuredField";
import { Topology } from "./Topology";
Expand Down Expand Up @@ -87,47 +85,33 @@ const steps: { id: EditorStep; title: string; inputs: string[] }[] = [

export function CommonEditor({
draft,
session = null,
savedConfigurationId = null,
onChange,
step,
onStepChange,
onOpenStorage,
onCreatePlatformCopy,
onOpenTemplates,
}: {
draft: CommonConfiguration;
session?: Session | null;
savedConfigurationId?: string | null;
onChange: (draft: CommonConfiguration) => void;
step: EditorStep;
onStepChange: (step: EditorStep) => void;
onOpenStorage: () => void;
onCreatePlatformCopy?: () => void;
onOpenTemplates: () => void;
}) {
const [error, setError] = useState("");
const [notice, setNotice] = useState("");
const [newKind, setNewKind] = useState<"public" | "corporate" | "sandbox">(
"public",
);
const [newKey, setNewKey] = useState("");
const [selectedTemplateId, setSelectedTemplateId] = useState<string | null>(
null,
);
const platformDraft = draft.projectTemplates !== undefined;
const selectedTemplate =
draft.projectTemplates?.find(
(template) => template.id === selectedTemplateId,
) ?? draft.projectTemplates?.[0];
const selectTemplate = (id: string) => {
setSelectedTemplateId(id);
onStepChange("projects");
};
const visibleSteps = steps.filter(
(item) => !platformDraft || item.id !== "projects",
);
const stepTitle = (id: EditorStep, title: string) =>
id === "projects"
? platformDraft
? "Template-Entwürfe"
: "Projekte (Bestand)"
: title;
id === "projects" ? "Projekte (Bestand)" : title;
const values = compileCommonConfiguration(draft);
const projects = commonProjects(draft);
const areas = commonNetworkAreas(draft);
Expand Down Expand Up @@ -158,7 +142,8 @@ export function CommonEditor({
)
.map((finding) => ({ field: finding.path, message: finding.message })),
];
const active = steps.find((item) => item.id === step) ?? steps[0];
const active =
visibleSteps.find((item) => item.id === step) ?? visibleSteps[0];
const perform = (action: () => CommonConfiguration) => {
try {
onChange(action());
Expand Down Expand Up @@ -257,11 +242,25 @@ export function CommonEditor({
{t("Konfigurationen →")}
</button>
</div>
{platformDraft && (
<p className="info-banner">
{t(
"Template-Entwürfe bearbeitest du unter Application Landing Zones. Sie werden weiterhin mit dieser Konfiguration gespeichert.",
)}{" "}
<button
type="button"
className="text-button"
onClick={onOpenTemplates}
>
{t("Zu den Application Landing Zones →")}
</button>
</p>
)}
<nav
aria-label={t("Konfigurationsschritte")}
className="steps shared-steps"
>
{steps.map((item, index) => (
{visibleSteps.map((item, index) => (
<button
type="button"
key={item.id}
Expand Down Expand Up @@ -313,16 +312,6 @@ export function CommonEditor({
)}
</p>
)}
{step === "projects" && platformDraft && (
<ProjectTemplates
session={session}
savedConfigurationId={savedConfigurationId}
draft={draft}
onChange={onChange}
selectedTemplateId={selectedTemplate?.id ?? null}
onSelectTemplate={selectTemplate}
/>
)}
{step === "projects" && !platformDraft && (
<>
<p className="info-banner">
Expand Down Expand Up @@ -816,10 +805,10 @@ export function CommonEditor({
className="button secondary"
onClick={() =>
onStepChange(
steps[
visibleSteps[
Math.max(
0,
steps.findIndex((item) => item.id === step) - 1,
visibleSteps.findIndex((item) => item.id === step) - 1,
)
]?.id ?? "basics",
)
Expand All @@ -834,8 +823,9 @@ export function CommonEditor({
className="button primary"
onClick={() =>
onStepChange(
steps[steps.findIndex((item) => item.id === step) + 1]
?.id ?? "review",
visibleSteps[
visibleSteps.findIndex((item) => item.id === step) + 1
]?.id ?? "review",
)
}
>
Expand All @@ -845,12 +835,7 @@ export function CommonEditor({
</div>
</section>
<div className="editor-previews">
<Topology
values={values}
projectTemplates={draft.projectTemplates}
selectedTemplateId={selectedTemplate?.id}
onSelectTemplate={selectTemplate}
/>
<Topology values={values} projectTemplates={draft.projectTemplates} />
{areas.length > 0 && (
<figure className="topology network-topology">
<figcaption>{t("Netzwerkzuordnung")}</figcaption>
Expand Down Expand Up @@ -888,20 +873,8 @@ export function CommonEditor({
)
.map((template) => (
<li key={template.id}>
<button
type="button"
className="text-button"
aria-pressed={
selectedTemplate?.id === template.id
}
onClick={() => selectTemplate(template.id)}
>
{t("Template ·")}{" "}
{
projectTemplateSummary(template, values)
.name
}
</button>
{t("Template ·")}{" "}
{projectTemplateSummary(template, values).name}
</li>
))}
</ul>
Expand Down
3 changes: 3 additions & 0 deletions landing-zone-configurator/app/apps/web/src/locales/en.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
export const englishMessages: Record<string, string> = {
"Template-Entwürfe bearbeitest du unter Application Landing Zones. Sie werden weiterhin mit dieser Konfiguration gespeichert.":
"Edit template drafts under Application Landing Zones. They are still saved with this configuration.",
"Zu den Application Landing Zones →": "Go to Application Landing Zones →",
"Assistant für Template-Entwürfe": "Assistant for template drafts",
"Der Assistant verwendet die geöffnete Plattformkonfiguration einschließlich ihrer Template-Entwürfe. Nenne das gewünschte Template und prüfe die vorgeschlagenen Änderungen vor der Übernahme. Speichere sie anschließend ausdrücklich; eine Veröffentlichung erfolgt separat.":
"The Assistant uses the open platform configuration, including its template drafts. Name the template you want to change and review the proposed changes before accepting them. Then save explicitly; publication is a separate step.",
Expand Down
94 changes: 82 additions & 12 deletions landing-zone-configurator/app/apps/web/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { assistantValuesEqual } from "@lzc/contracts";
import {
type CommonConfiguration,
commonNetworkAreas,
compileCommonConfiguration,
createEditorConfiguration,
createPlatformDraftCopy,
type EditorDraft,
isCommonDraft,
objectValue,
readEditorDraft,
textValue,
upgradeEditorDraft,
} from "@lzc/domain";
import {
Expand Down Expand Up @@ -42,6 +44,7 @@ import { ForkWorkspace } from "./components/ForkWorkspace";
import { InvitationAcceptance } from "./components/Invitations";
import { Organisation } from "./components/Organisation";
import { ProjectTemplates } from "./components/ProjectTemplates";
import { projectTemplateSummary } from "./components/project-template-summary";
import { TemplateAdvice } from "./components/TemplateAdvice";
import { Topology } from "./components/Topology";
import { currentLanguage, setLanguage, t } from "./i18n";
Expand Down Expand Up @@ -71,15 +74,64 @@ function TemplateDraftEditor({
const selected =
draft.projectTemplates?.find((template) => template.id === selectedId) ??
draft.projectTemplates?.[0];
const values = compileCommonConfiguration(draft);
const areas = commonNetworkAreas(draft);
return (
<ProjectTemplates
draft={draft}
session={session}
savedConfigurationId={savedConfigurationId}
onChange={onChange}
selectedTemplateId={selected?.id ?? null}
onSelectTemplate={setSelectedId}
/>
<div className="editor-layout">
<section className="panel">
<ProjectTemplates
draft={draft}
session={session}
savedConfigurationId={savedConfigurationId}
onChange={onChange}
selectedTemplateId={selected?.id ?? null}
onSelectTemplate={setSelectedId}
/>
</section>
<div className="editor-previews">
<Topology
values={values}
projectTemplates={draft.projectTemplates}
selectedTemplateId={selected?.id}
onSelectTemplate={setSelectedId}
/>
{areas.length > 0 && (
<figure className="topology network-topology">
<figcaption>{t("Netzwerkzuordnung")}</figcaption>
{areas.map((area) => (
<section key={area.id}>
<h3>
{area.region} · {textValue(area.settings.name) || area.key}
</h3>
<ul>
{draft.projectTemplates
?.filter(
(template) =>
template.kind === "corporate" &&
template.region === area.region &&
(textValue(template.settings.network_area_key) ||
"default") === area.key,
)
.map((template) => (
<li key={template.id}>
<button
type="button"
className="text-button"
aria-pressed={selected?.id === template.id}
onClick={() => setSelectedId(template.id)}
>
{t("Template ·")}{" "}
{projectTemplateSummary(template, values).name}
</button>
</li>
))}
</ul>
</section>
))}
</figure>
)}
</div>
</div>
);
}

Expand All @@ -96,6 +148,8 @@ function App() {
const [session, setSession] = useState<Session | null>(null);
const [returningFromLogin, setReturningFromLogin] = useState(false);
const [credentialRevision, setCredentialRevision] = useState(0);
const [applicationTemplateEditing, setApplicationTemplateEditing] =
useState(true);
const organisationWorkspace = session?.tenant?.kind === "organisation";
const platformAccess =
!organisationWorkspace ||
Expand Down Expand Up @@ -126,6 +180,17 @@ function App() {
draft &&
(!savedDraft || !assistantValuesEqual(draft, JSON.parse(savedDraft))),
);
useEffect(() => {
if (
platformAccess &&
view === "editor" &&
step === "projects" &&
draft &&
isCommonDraft(draft) &&
draft.projectTemplates !== undefined
)
setView("applications", undefined, true);
}, [platformAccess, view, step, draft, setView]);
const finishLogin = useCallback(() => {
if (draft) return;
setReturningFromLogin(true);
Expand Down Expand Up @@ -340,7 +405,7 @@ function App() {
);
setDraftEpoch((value) => value + 1);
setConfigurationBinding(null);
setView("editor", "projects");
setView("applications");
setLoginError("");
} catch {
setLoginError(
Expand Down Expand Up @@ -774,6 +839,7 @@ function App() {
configurationDirty={draftDirty}
configurationSaved={!!configurationBinding && !draftDirty}
onEditTemplates={() => setView("editor", "projects")}
onTemplateEditingChange={setApplicationTemplateEditing}
templateEditor={
platformAccess &&
draft &&
Expand Down Expand Up @@ -811,7 +877,12 @@ function App() {
)}
{platformAccess && (
<>
<div hidden={view !== "editor"}>
<div
hidden={
view !== "editor" &&
!(view === "applications" && applicationTemplateEditing)
}
>
<CloudCataloguePanel
session={session}
key={credentialRevision}
Expand Down Expand Up @@ -1083,11 +1154,10 @@ function App() {
draft &&
(isCommonDraft(draft) ? (
<CommonEditor
session={session}
savedConfigurationId={configurationBinding?.id ?? null}
draft={draft}
onChange={setDraft}
onCreatePlatformCopy={copyPlatform}
onOpenTemplates={() => setView("applications")}
step={step}
onStepChange={(next) => setView("editor", next)}
onOpenStorage={() => setView("repositories")}
Expand Down
Loading
Loading