druxt-views 0.17.2 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,16 +7,40 @@ import { parse, stringify } from 'qs'
7
7
  import { mapActions } from 'vuex'
8
8
 
9
9
  /**
10
- * Renders a Drupal View using DruxtEntity components, using data provided by
11
- * the Drupal JSON:API Views module.
10
+ * The DruxtView component renders Drupal Views using configuration and
11
+ * results provided by the Drupal View and the JSON:API Views module.
12
12
  *
13
- * Supports filtering, pagination and sorting.
13
+ * The component renders slots for the View's headers, footers, entity results,
14
+ * exposed sorts and filters, and supports contextual filters.
14
15
  *
15
- * @example
16
+ * @example @lang vue
17
+ * <DruxtView display-id="block_1" view-id="promoted_items" />
18
+ *
19
+ * @example <caption>View with contextual filter</caption> @lang vue
16
20
  * <DruxtView
21
+ * :arguments="[entity.attributes.drupal_internal__nid]"
17
22
  * display-id="block_1"
18
- * view-id="promoted_items"
23
+ * view-id="articles_aside"
19
24
  * />
25
+ *
26
+ * @example <caption>DruxtView Wrapper component boilerplate</caption> @lang vue
27
+ * <template>
28
+ * <DruxtDebug :json="results" />
29
+ * </template>
30
+ *
31
+ * <script>
32
+ * import { DruxtViewsViewMixin } from 'druxt-views'
33
+ * export default {
34
+ * mixins: [DruxtViewsViewMixin]
35
+ * }
36
+ *
37
+ * @example <caption>DruxtView with template injection</caption> @lang vue
38
+ * <DruxtView>
39
+ * <template #default="{ results }">
40
+ * <!-- Do whatever you want here -->
41
+ * <DruxtDebug :json="results" />
42
+ * </template>
43
+ * </DruxtView>
20
44
  */
