@tinacms/app 0.0.12 → 0.0.14

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.
@@ -1,351 +0,0 @@
1
- /**
2
- Copyright 2021 Forestry.io Holdings, Inc.
3
- Licensed under the Apache License, Version 2.0 (the "License");
4
- you may not use this file except in compliance with the License.
5
- You may obtain a copy of the License at
6
- http://www.apache.org/licenses/LICENSE-2.0
7
- Unless required by applicable law or agreed to in writing, software
8
- distributed under the License is distributed on an "AS IS" BASIS,
9
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
- See the License for the specific language governing permissions and
11
- limitations under the License.
12
- */
13
- import { Client, Form, FormOptions, TinaCMS } from 'tinacms'
14
- import { GlobalFormPlugin } from 'tinacms'
15
- import { assign, createMachine } from 'xstate'
16
- import { resolveForm, Templateable } from '@tinacms/schema-tools'
17
- import { sendParent } from 'xstate/lib/actions'
18
- import * as util from './util'
19
- import * as G from 'graphql'
20
- import type { DocumentBlueprint } from '../formify/types'
21
- import { SelectionNode } from 'graphql'
22
-
23
- export type DataType = Record<string, unknown>
24
-
25
- type Data = {
26
- _internalValues: object
27
- _internalSys: {
28
- breadcrumbs: string[]
29
- basename: string
30
- filename: string
31
- path: string
32
- extension: string
33
- relativePath: string
34
- title?: string
35
- template: string
36
- collection: {
37
- name: string
38
- slug: string
39
- label: string
40
- path: string
41
- format: string
42
- matches?: string
43
- templates?: object
44
- fields?: object
45
- __typename: string
46
- }
47
- }
48
- }
49
-
50
- type ContextType = {
51
- id: string
52
- data: null | Data
53
- form: null | Form
54
- cms: TinaCMS
55
- formifyCallback: (args: any) => Form
56
- locations: string[]
57
- subDocuments: string[]
58
- allBlueprints: DocumentBlueprint[]
59
- }
60
-
61
- export const documentMachine = createMachine(
62
- {
63
- tsTypes: {} as import('./document-machine.typegen').Typegen0,
64
- // predictableActionArguments: true,
65
- schema: {
66
- context: {} as ContextType,
67
- services: {} as {
68
- initializer: {
69
- data: {
70
- form: Form
71
- data: Data
72
- }
73
- }
74
- scanner: {
75
- data: {
76
- data: object
77
- }
78
- }
79
- },
80
- events: {} as
81
- | {
82
- type: 'ADD_LOCATION'
83
- value: string
84
- }
85
- | {
86
- type: 'INIT'
87
- }
88
- | {
89
- type: 'SCAN'
90
- }
91
- | {
92
- type: 'RESCAN'
93
- },
94
- },
95
- initial: 'initializing',
96
- states: {
97
- initializing: {
98
- invoke: {
99
- src: 'initializer',
100
- onDone: {
101
- actions: ['storeFormAndData', 'notifyParent'],
102
- target: 'ready',
103
- },
104
- onError: {
105
- target: 'error',
106
- actions: 'handleError',
107
- },
108
- },
109
- },
110
- ready: {},
111
- error: {},
112
- },
113
- },
114
- {
115
- actions: {
116
- notifyParent: sendParent((context) => {
117
- return {
118
- type: 'DOCUMENT_READY',
119
- value: context.id,
120
- }
121
- }),
122
- handleError: (_context, event) => {
123
- console.error(event.data)
124
- },
125
- storeFormAndData: assign((context, event) => {
126
- // context.cms.forms.add(event.data.form)
127
- return { ...context, form: event.data.form, data: event.data.data }
128
- }),
129
- },
130
- services: {
131
- initializer: async (context) => {
132
- const selections: SelectionNode[] = []
133
- context.locations.forEach((location) => {
134
- const blueprint = util.getBlueprintFromLocation(
135
- location,
136
- context.allBlueprints
137
- )
138
- // TODO: probably makes more sense to combine
139
- // the selections if possible so we don't get conflicting
140
- // return types
141
- selections.push(blueprint.selection)
142
- })
143
- const tina = context.cms.api.tina as Client
144
- const response = await tina.request<{
145
- node: Data
146
- }>(
147
- `query GetNode($id: String!) {
148
- node(id: $id) {
149
- ${selections.map((selection) => G.print(selection)).join('\n')}
150
- ...on Document {
151
- _internalValues: _values
152
- _internalSys: _sys {
153
- breadcrumbs
154
- basename
155
- filename
156
- path
157
- extension
158
- relativePath
159
- title
160
- template
161
- collection {
162
- name
163
- slug
164
- label
165
- path
166
- format
167
- matches
168
- templates
169
- fields
170
- __typename
171
- }
172
- __typename
173
- }
174
- }
175
- }
176
- }`,
177
- { variables: { id: context.id } }
178
- )
179
- const schema = context.cms.api.tina.schema
180
- if (!schema) {
181
- throw new Error(`Schema must be provided`)
182
- }
183
- const collection = schema.getCollection(
184
- response.node._internalSys.collection.name
185
- )
186
- let template: Templateable
187
- if (collection.templates) {
188
- template = collection.templates.find((template) => {
189
- if (typeof template === 'string') {
190
- throw new Error(`Global templates not supported`)
191
- }
192
- return template.name === response.node._internalSys.template
193
- }) as Templateable
194
- } else {
195
- template = collection
196
- }
197
- if (!template) {
198
- throw new Error(
199
- `Unable to find template for node ${response.node._internalSys.path}`
200
- )
201
- }
202
- const resolvedForm = resolveForm({
203
- collection,
204
- basename: response.node._internalSys.filename,
205
- schema,
206
- template,
207
- })
208
- const onSubmit = async (payload) => {
209
- try {
210
- const mutationString = `#graphql
211
- mutation UpdateDocument($collection: String!, $relativePath: String!, $params: DocumentMutation!) {
212
- updateDocument(collection: $collection, relativePath: $relativePath, params: $params) {
213
- __typename
214
- }
215
- }
216
- `
217
-
218
- await context.cms.api.tina.request(mutationString, {
219
- variables: {
220
- collection: response.node._internalSys.collection.name,
221
- relativePath: response.node._internalSys.relativePath,
222
- params: schema.transformPayload(
223
- response.node._internalSys.collection.name,
224
- payload
225
- ),
226
- },
227
- })
228
- context.cms.alerts.success('Document saved!')
229
- } catch (e) {
230
- context.cms.alerts.error('There was a problem saving your document')
231
- console.error(e)
232
- }
233
- }
234
- const formConfig = {
235
- id: context.id,
236
- label:
237
- response.node._internalSys.title ||
238
- response.node._internalSys.collection.label,
239
- initialValues: response.node._internalValues,
240
- fields: resolvedForm.fields,
241
- onSubmit,
242
- }
243
- const formifyCallback = context.formifyCallback
244
- const form = buildForm(
245
- formConfig,
246
- context.cms,
247
- (args) => {
248
- if (formifyCallback) {
249
- return formifyCallback(args, context.cms)
250
- } else {
251
- return args.createForm(args.formConfig)
252
- }
253
- },
254
- true,
255
- onSubmit
256
- )
257
- return { form, data: response.node }
258
- },
259
- },
260
- }
261
- )
262
-
263
- type FormCreator = (formConfig: FormOptions<any>) => Form
264
- interface GlobalFormOptions {
265
- icon?: any
266
- layout: 'fullscreen' | 'popup'
267
- }
268
- type GlobalFormCreator = (
269
- formConfig: FormOptions<any>,
270
- options?: GlobalFormOptions
271
- ) => Form
272
- interface GlobalFormOptions {
273
- icon?: any
274
- layout: 'fullscreen' | 'popup'
275
- }
276
- export interface FormifyArgs {
277
- formConfig: FormOptions<any>
278
- createForm: FormCreator
279
- createGlobalForm: FormCreator
280
- skip?: () => void
281
- }
282
-
283
- export type formifyCallback = (args: FormifyArgs, cms: TinaCMS) => Form | void
284
- export type onSubmitArgs = {
285
- /**
286
- * @deprecated queryString is actually a mutation string, use `mutationString` instead
287
- */
288
- queryString: string
289
- mutationString: string
290
- variables: object
291
- }
292
-
293
- export const generateFormCreators = (cms: TinaCMS, showInSidebar?: boolean) => {
294
- const createForm = (formConfig) => {
295
- return new Form(formConfig)
296
- }
297
- const createGlobalForm: GlobalFormCreator = (
298
- formConfig,
299
- options?: { icon?: any; layout: 'fullscreen' | 'popup' }
300
- ) => {
301
- const form = new Form({
302
- ...formConfig,
303
- global: { global: true, ...options },
304
- })
305
- return form
306
- }
307
- return { createForm, createGlobalForm }
308
- }
309
-
310
- export const buildForm = (
311
- formConfig: any,
312
- cms: TinaCMS,
313
- formify: formifyCallback,
314
- showInSidebar: boolean = false,
315
- onSubmit?: (args: any) => void
316
- ): Form | undefined => {
317
- const { createForm, createGlobalForm } = generateFormCreators(
318
- cms,
319
- showInSidebar
320
- )
321
- const SKIPPED = 'SKIPPED'
322
- let form
323
- let skipped
324
- const skip = () => {
325
- skipped = SKIPPED
326
- }
327
- if (skipped) return
328
-
329
- if (formify) {
330
- form = formify(
331
- {
332
- formConfig,
333
- createForm,
334
- createGlobalForm,
335
- skip,
336
- },
337
- cms
338
- )
339
- } else {
340
- form = createForm(formConfig)
341
- }
342
-
343
- if (!(form instanceof Form)) {
344
- if (skipped === SKIPPED) {
345
- return
346
- }
347
- throw new Error('formify must return a form or skip()')
348
- }
349
-
350
- return form
351
- }