@tanstack/cta-ui 0.10.0-alpha.19 → 0.10.0-alpha.21
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/lib/index.ts +16 -7
- package/lib-dist/index.d.ts +6 -1
- package/lib-dist/index.js +6 -3
- package/package.json +19 -7
- package/public/tailwind.svg +1 -0
- package/public/tanstack.png +0 -0
- package/public/typescript.svg +1 -0
- package/src/components/StatusList.tsx +22 -0
- package/src/components/add-on-info-dialog.tsx +39 -0
- package/src/components/cta-sidebar.tsx +55 -0
- package/src/components/custom-add-on-dialog.tsx +79 -0
- package/src/components/file-navigator.tsx +205 -0
- package/src/components/file-tree.tsx +18 -60
- package/src/components/file-viewer.tsx +11 -3
- package/src/components/sidebar-items/add-ons.tsx +91 -0
- package/src/components/sidebar-items/mode-selector.tsx +55 -0
- package/src/components/sidebar-items/project-name.tsx +29 -0
- package/src/components/sidebar-items/run-add-ons.tsx +71 -0
- package/src/components/sidebar-items/run-create-app.tsx +82 -0
- package/src/components/sidebar-items/starter.tsx +115 -0
- package/src/components/sidebar-items/typescript-switch.tsx +52 -0
- package/src/components/toaster.tsx +29 -0
- package/src/components/ui/button.tsx +21 -19
- package/src/components/ui/dialog.tsx +25 -20
- package/src/components/ui/dropdown-menu.tsx +255 -0
- package/src/components/ui/input.tsx +21 -0
- package/src/components/ui/label.tsx +22 -0
- package/src/components/ui/popover.tsx +46 -0
- package/src/components/ui/separator.tsx +28 -0
- package/src/components/ui/sheet.tsx +137 -0
- package/src/components/ui/sidebar.tsx +726 -0
- package/src/components/ui/skeleton.tsx +13 -0
- package/src/components/ui/sonner.tsx +23 -0
- package/src/components/ui/switch.tsx +29 -0
- package/src/components/ui/toggle-group.tsx +11 -11
- package/src/components/ui/toggle.tsx +15 -13
- package/src/components/ui/tooltip.tsx +61 -0
- package/src/components/ui/tree-view.tsx +17 -12
- package/src/engine-handling/add-to-app-wrapper.ts +114 -0
- package/src/engine-handling/create-app-wrapper.ts +107 -0
- package/src/engine-handling/file-helpers.ts +25 -0
- package/src/engine-handling/framework-registration.ts +11 -0
- package/src/engine-handling/generate-initial-payload.ts +93 -0
- package/src/engine-handling/server-environment.ts +13 -0
- package/src/file-classes.ts +54 -0
- package/src/hooks/use-mobile.ts +19 -0
- package/src/hooks/use-streaming-status.ts +70 -0
- package/src/lib/api.ts +90 -0
- package/src/routeTree.gen.ts +4 -27
- package/src/routes/__root.tsx +36 -7
- package/src/routes/api/add-to-app.ts +21 -0
- package/src/routes/api/create-app.ts +21 -0
- package/src/routes/api/dry-run-add-to-app.ts +16 -0
- package/src/routes/api/dry-run-create-app.ts +16 -0
- package/src/routes/api/initial-payload.ts +10 -0
- package/src/routes/api/load-remote-add-on.ts +42 -0
- package/src/routes/api/load-starter.ts +47 -0
- package/src/routes/api/shutdown.ts +11 -0
- package/src/routes/index.tsx +3 -210
- package/src/store/add-ons.ts +81 -0
- package/src/store/project.ts +268 -0
- package/src/styles.css +47 -0
- package/src/types.d.ts +87 -0
- package/tests/store/add-ons.test.ts +222 -0
- package/vitest.config.ts +6 -0
- package/.cursorrules +0 -7
- package/src/components/Header.tsx +0 -13
- package/src/components/applied-add-on.tsx +0 -149
- package/src/lib/server-fns.ts +0 -78
- package/src/routes/api.demo-names.ts +0 -11
- package/src/routes/demo.tanstack-query.tsx +0 -28
package/src/types.d.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { Mode, StatusStepType } from '@tanstack/cta-engine'
|
|
2
|
+
|
|
3
|
+
export type ApplicationMode = 'add' | 'setup' | 'none'
|
|
4
|
+
|
|
5
|
+
export type StarterInfo = {
|
|
6
|
+
url: string
|
|
7
|
+
id: string
|
|
8
|
+
name: string
|
|
9
|
+
description: string
|
|
10
|
+
version: string
|
|
11
|
+
author: string
|
|
12
|
+
license: string
|
|
13
|
+
mode: Mode
|
|
14
|
+
typescript: boolean
|
|
15
|
+
tailwind: boolean
|
|
16
|
+
banner?: string
|
|
17
|
+
dependsOn?: Array<string>
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Files
|
|
21
|
+
|
|
22
|
+
export type DryRunOutput = {
|
|
23
|
+
files: Record<string, string>
|
|
24
|
+
commands: Array<{
|
|
25
|
+
command: string
|
|
26
|
+
args: Array<string>
|
|
27
|
+
}>
|
|
28
|
+
deletedFiles: Array<string>
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type AddOnInfo = {
|
|
32
|
+
id: string
|
|
33
|
+
name: string
|
|
34
|
+
description: string
|
|
35
|
+
type: 'add-on' | 'example' | 'starter' | 'toolchain'
|
|
36
|
+
modes: Array<'code-router' | 'file-router'>
|
|
37
|
+
smallLogo?: string
|
|
38
|
+
logo?: string
|
|
39
|
+
link: string
|
|
40
|
+
dependsOn?: Array<string>
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type FileClass =
|
|
44
|
+
| 'unchanged'
|
|
45
|
+
| 'added'
|
|
46
|
+
| 'modified'
|
|
47
|
+
| 'deleted'
|
|
48
|
+
| 'overwritten'
|
|
49
|
+
|
|
50
|
+
export type FileTreeItem = TreeDataItem & {
|
|
51
|
+
contents: string
|
|
52
|
+
fullPath: string
|
|
53
|
+
fileClass: FileClass | undefined
|
|
54
|
+
originalFile?: string
|
|
55
|
+
modifiedFile?: string
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export type InitialData = {
|
|
59
|
+
options: SerializedOptions
|
|
60
|
+
output: GeneratorOutput
|
|
61
|
+
localFiles: Record<string, string>
|
|
62
|
+
addOns: {
|
|
63
|
+
'code-router': Array<AddOnInfo>
|
|
64
|
+
'file-router': Array<AddOnInfo>
|
|
65
|
+
}
|
|
66
|
+
applicationMode: ApplicationMode
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export type EventItem = {
|
|
70
|
+
msgType: 'start'
|
|
71
|
+
id: string
|
|
72
|
+
type: StatusStepType
|
|
73
|
+
message: string
|
|
74
|
+
}
|
|
75
|
+
export type EventFinish = {
|
|
76
|
+
msgType: 'finish'
|
|
77
|
+
id: string
|
|
78
|
+
message: string
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export type StreamEvent = EventItem | EventFinish
|
|
82
|
+
|
|
83
|
+
export type StreamItem = {
|
|
84
|
+
id: string
|
|
85
|
+
icon: typeof FileIcon
|
|
86
|
+
message: string
|
|
87
|
+
}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import type { AddOnInfo } from '@/types'
|
|
4
|
+
|
|
5
|
+
import { getAddOnStatus } from '@/store/add-ons'
|
|
6
|
+
|
|
7
|
+
describe('getAddOnStatus', () => {
|
|
8
|
+
it('everything should be enabled if nothing is selected', () => {
|
|
9
|
+
const addOnStatus = getAddOnStatus(
|
|
10
|
+
[
|
|
11
|
+
{
|
|
12
|
+
id: 'add-on-1',
|
|
13
|
+
dependsOn: ['add-on-2'],
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: 'add-on-2',
|
|
17
|
+
},
|
|
18
|
+
] as unknown as Array<AddOnInfo>,
|
|
19
|
+
[],
|
|
20
|
+
[],
|
|
21
|
+
)
|
|
22
|
+
expect(addOnStatus).toEqual({
|
|
23
|
+
'add-on-1': {
|
|
24
|
+
selected: false,
|
|
25
|
+
enabled: true,
|
|
26
|
+
},
|
|
27
|
+
'add-on-2': {
|
|
28
|
+
selected: false,
|
|
29
|
+
enabled: true,
|
|
30
|
+
},
|
|
31
|
+
})
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('should handle a single add-on', () => {
|
|
35
|
+
const addOnStatus = getAddOnStatus(
|
|
36
|
+
[
|
|
37
|
+
{
|
|
38
|
+
id: 'add-on-1',
|
|
39
|
+
dependsOn: [],
|
|
40
|
+
},
|
|
41
|
+
] as unknown as Array<AddOnInfo>,
|
|
42
|
+
['add-on-1'],
|
|
43
|
+
[],
|
|
44
|
+
)
|
|
45
|
+
expect(addOnStatus).toEqual({
|
|
46
|
+
'add-on-1': {
|
|
47
|
+
selected: true,
|
|
48
|
+
enabled: true,
|
|
49
|
+
},
|
|
50
|
+
})
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('should handle a depended-on add-on', () => {
|
|
54
|
+
const addOnStatus = getAddOnStatus(
|
|
55
|
+
[
|
|
56
|
+
{
|
|
57
|
+
id: 'add-on-1',
|
|
58
|
+
dependsOn: ['add-on-2'],
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
id: 'add-on-2',
|
|
62
|
+
dependsOn: [],
|
|
63
|
+
},
|
|
64
|
+
] as unknown as Array<AddOnInfo>,
|
|
65
|
+
['add-on-1'],
|
|
66
|
+
[],
|
|
67
|
+
)
|
|
68
|
+
expect(addOnStatus).toEqual({
|
|
69
|
+
'add-on-1': {
|
|
70
|
+
selected: true,
|
|
71
|
+
enabled: true,
|
|
72
|
+
},
|
|
73
|
+
'add-on-2': {
|
|
74
|
+
selected: true,
|
|
75
|
+
enabled: false,
|
|
76
|
+
},
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('should handle a selected depended-on add-on', () => {
|
|
81
|
+
const addOnStatus = getAddOnStatus(
|
|
82
|
+
[
|
|
83
|
+
{
|
|
84
|
+
id: 'add-on-1',
|
|
85
|
+
dependsOn: ['add-on-2'],
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
id: 'add-on-2',
|
|
89
|
+
dependsOn: [],
|
|
90
|
+
},
|
|
91
|
+
] as unknown as Array<AddOnInfo>,
|
|
92
|
+
['add-on-1', 'add-on-2'],
|
|
93
|
+
[],
|
|
94
|
+
)
|
|
95
|
+
expect(addOnStatus).toEqual({
|
|
96
|
+
'add-on-1': {
|
|
97
|
+
selected: true,
|
|
98
|
+
enabled: true,
|
|
99
|
+
},
|
|
100
|
+
'add-on-2': {
|
|
101
|
+
selected: true,
|
|
102
|
+
enabled: false,
|
|
103
|
+
},
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it('should handle a selected depended-on add-on', () => {
|
|
108
|
+
const addOnStatus = getAddOnStatus(
|
|
109
|
+
[
|
|
110
|
+
{
|
|
111
|
+
id: 'add-on-1',
|
|
112
|
+
dependsOn: ['add-on-2'],
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
id: 'add-on-2',
|
|
116
|
+
dependsOn: [],
|
|
117
|
+
},
|
|
118
|
+
] as unknown as Array<AddOnInfo>,
|
|
119
|
+
['add-on-2'],
|
|
120
|
+
[],
|
|
121
|
+
)
|
|
122
|
+
expect(addOnStatus).toEqual({
|
|
123
|
+
'add-on-1': {
|
|
124
|
+
selected: false,
|
|
125
|
+
enabled: true,
|
|
126
|
+
},
|
|
127
|
+
'add-on-2': {
|
|
128
|
+
selected: true,
|
|
129
|
+
enabled: true,
|
|
130
|
+
},
|
|
131
|
+
})
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
it('wont cycle', () => {
|
|
135
|
+
const addOnStatus = getAddOnStatus(
|
|
136
|
+
[
|
|
137
|
+
{
|
|
138
|
+
id: 'add-on-1',
|
|
139
|
+
dependsOn: ['add-on-2'],
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
id: 'add-on-2',
|
|
143
|
+
dependsOn: ['add-on-1'],
|
|
144
|
+
},
|
|
145
|
+
] as unknown as Array<AddOnInfo>,
|
|
146
|
+
['add-on-1'],
|
|
147
|
+
[],
|
|
148
|
+
)
|
|
149
|
+
expect(addOnStatus).toEqual({
|
|
150
|
+
'add-on-1': {
|
|
151
|
+
selected: true,
|
|
152
|
+
enabled: false,
|
|
153
|
+
},
|
|
154
|
+
'add-on-2': {
|
|
155
|
+
selected: true,
|
|
156
|
+
enabled: false,
|
|
157
|
+
},
|
|
158
|
+
})
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
it('should handle original add-ons', () => {
|
|
162
|
+
const addOnStatus = getAddOnStatus(
|
|
163
|
+
[
|
|
164
|
+
{
|
|
165
|
+
id: 'add-on-1',
|
|
166
|
+
dependsOn: ['add-on-2'],
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
id: 'add-on-2',
|
|
170
|
+
dependsOn: [],
|
|
171
|
+
},
|
|
172
|
+
] as unknown as Array<AddOnInfo>,
|
|
173
|
+
['add-on-1'],
|
|
174
|
+
['add-on-2'],
|
|
175
|
+
)
|
|
176
|
+
expect(addOnStatus).toEqual({
|
|
177
|
+
'add-on-1': {
|
|
178
|
+
selected: true,
|
|
179
|
+
enabled: true,
|
|
180
|
+
},
|
|
181
|
+
'add-on-2': {
|
|
182
|
+
selected: true,
|
|
183
|
+
enabled: false,
|
|
184
|
+
},
|
|
185
|
+
})
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
it('should handle original add-ons with dependencies', () => {
|
|
189
|
+
const addOnStatus = getAddOnStatus(
|
|
190
|
+
[
|
|
191
|
+
{
|
|
192
|
+
id: 'add-on-1',
|
|
193
|
+
dependsOn: ['add-on-2'],
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
id: 'add-on-2',
|
|
197
|
+
dependsOn: ['add-on-3'],
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
id: 'add-on-3',
|
|
201
|
+
dependsOn: [],
|
|
202
|
+
},
|
|
203
|
+
] as unknown as Array<AddOnInfo>,
|
|
204
|
+
['add-on-1'],
|
|
205
|
+
['add-on-2'],
|
|
206
|
+
)
|
|
207
|
+
expect(addOnStatus).toEqual({
|
|
208
|
+
'add-on-1': {
|
|
209
|
+
selected: true,
|
|
210
|
+
enabled: true,
|
|
211
|
+
},
|
|
212
|
+
'add-on-2': {
|
|
213
|
+
selected: true,
|
|
214
|
+
enabled: false,
|
|
215
|
+
},
|
|
216
|
+
'add-on-3': {
|
|
217
|
+
selected: true,
|
|
218
|
+
enabled: false,
|
|
219
|
+
},
|
|
220
|
+
})
|
|
221
|
+
})
|
|
222
|
+
})
|
package/vitest.config.ts
ADDED
package/.cursorrules
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { Link } from "@tanstack/react-router";
|
|
2
|
-
|
|
3
|
-
export default function Header() {
|
|
4
|
-
return (
|
|
5
|
-
<header className="p-2 flex gap-2 bg-white text-black justify-between">
|
|
6
|
-
<nav className="flex flex-row">
|
|
7
|
-
<div className="px-2 font-bold">
|
|
8
|
-
<Link to="/">Home</Link>
|
|
9
|
-
</div>
|
|
10
|
-
</nav>
|
|
11
|
-
</header>
|
|
12
|
-
);
|
|
13
|
-
}
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import { useState } from 'react'
|
|
2
|
-
|
|
3
|
-
import { Checkbox } from '@/components/ui/checkbox'
|
|
4
|
-
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group'
|
|
5
|
-
|
|
6
|
-
import { runCreateApp } from '@/lib/server-fns'
|
|
7
|
-
import FileViewer from './file-viewer'
|
|
8
|
-
import FileTree from './file-tree'
|
|
9
|
-
|
|
10
|
-
import type { Mode } from '@tanstack/cta-engine'
|
|
11
|
-
|
|
12
|
-
export default function AppliedAddOn({
|
|
13
|
-
projectPath,
|
|
14
|
-
output: originalOutput,
|
|
15
|
-
addOnInfo,
|
|
16
|
-
outputWithoutAddon: originalOutputWithoutAddon,
|
|
17
|
-
originalOptions,
|
|
18
|
-
addOns,
|
|
19
|
-
}: {
|
|
20
|
-
projectPath: string
|
|
21
|
-
output: {
|
|
22
|
-
files: Record<string, string>
|
|
23
|
-
}
|
|
24
|
-
outputWithoutAddon: {
|
|
25
|
-
files: Record<string, string>
|
|
26
|
-
}
|
|
27
|
-
addOnInfo: {
|
|
28
|
-
templates: Array<string>
|
|
29
|
-
}
|
|
30
|
-
originalOptions: {
|
|
31
|
-
existingAddOns: Array<string>
|
|
32
|
-
mode: Mode
|
|
33
|
-
}
|
|
34
|
-
addOns: Record<string, Array<any>>
|
|
35
|
-
}) {
|
|
36
|
-
const [selectedFile, setSelectedFile] = useState<string | null>(null)
|
|
37
|
-
|
|
38
|
-
const [options, setOptions] = useState(originalOptions)
|
|
39
|
-
const [output, setOutput] = useState(originalOutput)
|
|
40
|
-
const [outputWithoutAddon, setOutputWithoutAddon] = useState(
|
|
41
|
-
originalOutputWithoutAddon,
|
|
42
|
-
)
|
|
43
|
-
const [selectedAddOns, setSelectedAddOns] = useState<Array<string>>([])
|
|
44
|
-
|
|
45
|
-
async function updateOptions(
|
|
46
|
-
updatedOptions: Partial<typeof options>,
|
|
47
|
-
updatedAddOns: Array<string> = [],
|
|
48
|
-
) {
|
|
49
|
-
const newMode = updatedOptions.mode || options.mode
|
|
50
|
-
const existingAddOns = [
|
|
51
|
-
...(originalOptions.existingAddOns || []),
|
|
52
|
-
...(updatedAddOns || []),
|
|
53
|
-
].filter((id) => addOns[newMode as Mode].some((addOn) => addOn.id === id))
|
|
54
|
-
|
|
55
|
-
const newOptions = {
|
|
56
|
-
...options,
|
|
57
|
-
...updatedOptions,
|
|
58
|
-
existingAddOns,
|
|
59
|
-
}
|
|
60
|
-
setOptions(newOptions)
|
|
61
|
-
const [newOutput, newOutputWithoutAddon] = await Promise.all([
|
|
62
|
-
runCreateApp({
|
|
63
|
-
data: { withAddOn: true, options: newOptions },
|
|
64
|
-
}),
|
|
65
|
-
runCreateApp({
|
|
66
|
-
data: { withAddOn: false, options: newOptions },
|
|
67
|
-
}),
|
|
68
|
-
])
|
|
69
|
-
setOutput(newOutput)
|
|
70
|
-
setOutputWithoutAddon(newOutputWithoutAddon)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return (
|
|
74
|
-
<div>
|
|
75
|
-
<div className="flex flex-row items-center mb-5">
|
|
76
|
-
<ToggleGroup
|
|
77
|
-
type="single"
|
|
78
|
-
value={options.mode}
|
|
79
|
-
onValueChange={(v: string) => {
|
|
80
|
-
if (v) {
|
|
81
|
-
updateOptions(
|
|
82
|
-
{
|
|
83
|
-
mode: v as Mode,
|
|
84
|
-
},
|
|
85
|
-
selectedAddOns,
|
|
86
|
-
)
|
|
87
|
-
}
|
|
88
|
-
}}
|
|
89
|
-
>
|
|
90
|
-
<ToggleGroupItem
|
|
91
|
-
value="code-router"
|
|
92
|
-
disabled={!addOnInfo.templates.includes('code-router')}
|
|
93
|
-
>
|
|
94
|
-
Code Router
|
|
95
|
-
</ToggleGroupItem>
|
|
96
|
-
<ToggleGroupItem
|
|
97
|
-
value="file-router"
|
|
98
|
-
disabled={!addOnInfo.templates.includes('file-router')}
|
|
99
|
-
>
|
|
100
|
-
File Router
|
|
101
|
-
</ToggleGroupItem>
|
|
102
|
-
</ToggleGroup>
|
|
103
|
-
<div className="flex flex-row ml-5 flex-wrap">
|
|
104
|
-
{addOns[options.mode as Mode].map((addOn) => (
|
|
105
|
-
<div key={addOn.name} className="mr-2 flex items-center">
|
|
106
|
-
<Checkbox
|
|
107
|
-
id={addOn.id}
|
|
108
|
-
checked={
|
|
109
|
-
originalOptions.existingAddOns.includes(addOn.id) ||
|
|
110
|
-
selectedAddOns.includes(addOn.id)
|
|
111
|
-
}
|
|
112
|
-
disabled={originalOptions.existingAddOns.includes(addOn.id)}
|
|
113
|
-
onClick={() => {
|
|
114
|
-
let updatedAddOns = selectedAddOns.includes(addOn.id)
|
|
115
|
-
? selectedAddOns.filter((id) => id !== addOn.id)
|
|
116
|
-
: [...selectedAddOns, addOn.id]
|
|
117
|
-
setSelectedAddOns(updatedAddOns)
|
|
118
|
-
updateOptions({}, updatedAddOns)
|
|
119
|
-
}}
|
|
120
|
-
/>
|
|
121
|
-
<label htmlFor={addOn.id} className="ml-2">
|
|
122
|
-
{addOn.name}
|
|
123
|
-
</label>
|
|
124
|
-
</div>
|
|
125
|
-
))}
|
|
126
|
-
</div>
|
|
127
|
-
</div>
|
|
128
|
-
<div className="flex flex-row">
|
|
129
|
-
<FileTree
|
|
130
|
-
prefix={projectPath}
|
|
131
|
-
tree={output.files}
|
|
132
|
-
originalTree={outputWithoutAddon.files}
|
|
133
|
-
onFileSelected={(file) => {
|
|
134
|
-
setSelectedFile(file)
|
|
135
|
-
}}
|
|
136
|
-
/>
|
|
137
|
-
<div className="max-w-3/4 w-3/4 pl-2">
|
|
138
|
-
{selectedFile ? (
|
|
139
|
-
<FileViewer
|
|
140
|
-
filePath={selectedFile}
|
|
141
|
-
originalFile={outputWithoutAddon.files[selectedFile]}
|
|
142
|
-
modifiedFile={output.files[selectedFile]}
|
|
143
|
-
/>
|
|
144
|
-
) : null}
|
|
145
|
-
</div>
|
|
146
|
-
</div>
|
|
147
|
-
</div>
|
|
148
|
-
)
|
|
149
|
-
}
|
package/src/lib/server-fns.ts
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { createServerFn } from '@tanstack/react-start'
|
|
2
|
-
import { readFileSync } from 'node:fs'
|
|
3
|
-
import { basename, resolve } from 'node:path'
|
|
4
|
-
|
|
5
|
-
import { getAllAddOns, createMemoryEnvironment } from '@tanstack/cta-engine'
|
|
6
|
-
import { createAppOptionsFromPersisted } from '@tanstack/cta-custom-add-on'
|
|
7
|
-
|
|
8
|
-
import { createApp } from '@tanstack/cta-engine'
|
|
9
|
-
|
|
10
|
-
import type { AddOn, Mode, PersistedOptions } from '@tanstack/cta-engine'
|
|
11
|
-
|
|
12
|
-
export const getAddons = createServerFn({
|
|
13
|
-
method: 'GET',
|
|
14
|
-
})
|
|
15
|
-
.validator((data: unknown) => {
|
|
16
|
-
return data as { platform: string; mode: Mode }
|
|
17
|
-
})
|
|
18
|
-
.handler(({ data: { platform, mode } }) => {
|
|
19
|
-
return getAllAddOns(platform, mode)
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
export const getAddonInfo = createServerFn({
|
|
23
|
-
method: 'GET',
|
|
24
|
-
}).handler(async () => {
|
|
25
|
-
const addOnInfo = readFileSync(
|
|
26
|
-
resolve(process.env.PROJECT_PATH, 'add-on.json'),
|
|
27
|
-
)
|
|
28
|
-
return JSON.parse(addOnInfo.toString())
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
export const getOriginalOptions = createServerFn({
|
|
32
|
-
method: 'GET',
|
|
33
|
-
}).handler(async () => {
|
|
34
|
-
const addOnInfo = readFileSync(resolve(process.env.PROJECT_PATH, '.cta.json'))
|
|
35
|
-
return JSON.parse(addOnInfo.toString()) as PersistedOptions
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
export const runCreateApp = createServerFn({
|
|
39
|
-
method: 'POST',
|
|
40
|
-
})
|
|
41
|
-
.validator((data: unknown) => {
|
|
42
|
-
return data as { withAddOn: boolean; options: PersistedOptions }
|
|
43
|
-
})
|
|
44
|
-
.handler(
|
|
45
|
-
async ({
|
|
46
|
-
data: { withAddOn, options: persistedOptions },
|
|
47
|
-
}: {
|
|
48
|
-
data: { withAddOn: boolean; options: PersistedOptions }
|
|
49
|
-
}) => {
|
|
50
|
-
const { output, environment } = createMemoryEnvironment()
|
|
51
|
-
const options = await createAppOptionsFromPersisted(persistedOptions)
|
|
52
|
-
options.chosenAddOns = withAddOn
|
|
53
|
-
? [...options.chosenAddOns, (await getAddonInfo()) as AddOn]
|
|
54
|
-
: [...options.chosenAddOns]
|
|
55
|
-
await createApp(
|
|
56
|
-
{
|
|
57
|
-
...options,
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
silent: true,
|
|
61
|
-
environment,
|
|
62
|
-
cwd: process.env.PROJECT_PATH,
|
|
63
|
-
},
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
output.files = Object.keys(output.files).reduce<Record<string, string>>(
|
|
67
|
-
(acc, file) => {
|
|
68
|
-
if (basename(file) !== '.cta.json') {
|
|
69
|
-
acc[file] = output.files[file]
|
|
70
|
-
}
|
|
71
|
-
return acc
|
|
72
|
-
},
|
|
73
|
-
{},
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
return output
|
|
77
|
-
},
|
|
78
|
-
)
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { createAPIFileRoute } from '@tanstack/react-start/api'
|
|
2
|
-
|
|
3
|
-
export const APIRoute = createAPIFileRoute('/api/demo-names')({
|
|
4
|
-
GET: async ({ request }) => {
|
|
5
|
-
return new Response(JSON.stringify(['Alice', 'Bob', 'Charlie']), {
|
|
6
|
-
headers: {
|
|
7
|
-
'Content-Type': 'application/json',
|
|
8
|
-
},
|
|
9
|
-
})
|
|
10
|
-
},
|
|
11
|
-
})
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { createFileRoute } from '@tanstack/react-router'
|
|
2
|
-
import { useQuery } from '@tanstack/react-query'
|
|
3
|
-
|
|
4
|
-
export const Route = createFileRoute('/demo/tanstack-query')({
|
|
5
|
-
component: TanStackQueryDemo,
|
|
6
|
-
})
|
|
7
|
-
|
|
8
|
-
function TanStackQueryDemo() {
|
|
9
|
-
const { data } = useQuery({
|
|
10
|
-
queryKey: ['people'],
|
|
11
|
-
queryFn: () =>
|
|
12
|
-
fetch('https://swapi.dev/api/people')
|
|
13
|
-
.then((res) => res.json())
|
|
14
|
-
.then((d) => d.results as { name: string }[]),
|
|
15
|
-
initialData: [],
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
return (
|
|
19
|
-
<div className="p-4">
|
|
20
|
-
<h1 className="text-2xl mb-4">People list from Swapi</h1>
|
|
21
|
-
<ul>
|
|
22
|
-
{data.map((person) => (
|
|
23
|
-
<li key={person.name}>{person.name}</li>
|
|
24
|
-
))}
|
|
25
|
-
</ul>
|
|
26
|
-
</div>
|
|
27
|
-
)
|
|
28
|
-
}
|