feat(ui): add AWS Organizations types and Zustand store

Add const-enum types for discovery status, apply status, org/OU relations,
and secret state. Add persisted Zustand store to manage org wizard state
across setup, discovery, selection, and connection test phases.
This commit is contained in:
alejandrobailo committed 2026-02-17 09:46:03 +01:00
1 parent df8a7220ff
commit 6648212369
4 files changed
+256

No files matched your search

+1
View File
@@ -1 +1,2 @@
export * from "./organizations/store";
export * from "./ui/store";
+89
View File
@@ -0,0 +1,89 @@
import { create } from "zustand";
import { persist } from "zustand/middleware";
import { ConnectionTestStatus, DiscoveryResult } from "@/types/organizations";
interface OrgSetupState {
// Identity
organizationId: string | null;
organizationName: string | null;
organizationExternalId: string | null;
discoveryId: string | null;
// Discovery
discoveryResult: DiscoveryResult | null;
// Selection + aliases
selectedAccountIds: string[];
accountAliases: Record<string, string>;
// Apply result
createdProviderIds: string[];
// Connection test results
connectionResults: Record<string, ConnectionTestStatus>;
// Actions
setOrganization: (id: string, name: string, externalId: string) => void;
setDiscovery: (id: string, result: DiscoveryResult) => void;
setSelectedAccountIds: (ids: string[]) => void;
setAccountAlias: (accountId: string, alias: string) => void;
setCreatedProviderIds: (ids: string[]) => void;
setConnectionResult: (
providerId: string,
status: ConnectionTestStatus,
) => void;
reset: () => void;
}
const initialState = {
organizationId: null,
organizationName: null,
organizationExternalId: null,
discoveryId: null,
discoveryResult: null,
selectedAccountIds: [],
accountAliases: {},
createdProviderIds: [],
connectionResults: {},
};
export const useOrgSetupStore = create<OrgSetupState>()(
persist(
(set) => ({
...initialState,
setOrganization: (id, name, externalId) =>
set({
organizationId: id,
organizationName: name,
organizationExternalId: externalId,
}),
setDiscovery: (id, result) =>
set({ discoveryId: id, discoveryResult: result }),
setSelectedAccountIds: (ids) => set({ selectedAccountIds: ids }),
setAccountAlias: (accountId, alias) =>
set((state) => ({
accountAliases: { ...state.accountAliases, [accountId]: alias },
})),
setCreatedProviderIds: (ids) => set({ createdProviderIds: ids }),
setConnectionResult: (providerId, status) =>
set((state) => ({
connectionResults: {
...state.connectionResults,
[providerId]: status,
},
})),
reset: () => set(initialState),
}),
{
name: "org-setup-store",
},
),
);
+1
View File
@@ -2,6 +2,7 @@ export * from "./authFormSchema";
export * from "./components";
export * from "./filters";
export * from "./formSchemas";
export * from "./organizations";
export * from "./processors";
export * from "./providers";
export * from "./resources";
+165
View File
@@ -0,0 +1,165 @@
// ─── Const Enums ──────────────────────────────────────────────────────────────
export const DISCOVERY_STATUS = {
PENDING: "pending",
RUNNING: "running",
SUCCEEDED: "succeeded",
FAILED: "failed",
} as const;
export type DiscoveryStatus =
(typeof DISCOVERY_STATUS)[keyof typeof DISCOVERY_STATUS];
export const APPLY_STATUS = {
READY: "ready",
BLOCKED: "blocked",
} as const;
export type ApplyStatus = (typeof APPLY_STATUS)[keyof typeof APPLY_STATUS];
export const ORG_RELATION = {
ALREADY_LINKED: "already_linked",
LINK_REQUIRED: "link_required",
LINKED_TO_OTHER: "linked_to_other_organization",
} as const;
export type OrgRelation = (typeof ORG_RELATION)[keyof typeof ORG_RELATION];
export const OU_RELATION = {
NOT_APPLICABLE: "not_applicable",
ALREADY_LINKED: "already_linked",
LINK_REQUIRED: "link_required",
LINKED_TO_OTHER_OU: "linked_to_other_ou",
UNCHANGED: "unchanged",
} as const;
export type OuRelation = (typeof OU_RELATION)[keyof typeof OU_RELATION];
export const SECRET_STATE = {
ALREADY_EXISTS: "already_exists",
WILL_CREATE: "will_create",
MANUAL_REQUIRED: "manual_required",
} as const;
export type SecretState = (typeof SECRET_STATE)[keyof typeof SECRET_STATE];
export const ORG_WIZARD_STEP = {
SETUP: 0,
VALIDATE: 1,
LAUNCH: 2,
} as const;
export type OrgWizardStep =
(typeof ORG_WIZARD_STEP)[keyof typeof ORG_WIZARD_STEP];
// ─── Discovery Result Interfaces ──────────────────────────────────────────────
export interface AccountRegistration {
provider_exists: boolean;
provider_id: string | null;
organization_relation: OrgRelation;
organizational_unit_relation: OuRelation;
provider_secret_state: SecretState;
apply_status: ApplyStatus;
blocked_reasons: string[];
}
export interface DiscoveredAccount {
id: string;
name: string;
arn: string;
email: string;
status: "ACTIVE" | "SUSPENDED" | "PENDING_CLOSURE" | "CLOSED";
joined_method: "INVITED" | "CREATED";
joined_timestamp: string;
parent_id: string;
registration: AccountRegistration;
}
export interface DiscoveredOu {
id: string;
name: string;
arn: string;
parent_id: string;
}
export interface DiscoveredRoot {
id: string;
arn: string;
name: string;
policy_types: Array<{ Type: string; Status: string }>;
}
export interface DiscoveryResult {
roots: DiscoveredRoot[];
organizational_units: DiscoveredOu[];
accounts: DiscoveredAccount[];
}
// ─── JSON:API Resource Interfaces ─────────────────────────────────────────────
export interface OrganizationAttributes {
name: string;
org_type: "aws" | "azure" | "gcp";
external_id: string;
metadata: Record<string, unknown>;
root_external_id: string | null;
inserted_at?: string;
updated_at?: string;
}
export interface OrganizationResource {
id: string;
type: "organizations";
attributes: OrganizationAttributes;
}
export interface DiscoveryAttributes {
status: DiscoveryStatus;
result: DiscoveryResult | Record<string, never>;
error: string | null;
inserted_at: string;
updated_at: string;
}
export interface DiscoveryResource {
id: string;
type: "organization-discoveries";
attributes: DiscoveryAttributes;
}
export interface ApplyResultAttributes {
providers_created_count: number;
providers_linked_count: number;
providers_applied_count: number;
organizational_units_created_count: number;
}
export interface ApplyResultRelationships {
providers: {
data: Array<{ type: "providers"; id: string }>;
meta: { count: number };
};
organizational_units: {
data: Array<{ type: "organizational-units"; id: string }>;
meta: { count: number };
};
}
export interface ApplyResultResource {
id: string;
type: "organization-discovery-apply-results";
attributes: ApplyResultAttributes;
relationships: ApplyResultRelationships;
}
// ─── Connection Test Status ───────────────────────────────────────────────────
export const CONNECTION_TEST_STATUS = {
PENDING: "pending",
SUCCESS: "success",
ERROR: "error",
} as const;
export type ConnectionTestStatus =
(typeof CONNECTION_TEST_STATUS)[keyof typeof CONNECTION_TEST_STATUS];