Skip to content

Commit

Permalink
Merge pull request #8 from RTIInternational/routing-enhancements
Browse files Browse the repository at this point in the history
Routing enhancements
  • Loading branch information
hardingalexh authored Jan 23, 2024
2 parents 553067f + 29bb71b commit c5079f0
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 47 deletions.
3 changes: 2 additions & 1 deletion docs/introduction/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,13 @@ app.use(harnessPlugin, { pinia, pages, router })
app.use(router);
app.mount("#app");
```

## Automagic Page Stores
One of the goals of Harness-Vue is the ability to write components that are widely reusable across pages, charts and filters - having an API of helper functions that provide contextualized actions on each page is a convenience feature that allows for more robust and reusable components. In order to assist in that process, Harness-Vue exports a global mixin for the options API and a composable for the composition API that detect what page your component is currently referring to using the following logic:

* first by checking if the route name (if vue-router is used) matches the name of an installed page definition
* second by checking if there is only one page and no vue-router installed and using that by default
* third by checking for a `harness-waypoint` prop that matches a page definition key
* third by checking for a provided `waypoint` rop that matches a page definition key


### Options API mixin
Expand Down
24 changes: 21 additions & 3 deletions docs/introduction/page-definitions.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Page definitions
# Page Definitions

The core unit of the Harness-Vue plugin is the page definition. The page definition is an expected format for developers to provide to the plugin to be translated into Harness Vue pinia stores.

Expand Down Expand Up @@ -146,10 +146,28 @@ export default class ExamplePage {
}
}
```
### Before and After loadData
Similar to the `beforeSet` and `afterSet` functionality in the charts and filters, page definitions can include `beforeLoadData` and `afterLoadData` functions to be run before and after `loadData`, respectively.

## Routing
If a router was provided, a [named route](https://router.vuejs.org/guide/essentials/named-routes.html) will be created for your page definition. This route will be defined using defaults, all of which can be overridden by providing your page definition with select attributes.

## Other
Similar to the `beforeSet` and `afterSet` functionality in the charts and filters, page definitions can include `beforeLoadData` and `afterLoadData` functions to be run before and after `loadData`, respectively.
* The `path` of the route will default to the page key, but can be overridden by providing a `routePath` attribute. Note that this will have a prepended slash automatically.
* The `name` of the route will default to the page key, but can be overridden by providing a `routeName` attribute.
* The route will be provided with a [navigation guard](https://router.vuejs.org/guide/advanced/navigation-guards.html#Per-Route-Guard) using the `beforeEnter` syntax. By default, this will run `clearData()` on route exit and `loadData()` on route enter. This can be overridden by providing your own `routeBeforeEnter(to, from, next, store)` function, which takes the `to`/`from`/`next` arguments from `beforeEnter` and additionally provides the page store.

```javascript
export default class ExamplePage {
// ... //
routePath = 'dashboards/examplePage'
routeName = 'Example Page'
routeBeforeEnter(to, from, next, store){
console.log(`Came from ${from.name}`)
store.initializeDefaults()
store.loadData()
}
}
```

## Full Example

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@rtidatascience/harness-vue",
"author": "RTI CDS <[email protected]>",
"private": false,
"version": "1.6.0",
"version": "1.7.0-0",
"type": "module",
"repository": {
"type": "git",
Expand Down
50 changes: 25 additions & 25 deletions src/composable/composable.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,38 @@
// https://stackoverflow.com/questions/72209080/vue-3-is-getcurrentinstance-deprecated
import { getCurrentInstance } from "vue";
import { useHarnessStore } from "../harness.js";

export default function useHarnessComposable() {
/**
* Returns the current harness page store
* If a waypoint is provided, that store is returned
* If the route is provided and the route name matches a harness store key, that store is returned
* If there is no router and only a single harness page exists, that store is returned
* @param {any} waypoint=false a string matching a harness page store key
* @returns {Object} a pinia store representing a harness page
*/
export default function useHarnessComposable(waypoint = false) {
const harnessMetadata = useHarnessStore();
const vueInstance = getCurrentInstance();
if (waypoint === false) {
let currentRoute =
harnessMetadata.optionsProvided?.router?.currentRoute?.name;

let waypoint = false;
// check for a vue-router route
if (currentRoute && harnessMetadata.getPages.includes(currentRoute)) {
waypoint = currentRoute;
}

// check for a vue-router route
if (
vueInstance.appContext.config.globalProperties.$route?.name &&
harnessMetadata.getPages.includes(
vueInstance.appContext.config.globalProperties.$route.name,
)
) {
waypoint = vueInstance.appContext.config.globalProperties.$route.name;
// if router is not installed and only a single harness page exists, use it as waypoint
if (harnessMetadata.getPages.length === 1 && !currentRoute) {
waypoint = harnessMetadata.pages[0];
}
}

// if router is not installed and only a single harness page exists, use it as waypoint
if (
(harnessMetadata.getPages.length === 1) &
!vueInstance.appContext.config.globalProperties.$route
waypoint &&
Object.keys(harnessMetadata.getPageStores).includes(waypoint)
) {
waypoint = harnessMetadata.pages[0];
}

// // if a waypoint override was specified, use that
if (vueInstance.attrs["harness-waypoint"]) {
waypoint = vueInstance.attrs["harness-waypoint"];
}

if (waypoint) {
return harnessMetadata.getPageStores[waypoint]();
}
return waypoint;
console.error(
`The detected waypoint ${waypoint} is not a valid harness page.`,
);
}
2 changes: 1 addition & 1 deletion src/harness.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const harnessPlugin = {
install: (app, options) => {
// create harness metadata store in pinia
const harness = useHarnessStore(options.pinia);

harness.optionsProvided = options;
// validate page files
const validatedPages = pages(options.pages);

Expand Down
28 changes: 15 additions & 13 deletions src/router/route.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
export default function createHarnessRoute(store, pageDefinition) {
return {
path: "/" + pageDefinition.key,
name: pageDefinition.key,
path: `/${pageDefinition?.routePath || pageDefinition.key}`,
name: pageDefinition?.routeName || pageDefinition.key,
component: pageDefinition.pageComponent,
props: pageDefinition.pageProps ? pageDefinition.pageProps : false,
beforeEnter: pageDefinition.loadData
? (to, from, next) => {
if (from.name) {
store.clearData();
}
if (to.name) {
store.loadData();
}
next();
props: pageDefinition?.pageProps,
beforeEnter: (to, from, next) => {
if (pageDefinition?.routeBeforeEnter) {
pageDefinition.routeBeforeEnter(to, from, next, store);
} else {
if (from.name) {
store.clearData();
}
: null,
if (to.name) {
store.loadData();
}
next();
}
},
};
}
10 changes: 9 additions & 1 deletion src/store/harnessStore.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { defineStore } from "pinia";

export default defineStore("harnessVue", {
state: () => ({ pages: [], pageDefinitions: {}, pageStores: {} }),
state: () => ({
pages: [],
pageDefinitions: {},
pageStores: {},
optionsProvided: {},
}),
getters: {
getPages() {
return this.pages;
Expand All @@ -12,6 +17,9 @@ export default defineStore("harnessVue", {
getPageStores() {
return this.pageStores;
},
getOptionsProvided() {
return this.optionsProvided;
},
},
actions: {
addStore(key, definition, store) {
Expand Down

0 comments on commit c5079f0

Please sign in to comment.