Skip to content

Commit

Permalink
Merge pull request writer#484 from madeindjs/WF-31
Browse files Browse the repository at this point in the history
fix: handle template in `BuilderFieldsKeyValue`. WF-31
  • Loading branch information
ramedina86 authored Jul 30, 2024
2 parents e3ed971 + 469faea commit 37b25b1
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 94 deletions.
93 changes: 32 additions & 61 deletions src/ui/src/builder/BuilderFieldsKeyValue.vue
Original file line number Diff line number Diff line change
Expand Up @@ -75,42 +75,52 @@

<script setup lang="ts">
import {
PropType,
Ref,
computed,
inject,
nextTick,
onMounted,
Ref,
ref,
toRefs,
inject,
computed,
watch,
} from "vue";
import { Component } from "../writerTypes";
import BuilderFieldsObject from "./BuilderFieldsObject.vue";
import { useComponentActions } from "./useComponentActions";
import injectionKeys from "../injectionKeys";
import { useEvaluator } from "../renderer/useEvaluator";
import type { InstancePath } from "../writerTypes";
import BuilderFieldsObject from "./BuilderFieldsObject.vue";
import BuilderTemplateInput from "./BuilderTemplateInput.vue";
import { useComponentActions } from "./useComponentActions";
const wf = inject(injectionKeys.core);
const ssbm = inject(injectionKeys.builderManager);
const { setContentValue } = useComponentActions(wf, ssbm);
const props = defineProps<{
componentId: Component["id"];
fieldKey: string;
}>();
const props = defineProps({
componentId: { type: String, required: true },
fieldKey: { type: String, required: true },
instancePath: { type: Array as PropType<InstancePath>, required: true },
});
const { componentId, fieldKey } = toRefs(props);
const component = computed(() => wf.getComponentById(componentId.value));
const rootEl: Ref<HTMLElement> = ref(null);
const assistedKeyEl: Ref<HTMLInputElement> = ref(null);
type Mode = "assisted" | "freehand";
const mode: Ref<Mode> = ref(null);
const assistedEntries: Ref<Record<string, string>> = ref({});
const assistedEntries: Ref<Record<string, string | number | null>> = ref({});
const formAdd: Ref<{ key: string; value: string }> = ref({
key: "",
value: "",
});
const { getEvaluatedFields } = useEvaluator(wf);
const evaluatedValue = computed<Record<string, string | number | null>>(
() => getEvaluatedFields(props.instancePath)[fieldKey.value].value,
);
const setMode = async (newMode: Mode) => {
if (mode.value == newMode) return;
mode.value = newMode;
Expand All @@ -123,33 +133,13 @@ const setMode = async (newMode: Mode) => {
};
const handleSwitchToAssisted = () => {
let currentValue = component.value.content[fieldKey.value];
if (!currentValue) return;
let parsedValue: any;
// Attempt to populate assisted from existing JSON data
try {
parsedValue = JSON.parse(currentValue);
if (typeof parsedValue != "object") {
throw "Invalid structure.";
}
assistedEntries.value = parsedValue;
} catch {
component.value.content[fieldKey.value] = JSON.stringify(
assistedEntries.value,
null,
2,
);
}
assistedEntries.value = evaluatedValue.value ?? {};
};
const addAssistedEntry = () => {
const { key, value } = formAdd.value;
if (key === "" || value === "") return;
assistedEntries.value[key] = value;
assistedEntries.value = { ...assistedEntries.value, [key]: value };
setContentValue(
component.value.id,
fieldKey.value,
Expand All @@ -160,7 +150,9 @@ const addAssistedEntry = () => {
};
const removeAssistedEntry = (key: string) => {
delete assistedEntries.value[key];
const assistedEntriesCopy = assistedEntries.value;
delete assistedEntriesCopy[key];
assistedEntries.value = assistedEntriesCopy;
if (Object.keys(assistedEntries.value).length == 0) {
setContentValue(component.value.id, fieldKey.value, undefined);
Expand All @@ -179,39 +171,18 @@ const removeAssistedEntry = (key: string) => {
*/
watch(
() => component.value?.content[fieldKey.value],
async (currentValue) => {
if (!component.value) return;
let parsedValue: any;
try {
parsedValue = JSON.parse(currentValue);
assistedEntries.value = parsedValue;
} catch {
// If parsing fails, preserve the previous assistedEntries value
}
async () => {
if (!component.value || !evaluatedValue.value) return;
assistedEntries.value = evaluatedValue.value;
},
);
onMounted(async () => {
const currentValue = component.value.content[fieldKey.value];
let parsedValue: any;
if (!currentValue) {
setMode("assisted");
return;
}
// Attempt assisted mode first, if the JSON can be parsed into an object
try {
parsedValue = JSON.parse(currentValue);
if (typeof parsedValue != "object") {
throw "Invalid structure.";
}
assistedEntries.value = parsedValue;
if (evaluatedValue.value) {
assistedEntries.value = evaluatedValue.value;
setMode("assisted");
} catch {
// Fall back to freehand if assisted mode isn't possible
} else {
setMode("freehand");
}
});
Expand Down
18 changes: 12 additions & 6 deletions src/ui/src/builder/BuilderSettingsProperties.vue
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
class="content"
:field-key="fieldKey"
:component-id="selectedComponent.id"
:instance-path="selectedInstancePath"
></BuilderFieldsKeyValue>

<BuilderFieldsText
Expand Down Expand Up @@ -118,20 +119,25 @@

<script setup lang="ts">
import { computed, inject } from "vue";
import BuilderFieldsKeyValue from "./BuilderFieldsKeyValue.vue";
import { FieldType, FieldCategory } from "../writerTypes";
import injectionKeys from "../injectionKeys";
import { parseInstancePathString } from "../renderer/instancePath";
import { FieldCategory, FieldType, InstancePath } from "../writerTypes";
import BuilderFieldsAlign from "./BuilderFieldsAlign.vue";
import BuilderFieldsColor from "./BuilderFieldsColor.vue";
import BuilderFieldsKeyValue from "./BuilderFieldsKeyValue.vue";
import BuilderFieldsObject from "./BuilderFieldsObject.vue";
import BuilderFieldsPadding from "./BuilderFieldsPadding.vue";
import BuilderFieldsShadow from "./BuilderFieldsShadow.vue";
import BuilderFieldsText from "./BuilderFieldsText.vue";
import BuilderFieldsObject from "./BuilderFieldsObject.vue";
import BuilderFieldsWidth from "./BuilderFieldsWidth.vue";
import BuilderFieldsAlign from "./BuilderFieldsAlign.vue";
import BuilderFieldsPadding from "./BuilderFieldsPadding.vue";
import injectionKeys from "../injectionKeys";
const wf = inject(injectionKeys.core);
const ssbm = inject(injectionKeys.builderManager);
const selectedInstancePath = computed<InstancePath>(() =>
parseInstancePathString(ssbm.getSelection()?.instancePath),
);
const selectedComponent = computed(() => {
return wf.getComponentById(ssbm.getSelectedId());
});
Expand Down
39 changes: 26 additions & 13 deletions src/ui/src/builder/BuilderTemplateInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
ref="input"
v-capture-tabs
class="templateInput"
:variant="props.vatiant"
:variant="props.variant"
:value="props.value"
autocorrect="off"
autocomplete="off"
Expand All @@ -60,23 +60,36 @@
</template>

<script setup lang="ts">
import { inject, ref, nextTick } from "vue";
import injectionKeys from "../injectionKeys";
import Fuse from "fuse.js";
import { PropType, inject, nextTick, ref } from "vue";
import injectionKeys from "../injectionKeys";
const emit = defineEmits(["input", "update:value"]);
const props = defineProps<{
inputId?: string;
value?: string;
multiline?: boolean;
variant?: "code" | "text";
type?: "state" | "template";
options?: Record<string, string>;
placeholder?: string;
}>();
const props = defineProps({
inputId: { type: String, required: false, default: undefined },
value: { type: String, required: false, default: undefined },
multiline: { type: Boolean, required: false },
variant: {
type: String as PropType<"code" | "text">,
required: false,
default: undefined,
},
type: {
type: String as PropType<"state" | "template">,
required: false,
default: undefined,
},
options: {
type: Object as PropType<Record<string, string>>,
required: false,
default: undefined,
},
placeholder: { type: String, required: false, default: undefined },
});
const ss = inject(injectionKeys.core);
const autocompleteOptions = ref<string[]>([]);
const autocompleteOptions = ref<{ text: string; type: string }[]>([]);
const input = ref<HTMLInputElement | null>(null);
defineExpose({
Expand Down
37 changes: 23 additions & 14 deletions src/ui/src/renderer/ComponentProxy.vue
Original file line number Diff line number Diff line change
@@ -1,28 +1,42 @@
<script lang="ts">
import { Ref, computed, h, inject, provide, ref, watch } from "vue";
import {
PropType,
Ref,
VNode,
computed,
h,
inject,
provide,
ref,
watch,
} from "vue";
import { getTemplate } from "../core/templateMap";
import injectionKeys from "../injectionKeys";
import {
Component,
InstancePath,
InstancePathItem,
UserFunction,
} from "../writerTypes";
import ComponentProxy from "./ComponentProxy.vue";
import { useEvaluator } from "./useEvaluator";
import injectionKeys from "../injectionKeys";
import { VNode } from "vue";
import ChildlessPlaceholder from "./ChildlessPlaceholder.vue";
import ComponentProxy from "./ComponentProxy.vue";
import RenderError from "./RenderError.vue";
import { flattenInstancePath } from "./instancePath";
import { useEvaluator } from "./useEvaluator";
export default {
props: ["componentId", "instancePath", "instanceData"],
props: {
componentId: { type: String, required: true },
instancePath: { type: Array as PropType<InstancePath>, required: true },
instanceData: { validator: () => true, required: true },
},
setup(props) {
const wf = inject(injectionKeys.core);
const ssbm = inject(injectionKeys.builderManager);
const componentId: Component["id"] = props.componentId;
const componentId = props.componentId;
const component = computed(() => wf.getComponentById(componentId));
const template = getTemplate(component.value.type);
const instancePath: InstancePath = props.instancePath;
const instancePath = props.instancePath;
const instanceData = props.instanceData;
const { getEvaluatedFields, isComponentVisible } = useEvaluator(wf);
const evaluatedFields = getEvaluatedFields(instancePath);
Expand Down Expand Up @@ -141,19 +155,14 @@ export default {
];
};
const flattenInstancePath = (path: InstancePath) => {
return path
.map((ie) => `${ie.componentId}:${ie.instanceNumber}`)
.join(",");
};
const flattenedInstancePath = flattenInstancePath(instancePath);
provide(injectionKeys.evaluatedFields, evaluatedFields);
provide(injectionKeys.componentId, componentId);
provide(injectionKeys.isBeingEdited, isBeingEdited);
provide(injectionKeys.isDisabled, isDisabled);
provide(injectionKeys.instancePath, instancePath);
provide(injectionKeys.instanceData, instanceData);
provide(injectionKeys.instanceData, instanceData as any);
provide(injectionKeys.renderProxiedComponent, renderProxiedComponent);
provide(injectionKeys.getChildrenVNodes, getChildrenVNodes);
provide(injectionKeys.flattenedInstancePath, flattenedInstancePath);
Expand Down
13 changes: 13 additions & 0 deletions src/ui/src/renderer/instancePath.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { InstancePath } from "../writerTypes";

export function flattenInstancePath(path: InstancePath) {
return path.map((ie) => `${ie.componentId}:${ie.instanceNumber}`).join(",");
}

export function parseInstancePathString(raw?: string): InstancePath {
if (!raw) return [];
return raw.split(",").map((record) => {
const [componentId, instanceNumber] = record.split(":");
return { componentId, instanceNumber: Number(instanceNumber) };
});
}

0 comments on commit 37b25b1

Please sign in to comment.