Skip to content

Commit

Permalink
[observables] observe specific components when updating code componen…
Browse files Browse the repository at this point in the history
…ts meta

Issue: https://linear.app/plasmic/issue/PLA-10618/handle-update-of-code-component-meta
Change-Id: I44c5e53a36acdcdabf095df8b1669d3b2b3bf396
GitOrigin-RevId: 561e022f35b7a6cf55effc990f1b74bf141eacee
  • Loading branch information
IcaroG authored and Copybara committed Apr 9, 2024
1 parent 5af1b4c commit 25cefdc
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 59 deletions.
19 changes: 12 additions & 7 deletions platform/wab/src/wab/client/components/canvas/site-ops.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1532,9 +1532,10 @@ export class SiteOps {

await this.studioCtx.changeObserved(
() => {
return tokensUsages.flatMap(
(tokenUsage) => tokenUsage.usages[1].components
);
return tokensUsages.flatMap((tokenUsage) => [
...tokenUsage.usages[1].components,
...tokenUsage.usages[1].frames.map((f) => f.container.component),
]);
},
({ success }) => {
tokens.forEach((token) => {
Expand Down Expand Up @@ -1575,9 +1576,10 @@ export class SiteOps {

await this.studioCtx.changeObserved(
() => {
return mixinsUsages.flatMap(
(mixinUsage) => mixinUsage.usages[1].components
);
return mixinsUsages.flatMap((mixinUsage) => [
...mixinUsage.usages[1].components,
...mixinUsage.usages[1].frames.map((f) => f.container.component),
]);
},
({ success }) => {
mixins.forEach((mixin) => {
Expand All @@ -1596,7 +1598,10 @@ export class SiteOps {
const [_, summary] = extractTokenUsages(this.site, fromToken);
await this.studioCtx.changeObserved(
() => {
return summary.components;
return [
...summary.components,
...summary.frames.map((f) => f.container.component),
];
},
({ success }) => {
this.tplMgr.swapTokens(fromToken, toToken);
Expand Down
4 changes: 4 additions & 0 deletions platform/wab/src/wab/client/studio-ctx/StudioCtx.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1358,6 +1358,10 @@ export class StudioCtx extends WithDbCtx {
});
}

observeComponents(components: Component[]) {
return this.dbCtx().maybeObserveComponents(components);
}

private _isDocs = observable.box(false);

set isDocs(v: boolean) {
Expand Down
59 changes: 39 additions & 20 deletions platform/wab/src/wab/observable-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ export type ModelChange = AnyChange & {

export type ModelChangeListener = (event: ModelChange) => void;

type VisitFlags = {
incrementalObserve?: boolean;
};

type ObservableState = {
dispose: Lambda;
prune: Lambda;
Expand Down Expand Up @@ -385,15 +389,20 @@ export function observeModel(
* Returns disposal function, or `undefined` if the `path` contains
* a cycle.
*/
const observeInst = (inst: ObjInst): Lambda | undefined => {
const observeInst = (
inst: ObjInst,
flags: VisitFlags
): Lambda | undefined => {
if (instStates.has(inst)) {
// We've seen this `inst` before... So exit early
return makeDisposeInst(inst);
}

// We've never seen this `inst` before, so initialize `InstState`.
// We keep track of the disposal functions used to observe this inst
possiblyNewlyAddedInsts.add(inst);
if (!flags.incrementalObserve) {
possiblyNewlyAddedInsts.add(inst);
}
const fieldValueDisposes = new Map<string, Lambda>(); // tracks updates to field values

const state: InstState = {
Expand Down Expand Up @@ -432,7 +441,7 @@ export function observeModel(
addInstChildDispose(
fieldValueDisposes,
fieldName,
visitFieldValue(inst, field, event.newValue)
visitFieldValue(inst, field, event.newValue, flags)
);
}
});
Expand All @@ -446,7 +455,7 @@ export function observeModel(
addInstChildDispose(
fieldValueDisposes,
field.name,
visitFieldValue(inst, field, inst[field.name])
visitFieldValue(inst, field, inst[field.name], flags)
);
}

Expand All @@ -460,20 +469,21 @@ export function observeModel(
const visitFieldValue = (
inst: ObjInst,
field: Field,
value: any
value: any,
flags: VisitFlags
): Lambda | undefined => {
if (value == null) {
return undefined;
}

if (_instUtil.isObjInst(value)) {
return observeInstFieldValue(inst, field, value);
return observeInstFieldValue(inst, field, value, flags);
} else if (Array.isArray(value)) {
return observeArrayFieldValue(inst, field, value);
return observeArrayFieldValue(inst, field, value, flags);
} else if (React.isValidElement(value)) {
return undefined;
} else if (isLiteralObject(value, opts.localObject)) {
return observePlainObjFieldValue(inst, field, value);
return observePlainObjFieldValue(inst, field, value, flags);
} else if (isPrimitive(value) || typeof value === "function") {
// Primitive values don't need subscription. However, they might weakly
// reference another instance (e.g., by its uuid), so we should also
Expand All @@ -495,7 +505,8 @@ export function observeModel(
const observeInstFieldValue = (
inst: ObjInst,
field: Field,
value: ObjInst
value: ObjInst,
flags: VisitFlags
): Lambda | undefined => {
visitNodeListener?.(inst);

Expand All @@ -508,7 +519,7 @@ export function observeModel(
}

if (isStrongRefField(field)) {
const instDispose = observeInst(value);
const instDispose = observeInst(value, flags);
if (instDispose) {
// Add this value as a child of the owning inst
updateInstParent(inst, field.name, value, true);
Expand Down Expand Up @@ -549,7 +560,9 @@ export function observeModel(
const observeArrayFieldValue = (
inst: ObjInst,
field: Field,
array: any[]
array: any[],

flags: VisitFlags
): Lambda => {
const childDisposes = new Map<any, Lambda[]>();
// Support repeated children in the array
Expand All @@ -560,7 +573,7 @@ export function observeModel(
addCollectionChildDispose(
childDisposes,
child,
visitFieldValue(inst, field, child)
visitFieldValue(inst, field, child, flags)
);
}
childCount.set(child, (childCount.get(child) ?? 0) + 1);
Expand Down Expand Up @@ -636,7 +649,8 @@ export function observeModel(
const observePlainObjFieldValue = (
inst: ObjInst,
field: Field,
obj: Record<string, any>
obj: Record<string, any>,
flags: VisitFlags
): Lambda => {
// Disposes for children value stores mapping from child value to
// a list of dispose functions. It's a list because the same
Expand All @@ -653,7 +667,7 @@ export function observeModel(
addCollectionChildDispose(
childDisposes,
val,
visitFieldValue(inst, field, val)
visitFieldValue(inst, field, val, flags)
);
}

Expand All @@ -662,7 +676,7 @@ export function observeModel(
addCollectionChildDispose(
childDisposes,
val,
visitFieldValue(inst, field, val)
visitFieldValue(inst, field, val, flags)
);
}

Expand All @@ -685,12 +699,12 @@ export function observeModel(
addCollectionChildDispose(
childDisposes,
event.newValue,
visitFieldValue(inst, field, event.newValue)
visitFieldValue(inst, field, event.newValue, flags)
);
addCollectionChildDispose(
childDisposes,
event.name,
visitFieldValue(inst, field, event.name)
visitFieldValue(inst, field, event.name, flags)
);
} else if (event.type === "update") {
fireFieldChange(inst, field.name, {
Expand All @@ -704,7 +718,7 @@ export function observeModel(
addCollectionChildDispose(
childDisposes,
event.newValue,
visitFieldValue(inst, field, event.newValue)
visitFieldValue(inst, field, event.newValue, flags)
);
} else if (event.type === "remove") {
fireFieldChange(inst, field.name, {
Expand Down Expand Up @@ -1028,7 +1042,10 @@ export function observeModel(
};

// Finally, we begin by observing the root instance!
const rootDispose = ensure(observeInst(rootInst), "Expected root dispose");
const rootDispose = ensure(
observeInst(rootInst, {}),
"Expected root dispose"
);

firstRun = false;
firstRunData.allGlobalVariants =
Expand Down Expand Up @@ -1167,7 +1184,9 @@ export function observeModel(
addInstChildDispose(
state.fieldValueDisposes,
fieldToUpdate.name,
visitFieldValue(inst, fieldToUpdate, inst[fieldToUpdate.name])
visitFieldValue(inst, fieldToUpdate, inst[fieldToUpdate.name], {
incrementalObserve: true,
})
);
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ export async function updateHostlessPackage(
const result = await syncCodeComponents(
{
change: async (f) => failable((args) => f(args)),
observeComponents: (_) => true,
codeComponentsRegistry: new CodeComponentsRegistry(
globalThis,
getBuiltinComponentRegistrations()
Expand Down
Loading

0 comments on commit 25cefdc

Please sign in to comment.