druxt-views 0.17.2 → 0.18.2

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',
@@ -389,7 +413,11 @@ export default {
389
413
  * @param {object} context - The module component ViewModel.
390
414
  * @returns {ComponentOptions}
391
415
  */
392
- componentOptions: ({ displayId, uuid, viewId }) => ([[viewId || uuid, displayId]]),
416
+ componentOptions: ({ displayId, uuid, view, viewId }) => ([
417
+ [viewId || ((view.data || {}).attributes || {}).drupal_internal__id, displayId],
418
+ [uuid || (view.data || {}).id, displayId],
419
+ [displayId]
420
+ ]),
393
421
 
394
422
  /**
395
423
  * Fetch View configuration resource.
@@ -475,6 +503,17 @@ export default {
475
503
  // Build scoped slots.
476
504
  const scopedSlots = {}
477
505
 
506
+ // Ensure an ID or UUID.
507
+ if (!this.viewId && !this.uuid) {
508
+ return {
509
+ default: () => h(
510
+ 'DruxtDebug',
511
+ { props: { summary: "Missing required 'uuid' or 'viewId' prop.", }},
512
+ [h('p', "The DruxtView component requires either the 'uuid' or 'viewId' prop to be set.")]
513
+ )
514
+ }
515
+ }
516
+
478
517
  // Headers.
479
518
  scopedSlots.header = () => Object.entries(this.headers).map(([key, header]) => h('span', {
480
519
  domProps: { innerHTML: (header.content || {}).value }, key
@@ -604,13 +643,19 @@ export default {
604
643
  * @example @lang js
605
644
  * [
606
645
  * 'DruxtView[ViewId][DisplayId]',
607
- * 'DruxtView[ViewId]'
646
+ * 'DruxtView[ViewId]',
647
+ * 'DruxtView[UUID][DisplayId]',
648
+ * 'DruxtView[UUID]',
649
+ * 'DruxtView[DisplayId]',
608
650
  * ]
609
651
  *
610
652
  * @example <caption>featured_articles (default)</caption> @lang js
611
653
  * [
612
654
  * 'DruxtViewFeaturedArticlesDefault',
613
- * 'DruxtViewFeaturedArticles'
655
+ * 'DruxtViewFeaturedArticles',
656
+ * 'DruxtView16f5d68e5bae4d7aa61c6b2bc3b6d3b6Default',
657
+ * 'DruxtView16f5d68e5bae4d7aa61c6b2bc3b6d3b6',
658
+ * 'DruxtViewDefault',
614
659
  * ]
615
660
  */
616
661
 
@@ -22,7 +22,7 @@ import { DruxtBlocksBlockMixin } from 'druxt-blocks'
22
22
  * uuid="43d613c6-ab66-453d-bce1-e1dfc990b4a1"
23
23
  * />
24
24
  *
25
- * @see {@link https://blocks.druxtjs.org/api/components/DruxtBlock.html|DruxtBlock}
25
+ * @see {@link https://blocks.druxtjs.org/api/components/DruxtBlock|DruxtBlock}
26
26
  */
27
27
  export default {
28
28
  name: 'DruxtBlockViewsBlock',
@@ -30,7 +30,7 @@ export default {
30
30
  /**
31
31
  * Vue.js Mixins.
32
32
  *
33
- * @see {@link https://blocks.druxtjs.org/api/mixins/block.html|DruxtBlocksBlockMixin}
33
+ * @see {@link https://blocks.druxtjs.org/api/mixins/block|DruxtBlocksBlockMixin}
34
34
  */
35
35
  mixins: [DruxtBlocksBlockMixin],
36
36
 
@@ -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.2",
4
4
  "description": "Drupal Views components for Druxt with support for filters, pagination and sorting.",
5
5
  "keywords": [
6
6
  "cms",
@@ -43,11 +43,11 @@
43
43
  "dependencies": {
44
44
  "axios": "^0.21.1",
45
45
  "deepmerge": "^4.2.2",
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",
46
+ "drupal-jsonapi-params": "^2.0.0",
47
+ "druxt": "^0.18.2",
48
+ "druxt-blocks": "^0.15.2",
49
+ "druxt-entity": "^0.24.3",
50
+ "druxt-router": "^0.26.1",
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'