druxt 0.15.0 → 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.
package/dist/druxt.ssr.js CHANGED
@@ -22,7 +22,7 @@ const md5__default = /*#__PURE__*/_interopDefaultLegacy(md5);
22
22
  const Vue__default = /*#__PURE__*/_interopDefaultLegacy(Vue);
23
23
 
24
24
  var name = "druxt";
25
- var version = "0.15.0";
25
+ var version = "0.18.0";
26
26
  var description = "The Fully Decoupled Drupal Framework for Nuxt.js.";
27
27
  var keywords = [
28
28
  "cms",
@@ -56,11 +56,12 @@ var main = "dist/druxt.ssr.js";
56
56
  var module$1 = "dist/druxt.esm.js";
57
57
  var files = [
58
58
  "dist",
59
+ "stories",
59
60
  "templates"
60
61
  ];
61
62
  var dependencies = {
63
+ "@nuxtjs/axios": "^5.13.6",
62
64
  "@nuxtjs/proxy": "^2.1.0",
63
- axios: "^0.21.1",
64
65
  chalk: "^4.1.2",
65
66
  deepmerge: "^4.2.2",
66
67
  "drupal-jsonapi-params": "^1.2.1",
@@ -68,7 +69,11 @@ var dependencies = {
68
69
  querystring: "^0.2.0",
69
70
  scule: "^0.2.0"
70
71
  };
72
+ var devDependencies = {
73
+ "@storybook/addon-docs": "^6.4.13"
74
+ };
71
75
  var peerDependencies = {
76
+ axios: "*",
72
77
  consola: "*"
73
78
  };
74
79
  var optionalDependencies = {
@@ -93,6 +98,7 @@ const meta = {
93
98
  module: module$1,
94
99
  files: files,
95
100
  dependencies: dependencies,
101
+ devDependencies: devDependencies,
96
102
  peerDependencies: peerDependencies,
97
103
  optionalDependencies: optionalDependencies,
98
104
  publishConfig: publishConfig
@@ -132,6 +138,14 @@ const DruxtNuxtModule = function(moduleOptions = {}) {
132
138
  }
133
139
  this.addModule("@nuxtjs/proxy");
134
140
  }
141
+ if (!options.axios) {
142
+ this.options.axios = {
143
+ baseURL: options.baseUrl,
144
+ proxy: !!this.options.proxy,
145
+ ...this.options.axios
146
+ };
147
+ this.addModule("@nuxtjs/axios");
148
+ }
135
149
  this.nuxt.hook("components:dirs", (dirs) => {
136
150
  dirs.push({ path: path.join(__dirname, "components") });
137
151
  });
@@ -140,6 +154,18 @@ const DruxtNuxtModule = function(moduleOptions = {}) {
140
154
  fileName: "druxt.js",
141
155
  options
142
156
  });
157
+ const extendPlugins = this.options.extendPlugins;
158
+ this.options.extendPlugins = (plugins) => {
159
+ plugins = typeof extendPlugins === "function" ? extendPlugins(plugins) : plugins;
160
+ const axiosIndex = plugins.findIndex(({ src }) => src === `${this.options.buildDir}/axios.js`);
161
+ const axiosPlugin = plugins[axiosIndex];
162
+ plugins.splice(axiosIndex, 1);
163
+ const druxtIndex = plugins.findIndex(({ src }) => src === `${this.options.buildDir}/druxt.js`);
164
+ const druxtPlugin = plugins[druxtIndex];
165
+ plugins.splice(druxtIndex, 1);
166
+ plugins = [axiosPlugin, druxtPlugin, ...plugins];
167
+ return plugins;
168
+ };
143
169
  this.addPlugin({
144
170
  src: path.resolve(__dirname, "../templates/store.js"),
145
171
  fileName: "store/druxt.js",
@@ -149,8 +175,12 @@ const DruxtNuxtModule = function(moduleOptions = {}) {
149
175
  this.options.components = (_a = this.options.components) != null ? _a : true;
150
176
  this.options.cli.badgeMessages.push(`${chalk__default['default'].blue.bold("Druxt")} @ v${meta.version}`);
151
177
  this.options.cli.badgeMessages.push(`${chalk__default['default'].bold("API:")} ${chalk__default['default'].blue.underline(options.baseUrl + options.endpoint)}`);
178
+ this.nuxt.hook("storybook:config", async ({ stories }) => {
179
+ stories.push("druxt/stories/*.stories.mdx");
180
+ stories.push("druxt/dist/components/*.stories.mdx");
181
+ stories.push("druxt/dist/components/*.stories.mjs");
182
+ });
152
183
  };
153
- DruxtNuxtModule.meta = meta;
154
184
 
155
185
  class DruxtClient {
156
186
  constructor(baseUrl, options = {}) {
@@ -160,14 +190,15 @@ class DruxtClient {
160
190
  if (!baseUrl) {
161
191
  throw new Error("The 'baseUrl' parameter is required.");
162
192
  }
163
- let axiosSettings = {};
164
- if (baseUrl && !(options.proxy || {}).api) {
165
- axiosSettings.baseURL = baseUrl;
166
- }
167
- if (typeof options.axios === "object") {
168
- axiosSettings = Object.assign(axiosSettings, options.axios);
193
+ this.axios = {};
194
+ if (typeof options.axios === "function") {
195
+ this.axios = options.axios;
196
+ } else {
197
+ this.axios = axios__default['default'].create({
198
+ ...options.axios || {},
199
+ baseURL: baseUrl
200
+ });
169
201
  }
170
- this.axios = axios__default['default'].create(axiosSettings);
171
202
  if (options.debug) {
172
203
  const log = this.log;
173
204
  this.axios.interceptors.request.use((config) => {
@@ -219,9 +250,16 @@ class DruxtClient {
219
250
  }
220
251
  }
221
252
  if (Object.keys(permissions).length) {
222
- throw new TypeError(`${res.data.meta.omitted.detail}
223
-
224
- Required permissions: ${Object.keys(permissions).join(", ")}.`);
253
+ const err = {
254
+ response: {
255
+ statusText: res.data.meta.omitted.detail,
256
+ data: {
257
+ errors: [{ detail: `Required permissions:
258
+ - ${Object.keys(permissions).join("\n - ")}` }]
259
+ }
260
+ }
261
+ };
262
+ throw err;
225
263
  }
226
264
  }
227
265
  }
@@ -241,19 +279,49 @@ class DruxtClient {
241
279
  }
242
280
  });
243
281
  } catch (err) {
244
- response = (err.response || {}).data || err.message;
282
+ this.error(err, { url: href });
245
283
  }
246
284
  return response;
247
285
  }
286
+ error(err, context = {}) {
287
+ let { url } = context;
288
+ if (!url && ((err.response || {}).config || {}).url) {
289
+ url = err.response.config.url;
290
+ }
291
+ const title = [
292
+ (err.response || {}).status,
293
+ (err.response || {}).statusText || err.message
294
+ ].filter((s) => s).join(": ");
295
+ const meta = { url: url && [this.options.baseUrl, url].join("") };
296
+ let message = [title];
297
+ if (Object.values(meta).filter((o) => o).length) {
298
+ message.push(Object.entries(meta).filter(([, v]) => v).map(([key, value]) => `${key.toUpperCase()}: ${value}`).join("\n"));
299
+ }
300
+ if (((((err.response || {}).data || {}).errors || [])[0] || {}).detail) {
301
+ message.push(err.response.data.errors[0].detail);
302
+ }
303
+ const error = Error(message.join("\n\n"));
304
+ error.response = err.response;
305
+ error.druxt = context;
306
+ throw error;
307
+ }
308
+ async get(url, options) {
309
+ try {
310
+ const res = await this.axios.get(url, options);
311
+ this.checkPermissions(res);
312
+ return res;
313
+ } catch (err) {
314
+ this.error(err, { url });
315
+ }
316
+ }
248
317
  async getCollection(type, query) {
249
318
  const { href } = await this.getIndex(type);
250
319
  if (!href) {
251
320
  return false;
252
321
  }
253
322
  const url = this.buildQueryUrl(href, query);
254
- const res = await this.axios.get(url);
255
- this.checkPermissions(res);
256
- return res.data;
323
+ const { data } = await this.get(url);
324
+ return data;
257
325
  }
258
326
  async getCollectionAll(type, query) {
259
327
  const collections = [];
@@ -273,16 +341,27 @@ class DruxtClient {
273
341
  if (this.index && resource) {
274
342
  return this.index[resource] ? this.index[resource] : false;
275
343
  }
276
- let index = ((await this.axios.get(this.options.endpoint) || {}).data || {}).links;
344
+ const url = this.options.endpoint;
345
+ const { data } = await this.get(url);
346
+ let index = data.links;
347
+ if (typeof index !== "object") {
348
+ const err = { response: { statusText: "Invalid JSON:API endpoint" } };
349
+ this.error(err, { url });
350
+ }
277
351
  const baseUrl = this.options.baseUrl;
278
352
  index = Object.fromEntries(Object.entries(index).map(([key, value]) => {
279
353
  value.href = value.href.replace(baseUrl, "");
280
354
  return [key, value];
281
355
  }));
282
356
  if (index[this.options.jsonapiResourceConfig]) {
283
- const resources = await this.axios.get(index[this.options.jsonapiResourceConfig].href);
284
- for (const resourceType in resources.data.data) {
285
- const resource2 = resources.data.data[resourceType];
357
+ let resources = [];
358
+ try {
359
+ resources = (await this.get(index[this.options.jsonapiResourceConfig].href)).data.data;
360
+ } catch (err) {
361
+ this.log.warn(err.message);
362
+ }
363
+ for (const resourceType in resources) {
364
+ const resource2 = resources[resourceType];
286
365
  const internal = resource2.attributes.drupal_internal__id.split("--");
287
366
  const item = {
288
367
  resourceType: resource2.attributes.resourceType,
@@ -298,11 +377,7 @@ class DruxtClient {
298
377
  }
299
378
  }
300
379
  this.index = index;
301
- if (resource) {
302
- const response = this.index[resource] ? this.index[resource] : false;
303
- return response;
304
- }
305
- return this.index;
380
+ return resource ? this.index[resource] || false : this.index;
306
381
  }
307
382
  async getRelated(type, id, related, query) {
308
383
  if (!id || !type || !related) {
@@ -313,12 +388,8 @@ class DruxtClient {
313
388
  href = this.options.endpoint + "/" + type.replace("--", "/");
314
389
  }
315
390
  const url = this.buildQueryUrl(`${href}/${id}/${related}`, query);
316
- try {
317
- const related2 = await this.axios.get(url);
318
- return related2.data;
319
- } catch (e) {
320
- return false;
321
- }
391
+ const { data } = await this.get(url);
392
+ return data;
322
393
  }
323
394
  async getResource(type, id, query) {
324
395
  if (!id || !type) {
@@ -328,13 +399,9 @@ class DruxtClient {
328
399
  if (!href) {
329
400
  href = this.options.endpoint + "/" + type.replace("--", "/");
330
401
  }
331
- const url = this.buildQueryUrl(`${href}/${id}`, query);
332
- try {
333
- const resource = await this.axios.get(url);
334
- return resource.data;
335
- } catch (e) {
336
- return false;
337
- }
402
+ const url = this.buildQueryUrl([href, id].join("/"), query);
403
+ const { data } = await this.get(url);
404
+ return data;
338
405
  }
339
406
  async updateResource(resource) {
340
407
  const { href } = await this.getIndex(resource.type);
@@ -350,7 +417,7 @@ class DruxtClient {
350
417
  }
351
418
  });
352
419
  } catch (err) {
353
- response = (err.response || {}).data || err.message;
420
+ this.error(err);
354
421
  }
355
422
  return response;
356
423
  }
@@ -361,7 +428,7 @@ const getDrupalJsonApiParams = (query) => {
361
428
  };
362
429
 
363
430
  const dehydrateResources = ({ commit, queryObject, resources }) => {
364
- return resources.map((data) => {
431
+ return (resources || []).map((data) => {
365
432
  const link = decodeURI(((data.links || {}).self || {}).href || "");
366
433
  const href = typeof (queryObject.fields || {})[data.type] === "string" ? [link.split("?")[0], `fields[${data.type}]=${queryObject.fields[data.type]}`].join("?") : link;
367
434
  commit("druxt/addResource", {
@@ -552,6 +619,8 @@ class DruxtClass {
552
619
  }
553
620
  }
554
621
 
622
+ DruxtNuxtModule.meta = require("../package.json");
623
+
555
624
  exports.DruxtClass = DruxtClass;
556
625
  exports.DruxtClient = DruxtClient;
557
626
  exports.DruxtStore = DruxtStore;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "druxt",
3
- "version": "0.15.0",
3
+ "version": "0.18.0",
4
4
  "description": "The Fully Decoupled Drupal Framework for Nuxt.js.",
5
5
  "keywords": [
6
6
  "cms",
@@ -34,11 +34,12 @@
34
34
  "module": "dist/druxt.esm.js",
35
35
  "files": [
36
36
  "dist",
37
+ "stories",
37
38
  "templates"
38
39
  ],
39
40
  "dependencies": {
41
+ "@nuxtjs/axios": "^5.13.6",
40
42
  "@nuxtjs/proxy": "^2.1.0",
41
- "axios": "^0.21.1",
42
43
  "chalk": "^4.1.2",
43
44
  "deepmerge": "^4.2.2",
44
45
  "drupal-jsonapi-params": "^1.2.1",
@@ -46,7 +47,11 @@
46
47
  "querystring": "^0.2.0",
47
48
  "scule": "^0.2.0"
48
49
  },
50
+ "devDependencies": {
51
+ "@storybook/addon-docs": "^6.4.13"
52
+ },
49
53
  "peerDependencies": {
54
+ "axios": "*",
50
55
  "consola": "*"
51
56
  },
52
57
  "optionalDependencies": {
@@ -0,0 +1,74 @@
1
+ import { Meta } from '@storybook/addon-docs'
2
+
3
+ <Meta title="Druxt/README" />
4
+
5
+ # Druxt Storybook
6
+
7
+ > Druxt + @nuxtjs/Storybook
8
+
9
+ The following documentation and stories are provided by
10
+ [DruxtJS](https://druxtjs.org) and the installed Druxt modules.
11
+
12
+ The stories are connected to your Drupal JSON:API via the DruxtClient; this
13
+ allows you to test your Druxt Wrapper components using live data.
14
+
15
+ - For more information, refer to the
16
+ [Druxt Storybook guide](https://druxtjs.org/guide/storybook).
17
+
18
+ ---
19
+
20
+ ## Introduction
21
+
22
+ This is a live Druxt Storybook, with autogenerated stories based on the
23
+ configuration of your Drupal backend.
24
+
25
+ ---
26
+
27
+ ### Autogenerated stories
28
+
29
+ Each Druxt module is able to use configuration from your Drupal backend to craft
30
+ site specific stories.
31
+
32
+ For instance, the DruxtEntity module will create a story for each Entity type,
33
+ Bundle and Display mode, while the Block module will create a story for each
34
+ backend Theme, Region and Block.
35
+
36
+ Search or navigate through the Druxt components and stories in the Storybook
37
+ sidebar.
38
+
39
+ ---
40
+
41
+ ### What is Druxt?
42
+
43
+ > Drupal + Nuxt = Druxt
44
+
45
+ Druxt is a framework for building Fully Decoupled Drupal and Nuxt.js
46
+ applications and sites. It allows you to leverage the content modelling and
47
+ management power of Drupal, and build elegant user experiences with Nuxt.js.
48
+
49
+ - Find out more @ [DruxtJS.org](https://druxtjs.org)
50
+
51
+ ---
52
+
53
+ ### Druxt components
54
+
55
+ Druxt components are provided by Druxt modules to provide targetted decoupled
56
+ Drupal functionality; A **DruxtEntity** component to render Drupal Content
57
+ entities, or a **DruxtMenu** component to render a Drupal menu, etc.
58
+
59
+ - See the core Druxt components @
60
+ [https://druxtjs.org/api/components](https://druxtjs.org/api/components)
61
+
62
+ ---
63
+
64
+ ### Druxt Wrapper theme system
65
+
66
+ Druxt components that extend the **DruxtModule** use slot based wrapper system,
67
+ providing the frontend developer the ability to create theme templates per
68
+ Content type, or Display mode, and many more component options depending on the
69
+ module.
70
+
71
+ The available component options are provided via the `component.options` data
72
+ on the relevant Druxt module component.
73
+
74
+ - For more information, see the [Themeing guide](https://druxtjs.org/guide/theming)
@@ -1,6 +1,6 @@
1
1
  import { DruxtClient } from 'druxt'
2
2
 
3
- export default (context, inject) => {
3
+ export default ({ app }, inject) => {
4
4
  const options = <%= JSON.stringify(options) %>
5
5
 
6
6
  // Disable the proxy for server side requests.
@@ -8,6 +8,15 @@ export default (context, inject) => {
8
8
  options.proxy.api = false
9
9
  }
10
10
 
11
+ <% if (typeof options.axios === 'object') { %>
12
+ // Axios settings.
13
+ console.warn('[druxt] Axios instance settings are deprecated, use @nuxtjs/axios module configuration instead.')
14
+ options.axios = <%= JSON.stringify(options.axios) %>
15
+ <% } else { %>
16
+ // Use the @nuxtjs/axios module Axios instance.
17
+ options.axios = app.$axios
18
+ <% } %>
19
+
11
20
  const druxt = new DruxtClient(options.baseUrl, options)
12
21
  druxt.settings = options
13
22
  inject('druxt', druxt)