Skip to content

Commit

Permalink
feat: pick up the URL variables at the start of the app
Browse files Browse the repository at this point in the history
  • Loading branch information
FabienArcellier committed Sep 24, 2024
1 parent bd9db0c commit 49c9cee
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 11 deletions.
38 changes: 29 additions & 9 deletions src/ui/src/components/core/root/CoreRoot.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,14 @@ import { useEvaluator } from "@/renderer/useEvaluator";
const ssHashChangeStub = `
def handle_hashchange(state, payload):
# The payload is a dictionary with the page key and all the route variables in the URL hash.
# For example, if the current URL is
# http://localhost:3000/#main/animal=duck&colour=yellow
# For example, if the current URL is http://localhost:3000/#main/animal=duck&colour=yellow
# you will get the following dictionary
# {
# "page_key": "main",
# "route_vars": {
# "animal": "duck",
# "colour": "yellow"
# }
# "page_key": "main",
# "route_vars": {
# "animal": "duck",
# "colour": "yellow"
# }
# }
page_key = payload.get("page_key")
Expand All @@ -39,6 +38,23 @@ def handle_hashchange(state, payload):
else:
state["message"] = "You're not in the Duck zone.`.trim();
const wfAppOpenStub = `
def handle_app_open(state):
# The payload is a dictionary with the page key and all the route variables in the URL hash.
# For example, if the current URL is http://localhost:3000/#/animal=duck&colour=yellow
# you will get the following dictionary
# {
# "page_key": "main",
# "route_vars": {
# "animal": "duck",
# "colour": "yellow"
# }
# }
page_key = payload.get("page_key")
route_vars = payload.get("route_vars")
`.trim();
const description =
"The root component of the application, which serves as the starting point of the component hierarchy.";
Expand All @@ -57,6 +73,10 @@ export default {
...sharedStyleFields,
},
events: {
"wf-app-open": {
desc: "Captures the first application load, including page key and route vars.",
stub: wfAppOpenStub,
},
"wf-hashchange": {
desc: "Capture changes to the URL hash, including page key and route vars.",
stub: ssHashChangeStub,
Expand All @@ -76,7 +96,7 @@ import {
onBeforeMount,
} from "vue";
import injectionKeys from "@/injectionKeys";
import { changePageInHash, getParsedHash } from "@/core/navigation";
import { changePageInHash, serializeParsedHash } from "@/core/navigation";
const wf = inject(injectionKeys.core);
const ssbm = inject(injectionKeys.builderManager);
Expand All @@ -100,7 +120,7 @@ const displayedPageId = computed(() => {
});
function handleHashChange() {
const parsedHash = getParsedHash();
const parsedHash = serializeParsedHash();
const event = new CustomEvent("wf-hashchange", {
detail: {
payload: parsedHash,
Expand Down
31 changes: 31 additions & 0 deletions src/ui/src/core/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,23 @@ type ParsedHash = {
routeVars: Map<string, string>; // Stored as Map to avoid injection e.g. prototype pollution
};

// Use to communicate with the backend
type SerializedHash = {
pageKey?: string;
routeVars: Record<string, string>;
};

const hashRegex = /^((?<pageKey>[^/]*))?(\/(?<routeVars>.*))?$/;
const routeVarRegex = /^(?<key>[^=]+)=(?<value>.*)$/;

/**
* Parses the current URL hash
*
* * http://x.x.x.x:5000/#main/var1=value1&var2=value2
*
* pageKey: "main"
* routeVars: { var1: "value1", var2: "value2" }
*/
export function getParsedHash(): ParsedHash {
const docHash = document.location.hash.substring(1);
const hashMatchGroups = docHash.match(hashRegex)?.groups;
Expand All @@ -29,6 +43,23 @@ export function getParsedHash(): ParsedHash {
return { pageKey, routeVars };
}

/**
* Serializes the URL information into a JSON.stringify-compatible object.
*
* It's used to send the current URL information to the server.
*
* @example
* ```ts
* const serializedHash = serializeParsedHash();
* const urlinfoString = JSON.stringify(serializedHash);
* ```
*/
export function serializeParsedHash(): SerializedHash {
const parsedHash = getParsedHash();
const routeVars = Object.fromEntries(parsedHash.routeVars.entries());
return { pageKey: parsedHash.pageKey, routeVars };
}

function setHash(parsedHash: ParsedHash) {
const { pageKey, routeVars } = parsedHash;

Expand Down
32 changes: 30 additions & 2 deletions src/ui/src/renderer/ComponentRenderer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,25 @@
</template>

<script setup lang="ts">
import { inject, ref, computed, watch, ComputedRef, onBeforeMount } from "vue";
import {
inject,
ref,
computed,
watch,
ComputedRef,
onBeforeMount,
onMounted,
} from "vue";
import { Component } from "@/writerTypes";
import ComponentProxy from "./ComponentProxy.vue";
import RendererNotifications from "./RendererNotifications.vue";
import injectionKeys from "@/injectionKeys";
import { useEvaluator } from "./useEvaluator";
import { changePageInHash, changeRouteVarsInHash } from "@/core/navigation";
import {
changePageInHash,
changeRouteVarsInHash,
serializeParsedHash,
} from "@/core/navigation";
const wf = inject(injectionKeys.core);
const wfbm = inject(injectionKeys.builderManager);
Expand Down Expand Up @@ -203,9 +215,25 @@ function addMailSubscriptions() {
);
}
function handleAppOpenChange() {
const parsedHash = serializeParsedHash();
const event = new CustomEvent("wf-app-open", {
detail: {
payload: parsedHash,
},
});
const rootInstance = { componentId: "root", instanceNumber: 0 };
wf.forwardEvent(event, [rootInstance], true);
}
onBeforeMount(() => {
addMailSubscriptions();
});
onMounted(() => {
handleAppOpenChange();
});
</script>

<style scoped>
Expand Down
10 changes: 10 additions & 0 deletions src/writer/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1306,6 +1306,16 @@ def _transform_page_open(self, ev) -> str:
payload = str(ev.payload)
return payload

def _transform_app_open(self, ev) -> dict:
payload = ev.payload
page_key = payload.get("pageKey")
route_vars = dict(payload.get("routeVars"))
tf_payload = {
"page_key": page_key,
"route_vars": route_vars
}
return tf_payload

def _transform_chatbot_message(self, ev) -> dict:
payload = dict(ev.payload)
return payload
Expand Down

0 comments on commit 49c9cee

Please sign in to comment.