@cooperco/cooper-component-library 0.1.130 → 0.1.131
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/cms/0096-delete-body-copy-content-type.cjs +70 -4
- package/dist/cms/0097-create-table-module.cjs +174 -0
- package/dist/cms/0098-update-container-collection-filtered-table.cjs +54 -0
- package/dist/cms/containerCollectionModule.query.ts +6 -0
- package/dist/cms/contentful/migrations/scripts/0096-delete-body-copy-content-type.cjs +70 -4
- package/dist/cms/contentful/migrations/scripts/0097-create-table-module.cjs +174 -0
- package/dist/cms/contentful/migrations/scripts/0098-update-container-collection-filtered-table.cjs +54 -0
- package/dist/cms/contentful/queries/containerCollectionModule.query.js +6 -0
- package/dist/cms/contentful/queries/containerCollectionModule.query.ts +6 -0
- package/dist/cms/contentful/queries/index.d.ts +1 -0
- package/dist/cms/contentful/queries/index.js +1 -0
- package/dist/cms/contentful/queries/index.ts +2 -0
- package/dist/cms/contentful/queries/tableModule.query.d.ts +2 -0
- package/dist/cms/contentful/queries/tableModule.query.js +60 -0
- package/dist/cms/contentful/queries/tableModule.query.ts +62 -0
- package/dist/cms/index.ts +2 -0
- package/dist/cms/migrations/scripts/0096-delete-body-copy-content-type.cjs +70 -4
- package/dist/cms/migrations/scripts/0097-create-table-module.cjs +174 -0
- package/dist/cms/migrations/scripts/0098-update-container-collection-filtered-table.cjs +54 -0
- package/dist/cms/queries/containerCollectionModule.query.ts +6 -0
- package/dist/cms/queries/index.ts +2 -0
- package/dist/cms/queries/tableModule.query.ts +62 -0
- package/dist/cms/scripts/0096-delete-body-copy-content-type.cjs +70 -4
- package/dist/cms/scripts/0097-create-table-module.cjs +174 -0
- package/dist/cms/scripts/0098-update-container-collection-filtered-table.cjs +54 -0
- package/dist/cms/tableModule.query.ts +62 -0
- package/dist/lib/component-lib.js +3850 -3456
- package/dist/lib/component-lib.umd.cjs +23 -23
- package/dist/lib/css/main.css +48 -18
- package/dist/lib/style.css +1 -1
- package/dist/types/cms/contentful/queries/index.d.ts +1 -0
- package/dist/types/cms/contentful/queries/tableModule.query.d.ts +2 -0
- package/dist/types/src/components/ContainerCollectionModule/ContainerCollectionModule.d.ts +4 -1
- package/dist/types/src/components/TableModule/TableModule.d.ts +51 -0
- package/dist/types/src/components/TableModule/TableModule.vue.d.ts +3 -0
- package/dist/types/src/components/components.d.ts +1 -0
- package/dist/types/src/components/types.d.ts +1 -0
- package/dist/types/src/config/defaultPassthrough/index.d.ts +1 -0
- package/dist/types/src/config/defaultPassthrough/types.d.ts +3 -1
- package/dist/types/src/types.d.ts +1 -0
- package/package.json +1 -1
|
@@ -95,8 +95,46 @@ async function deleteEntry(makeRequest, entryId) {
|
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Check whether a content type exists on the current environment.
|
|
100
|
+
*
|
|
101
|
+
* @param {Function} makeRequest
|
|
102
|
+
* @param {string} contentTypeId
|
|
103
|
+
* @returns {Promise<boolean>}
|
|
104
|
+
*/
|
|
105
|
+
async function contentTypeExists(makeRequest, contentTypeId) {
|
|
106
|
+
try {
|
|
107
|
+
await makeRequest({
|
|
108
|
+
method: 'GET',
|
|
109
|
+
url: `/content_types/${contentTypeId}`,
|
|
110
|
+
})
|
|
111
|
+
return true
|
|
112
|
+
} catch (error) {
|
|
113
|
+
if (
|
|
114
|
+
error?.status === 404 ||
|
|
115
|
+
error?.response?.status === 404 ||
|
|
116
|
+
error?.name === 'NotFound'
|
|
117
|
+
) {
|
|
118
|
+
return false
|
|
119
|
+
}
|
|
120
|
+
// contentful-sdk-core packs status into error.message JSON
|
|
121
|
+
if (typeof error?.message === 'string') {
|
|
122
|
+
try {
|
|
123
|
+
const parsed = JSON.parse(error.message)
|
|
124
|
+
if (parsed?.status === 404) {
|
|
125
|
+
return false
|
|
126
|
+
}
|
|
127
|
+
} catch {
|
|
128
|
+
// message is not JSON — ignore
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
throw error
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
98
135
|
/**
|
|
99
136
|
* Delete every entry of the given content type (paginated).
|
|
137
|
+
* Returns early if the content type does not exist (nothing to delete).
|
|
100
138
|
*
|
|
101
139
|
* @param {Function} makeRequest
|
|
102
140
|
* @param {string} contentTypeId
|
|
@@ -107,10 +145,30 @@ async function deleteAllEntriesOfContentType(makeRequest, contentTypeId) {
|
|
|
107
145
|
// Re-query from skip 0 after each page of deletes — indexes shift as
|
|
108
146
|
// entries drop, so a single ascending skip walk would miss rows.
|
|
109
147
|
for (;;) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
148
|
+
let page
|
|
149
|
+
try {
|
|
150
|
+
page = await makeRequest({
|
|
151
|
+
method: 'GET',
|
|
152
|
+
url: `/entries?content_type=${contentTypeId}&limit=${limit}&skip=0&sys.archivedAt[exists]=false`,
|
|
153
|
+
})
|
|
154
|
+
} catch (error) {
|
|
155
|
+
// Contentful returns 400 with unknownContentType when the content
|
|
156
|
+
// type doesn't exist — treat it the same as "no entries".
|
|
157
|
+
const errorMessage =
|
|
158
|
+
typeof error?.message === 'string' ? error.message : ''
|
|
159
|
+
if (
|
|
160
|
+
error?.status === 400 ||
|
|
161
|
+
error?.response?.status === 400 ||
|
|
162
|
+
errorMessage.includes('unknownContentType')
|
|
163
|
+
) {
|
|
164
|
+
process.stdout.write(
|
|
165
|
+
`[0096] Content type "${contentTypeId}" does not exist ` +
|
|
166
|
+
`or is not queryable — skipping entry deletion.\n`
|
|
167
|
+
)
|
|
168
|
+
return
|
|
169
|
+
}
|
|
170
|
+
throw error
|
|
171
|
+
}
|
|
114
172
|
|
|
115
173
|
const items = page.items ?? []
|
|
116
174
|
if (items.length === 0) {
|
|
@@ -127,6 +185,14 @@ module.exports = {
|
|
|
127
185
|
// @ts-check
|
|
128
186
|
/** @type { import('contentful-migration').MigrationFunction } */
|
|
129
187
|
up: async function (migration, { makeRequest }) {
|
|
188
|
+
const exists = await contentTypeExists(makeRequest, 'bodyCopy')
|
|
189
|
+
if (!exists) {
|
|
190
|
+
process.stdout.write(
|
|
191
|
+
'[0096] bodyCopy content type does not exist — nothing to delete.\n'
|
|
192
|
+
)
|
|
193
|
+
return
|
|
194
|
+
}
|
|
195
|
+
|
|
130
196
|
await deleteAllEntriesOfContentType(makeRequest, 'bodyCopy')
|
|
131
197
|
migration.deleteContentType('bodyCopy')
|
|
132
198
|
},
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
const addEntryNameField = require('../helpers/addEntryNameField.cjs')
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
// @ts-check
|
|
5
|
+
/** @type { import('contentful-migration').MigrationFunction } */
|
|
6
|
+
up: function (migration) {
|
|
7
|
+
const tableModule = migration.createContentType('tableModule', {
|
|
8
|
+
name: 'Table Module',
|
|
9
|
+
displayField: 'entryName',
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
// Add mandatory entryName field
|
|
13
|
+
addEntryNameField(tableModule)
|
|
14
|
+
|
|
15
|
+
// Title
|
|
16
|
+
tableModule.createField('title', {
|
|
17
|
+
name: 'Title',
|
|
18
|
+
type: 'Symbol',
|
|
19
|
+
required: false,
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
// Description (RichText)
|
|
23
|
+
tableModule.createField('description', {
|
|
24
|
+
name: 'Description',
|
|
25
|
+
type: 'RichText',
|
|
26
|
+
required: false,
|
|
27
|
+
validations: [
|
|
28
|
+
{
|
|
29
|
+
enabledMarks: ['bold', 'italic', 'underline'],
|
|
30
|
+
message: 'Only bold, italic, and underline marks are allowed',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
enabledNodeTypes: [
|
|
34
|
+
'ordered-list',
|
|
35
|
+
'unordered-list',
|
|
36
|
+
'hr',
|
|
37
|
+
'hyperlink',
|
|
38
|
+
'embedded-entry-inline',
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
nodes: {
|
|
43
|
+
'embedded-entry-inline': [
|
|
44
|
+
{
|
|
45
|
+
linkContentType: ['highlightedText'],
|
|
46
|
+
message: 'You can only embed Highlighted Text.',
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
// Body Copy Alignment
|
|
55
|
+
tableModule.createField('bodyCopyAlignment', {
|
|
56
|
+
name: 'Body Copy Alignment',
|
|
57
|
+
type: 'Symbol',
|
|
58
|
+
required: false,
|
|
59
|
+
validations: [
|
|
60
|
+
{
|
|
61
|
+
in: ['Left', 'Center', 'Right'],
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
})
|
|
65
|
+
tableModule.changeFieldControl('bodyCopyAlignment', 'builtin', 'dropdown', {
|
|
66
|
+
helpText: 'Override the description copy text alignment independently. If not set, it will follow the default alignment.',
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
// Table Highlight
|
|
70
|
+
tableModule.createField('tableHighlight', {
|
|
71
|
+
name: 'Table Highlight',
|
|
72
|
+
type: 'Symbol',
|
|
73
|
+
required: false,
|
|
74
|
+
validations: [
|
|
75
|
+
{
|
|
76
|
+
in: ['Row', 'Column'],
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
})
|
|
80
|
+
tableModule.changeFieldControl('tableHighlight', 'builtin', 'dropdown', {
|
|
81
|
+
helpText: 'Highlight a specific row or column in the table.',
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
// Table (RichText with table node enabled)
|
|
85
|
+
tableModule.createField('table', {
|
|
86
|
+
name: 'Table',
|
|
87
|
+
type: 'RichText',
|
|
88
|
+
required: true,
|
|
89
|
+
validations: [
|
|
90
|
+
{
|
|
91
|
+
enabledMarks: ['bold', 'italic', 'underline'],
|
|
92
|
+
message: 'Only bold, italic, and underline marks are allowed',
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
enabledNodeTypes: [
|
|
96
|
+
'table',
|
|
97
|
+
'hyperlink',
|
|
98
|
+
'embedded-entry-inline',
|
|
99
|
+
'unordered-list',
|
|
100
|
+
'ordered-list',
|
|
101
|
+
],
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
nodes: {
|
|
105
|
+
'embedded-entry-inline': [
|
|
106
|
+
{
|
|
107
|
+
linkContentType: ['highlightedText'],
|
|
108
|
+
message: 'You can only embed Highlighted Text.',
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
// Filter columns (Symbol list)
|
|
117
|
+
tableModule.createField('filterColumns', {
|
|
118
|
+
name: 'Filter Columns',
|
|
119
|
+
type: 'Array',
|
|
120
|
+
required: false,
|
|
121
|
+
items: {
|
|
122
|
+
type: 'Symbol',
|
|
123
|
+
validations: [],
|
|
124
|
+
},
|
|
125
|
+
})
|
|
126
|
+
tableModule.changeFieldControl('filterColumns', 'builtin', 'tagEditor', {
|
|
127
|
+
helpText: 'Enter the exact column heading(s) to make filterable. Max 4 suggested.',
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
// Footer (RichText)
|
|
131
|
+
tableModule.createField('footer', {
|
|
132
|
+
name: 'Footer',
|
|
133
|
+
type: 'RichText',
|
|
134
|
+
required: false,
|
|
135
|
+
validations: [
|
|
136
|
+
{
|
|
137
|
+
enabledMarks: ['bold', 'italic', 'underline'],
|
|
138
|
+
message: 'Only bold, italic, and underline marks are allowed',
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
enabledNodeTypes: ['hyperlink', 'embedded-entry-inline'],
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
nodes: {
|
|
145
|
+
'embedded-entry-inline': [
|
|
146
|
+
{
|
|
147
|
+
linkContentType: ['highlightedText'],
|
|
148
|
+
message: 'You can only embed Highlighted Text.',
|
|
149
|
+
},
|
|
150
|
+
],
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
],
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
// Background Color
|
|
157
|
+
tableModule.createField('backgroundColor', {
|
|
158
|
+
name: 'Background Color',
|
|
159
|
+
type: 'Symbol',
|
|
160
|
+
required: false,
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
// Change field control for Color Picker App
|
|
164
|
+
tableModule.changeFieldControl(
|
|
165
|
+
'backgroundColor',
|
|
166
|
+
'app',
|
|
167
|
+
process.env.COLOR_PICKER_APP_ID
|
|
168
|
+
)
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
down: async function (migration) {
|
|
172
|
+
await migration.deleteContentType('tableModule')
|
|
173
|
+
},
|
|
174
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
// @ts-check
|
|
3
|
+
/** @type { import('contentful-migration').MigrationFunction } */
|
|
4
|
+
up: function (migration) {
|
|
5
|
+
const collection = migration.editContentType('containerCollectionModule')
|
|
6
|
+
|
|
7
|
+
// Subheadline field
|
|
8
|
+
collection.createField('subheadline', {
|
|
9
|
+
name: 'Subheadline',
|
|
10
|
+
type: 'Symbol',
|
|
11
|
+
required: false,
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
// Order the fields
|
|
15
|
+
collection.moveField('subheadline').afterField('headline')
|
|
16
|
+
|
|
17
|
+
// Update link validations for modules collection to accept splitModule and tableModule
|
|
18
|
+
collection.editField('modules').items({
|
|
19
|
+
type: 'Link',
|
|
20
|
+
linkType: 'Entry',
|
|
21
|
+
validations: [
|
|
22
|
+
{
|
|
23
|
+
linkContentType: ['splitModule', 'tableModule'],
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
// Add helper text to modules field
|
|
29
|
+
collection.changeFieldControl('modules', 'builtin', 'entryCardsEditor', {
|
|
30
|
+
helpText:
|
|
31
|
+
'Add Table Modules to render filtered tables with tabs, or Split Modules for standard collections.',
|
|
32
|
+
})
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
// @ts-check
|
|
36
|
+
/** @type { import('contentful-migration').MigrationFunction } */
|
|
37
|
+
down: function (migration) {
|
|
38
|
+
const collection = migration.editContentType('containerCollectionModule')
|
|
39
|
+
|
|
40
|
+
// Delete subheadline field
|
|
41
|
+
collection.deleteField('subheadline')
|
|
42
|
+
|
|
43
|
+
// Revert validations on modules collection to splitModule only
|
|
44
|
+
collection.editField('modules').items({
|
|
45
|
+
type: 'Link',
|
|
46
|
+
linkType: 'Entry',
|
|
47
|
+
validations: [
|
|
48
|
+
{
|
|
49
|
+
linkContentType: ['splitModule'],
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
})
|
|
53
|
+
},
|
|
54
|
+
}
|
|
@@ -12,6 +12,7 @@ export const getContainerCollectionModule: DocumentNode = gql`
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
headline
|
|
15
|
+
subheadline
|
|
15
16
|
|
|
16
17
|
modulesCollection {
|
|
17
18
|
items {
|
|
@@ -22,6 +23,11 @@ export const getContainerCollectionModule: DocumentNode = gql`
|
|
|
22
23
|
id
|
|
23
24
|
}
|
|
24
25
|
}
|
|
26
|
+
... on TableModule {
|
|
27
|
+
sys {
|
|
28
|
+
id
|
|
29
|
+
}
|
|
30
|
+
}
|
|
25
31
|
}
|
|
26
32
|
}
|
|
27
33
|
|
|
@@ -95,8 +95,46 @@ async function deleteEntry(makeRequest, entryId) {
|
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Check whether a content type exists on the current environment.
|
|
100
|
+
*
|
|
101
|
+
* @param {Function} makeRequest
|
|
102
|
+
* @param {string} contentTypeId
|
|
103
|
+
* @returns {Promise<boolean>}
|
|
104
|
+
*/
|
|
105
|
+
async function contentTypeExists(makeRequest, contentTypeId) {
|
|
106
|
+
try {
|
|
107
|
+
await makeRequest({
|
|
108
|
+
method: 'GET',
|
|
109
|
+
url: `/content_types/${contentTypeId}`,
|
|
110
|
+
})
|
|
111
|
+
return true
|
|
112
|
+
} catch (error) {
|
|
113
|
+
if (
|
|
114
|
+
error?.status === 404 ||
|
|
115
|
+
error?.response?.status === 404 ||
|
|
116
|
+
error?.name === 'NotFound'
|
|
117
|
+
) {
|
|
118
|
+
return false
|
|
119
|
+
}
|
|
120
|
+
// contentful-sdk-core packs status into error.message JSON
|
|
121
|
+
if (typeof error?.message === 'string') {
|
|
122
|
+
try {
|
|
123
|
+
const parsed = JSON.parse(error.message)
|
|
124
|
+
if (parsed?.status === 404) {
|
|
125
|
+
return false
|
|
126
|
+
}
|
|
127
|
+
} catch {
|
|
128
|
+
// message is not JSON — ignore
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
throw error
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
98
135
|
/**
|
|
99
136
|
* Delete every entry of the given content type (paginated).
|
|
137
|
+
* Returns early if the content type does not exist (nothing to delete).
|
|
100
138
|
*
|
|
101
139
|
* @param {Function} makeRequest
|
|
102
140
|
* @param {string} contentTypeId
|
|
@@ -107,10 +145,30 @@ async function deleteAllEntriesOfContentType(makeRequest, contentTypeId) {
|
|
|
107
145
|
// Re-query from skip 0 after each page of deletes — indexes shift as
|
|
108
146
|
// entries drop, so a single ascending skip walk would miss rows.
|
|
109
147
|
for (;;) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
148
|
+
let page
|
|
149
|
+
try {
|
|
150
|
+
page = await makeRequest({
|
|
151
|
+
method: 'GET',
|
|
152
|
+
url: `/entries?content_type=${contentTypeId}&limit=${limit}&skip=0&sys.archivedAt[exists]=false`,
|
|
153
|
+
})
|
|
154
|
+
} catch (error) {
|
|
155
|
+
// Contentful returns 400 with unknownContentType when the content
|
|
156
|
+
// type doesn't exist — treat it the same as "no entries".
|
|
157
|
+
const errorMessage =
|
|
158
|
+
typeof error?.message === 'string' ? error.message : ''
|
|
159
|
+
if (
|
|
160
|
+
error?.status === 400 ||
|
|
161
|
+
error?.response?.status === 400 ||
|
|
162
|
+
errorMessage.includes('unknownContentType')
|
|
163
|
+
) {
|
|
164
|
+
process.stdout.write(
|
|
165
|
+
`[0096] Content type "${contentTypeId}" does not exist ` +
|
|
166
|
+
`or is not queryable — skipping entry deletion.\n`
|
|
167
|
+
)
|
|
168
|
+
return
|
|
169
|
+
}
|
|
170
|
+
throw error
|
|
171
|
+
}
|
|
114
172
|
|
|
115
173
|
const items = page.items ?? []
|
|
116
174
|
if (items.length === 0) {
|
|
@@ -127,6 +185,14 @@ module.exports = {
|
|
|
127
185
|
// @ts-check
|
|
128
186
|
/** @type { import('contentful-migration').MigrationFunction } */
|
|
129
187
|
up: async function (migration, { makeRequest }) {
|
|
188
|
+
const exists = await contentTypeExists(makeRequest, 'bodyCopy')
|
|
189
|
+
if (!exists) {
|
|
190
|
+
process.stdout.write(
|
|
191
|
+
'[0096] bodyCopy content type does not exist — nothing to delete.\n'
|
|
192
|
+
)
|
|
193
|
+
return
|
|
194
|
+
}
|
|
195
|
+
|
|
130
196
|
await deleteAllEntriesOfContentType(makeRequest, 'bodyCopy')
|
|
131
197
|
migration.deleteContentType('bodyCopy')
|
|
132
198
|
},
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
const addEntryNameField = require('../helpers/addEntryNameField.cjs')
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
// @ts-check
|
|
5
|
+
/** @type { import('contentful-migration').MigrationFunction } */
|
|
6
|
+
up: function (migration) {
|
|
7
|
+
const tableModule = migration.createContentType('tableModule', {
|
|
8
|
+
name: 'Table Module',
|
|
9
|
+
displayField: 'entryName',
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
// Add mandatory entryName field
|
|
13
|
+
addEntryNameField(tableModule)
|
|
14
|
+
|
|
15
|
+
// Title
|
|
16
|
+
tableModule.createField('title', {
|
|
17
|
+
name: 'Title',
|
|
18
|
+
type: 'Symbol',
|
|
19
|
+
required: false,
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
// Description (RichText)
|
|
23
|
+
tableModule.createField('description', {
|
|
24
|
+
name: 'Description',
|
|
25
|
+
type: 'RichText',
|
|
26
|
+
required: false,
|
|
27
|
+
validations: [
|
|
28
|
+
{
|
|
29
|
+
enabledMarks: ['bold', 'italic', 'underline'],
|
|
30
|
+
message: 'Only bold, italic, and underline marks are allowed',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
enabledNodeTypes: [
|
|
34
|
+
'ordered-list',
|
|
35
|
+
'unordered-list',
|
|
36
|
+
'hr',
|
|
37
|
+
'hyperlink',
|
|
38
|
+
'embedded-entry-inline',
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
nodes: {
|
|
43
|
+
'embedded-entry-inline': [
|
|
44
|
+
{
|
|
45
|
+
linkContentType: ['highlightedText'],
|
|
46
|
+
message: 'You can only embed Highlighted Text.',
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
// Body Copy Alignment
|
|
55
|
+
tableModule.createField('bodyCopyAlignment', {
|
|
56
|
+
name: 'Body Copy Alignment',
|
|
57
|
+
type: 'Symbol',
|
|
58
|
+
required: false,
|
|
59
|
+
validations: [
|
|
60
|
+
{
|
|
61
|
+
in: ['Left', 'Center', 'Right'],
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
})
|
|
65
|
+
tableModule.changeFieldControl('bodyCopyAlignment', 'builtin', 'dropdown', {
|
|
66
|
+
helpText: 'Override the description copy text alignment independently. If not set, it will follow the default alignment.',
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
// Table Highlight
|
|
70
|
+
tableModule.createField('tableHighlight', {
|
|
71
|
+
name: 'Table Highlight',
|
|
72
|
+
type: 'Symbol',
|
|
73
|
+
required: false,
|
|
74
|
+
validations: [
|
|
75
|
+
{
|
|
76
|
+
in: ['Row', 'Column'],
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
})
|
|
80
|
+
tableModule.changeFieldControl('tableHighlight', 'builtin', 'dropdown', {
|
|
81
|
+
helpText: 'Highlight a specific row or column in the table.',
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
// Table (RichText with table node enabled)
|
|
85
|
+
tableModule.createField('table', {
|
|
86
|
+
name: 'Table',
|
|
87
|
+
type: 'RichText',
|
|
88
|
+
required: true,
|
|
89
|
+
validations: [
|
|
90
|
+
{
|
|
91
|
+
enabledMarks: ['bold', 'italic', 'underline'],
|
|
92
|
+
message: 'Only bold, italic, and underline marks are allowed',
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
enabledNodeTypes: [
|
|
96
|
+
'table',
|
|
97
|
+
'hyperlink',
|
|
98
|
+
'embedded-entry-inline',
|
|
99
|
+
'unordered-list',
|
|
100
|
+
'ordered-list',
|
|
101
|
+
],
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
nodes: {
|
|
105
|
+
'embedded-entry-inline': [
|
|
106
|
+
{
|
|
107
|
+
linkContentType: ['highlightedText'],
|
|
108
|
+
message: 'You can only embed Highlighted Text.',
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
// Filter columns (Symbol list)
|
|
117
|
+
tableModule.createField('filterColumns', {
|
|
118
|
+
name: 'Filter Columns',
|
|
119
|
+
type: 'Array',
|
|
120
|
+
required: false,
|
|
121
|
+
items: {
|
|
122
|
+
type: 'Symbol',
|
|
123
|
+
validations: [],
|
|
124
|
+
},
|
|
125
|
+
})
|
|
126
|
+
tableModule.changeFieldControl('filterColumns', 'builtin', 'tagEditor', {
|
|
127
|
+
helpText: 'Enter the exact column heading(s) to make filterable. Max 4 suggested.',
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
// Footer (RichText)
|
|
131
|
+
tableModule.createField('footer', {
|
|
132
|
+
name: 'Footer',
|
|
133
|
+
type: 'RichText',
|
|
134
|
+
required: false,
|
|
135
|
+
validations: [
|
|
136
|
+
{
|
|
137
|
+
enabledMarks: ['bold', 'italic', 'underline'],
|
|
138
|
+
message: 'Only bold, italic, and underline marks are allowed',
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
enabledNodeTypes: ['hyperlink', 'embedded-entry-inline'],
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
nodes: {
|
|
145
|
+
'embedded-entry-inline': [
|
|
146
|
+
{
|
|
147
|
+
linkContentType: ['highlightedText'],
|
|
148
|
+
message: 'You can only embed Highlighted Text.',
|
|
149
|
+
},
|
|
150
|
+
],
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
],
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
// Background Color
|
|
157
|
+
tableModule.createField('backgroundColor', {
|
|
158
|
+
name: 'Background Color',
|
|
159
|
+
type: 'Symbol',
|
|
160
|
+
required: false,
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
// Change field control for Color Picker App
|
|
164
|
+
tableModule.changeFieldControl(
|
|
165
|
+
'backgroundColor',
|
|
166
|
+
'app',
|
|
167
|
+
process.env.COLOR_PICKER_APP_ID
|
|
168
|
+
)
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
down: async function (migration) {
|
|
172
|
+
await migration.deleteContentType('tableModule')
|
|
173
|
+
},
|
|
174
|
+
}
|
package/dist/cms/contentful/migrations/scripts/0098-update-container-collection-filtered-table.cjs
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
// @ts-check
|
|
3
|
+
/** @type { import('contentful-migration').MigrationFunction } */
|
|
4
|
+
up: function (migration) {
|
|
5
|
+
const collection = migration.editContentType('containerCollectionModule')
|
|
6
|
+
|
|
7
|
+
// Subheadline field
|
|
8
|
+
collection.createField('subheadline', {
|
|
9
|
+
name: 'Subheadline',
|
|
10
|
+
type: 'Symbol',
|
|
11
|
+
required: false,
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
// Order the fields
|
|
15
|
+
collection.moveField('subheadline').afterField('headline')
|
|
16
|
+
|
|
17
|
+
// Update link validations for modules collection to accept splitModule and tableModule
|
|
18
|
+
collection.editField('modules').items({
|
|
19
|
+
type: 'Link',
|
|
20
|
+
linkType: 'Entry',
|
|
21
|
+
validations: [
|
|
22
|
+
{
|
|
23
|
+
linkContentType: ['splitModule', 'tableModule'],
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
// Add helper text to modules field
|
|
29
|
+
collection.changeFieldControl('modules', 'builtin', 'entryCardsEditor', {
|
|
30
|
+
helpText:
|
|
31
|
+
'Add Table Modules to render filtered tables with tabs, or Split Modules for standard collections.',
|
|
32
|
+
})
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
// @ts-check
|
|
36
|
+
/** @type { import('contentful-migration').MigrationFunction } */
|
|
37
|
+
down: function (migration) {
|
|
38
|
+
const collection = migration.editContentType('containerCollectionModule')
|
|
39
|
+
|
|
40
|
+
// Delete subheadline field
|
|
41
|
+
collection.deleteField('subheadline')
|
|
42
|
+
|
|
43
|
+
// Revert validations on modules collection to splitModule only
|
|
44
|
+
collection.editField('modules').items({
|
|
45
|
+
type: 'Link',
|
|
46
|
+
linkType: 'Entry',
|
|
47
|
+
validations: [
|
|
48
|
+
{
|
|
49
|
+
linkContentType: ['splitModule'],
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
})
|
|
53
|
+
},
|
|
54
|
+
}
|
|
@@ -10,6 +10,7 @@ export const getContainerCollectionModule = gql `
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
headline
|
|
13
|
+
subheadline
|
|
13
14
|
|
|
14
15
|
modulesCollection {
|
|
15
16
|
items {
|
|
@@ -20,6 +21,11 @@ export const getContainerCollectionModule = gql `
|
|
|
20
21
|
id
|
|
21
22
|
}
|
|
22
23
|
}
|
|
24
|
+
... on TableModule {
|
|
25
|
+
sys {
|
|
26
|
+
id
|
|
27
|
+
}
|
|
28
|
+
}
|
|
23
29
|
}
|
|
24
30
|
}
|
|
25
31
|
|
|
@@ -12,6 +12,7 @@ export const getContainerCollectionModule: DocumentNode = gql`
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
headline
|
|
15
|
+
subheadline
|
|
15
16
|
|
|
16
17
|
modulesCollection {
|
|
17
18
|
items {
|
|
@@ -22,6 +23,11 @@ export const getContainerCollectionModule: DocumentNode = gql`
|
|
|
22
23
|
id
|
|
23
24
|
}
|
|
24
25
|
}
|
|
26
|
+
... on TableModule {
|
|
27
|
+
sys {
|
|
28
|
+
id
|
|
29
|
+
}
|
|
30
|
+
}
|
|
25
31
|
}
|
|
26
32
|
}
|
|
27
33
|
|