Skip to content
This repository was archived by the owner on Jan 19, 2026. It is now read-only.

Commit 44adc0c

Browse files
committed
refactor(graph): add preset nodes and dependencies to graph
1 parent 6e22c6a commit 44adc0c

5 files changed

Lines changed: 114 additions & 18 deletions

File tree

src/commands/components/push/actions.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ export const upsertComponentGroup = async (
108108
};
109109

110110
// Component preset actions
111-
export const pushComponentPreset = async (space: string, componentPreset: { preset: Partial<SpaceComponentPreset> }, _token?: string, _region?: RegionCode): Promise<SpaceComponentPreset | undefined> => {
111+
export const pushComponentPreset = async (space: string, componentPreset: { preset: Partial<SpaceComponentPreset> }): Promise<SpaceComponentPreset | undefined> => {
112112
try {
113113
const client = mapiClient();
114114

@@ -124,7 +124,7 @@ export const pushComponentPreset = async (space: string, componentPreset: { pres
124124
}
125125
};
126126

127-
export const updateComponentPreset = async (space: string, presetId: number, componentPreset: { preset: Partial<SpaceComponentPreset> }, _token?: string, _region?: RegionCode): Promise<SpaceComponentPreset | undefined> => {
127+
export const updateComponentPreset = async (space: string, presetId: number, componentPreset: { preset: Partial<SpaceComponentPreset> }): Promise<SpaceComponentPreset | undefined> => {
128128
try {
129129
const client = mapiClient();
130130

@@ -143,17 +143,15 @@ export const updateComponentPreset = async (space: string, presetId: number, com
143143
export const upsertComponentPreset = async (
144144
space: string,
145145
preset: Partial<SpaceComponentPreset>,
146-
token: string,
147-
region: RegionCode,
148146
existingId?: number,
149147
): Promise<SpaceComponentPreset | undefined> => {
150148
if (existingId) {
151149
// We know it exists, update directly
152-
return await updateComponentPreset(space, existingId, { preset }, token, region);
150+
return await updateComponentPreset(space, existingId, { preset });
153151
}
154152
else {
155153
// New resource, create directly
156-
return await pushComponentPreset(space, { preset }, token, region);
154+
return await pushComponentPreset(space, { preset });
157155
}
158156
};
159157

src/commands/components/push/graph-operations/dependency-graph.ts

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ import type {
22
SpaceComponent,
33
SpaceComponentGroup,
44
SpaceComponentInternalTag,
5+
SpaceComponentPreset,
56
} from '../../constants';
67
import type { DependencyGraph, GraphBuildingContext, NodeData, NodeType, SchemaDependencies, TargetResourceInfo, UnifiedNode } from './types';
7-
import { upsertComponent, upsertComponentGroup, upsertComponentInternalTag } from '../actions';
8+
import { upsertComponent, upsertComponentGroup, upsertComponentInternalTag, upsertComponentPreset } from '../actions';
89
import {
910
generateContentHash,
1011
normalizeComponentForComparison,
1112
normalizeGroupForComparison,
13+
normalizePresetForComparison,
1214
normalizeTagForComparison,
1315
} from './comparison-utils';
1416

@@ -61,6 +63,21 @@ export function buildDependencyGraph(context: GraphBuildingContext): DependencyG
6163
graph.nodes.set(nodeId, node);
6264
});
6365

66+
// Create nodes for all presets with colocated target data
67+
spaceState.local.presets.forEach((preset) => {
68+
const nodeId = `preset:${preset.name}`;
69+
const targetPreset = spaceState.target.presets.get(preset.name);
70+
const targetData = targetPreset
71+
? {
72+
resource: targetPreset,
73+
id: targetPreset.id,
74+
hash: generateContentHash(normalizePresetForComparison(preset)),
75+
}
76+
: undefined;
77+
const node = new PresetNode(preset, targetData);
78+
graph.nodes.set(nodeId, node);
79+
});
80+
6481
// Add group parent dependencies
6582
spaceState.local.groups.forEach((group) => {
6683
if (group.parent_uuid) {
@@ -111,6 +128,18 @@ export function buildDependencyGraph(context: GraphBuildingContext): DependencyG
111128
}
112129
});
113130

131+
// Add preset dependencies on components
132+
spaceState.local.presets.forEach((preset) => {
133+
const presetId = `preset:${preset.name}`;
134+
135+
// Find the component this preset belongs to
136+
const component = spaceState.local.components.find(c => c.id === preset.component_id);
137+
if (component) {
138+
const componentId = `component:${component.name}`;
139+
addDependency(presetId, componentId);
140+
}
141+
});
142+
114143
return graph;
115144
}
116145

@@ -589,3 +618,77 @@ export class ComponentNode extends GraphNode<SpaceComponent> {
589618
return result;
590619
}
591620
}
621+
622+
/**
623+
* Preset node implementation
624+
* Presets depend on components (via component_id)
625+
*/
626+
class PresetNode implements UnifiedNode<SpaceComponentPreset> {
627+
public readonly id: string;
628+
public readonly name: string;
629+
public readonly type: NodeType = 'preset';
630+
public readonly sourceData: SpaceComponentPreset;
631+
public targetData?: TargetResourceInfo<SpaceComponentPreset>;
632+
public readonly dependencies = new Set<string>();
633+
public readonly dependents = new Set<string>();
634+
635+
constructor(preset: SpaceComponentPreset, targetData?: TargetResourceInfo<SpaceComponentPreset>) {
636+
this.sourceData = preset;
637+
this.targetData = targetData;
638+
this.id = `preset:${preset.name}`;
639+
this.name = preset.name;
640+
}
641+
642+
getName(): string {
643+
return this.name;
644+
}
645+
646+
normalize(): any {
647+
return normalizePresetForComparison(this.sourceData);
648+
}
649+
650+
shouldSkip(): boolean {
651+
if (!this.targetData) { return false; }
652+
653+
const sourceHash = generateContentHash(this.normalize());
654+
return sourceHash === this.targetData.hash;
655+
}
656+
657+
resolveReferences(graph: DependencyGraph): void {
658+
// Find the component this preset belongs to and update component_id
659+
const componentName = this.findComponentNameById(this.sourceData.component_id, graph);
660+
if (componentName) {
661+
const componentNode = graph.nodes.get(`component:${componentName}`);
662+
if (componentNode?.targetData) {
663+
this.sourceData.component_id = componentNode.targetData.id as number;
664+
}
665+
}
666+
}
667+
668+
private findComponentNameById(componentId: number, graph: DependencyGraph): string | null {
669+
// Find component by matching source component_id
670+
for (const [_nodeId, node] of graph.nodes) {
671+
if (node.type === 'component' && (node.sourceData as SpaceComponent).id === componentId) {
672+
return node.name;
673+
}
674+
}
675+
return null;
676+
}
677+
678+
async upsert(space: string): Promise<SpaceComponentPreset> {
679+
const existingId = this.targetData?.id as number | undefined;
680+
const result = await upsertComponentPreset(space, this.sourceData, existingId);
681+
if (!result) {
682+
throw new Error(`Failed to upsert preset: ${this.name}`);
683+
}
684+
return result;
685+
}
686+
687+
updateTargetData(result: SpaceComponentPreset): void {
688+
this.targetData = {
689+
resource: result,
690+
id: result.id,
691+
hash: generateContentHash(this.normalize()),
692+
};
693+
}
694+
}

src/commands/components/push/graph-operations/index.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,8 @@ export async function pushWithDependencyGraph(
3737
const graph = buildDependencyGraph(context);
3838
validateGraph(graph);
3939

40-
// Process resources with 2-pass per level approach:
41-
// - Pass 1: Resolve references (dependencies from previous levels exist)
42-
// - Pass 2: Process resources with resolved references
40+
// Process all resources using the dependency graph
4341
const results = await processAllResources(graph, space, maxConcurrency, force);
4442

45-
// TODO: Process presets after main resources
46-
// const presetResults = await processPresets(spaceData.presets, graph, space, password, region);
47-
// results.successful.push(...presetResults.successful);
48-
// results.failed.push(...presetResults.failed);
49-
// results.skipped.push(...presetResults.skipped);
50-
5143
return results;
5244
}

src/commands/components/push/graph-operations/resource-processor.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ function getResourceTypeName(type: string): string {
168168
case 'component': return 'component';
169169
case 'group': return 'group';
170170
case 'tag': return 'tag';
171+
case 'preset': return 'preset';
171172
default: return type;
172173
}
173174
}
@@ -180,6 +181,7 @@ function getResourceTypeColor(type: string): string {
180181
case 'component': return colorPalette.COMPONENTS;
181182
case 'group': return '#4ade80'; // green
182183
case 'tag': return '#fbbf24'; // yellow
184+
case 'preset': return '#a855f7'; // purple
183185
default: return colorPalette.COMPONENTS;
184186
}
185187
}

src/commands/components/push/graph-operations/types.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type {
33
SpaceComponent,
44
SpaceComponentGroup,
55
SpaceComponentInternalTag,
6+
SpaceComponentPreset,
67
SpaceDataState,
78
} from '../../constants';
89

@@ -11,10 +12,10 @@ import type {
1112
// =============================================================================
1213

1314
/** Types of nodes in our dependency graph */
14-
export type NodeType = 'component' | 'group' | 'tag';
15+
export type NodeType = 'component' | 'group' | 'tag' | 'preset';
1516

1617
/** Data that can be stored in a graph node */
17-
export type NodeData = SpaceComponent | SpaceComponentGroup | SpaceComponentInternalTag;
18+
export type NodeData = SpaceComponent | SpaceComponentGroup | SpaceComponentInternalTag | SpaceComponentPreset;
1819

1920
/** Target resource information colocated with graph nodes */
2021
export interface TargetResourceInfo<T extends NodeData> {

0 commit comments

Comments
 (0)