druxt 0.13.0 → 0.17.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/components/DruxtDebug.stories.mjs +48 -0
- package/dist/components/DruxtDebug.vue +31 -4
- package/dist/components/DruxtModule.stories.mdx +126 -0
- package/dist/components/DruxtModule.vue +67 -11
- package/dist/druxt.esm.js +181 -33
- package/dist/druxt.ssr.js +182 -33
- package/package.json +8 -1
- package/stories/README.stories.mdx +74 -0
- package/CHANGELOG.md +0 -338
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import DruxtDebug from './DruxtDebug.vue'
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
title: 'Druxt/DruxtDebug',
|
|
5
|
+
component: DruxtDebug
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const Template = (args) => ({
|
|
9
|
+
components: { DruxtDebug },
|
|
10
|
+
props: Object.keys(args),
|
|
11
|
+
template: `<DruxtDebug v-bind="$props">Debug information.</DruxtDebug>`
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
export const Default = Template.bind({})
|
|
15
|
+
Default.storyName = 'Default slot'
|
|
16
|
+
|
|
17
|
+
export const Json = Template.bind({})
|
|
18
|
+
Json.args = {
|
|
19
|
+
json: {
|
|
20
|
+
type: '',
|
|
21
|
+
id: '',
|
|
22
|
+
links: {},
|
|
23
|
+
attributes: {},
|
|
24
|
+
relationships: {},
|
|
25
|
+
},
|
|
26
|
+
open: true,
|
|
27
|
+
}
|
|
28
|
+
Json.parameters = {
|
|
29
|
+
docs: {
|
|
30
|
+
storyDescription: 'The **json** prop takes any data and runs it through a basic JSON formatter for improved readability.',
|
|
31
|
+
source: {
|
|
32
|
+
code: '<DruxtDebug :json="entity" open>Debug information</DruxtDebug>'
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const Summary = Template.bind({})
|
|
38
|
+
Summary.args = {
|
|
39
|
+
summary: 'A brief debug message'
|
|
40
|
+
}
|
|
41
|
+
Summary.parameters = {
|
|
42
|
+
docs: {
|
|
43
|
+
storyDescription: 'The **summary** prop can be used to provide a quick explanation of the debug component.',
|
|
44
|
+
source: {
|
|
45
|
+
code: `<DruxtDebug summary="${Summary.args.sumary}">Debug information</DruxtDebug>`
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<details v-if="$nuxt.context.isDev">
|
|
3
3
|
<summary v-text="title" />
|
|
4
|
+
<pre v-if="json"><!--
|
|
5
|
+
--><code>{{ JSON.stringify(json, null, ' ') }}</code><!--
|
|
6
|
+
--></pre>
|
|
7
|
+
<!-- @slot Debug content -->
|
|
4
8
|
<slot />
|
|
5
9
|
</details>
|
|
6
10
|
|
|
@@ -10,19 +14,40 @@
|
|
|
10
14
|
<script>
|
|
11
15
|
|
|
12
16
|
/**
|
|
13
|
-
*
|
|
17
|
+
* The DruxtDebug component can be used to render debug information that is
|
|
18
|
+
* visible only when Nuxt is run in development mode.
|
|
19
|
+
*
|
|
20
|
+
* You can render your debug information through the default slot, or via the
|
|
21
|
+
* **json** prop to format your data, or a combination of the two.
|
|
22
|
+
*
|
|
23
|
+
* @example @lang vue
|
|
24
|
+
* <DruxtDebug :json="entity">Debug information</DruxtDebug>
|
|
14
25
|
*/
|
|
15
26
|
export default {
|
|
16
27
|
/** */
|
|
17
28
|
props: {
|
|
18
29
|
/**
|
|
19
|
-
*
|
|
30
|
+
* JSON data to format for readability.
|
|
31
|
+
*
|
|
32
|
+
* @type {*}
|
|
33
|
+
* @example @lang vue
|
|
34
|
+
* <DruxtDebug :json="{ data: [{ one: true, two: false }] }" />
|
|
35
|
+
*/
|
|
36
|
+
json: {
|
|
37
|
+
type: [Array, Boolean, Object, Number, String],
|
|
38
|
+
default: undefined
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Text to use for debug summary.
|
|
20
43
|
*
|
|
21
44
|
* @type {string}
|
|
45
|
+
* @example @lang vue
|
|
46
|
+
* <DruxtDebug summary="Foo bar" />
|
|
22
47
|
*/
|
|
23
48
|
summary: {
|
|
24
49
|
type: String,
|
|
25
|
-
|
|
50
|
+
default: 'Debug',
|
|
26
51
|
},
|
|
27
52
|
},
|
|
28
53
|
|
|
@@ -43,7 +68,9 @@ export default {
|
|
|
43
68
|
*
|
|
44
69
|
* @return {string}
|
|
45
70
|
*/
|
|
46
|
-
title: ({ module, summary }) =>
|
|
71
|
+
title: ({ module, summary }) => module.$options._componentTag
|
|
72
|
+
? `[${module.$options._componentTag}] ${summary}`
|
|
73
|
+
: summary,
|
|
47
74
|
},
|
|
48
75
|
};
|
|
49
76
|
</script>
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { Canvas, Meta, Story } from '@storybook/addon-docs'
|
|
2
|
+
|
|
3
|
+
<Meta title="Druxt/DruxtModule" />
|
|
4
|
+
|
|
5
|
+
# DruxtModule
|
|
6
|
+
|
|
7
|
+
The DruxtModule component is the core component to be extended by core and
|
|
8
|
+
custom modules.
|
|
9
|
+
|
|
10
|
+
```js
|
|
11
|
+
import DruxtModule from 'druxt/dist/components/DruxtModule.vue'
|
|
12
|
+
export default {
|
|
13
|
+
extends: DruxtModule
|
|
14
|
+
}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Fetch config
|
|
20
|
+
|
|
21
|
+
All modules have a two part fetch system available to them; **fetchConfig** and
|
|
22
|
+
**fetchData**.
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
async fetchConfig() {
|
|
26
|
+
// Load configuration data here.
|
|
27
|
+
this.config = await this.getResource({...})
|
|
28
|
+
},
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Fetch config is used to load information from Drupal to determine the default
|
|
32
|
+
behaviour of that component, as well as to determine the available component
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Component options
|
|
37
|
+
|
|
38
|
+
The Druxt Wrapper system looks for available Vue components using a specific
|
|
39
|
+
naming convention, determined by the Druxt module **componentOptions**.
|
|
40
|
+
|
|
41
|
+
This allows for targetted theming of components based on the props or
|
|
42
|
+
configuration data.
|
|
43
|
+
|
|
44
|
+
```js
|
|
45
|
+
componentOptions: (context) => ([[context.attributes.foo, 'default']]),
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Fetch data
|
|
51
|
+
|
|
52
|
+
After the Component options are determined, the first available component is
|
|
53
|
+
determined, and any exported Druxt settings are loaded and used to fetch the
|
|
54
|
+
main module data.
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
async fetchData(settings) {
|
|
58
|
+
// Load data using the settings determine based on the configuration data.
|
|
59
|
+
this.resource = await this.getResource({
|
|
60
|
+
type: this.config.attributes.foo,
|
|
61
|
+
id: this.id,
|
|
62
|
+
query: this.getQuery(settings)
|
|
63
|
+
})
|
|
64
|
+
},
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Props data
|
|
70
|
+
|
|
71
|
+
The **propsData** callback returns the props data for the render Wrapper
|
|
72
|
+
component, making props data available to the frontend developer.
|
|
73
|
+
|
|
74
|
+
```js
|
|
75
|
+
propsData: (context) => ({ foo: context.config.attributes.foo })
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Slots
|
|
81
|
+
|
|
82
|
+
The **slots** method builds the slots that are made available to the Wrapper
|
|
83
|
+
component. It is expected to return an object of scoped slot functions.
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
slots(h) {
|
|
87
|
+
return {
|
|
88
|
+
default: () => h('div', ['Hello world']),
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
### Custom module boilerplate
|
|
96
|
+
|
|
97
|
+
Paste this into a Vue component as a starting point for a custom or contrib
|
|
98
|
+
Druxt module.
|
|
99
|
+
|
|
100
|
+
```vue
|
|
101
|
+
<script>
|
|
102
|
+
import DruxtModule from 'druxt/dist/components/DruxtModule.vue'
|
|
103
|
+
export default {
|
|
104
|
+
name: 'MyModule',
|
|
105
|
+
extends: DruxtModule
|
|
106
|
+
druxt: {
|
|
107
|
+
async fetchConfig() {
|
|
108
|
+
// Load configuration data here.
|
|
109
|
+
},
|
|
110
|
+
async fetchData(settings) {
|
|
111
|
+
// Load data using the settings determine based on the configuration data.
|
|
112
|
+
},
|
|
113
|
+
// Build nested arrays of component options based on the context.
|
|
114
|
+
componentOptions: (context) => ([['default']]),
|
|
115
|
+
// Map props data from the context.
|
|
116
|
+
propsData: (context) => ({ ...context }),
|
|
117
|
+
// Build slots render arrays.
|
|
118
|
+
slots(h) {
|
|
119
|
+
return {
|
|
120
|
+
default: () => h('div', ['Hello world'])
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
</script>
|
|
126
|
+
```
|
|
@@ -6,7 +6,11 @@ import Vue from 'vue'
|
|
|
6
6
|
import DruxtWrapper from './DruxtWrapper.vue'
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
9
|
+
* The DruxtModule component is used to make a Druxt module, simply import and
|
|
10
|
+
* extend the component to get started.
|
|
11
|
+
*
|
|
12
|
+
* The component provides access to the Druxt Wrapper theming and fetch system
|
|
13
|
+
* via the druxt settings object.
|
|
10
14
|
*
|
|
11
15
|
* @example @lang js
|
|
12
16
|
* import DruxtModule from 'druxt/dist/components/DruxtModule.vue'
|
|
@@ -14,11 +18,18 @@ import DruxtWrapper from './DruxtWrapper.vue'
|
|
|
14
18
|
* name: 'DruxtTestModule',
|
|
15
19
|
* extends: DruxtModule,
|
|
16
20
|
* druxt: {
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
+
* async fetchConfig() {},
|
|
22
|
+
* async fetchData(settings) {},
|
|
23
|
+
* componentOptions: (context) => ([[context.foo, context.bar, 'default']]),
|
|
24
|
+
* propsData: (context) => ({
|
|
25
|
+
* foo: context.foo,
|
|
26
|
+
* bar: context.bar,
|
|
21
27
|
* }),
|
|
28
|
+
* slots(h) {
|
|
29
|
+
* return {
|
|
30
|
+
* default: (attrs) => h('DruxtDebug', ['Hello world'])
|
|
31
|
+
* }
|
|
32
|
+
* }
|
|
22
33
|
* }
|
|
23
34
|
* }
|
|
24
35
|
*/
|
|
@@ -107,12 +118,16 @@ export default {
|
|
|
107
118
|
|
|
108
119
|
// Fetch configuration.
|
|
109
120
|
if ((this.$options.druxt || {}).fetchConfig) {
|
|
110
|
-
|
|
121
|
+
try {
|
|
122
|
+
await this.$options.druxt.fetchConfig.call(this)
|
|
123
|
+
} catch(err) {
|
|
124
|
+
return this.error(err)
|
|
125
|
+
}
|
|
111
126
|
}
|
|
112
127
|
|
|
113
128
|
// Build wrapper component object.
|
|
114
129
|
let options = []
|
|
115
|
-
const hasDefaultTemplate = !!(this.$vnode.data.scopedSlots || {}).default
|
|
130
|
+
const hasDefaultTemplate = !!(((this.$vnode || {}).data || {}).scopedSlots || {}).default
|
|
116
131
|
// Load wrapper components if:
|
|
117
132
|
if (
|
|
118
133
|
// No default template and wrapper isn't false OR
|
|
@@ -138,7 +153,11 @@ export default {
|
|
|
138
153
|
|
|
139
154
|
// Fetch resource.
|
|
140
155
|
if ((this.$options.druxt || {}).fetchData) {
|
|
141
|
-
|
|
156
|
+
try {
|
|
157
|
+
await this.$options.druxt.fetchData.call(this, component.settings)
|
|
158
|
+
} catch(err) {
|
|
159
|
+
return this.error(err, { component })
|
|
160
|
+
}
|
|
142
161
|
}
|
|
143
162
|
|
|
144
163
|
// Get scoped slots.
|
|
@@ -153,7 +172,7 @@ export default {
|
|
|
153
172
|
|
|
154
173
|
watch: {
|
|
155
174
|
model() {
|
|
156
|
-
if (this.component.props.value !== this.model) {
|
|
175
|
+
if (this.component.props && this.component.props.value !== this.model) {
|
|
157
176
|
this.component.props.value = this.model
|
|
158
177
|
|
|
159
178
|
// Only emit 'input' if using the default 'DruxtWrapper' component.
|
|
@@ -172,6 +191,31 @@ export default {
|
|
|
172
191
|
|
|
173
192
|
/** */
|
|
174
193
|
methods: {
|
|
194
|
+
/**
|
|
195
|
+
* Sets the component to render a DruxtDebug error message.
|
|
196
|
+
*/
|
|
197
|
+
error(err, context = {}) {
|
|
198
|
+
// Build error details.
|
|
199
|
+
const { url } = err.druxt || {}
|
|
200
|
+
const title = (err.response || {}).statusText || ((((err.response || {}).data || {}).errors || [])[0] || {}).title
|
|
201
|
+
const summary = (err.response || {}).status
|
|
202
|
+
? [(err.response || {}).status, title].filter((s) => s).join(': ')
|
|
203
|
+
: err.message
|
|
204
|
+
|
|
205
|
+
// Set the component to a Debug component with error details.
|
|
206
|
+
this.component = {
|
|
207
|
+
...context.component || {},
|
|
208
|
+
is: 'DruxtDebug',
|
|
209
|
+
props: {
|
|
210
|
+
json: {
|
|
211
|
+
url,
|
|
212
|
+
errors: ((err.response || {}).data || {}).errors
|
|
213
|
+
},
|
|
214
|
+
summary
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
|
|
175
219
|
/**
|
|
176
220
|
* Get list of module wrapper components.
|
|
177
221
|
*
|
|
@@ -193,7 +237,7 @@ export default {
|
|
|
193
237
|
let components = []
|
|
194
238
|
for (const set of options.filter(set => Array.isArray(set))) {
|
|
195
239
|
const variants = []
|
|
196
|
-
components = [...components, ...set.map(item => {
|
|
240
|
+
components = [...components, ...set.filter((o) => o).map(item => {
|
|
197
241
|
// Build array of name parts.
|
|
198
242
|
const parts = variants.length ? [...variants[0].parts] : []
|
|
199
243
|
parts.push(pascalCase(splitByCase(item)))
|
|
@@ -265,6 +309,18 @@ export default {
|
|
|
265
309
|
*/
|
|
266
310
|
getScopedSlots() {
|
|
267
311
|
const h = this.$createElement
|
|
312
|
+
|
|
313
|
+
// Get an array of unmet required props.
|
|
314
|
+
const required = Object.entries(this.$options.props)
|
|
315
|
+
.filter(([k, o]) => o.required && !this[k])
|
|
316
|
+
.map(([k]) => k)
|
|
317
|
+
// Return debug error if any missing props are found.
|
|
318
|
+
if (required.length) {
|
|
319
|
+
return {
|
|
320
|
+
default: () => h('DruxtDebug', { props: { summary: `Missing required props: ${required.join(', ')}.` } })
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
268
324
|
const scopedSlots = typeof (this.$options.druxt || {}).slots === 'function'
|
|
269
325
|
? this.$options.druxt.slots.call(this, h)
|
|
270
326
|
: {}
|
|
@@ -336,7 +392,7 @@ export default {
|
|
|
336
392
|
}
|
|
337
393
|
|
|
338
394
|
// Return only wrapper if fetch state is still pending.
|
|
339
|
-
if (this.$fetchState.pending) {
|
|
395
|
+
if (this.$fetchState.pending && this.component.is === 'DruxtWrapper') {
|
|
340
396
|
return h((this.wrapper || {}).component || 'div', wrapperData)
|
|
341
397
|
}
|
|
342
398
|
|
package/dist/druxt.esm.js
CHANGED
|
@@ -2,11 +2,94 @@ import chalk from 'chalk';
|
|
|
2
2
|
import { join, resolve } from 'path';
|
|
3
3
|
import axios from 'axios';
|
|
4
4
|
import { stringify } from 'querystring';
|
|
5
|
+
import consola from 'consola';
|
|
5
6
|
import merge from 'deepmerge';
|
|
6
7
|
import md5 from 'md5';
|
|
7
8
|
import Vue from 'vue';
|
|
8
9
|
import { DrupalJsonApiParams } from 'drupal-jsonapi-params';
|
|
9
10
|
|
|
11
|
+
var name = "druxt";
|
|
12
|
+
var version = "0.17.0";
|
|
13
|
+
var description = "The Fully Decoupled Drupal Framework for Nuxt.js.";
|
|
14
|
+
var keywords = [
|
|
15
|
+
"cms",
|
|
16
|
+
"decoupled",
|
|
17
|
+
"drupal",
|
|
18
|
+
"druxt",
|
|
19
|
+
"headless",
|
|
20
|
+
"jsonapi",
|
|
21
|
+
"json:api",
|
|
22
|
+
"nuxt",
|
|
23
|
+
"module",
|
|
24
|
+
"vue"
|
|
25
|
+
];
|
|
26
|
+
var homepage = "https://druxtjs.org";
|
|
27
|
+
var bugs = {
|
|
28
|
+
url: "https://github.com/druxt/druxt.js/issues"
|
|
29
|
+
};
|
|
30
|
+
var repository = {
|
|
31
|
+
type: "git",
|
|
32
|
+
url: "git+https://github.com/druxt/druxt.js"
|
|
33
|
+
};
|
|
34
|
+
var license = "MIT";
|
|
35
|
+
var exports = {
|
|
36
|
+
".": {
|
|
37
|
+
require: "./dist/druxt.ssr.js",
|
|
38
|
+
"import": "./dist/druxt.esm.js"
|
|
39
|
+
},
|
|
40
|
+
"./components/*": "./dist/components/*"
|
|
41
|
+
};
|
|
42
|
+
var main = "dist/druxt.ssr.js";
|
|
43
|
+
var module = "dist/druxt.esm.js";
|
|
44
|
+
var files = [
|
|
45
|
+
"dist",
|
|
46
|
+
"stories",
|
|
47
|
+
"templates"
|
|
48
|
+
];
|
|
49
|
+
var dependencies = {
|
|
50
|
+
"@nuxtjs/proxy": "^2.1.0",
|
|
51
|
+
axios: "^0.21.1",
|
|
52
|
+
chalk: "^4.1.2",
|
|
53
|
+
deepmerge: "^4.2.2",
|
|
54
|
+
"drupal-jsonapi-params": "^1.2.1",
|
|
55
|
+
md5: "^2.3.0",
|
|
56
|
+
querystring: "^0.2.0",
|
|
57
|
+
scule: "^0.2.0"
|
|
58
|
+
};
|
|
59
|
+
var devDependencies = {
|
|
60
|
+
"@storybook/addon-docs": "^6.4.13"
|
|
61
|
+
};
|
|
62
|
+
var peerDependencies = {
|
|
63
|
+
consola: "*"
|
|
64
|
+
};
|
|
65
|
+
var optionalDependencies = {
|
|
66
|
+
"core-js": "^3.16.1",
|
|
67
|
+
vue: "^2.6.14",
|
|
68
|
+
vuex: "^3.6.2"
|
|
69
|
+
};
|
|
70
|
+
var publishConfig = {
|
|
71
|
+
access: "public"
|
|
72
|
+
};
|
|
73
|
+
var meta = {
|
|
74
|
+
name: name,
|
|
75
|
+
version: version,
|
|
76
|
+
description: description,
|
|
77
|
+
keywords: keywords,
|
|
78
|
+
homepage: homepage,
|
|
79
|
+
bugs: bugs,
|
|
80
|
+
repository: repository,
|
|
81
|
+
license: license,
|
|
82
|
+
exports: exports,
|
|
83
|
+
main: main,
|
|
84
|
+
module: module,
|
|
85
|
+
files: files,
|
|
86
|
+
dependencies: dependencies,
|
|
87
|
+
devDependencies: devDependencies,
|
|
88
|
+
peerDependencies: peerDependencies,
|
|
89
|
+
optionalDependencies: optionalDependencies,
|
|
90
|
+
publishConfig: publishConfig
|
|
91
|
+
};
|
|
92
|
+
|
|
10
93
|
const DruxtNuxtModule = function(moduleOptions = {}) {
|
|
11
94
|
var _a;
|
|
12
95
|
const options = {
|
|
@@ -49,6 +132,15 @@ const DruxtNuxtModule = function(moduleOptions = {}) {
|
|
|
49
132
|
fileName: "druxt.js",
|
|
50
133
|
options
|
|
51
134
|
});
|
|
135
|
+
const extendPlugins = this.options.extendPlugins;
|
|
136
|
+
this.options.extendPlugins = (plugins) => {
|
|
137
|
+
plugins = typeof extendPlugins === "function" ? extendPlugins(plugins) : plugins;
|
|
138
|
+
const index = plugins.findIndex(({ src }) => src === `${this.options.buildDir}/druxt.js`);
|
|
139
|
+
const plugin = plugins[index];
|
|
140
|
+
plugins.splice(index, 1);
|
|
141
|
+
plugins.unshift(plugin);
|
|
142
|
+
return plugins;
|
|
143
|
+
};
|
|
52
144
|
this.addPlugin({
|
|
53
145
|
src: resolve(__dirname, "../templates/store.js"),
|
|
54
146
|
fileName: "store/druxt.js",
|
|
@@ -56,12 +148,20 @@ const DruxtNuxtModule = function(moduleOptions = {}) {
|
|
|
56
148
|
});
|
|
57
149
|
this.options.store = true;
|
|
58
150
|
this.options.components = (_a = this.options.components) != null ? _a : true;
|
|
59
|
-
this.options.cli.badgeMessages.push(`${chalk.bold("Druxt
|
|
151
|
+
this.options.cli.badgeMessages.push(`${chalk.blue.bold("Druxt")} @ v${meta.version}`);
|
|
152
|
+
this.options.cli.badgeMessages.push(`${chalk.bold("API:")} ${chalk.blue.underline(options.baseUrl + options.endpoint)}`);
|
|
153
|
+
this.nuxt.hook("storybook:config", async ({ stories }) => {
|
|
154
|
+
stories.push("druxt/stories/*.stories.mdx");
|
|
155
|
+
stories.push("druxt/dist/components/*.stories.mdx");
|
|
156
|
+
stories.push("druxt/dist/components/*.stories.mjs");
|
|
157
|
+
});
|
|
60
158
|
};
|
|
61
|
-
DruxtNuxtModule.meta = require("../package.json");
|
|
62
159
|
|
|
63
160
|
class DruxtClient {
|
|
64
161
|
constructor(baseUrl, options = {}) {
|
|
162
|
+
this.log = consola.create({ defaults: {
|
|
163
|
+
tag: "DruxtClient"
|
|
164
|
+
} });
|
|
65
165
|
if (!baseUrl) {
|
|
66
166
|
throw new Error("The 'baseUrl' parameter is required.");
|
|
67
167
|
}
|
|
@@ -73,6 +173,16 @@ class DruxtClient {
|
|
|
73
173
|
axiosSettings = Object.assign(axiosSettings, options.axios);
|
|
74
174
|
}
|
|
75
175
|
this.axios = axios.create(axiosSettings);
|
|
176
|
+
if (options.debug) {
|
|
177
|
+
const log = this.log;
|
|
178
|
+
this.axios.interceptors.request.use((config) => {
|
|
179
|
+
log.info(config.url);
|
|
180
|
+
return config;
|
|
181
|
+
}, (error) => {
|
|
182
|
+
log.error(error);
|
|
183
|
+
return Promise.reject(error);
|
|
184
|
+
});
|
|
185
|
+
}
|
|
76
186
|
this.options = {
|
|
77
187
|
endpoint: "/jsonapi",
|
|
78
188
|
jsonapiResourceConfig: "jsonapi_resource_config--jsonapi_resource_config",
|
|
@@ -114,9 +224,16 @@ class DruxtClient {
|
|
|
114
224
|
}
|
|
115
225
|
}
|
|
116
226
|
if (Object.keys(permissions).length) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
227
|
+
const err = {
|
|
228
|
+
response: {
|
|
229
|
+
statusText: res.data.meta.omitted.detail,
|
|
230
|
+
data: {
|
|
231
|
+
errors: [{ detail: `Required permissions:
|
|
232
|
+
- ${Object.keys(permissions).join("\n - ")}` }]
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
throw err;
|
|
120
237
|
}
|
|
121
238
|
}
|
|
122
239
|
}
|
|
@@ -136,19 +253,49 @@ class DruxtClient {
|
|
|
136
253
|
}
|
|
137
254
|
});
|
|
138
255
|
} catch (err) {
|
|
139
|
-
|
|
256
|
+
this.error(err, { url: href });
|
|
140
257
|
}
|
|
141
258
|
return response;
|
|
142
259
|
}
|
|
260
|
+
error(err, context = {}) {
|
|
261
|
+
let { url } = context;
|
|
262
|
+
if (!url && ((err.response || {}).config || {}).url) {
|
|
263
|
+
url = err.response.config.url;
|
|
264
|
+
}
|
|
265
|
+
const title = [
|
|
266
|
+
(err.response || {}).status,
|
|
267
|
+
(err.response || {}).statusText || err.message
|
|
268
|
+
].filter((s) => s).join(": ");
|
|
269
|
+
const meta = { url: url && [this.options.baseUrl, url].join("") };
|
|
270
|
+
let message = [title];
|
|
271
|
+
if (Object.values(meta).filter((o) => o).length) {
|
|
272
|
+
message.push(Object.entries(meta).filter(([, v]) => v).map(([key, value]) => `${key.toUpperCase()}: ${value}`).join("\n"));
|
|
273
|
+
}
|
|
274
|
+
if (((((err.response || {}).data || {}).errors || [])[0] || {}).detail) {
|
|
275
|
+
message.push(err.response.data.errors[0].detail);
|
|
276
|
+
}
|
|
277
|
+
const error = Error(message.join("\n\n"));
|
|
278
|
+
error.response = err.response;
|
|
279
|
+
error.druxt = context;
|
|
280
|
+
throw error;
|
|
281
|
+
}
|
|
282
|
+
async get(url, options) {
|
|
283
|
+
try {
|
|
284
|
+
const res = await this.axios.get(url, options);
|
|
285
|
+
this.checkPermissions(res);
|
|
286
|
+
return res;
|
|
287
|
+
} catch (err) {
|
|
288
|
+
this.error(err, { url });
|
|
289
|
+
}
|
|
290
|
+
}
|
|
143
291
|
async getCollection(type, query) {
|
|
144
292
|
const { href } = await this.getIndex(type);
|
|
145
293
|
if (!href) {
|
|
146
294
|
return false;
|
|
147
295
|
}
|
|
148
296
|
const url = this.buildQueryUrl(href, query);
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
return res.data;
|
|
297
|
+
const { data } = await this.get(url);
|
|
298
|
+
return data;
|
|
152
299
|
}
|
|
153
300
|
async getCollectionAll(type, query) {
|
|
154
301
|
const collections = [];
|
|
@@ -168,16 +315,27 @@ class DruxtClient {
|
|
|
168
315
|
if (this.index && resource) {
|
|
169
316
|
return this.index[resource] ? this.index[resource] : false;
|
|
170
317
|
}
|
|
171
|
-
|
|
318
|
+
const url = this.options.endpoint;
|
|
319
|
+
const { data } = await this.get(url);
|
|
320
|
+
let index = data.links;
|
|
321
|
+
if (typeof index !== "object") {
|
|
322
|
+
const err = { response: { statusText: "Invalid JSON:API endpoint" } };
|
|
323
|
+
this.error(err, { url });
|
|
324
|
+
}
|
|
172
325
|
const baseUrl = this.options.baseUrl;
|
|
173
326
|
index = Object.fromEntries(Object.entries(index).map(([key, value]) => {
|
|
174
327
|
value.href = value.href.replace(baseUrl, "");
|
|
175
328
|
return [key, value];
|
|
176
329
|
}));
|
|
177
330
|
if (index[this.options.jsonapiResourceConfig]) {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
331
|
+
let resources = [];
|
|
332
|
+
try {
|
|
333
|
+
resources = (await this.get(index[this.options.jsonapiResourceConfig].href)).data.data;
|
|
334
|
+
} catch (err) {
|
|
335
|
+
this.log.warn(err.message);
|
|
336
|
+
}
|
|
337
|
+
for (const resourceType in resources) {
|
|
338
|
+
const resource2 = resources[resourceType];
|
|
181
339
|
const internal = resource2.attributes.drupal_internal__id.split("--");
|
|
182
340
|
const item = {
|
|
183
341
|
resourceType: resource2.attributes.resourceType,
|
|
@@ -193,11 +351,7 @@ class DruxtClient {
|
|
|
193
351
|
}
|
|
194
352
|
}
|
|
195
353
|
this.index = index;
|
|
196
|
-
|
|
197
|
-
const response = this.index[resource] ? this.index[resource] : false;
|
|
198
|
-
return response;
|
|
199
|
-
}
|
|
200
|
-
return this.index;
|
|
354
|
+
return resource ? this.index[resource] || false : this.index;
|
|
201
355
|
}
|
|
202
356
|
async getRelated(type, id, related, query) {
|
|
203
357
|
if (!id || !type || !related) {
|
|
@@ -208,12 +362,8 @@ class DruxtClient {
|
|
|
208
362
|
href = this.options.endpoint + "/" + type.replace("--", "/");
|
|
209
363
|
}
|
|
210
364
|
const url = this.buildQueryUrl(`${href}/${id}/${related}`, query);
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
return related2.data;
|
|
214
|
-
} catch (e) {
|
|
215
|
-
return false;
|
|
216
|
-
}
|
|
365
|
+
const { data } = await this.get(url);
|
|
366
|
+
return data;
|
|
217
367
|
}
|
|
218
368
|
async getResource(type, id, query) {
|
|
219
369
|
if (!id || !type) {
|
|
@@ -223,13 +373,9 @@ class DruxtClient {
|
|
|
223
373
|
if (!href) {
|
|
224
374
|
href = this.options.endpoint + "/" + type.replace("--", "/");
|
|
225
375
|
}
|
|
226
|
-
const url = this.buildQueryUrl(
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
return resource.data;
|
|
230
|
-
} catch (e) {
|
|
231
|
-
return false;
|
|
232
|
-
}
|
|
376
|
+
const url = this.buildQueryUrl([href, id].join("/"), query);
|
|
377
|
+
const { data } = await this.get(url);
|
|
378
|
+
return data;
|
|
233
379
|
}
|
|
234
380
|
async updateResource(resource) {
|
|
235
381
|
const { href } = await this.getIndex(resource.type);
|
|
@@ -245,7 +391,7 @@ class DruxtClient {
|
|
|
245
391
|
}
|
|
246
392
|
});
|
|
247
393
|
} catch (err) {
|
|
248
|
-
|
|
394
|
+
this.error(err);
|
|
249
395
|
}
|
|
250
396
|
return response;
|
|
251
397
|
}
|
|
@@ -256,7 +402,7 @@ const getDrupalJsonApiParams = (query) => {
|
|
|
256
402
|
};
|
|
257
403
|
|
|
258
404
|
const dehydrateResources = ({ commit, queryObject, resources }) => {
|
|
259
|
-
return resources.map((data) => {
|
|
405
|
+
return (resources || []).map((data) => {
|
|
260
406
|
const link = decodeURI(((data.links || {}).self || {}).href || "");
|
|
261
407
|
const href = typeof (queryObject.fields || {})[data.type] === "string" ? [link.split("?")[0], `fields[${data.type}]=${queryObject.fields[data.type]}`].join("?") : link;
|
|
262
408
|
commit("druxt/addResource", {
|
|
@@ -447,5 +593,7 @@ class DruxtClass {
|
|
|
447
593
|
}
|
|
448
594
|
}
|
|
449
595
|
|
|
596
|
+
DruxtNuxtModule.meta = require("../package.json");
|
|
597
|
+
|
|
450
598
|
export default DruxtNuxtModule;
|
|
451
599
|
export { DruxtClass, DruxtClient, DruxtStore };
|