21
45
  export default {
22
46
  name: 'DruxtView',
@@ -475,6 +499,17 @@ export default {
475
499
  // Build scoped slots.
476
500
  const scopedSlots = {}
477
501
 
502
+ // Ensure an ID or UUID.
503
+ if (!this.viewId && !this.uuid) {
504
+ return {
505
+ default: () => h(
506
+ 'DruxtDebug',
507
+ { props: { summary: "Missing required 'uuid' or 'viewId' prop.", }},
508
+ [h('p', "The DruxtView component requires either the 'uuid' or 'viewId' prop to be set.")]
509
+ )
510
+ }
511
+ }
512
+
478
513
  // Headers.
479
514
  scopedSlots.header = () => Object.entries(this.headers).map(([key, header]) => h('span', {
480
515
  domProps: { innerHTML: (header.content || {}).value }, key
@@ -10,32 +10,40 @@ async function DruxtViewsStorybook({ stories }) {
10
10
  const druxt = new DruxtClient(options.druxt.baseUrl, { ...options.druxt, proxy: { api: false } });
11
11
  const resourceType = "view--view";
12
12
  const query = new DrupalJsonApiParams().addFilter("status", 1).addFields(resourceType, ["display", "description", "drupal_internal__id", "label"]);
13
- const collections = await druxt.getCollectionAll(resourceType, query);
13
+ const collections = (await druxt.getCollectionAll(resourceType, query)).map((collection) => collection.data).flat();
14
14
  const views = {};
15
- for (const collection of collections) {
16
- for (const view of collection.data) {
17
- const { description, display, drupal_internal__id, label } = view.attributes;
18
- const displays = Object.values(display).filter((item) => {
19
- const options2 = item.id === "default" ? item : merge(display.default, item);
20
- const extenders = options2.display_options.display_extenders;
21
- if (!Array.isArray(extenders) && !(extenders.jsonapi_views || {}).enabled) {
22
- return false;
23
- }
24
- return options2.display_options.row.type.startsWith("entity:");
25
- });
26
- if (displays.length) {
27
- views[drupal_internal__id] = { description, displays, uuid: view.id, label };
28
- }
15
+ for (const view of collections) {
16
+ const { description, display, drupal_internal__id, label } = view.attributes;
17
+ const displays = Object.values(display).filter((item) => {
18
+ const options2 = item.id === "default" ? item : merge(display.default, item);
19
+ const extenders = options2.display_options.display_extenders;
20
+ const enabled = !(!Array.isArray(extenders) && !(extenders.jsonapi_views || {}).enabled);
21
+ return enabled ? options2.display_options.row.type.startsWith("entity:") : false;
22
+ });
23
+ if (displays.length) {
24
+ views[drupal_internal__id] = {
25
+ description,
26
+ displays,
27
+ uuid: view.id,
28
+ viewId: drupal_internal__id,
29
+ label
30
+ };
29
31
  }
30
32
  }
33
+ addTemplate({
34
+ src: resolve(__dirname, `../templates/druxt-views.stories.js`),
35
+ fileName: `stories/druxt-views.stories.js`,
36
+ options: { views }
37
+ });
38
+ stories.push(resolve(options.buildDir, "./stories/druxt-views.stories.js"));
31
39
  for (const viewId of Object.keys(views)) {
32
40
  const { description, displays, label, uuid } = views[viewId];
33
41
  displays.sort((a) => a.id === "default" ? -1 : 0);
34
42
  const title = ["Druxt", "Views", label].join("/");
35
43
  addTemplate({
36
- src: resolve(__dirname, "../templates/druxt-views.stories.js"),
44
+ src: resolve(__dirname, "../templates/druxt-views.instance.stories.js"),
37
45
  fileName: `stories/druxt-views.${viewId}.stories.js`,
38
- options: { description, displays, title, uuid, viewId }
46
+ options: { description, displays, label, title, uuid, viewId }
39
47
  });
40
48
  }
41
49
  stories.push(resolve(options.buildDir, "./stories/druxt-views.*.stories.js"));
@@ -67,7 +75,6 @@ const DruxtViewsNuxtModule = function(moduleOptions = {}) {
67
75
  });
68
76
  options.store = true;
69
77
  this.nuxt.hook("storybook:config", async ({ stories }) => {
70
- stories.push("druxt-views/dist/components/*.stories.mjs");
71
78
  await DruxtViewsStorybook.call(this, { stories });
72
79
  });
73
80
  };
@@ -19,32 +19,40 @@ async function DruxtViewsStorybook({ stories }) {
19
19
  const druxt$1 = new druxt.DruxtClient(options.druxt.baseUrl, { ...options.druxt, proxy: { api: false } });
20
20
  const resourceType = "view--view";
21
21
  const query = new drupalJsonapiParams.DrupalJsonApiParams().addFilter("status", 1).addFields(resourceType, ["display", "description", "drupal_internal__id", "label"]);
22
- const collections = await druxt$1.getCollectionAll(resourceType, query);
22
+ const collections = (await druxt$1.getCollectionAll(resourceType, query)).map((collection) => collection.data).flat();
23
23
  const views = {};
24
- for (const collection of collections) {
25
- for (const view of collection.data) {
26
- const { description, display, drupal_internal__id, label } = view.attributes;
27
- const displays = Object.values(display).filter((item) => {
28
- const options2 = item.id === "default" ? item : merge__default['default'](display.default, item);
29
- const extenders = options2.display_options.display_extenders;
30
- if (!Array.isArray(extenders) && !(extenders.jsonapi_views || {}).enabled) {
31
- return false;
32
- }
33
- return options2.display_options.row.type.startsWith("entity:");
34
- });
35
- if (displays.length) {
36
- views[drupal_internal__id] = { description, displays, uuid: view.id, label };
37
- }
24
+ for (const view of collections) {
25
+ const { description, display, drupal_internal__id, label } = view.attributes;
26
+ const displays = Object.values(display).filter((item) => {
27
+ const options2 = item.id === "default" ? item : merge__default['default'](display.default, item);
28
+ const extenders = options2.display_options.display_extenders;
29
+ const enabled = !(!Array.isArray(extenders) && !(extenders.jsonapi_views || {}).enabled);
30
+ return enabled ? options2.display_options.row.type.startsWith("entity:") : false;
31
+ });
32
+ if (displays.length) {
33
+ views[drupal_internal__id] = {
34
+ description,
35
+ displays,
36
+ uuid: view.id,
37
+ viewId: drupal_internal__id,
38
+ label
39
+ };
38
40
  }
39
41
  }
42
+ addTemplate({
43
+ src: path.resolve(__dirname, `../templates/druxt-views.stories.js`),
44
+ fileName: `stories/druxt-views.stories.js`,
45
+ options: { views }
46
+ });
47
+ stories.push(path.resolve(options.buildDir, "./stories/druxt-views.stories.js"));
40
48
  for (const viewId of Object.keys(views)) {
41
49
  const { description, displays, label, uuid } = views[viewId];
42
50
  displays.sort((a) => a.id === "default" ? -1 : 0);
43
51
  const title = ["Druxt", "Views", label].join("/");
44
52
  addTemplate({
45
- src: path.resolve(__dirname, "../templates/druxt-views.stories.js"),
53
+ src: path.resolve(__dirname, "../templates/druxt-views.instance.stories.js"),
46
54
  fileName: `stories/druxt-views.${viewId}.stories.js`,
47
- options: { description, displays, title, uuid, viewId }
55
+ options: { description, displays, label, title, uuid, viewId }
48
56
  });
49
57
  }
50
58
  stories.push(path.resolve(options.buildDir, "./stories/druxt-views.*.stories.js"));
@@ -76,7 +84,6 @@ const DruxtViewsNuxtModule = function(moduleOptions = {}) {
76
84
  });
77
85
  options.store = true;
78
86
  this.nuxt.hook("storybook:config", async ({ stories }) => {
79
- stories.push("druxt-views/dist/components/*.stories.mjs");
80
87
  await DruxtViewsStorybook.call(this, { stories });
81
88
  });
82
89
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "druxt-views",
3
- "version": "0.17.2",
3
+ "version": "0.18.0",
4
4
  "description": "Drupal Views components for Druxt with support for filters, pagination and sorting.",
5
5
  "keywords": [
6
6
  "cms",
@@ -44,10 +44,10 @@
44
44
  "axios": "^0.21.1",
45
45
  "deepmerge": "^4.2.2",
46
46
  "drupal-jsonapi-params": "^1.1.12",
47
- "druxt": "^0.16.0",
48
- "druxt-blocks": "^0.14.5",
49
- "druxt-entity": "^0.23.0",
50
- "druxt-router": "^0.25.0",
47
+ "druxt": "^0.17.0",
48
+ "druxt-blocks": "^0.15.0",
49
+ "druxt-entity": "^0.24.0",
50
+ "druxt-router": "^0.26.0",
51
51
  "md5": "^2.3.0"
52
52
  },
53
53
  "optionalDependencies": {
@@ -0,0 +1,45 @@
1
+ import DruxtView from 'druxt-views/dist/components/DruxtView.vue'
2
+
3
+ export default {
4
+ title: <%= devalue(options.title) %>,
5
+ component: DruxtView,
6
+ argTypes: {
7
+ displayId: {
8
+ options: [<%= options.displays.map(({ id }) => `'${id}'`).join(', ') %>],
9
+ control: {
10
+ type: 'select',
11
+ },
12
+ },
13
+ type: { table: { disable: true }},
14
+ viewId: { table: { disable: true }},
15
+ uuid: { table: { disable: true }},
16
+ },
17
+ parameters: {
18
+ docs: {
19
+ description: {
20
+ component: <%= options.description ? devalue(options.description) : `"Renders the **${options.label}** view."` %> + '\n\n```jsx\n\n<DruxtView view-id="<%= options.viewId %>" />\n```'
21
+ }
22
+ }
23
+ }
24
+ }
25
+
26
+ const Template = (args, { argTypes }) => ({
27
+ props: Object.keys(args),
28
+ template: '<DruxtView v-bind="$props" v-on="$props" />',
29
+ })
30
+
31
+ <% for (display of options.displays) { %>
32
+ export const <%= display.id.charAt(0).toUpperCase() + display.id.slice(1) %> = Template.bind({})
33
+ <%= display.id.charAt(0).toUpperCase() + display.id.slice(1) %>.args = {
34
+ displayId: '<%= display.id %>',
35
+ viewId: '<%= options.viewId %>',
36
+ }
37
+ <%= display.id.charAt(0).toUpperCase() + display.id.slice(1) %>.storyName = '<%= display.display_title %>'
38
+ <%= display.id.charAt(0).toUpperCase() + display.id.slice(1) %>.parameters = {
39
+ docs: {
40
+ source: {
41
+ code: '<DruxtView display-id="<%= display.id %>" view-id="<%= options.viewId %>" />'
42
+ }
43
+ }
44
+ }
45
+ <% } %>
@@ -1,42 +1,82 @@
1
1
  import DruxtView from 'druxt-views/dist/components/DruxtView.vue'
2
2
 
3
3
  export default {
4
- title: <%= devalue(options.title) %>,
4
+ title: 'Druxt/Views/DruxtView',
5
5
  component: DruxtView,
6
6
  argTypes: {
7
- displayId: {
7
+ uuid: {
8
+ options: [<%= (Object.values(options.views) || []).map((o) => `'${o.uuid}'`).join(', ') %>],
8
9
  control: {
9
10
  type: 'select',
10
- options: [<%= options.displays.map(({ id }) => `'${id}'`).join(', ') %>]
11
+ labels: Object.fromEntries([<%= (Object.values(options.views) || []).map((o) => `['${o.uuid}', "${o.label} (${o.uuid})"]`).join(', ') %>])
11
12
  },
12
13
  },
13
- },
14
- parameters: {
15
- docs: {
16
- description: {
17
- component: <%= options.description ? devalue(options.description) : '" "' %>
18
- }
14
+ viewId: {
15
+ options: [<%= (Object.keys(options.views) || []).map((s) => `'${s}'`).join(', ') %>],
16
+ control: {
17
+ type: 'select',
18
+ labels: Object.fromEntries([<%= (Object.values(options.views) || []).map((o) => `['${o.viewId}', "${o.label} (${o.viewId})"]`).join(', ') %>])
19
+ },
19
20
  }
20
21
  }
21
22
  }
22
23
 
23
24
  const Template = (args, { argTypes }) => ({
24
- props: Object.keys(args),
25
- template: '<DruxtView v-bind="$props" v-on="$props" />',
25
+ components: { DruxtView },
26
+ props: Object.keys(argTypes),
27
+ template: `<DruxtView v-bind="$props" />`
26
28
  })
27
29
 
28
- <% for (display of options.displays) { %>
29
- export const <%= display.id.charAt(0).toUpperCase() + display.id.slice(1) %> = Template.bind({})
30
- <%= display.id.charAt(0).toUpperCase() + display.id.slice(1) %>.args = {
31
- displayId: '<%= display.id %>',
32
- viewId: '<%= options.viewId %>',
30
+ export const Default = Template.bind({})
31
+ Default.storyName = 'DruxtView'
32
+
33
+ let code
34
+
35
+ // Wrapper story.
36
+ code = `<template>
37
+ <DruxtDebug :json="results" />
38
+ </template>
39
+
40
+ <script>
41
+ import { DruxtViewsViewMixin } from 'druxt-views'
42
+ export default {
43
+ mixins: [DruxtViewsViewMixin]
33
44
  }
34
- <%= display.id.charAt(0).toUpperCase() + display.id.slice(1) %>.storyName = '<%= display.display_title %>'
35
- <%= display.id.charAt(0).toUpperCase() + display.id.slice(1) %>.parameters = {
45
+ </script>`
46
+ export const Wrapper = (args, { argTypes }) => ({
47
+ components: { DruxtView },
48
+ props: Object.keys(argTypes),
49
+ template: `<DruxtView v-bind="$props" ref="module">
50
+ <template #default>
51
+ Component options:
52
+ <ul>
53
+ <li v-for="option of $refs.module.getModuleComponents()" :key="option.name">{{ option.name }}</li>
54
+ </ul>
55
+ </template>
56
+ </DruxtView>`
57
+ })
58
+ Wrapper.parameters = {
36
59
  docs: {
37
- source: {
38
- code: '<DruxtView display-id="<%= display.id %>" view-id="<%= options.viewId %>" />'
39
- }
60
+ storyDescription: 'The DruxtView component can be themed by using a Druxt Wrapper component.\n\nCreate an appropriately named component, using the relevant component option, with the following boilerplate:\n\n```jsx\n' + code + '\n```',
61
+ source: { code }
62
+ }
63
+ }
64
+
65
+ // Template injection story.
66
+ code = `<DruxtView viewId="">
67
+ <template #default="{ results }">
68
+ <!-- Do whatever you want here -->
69
+ <DruxtDebug :json="results" open />
70
+ </template>
71
+ </DruxtView>`
72
+ export const TemplateInjection = (args, { argTypes }) => ({
73
+ components: { DruxtView },
74
+ props: Object.keys(argTypes),
75
+ template: code.replace('viewId=""', 'v-bind="$props"')
76
+ })
77
+ TemplateInjection.parameters = {
78
+ docs: {
79
+ storyDescription: 'The DruxtView component can be themed by injecting the default template into the compomnent.\n\n```jsx\n' + code + '\n```',
80
+ source: { code }
40
81
  }
41
82
  }
42
- <% } %>
@@ -1,15 +0,0 @@
1
- import DruxtView from './DruxtView.vue'
2
-
3
- export default {
4
- title: 'Druxt/Views/DruxtView',
5
- component: DruxtView
6
- }
7
-
8
- const Template = (args, { argTypes }) => ({
9
- components: { DruxtView },
10
- props: Object.keys(argTypes),
11
- template: `<DruxtView v-bind="$props" />`
12
- })
13
-
14
- export const Default = Template.bind({})
15
- Default.storyName = 'DruxtView'