@tanstack/devtools 0.6.19 → 0.6.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/dist/chunk/{XFQ6P775.js → XF4JFOLU.js} +15 -0
- package/dist/dev.js +13 -3
- package/dist/devtools/MBQPV7BO.js +3584 -0
- package/dist/devtools/{3YT62TLF.js → YRFZDV5N.js} +2334 -231
- package/dist/index.js +13 -3
- package/dist/server.js +9 -2
- package/package.json +5 -2
- package/src/components/source-inspector.tsx +158 -0
- package/src/context/devtools-context.tsx +24 -1
- package/src/core.tsx +15 -1
- package/src/devtools.tsx +3 -28
- package/src/styles/use-styles.ts +894 -53
- package/src/tabs/marketplace/card-utils.test.ts +219 -0
- package/src/tabs/marketplace/card-utils.ts +85 -0
- package/src/tabs/marketplace/marketplace-header.tsx +54 -0
- package/src/tabs/marketplace/plugin-card.tsx +165 -0
- package/src/tabs/marketplace/plugin-section.tsx +51 -0
- package/src/tabs/marketplace/plugin-utils.test.ts +518 -0
- package/src/tabs/marketplace/plugin-utils.ts +248 -0
- package/src/tabs/marketplace/settings-panel.tsx +41 -0
- package/src/tabs/marketplace/tag-filters.tsx +35 -0
- package/src/tabs/marketplace/types.ts +47 -0
- package/src/tabs/plugin-marketplace.tsx +346 -0
- package/src/tabs/plugin-registry.ts +222 -0
- package/src/tabs/plugins-tab.tsx +112 -65
- package/src/tabs/semver-utils.test.ts +218 -0
- package/src/tabs/semver-utils.ts +114 -0
- package/dist/devtools/MV3V7CMW.js +0 -1735
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import {
|
|
3
|
+
getBadgeClass,
|
|
4
|
+
getBadgeText,
|
|
5
|
+
getButtonText,
|
|
6
|
+
getButtonVariant,
|
|
7
|
+
} from './card-utils'
|
|
8
|
+
import type { PluginCard } from './types'
|
|
9
|
+
|
|
10
|
+
const createMockCard = (overrides: Partial<PluginCard>): PluginCard => ({
|
|
11
|
+
requiredPackageName: '@tanstack/react-query',
|
|
12
|
+
devtoolsPackage: '@tanstack/react-query-devtools',
|
|
13
|
+
framework: 'react',
|
|
14
|
+
hasPackage: false,
|
|
15
|
+
hasDevtools: false,
|
|
16
|
+
isRegistered: false,
|
|
17
|
+
actionType: 'install',
|
|
18
|
+
status: 'idle',
|
|
19
|
+
isCurrentFramework: true,
|
|
20
|
+
metadata: {
|
|
21
|
+
packageName: '@tanstack/react-query-devtools',
|
|
22
|
+
title: 'Query Devtools',
|
|
23
|
+
framework: 'react',
|
|
24
|
+
},
|
|
25
|
+
...overrides,
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
describe('getButtonText', () => {
|
|
29
|
+
it('should return Installing... when status is installing', () => {
|
|
30
|
+
const card = createMockCard({ status: 'installing' })
|
|
31
|
+
expect(getButtonText(card)).toBe('Installing...')
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('should return Installed! when status is success', () => {
|
|
35
|
+
const card = createMockCard({ status: 'success' })
|
|
36
|
+
expect(getButtonText(card)).toBe('Installed!')
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('should return Error when status is error', () => {
|
|
40
|
+
const card = createMockCard({ status: 'error' })
|
|
41
|
+
expect(getButtonText(card)).toBe('Error')
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('should return Install for install action', () => {
|
|
45
|
+
const card = createMockCard({ actionType: 'install' })
|
|
46
|
+
expect(getButtonText(card)).toBe('Install')
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('should return Install Devtools for install-devtools action', () => {
|
|
50
|
+
const card = createMockCard({ actionType: 'install-devtools' })
|
|
51
|
+
expect(getButtonText(card)).toBe('Install Devtools')
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('should return Add to Devtools for add-to-devtools action', () => {
|
|
55
|
+
const card = createMockCard({ actionType: 'add-to-devtools' })
|
|
56
|
+
expect(getButtonText(card)).toBe('Add to Devtools')
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('should return package name for requires-package action', () => {
|
|
60
|
+
const card = createMockCard({
|
|
61
|
+
actionType: 'requires-package',
|
|
62
|
+
requiredPackageName: '@tanstack/react-query',
|
|
63
|
+
})
|
|
64
|
+
expect(getButtonText(card)).toBe('Requires @tanstack/react-query')
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('should return Different Framework for wrong-framework action', () => {
|
|
68
|
+
const card = createMockCard({ actionType: 'wrong-framework' })
|
|
69
|
+
expect(getButtonText(card)).toBe('Different Framework')
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('should return Already Installed for already-installed action', () => {
|
|
73
|
+
const card = createMockCard({ actionType: 'already-installed' })
|
|
74
|
+
expect(getButtonText(card)).toBe('Already Installed')
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('should return Bump Version for bump-version action', () => {
|
|
78
|
+
const card = createMockCard({ actionType: 'bump-version' })
|
|
79
|
+
expect(getButtonText(card)).toBe('Bump Version')
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('should return Version Mismatch for version-mismatch action', () => {
|
|
83
|
+
const card = createMockCard({ actionType: 'version-mismatch' })
|
|
84
|
+
expect(getButtonText(card)).toBe('Version Mismatch')
|
|
85
|
+
})
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
describe('getButtonVariant', () => {
|
|
89
|
+
it('should return danger for requires-package', () => {
|
|
90
|
+
const card = createMockCard({ actionType: 'requires-package' })
|
|
91
|
+
expect(getButtonVariant(card)).toBe('danger')
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it('should return danger for wrong-framework', () => {
|
|
95
|
+
const card = createMockCard({ actionType: 'wrong-framework' })
|
|
96
|
+
expect(getButtonVariant(card)).toBe('danger')
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it('should return danger for version-mismatch', () => {
|
|
100
|
+
const card = createMockCard({ actionType: 'version-mismatch' })
|
|
101
|
+
expect(getButtonVariant(card)).toBe('danger')
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it('should return warning for bump-version', () => {
|
|
105
|
+
const card = createMockCard({ actionType: 'bump-version' })
|
|
106
|
+
expect(getButtonVariant(card)).toBe('warning')
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it('should return secondary for already-installed', () => {
|
|
110
|
+
const card = createMockCard({ actionType: 'already-installed' })
|
|
111
|
+
expect(getButtonVariant(card)).toBe('secondary')
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('should return primary for install actions', () => {
|
|
115
|
+
const installCard = createMockCard({ actionType: 'install' })
|
|
116
|
+
expect(getButtonVariant(installCard)).toBe('primary')
|
|
117
|
+
|
|
118
|
+
const installDevtoolsCard = createMockCard({
|
|
119
|
+
actionType: 'install-devtools',
|
|
120
|
+
})
|
|
121
|
+
expect(getButtonVariant(installDevtoolsCard)).toBe('primary')
|
|
122
|
+
|
|
123
|
+
const addToDevtoolsCard = createMockCard({ actionType: 'add-to-devtools' })
|
|
124
|
+
expect(getButtonVariant(addToDevtoolsCard)).toBe('primary')
|
|
125
|
+
})
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
describe('getBadgeClass', () => {
|
|
129
|
+
const mockStyles = () => ({
|
|
130
|
+
pluginMarketplaceCardBadge: 'badge',
|
|
131
|
+
pluginMarketplaceCardBadgeInstall: 'badge-install',
|
|
132
|
+
pluginMarketplaceCardBadgeAdd: 'badge-add',
|
|
133
|
+
pluginMarketplaceCardBadgeRequires: 'badge-requires',
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
it('should return install badge class for install', () => {
|
|
137
|
+
const card = createMockCard({ actionType: 'install' })
|
|
138
|
+
expect(getBadgeClass(card, mockStyles)).toBe('badge badge-install')
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
it('should return install badge class for install-devtools', () => {
|
|
142
|
+
const card = createMockCard({ actionType: 'install-devtools' })
|
|
143
|
+
expect(getBadgeClass(card, mockStyles)).toBe('badge badge-install')
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
it('should return add badge class for add-to-devtools', () => {
|
|
147
|
+
const card = createMockCard({ actionType: 'add-to-devtools' })
|
|
148
|
+
expect(getBadgeClass(card, mockStyles)).toBe('badge badge-add')
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
it('should return add badge class for already-installed', () => {
|
|
152
|
+
const card = createMockCard({ actionType: 'already-installed' })
|
|
153
|
+
expect(getBadgeClass(card, mockStyles)).toBe('badge badge-add')
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
it('should return requires badge class for bump-version', () => {
|
|
157
|
+
const card = createMockCard({ actionType: 'bump-version' })
|
|
158
|
+
expect(getBadgeClass(card, mockStyles)).toBe('badge badge-requires')
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
it('should return requires badge class for version-mismatch', () => {
|
|
162
|
+
const card = createMockCard({ actionType: 'version-mismatch' })
|
|
163
|
+
expect(getBadgeClass(card, mockStyles)).toBe('badge badge-requires')
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
it('should return requires badge class for requires-package', () => {
|
|
167
|
+
const card = createMockCard({ actionType: 'requires-package' })
|
|
168
|
+
expect(getBadgeClass(card, mockStyles)).toBe('badge badge-requires')
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
it('should return requires badge class for wrong-framework', () => {
|
|
172
|
+
const card = createMockCard({ actionType: 'wrong-framework' })
|
|
173
|
+
expect(getBadgeClass(card, mockStyles)).toBe('badge badge-requires')
|
|
174
|
+
})
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
describe('getBadgeText', () => {
|
|
178
|
+
it('should return Available for install', () => {
|
|
179
|
+
const card = createMockCard({ actionType: 'install' })
|
|
180
|
+
expect(getBadgeText(card)).toBe('Available')
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
it('should return Available for install-devtools', () => {
|
|
184
|
+
const card = createMockCard({ actionType: 'install-devtools' })
|
|
185
|
+
expect(getBadgeText(card)).toBe('Available')
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
it('should return Installed for add-to-devtools', () => {
|
|
189
|
+
const card = createMockCard({ actionType: 'add-to-devtools' })
|
|
190
|
+
expect(getBadgeText(card)).toBe('Installed')
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
it('should return Active for already-installed', () => {
|
|
194
|
+
const card = createMockCard({ actionType: 'already-installed' })
|
|
195
|
+
expect(getBadgeText(card)).toBe('Active')
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
it('should return Incompatible for version-mismatch', () => {
|
|
199
|
+
const card = createMockCard({ actionType: 'version-mismatch' })
|
|
200
|
+
expect(getBadgeText(card)).toBe('Incompatible')
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
it('should return Unavailable for requires-package', () => {
|
|
204
|
+
const card = createMockCard({ actionType: 'requires-package' })
|
|
205
|
+
expect(getBadgeText(card)).toBe('Unavailable')
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
it('should return Other Framework for wrong-framework', () => {
|
|
209
|
+
const card = createMockCard({ actionType: 'wrong-framework' })
|
|
210
|
+
expect(getBadgeText(card)).toBe('Other Framework')
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
it('should return empty string for unknown action type', () => {
|
|
214
|
+
const card = createMockCard({ actionType: 'install' })
|
|
215
|
+
// @ts-expect-error - testing invalid action type
|
|
216
|
+
card.actionType = 'invalid'
|
|
217
|
+
expect(getBadgeText(card)).toBe('')
|
|
218
|
+
})
|
|
219
|
+
})
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { PluginCard } from './types'
|
|
2
|
+
|
|
3
|
+
export const getButtonText = (card: PluginCard): string => {
|
|
4
|
+
if (card.status === 'installing') return 'Installing...'
|
|
5
|
+
if (card.status === 'success') return 'Installed!'
|
|
6
|
+
if (card.status === 'error') return 'Error'
|
|
7
|
+
|
|
8
|
+
switch (card.actionType) {
|
|
9
|
+
case 'install':
|
|
10
|
+
return 'Install'
|
|
11
|
+
case 'install-devtools':
|
|
12
|
+
return 'Install Devtools'
|
|
13
|
+
case 'add-to-devtools':
|
|
14
|
+
return 'Add to Devtools'
|
|
15
|
+
case 'requires-package':
|
|
16
|
+
return `Requires ${card.requiredPackageName}`
|
|
17
|
+
case 'wrong-framework':
|
|
18
|
+
return 'Different Framework'
|
|
19
|
+
case 'already-installed':
|
|
20
|
+
return 'Already Installed'
|
|
21
|
+
case 'bump-version':
|
|
22
|
+
return 'Bump Version'
|
|
23
|
+
case 'version-mismatch':
|
|
24
|
+
return 'Version Mismatch'
|
|
25
|
+
default:
|
|
26
|
+
return 'Install'
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const getButtonVariant = (
|
|
31
|
+
card: PluginCard,
|
|
32
|
+
): 'primary' | 'secondary' | 'danger' | 'warning' => {
|
|
33
|
+
if (
|
|
34
|
+
card.actionType === 'requires-package' ||
|
|
35
|
+
card.actionType === 'wrong-framework' ||
|
|
36
|
+
card.actionType === 'version-mismatch'
|
|
37
|
+
)
|
|
38
|
+
return 'danger'
|
|
39
|
+
if (card.actionType === 'bump-version') return 'warning'
|
|
40
|
+
if (card.actionType === 'already-installed') return 'secondary'
|
|
41
|
+
return 'primary'
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const getBadgeClass = (card: PluginCard, styles: any): string => {
|
|
45
|
+
const s = styles()
|
|
46
|
+
const base = s.pluginMarketplaceCardBadge
|
|
47
|
+
switch (card.actionType) {
|
|
48
|
+
case 'install':
|
|
49
|
+
case 'install-devtools':
|
|
50
|
+
return `${base} ${s.pluginMarketplaceCardBadgeInstall}`
|
|
51
|
+
case 'add-to-devtools':
|
|
52
|
+
return `${base} ${s.pluginMarketplaceCardBadgeAdd}`
|
|
53
|
+
case 'already-installed':
|
|
54
|
+
return `${base} ${s.pluginMarketplaceCardBadgeAdd}`
|
|
55
|
+
case 'bump-version':
|
|
56
|
+
return `${base} ${s.pluginMarketplaceCardBadgeRequires}`
|
|
57
|
+
case 'version-mismatch':
|
|
58
|
+
return `${base} ${s.pluginMarketplaceCardBadgeRequires}`
|
|
59
|
+
case 'requires-package':
|
|
60
|
+
case 'wrong-framework':
|
|
61
|
+
return `${base} ${s.pluginMarketplaceCardBadgeRequires}`
|
|
62
|
+
default:
|
|
63
|
+
return base
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export const getBadgeText = (card: PluginCard): string => {
|
|
68
|
+
switch (card.actionType) {
|
|
69
|
+
case 'install':
|
|
70
|
+
case 'install-devtools':
|
|
71
|
+
return 'Available'
|
|
72
|
+
case 'add-to-devtools':
|
|
73
|
+
return 'Installed'
|
|
74
|
+
case 'already-installed':
|
|
75
|
+
return 'Active'
|
|
76
|
+
case 'version-mismatch':
|
|
77
|
+
return 'Incompatible'
|
|
78
|
+
case 'requires-package':
|
|
79
|
+
return 'Unavailable'
|
|
80
|
+
case 'wrong-framework':
|
|
81
|
+
return 'Other Framework'
|
|
82
|
+
default:
|
|
83
|
+
return ''
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { SearchIcon, SettingsIcon } from '@tanstack/devtools-ui'
|
|
2
|
+
import { useStyles } from '../../styles/use-styles'
|
|
3
|
+
import { TagFilters } from './tag-filters'
|
|
4
|
+
import type { Accessor } from 'solid-js'
|
|
5
|
+
|
|
6
|
+
interface MarketplaceHeaderProps {
|
|
7
|
+
searchInput: Accessor<string>
|
|
8
|
+
onSearchInput: (value: string) => void
|
|
9
|
+
onSettingsClick: () => void
|
|
10
|
+
tags: Accessor<Array<string>>
|
|
11
|
+
selectedTags: Accessor<Set<string>>
|
|
12
|
+
onToggleTag: (tag: string) => void
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const MarketplaceHeader = (props: MarketplaceHeaderProps) => {
|
|
16
|
+
const styles = useStyles()
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<div class={styles().pluginMarketplaceHeader}>
|
|
20
|
+
<div class={styles().pluginMarketplaceTitleRow}>
|
|
21
|
+
<h2 class={styles().pluginMarketplaceTitle}>Plugin Marketplace</h2>
|
|
22
|
+
<div style={{ display: 'flex', 'align-items': 'center' }}>
|
|
23
|
+
<div class={styles().pluginMarketplaceSearchWrapper}>
|
|
24
|
+
<SearchIcon />
|
|
25
|
+
<input
|
|
26
|
+
type="text"
|
|
27
|
+
class={styles().pluginMarketplaceSearch}
|
|
28
|
+
placeholder="Search plugins..."
|
|
29
|
+
value={props.searchInput()}
|
|
30
|
+
onInput={(e) => props.onSearchInput(e.currentTarget.value)}
|
|
31
|
+
/>
|
|
32
|
+
</div>
|
|
33
|
+
<button
|
|
34
|
+
class={styles().pluginMarketplaceSettingsButton}
|
|
35
|
+
onClick={props.onSettingsClick}
|
|
36
|
+
>
|
|
37
|
+
<SettingsIcon />
|
|
38
|
+
</button>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<p class={styles().pluginMarketplaceDescription}>
|
|
43
|
+
Discover and install devtools for TanStack Query, Router, Form, and
|
|
44
|
+
Pacer
|
|
45
|
+
</p>
|
|
46
|
+
|
|
47
|
+
<TagFilters
|
|
48
|
+
tags={props.tags}
|
|
49
|
+
selectedTags={props.selectedTags}
|
|
50
|
+
onToggleTag={props.onToggleTag}
|
|
51
|
+
/>
|
|
52
|
+
</div>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { For, Show } from 'solid-js'
|
|
2
|
+
import {
|
|
3
|
+
Button,
|
|
4
|
+
CheckCircleIcon,
|
|
5
|
+
ExternalLinkIcon,
|
|
6
|
+
PackageIcon,
|
|
7
|
+
XCircleIcon,
|
|
8
|
+
} from '@tanstack/devtools-ui'
|
|
9
|
+
import { useStyles } from '../../styles/use-styles'
|
|
10
|
+
import {
|
|
11
|
+
getBadgeClass,
|
|
12
|
+
getBadgeText,
|
|
13
|
+
getButtonText,
|
|
14
|
+
getButtonVariant,
|
|
15
|
+
} from './card-utils'
|
|
16
|
+
import type { PluginCard } from './types'
|
|
17
|
+
|
|
18
|
+
interface PluginCardComponentProps {
|
|
19
|
+
card: PluginCard
|
|
20
|
+
onAction: (card: PluginCard) => void
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const PluginCardComponent = (props: PluginCardComponentProps) => {
|
|
24
|
+
const styles = useStyles()
|
|
25
|
+
const { card } = props
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<div
|
|
29
|
+
class={styles().pluginMarketplaceCard}
|
|
30
|
+
classList={{
|
|
31
|
+
[styles().pluginMarketplaceCardDisabled]:
|
|
32
|
+
!card.isCurrentFramework && card.actionType !== 'already-installed',
|
|
33
|
+
[styles().pluginMarketplaceCardFeatured]:
|
|
34
|
+
!!card.metadata?.featured && card.actionType !== 'already-installed',
|
|
35
|
+
[styles().pluginMarketplaceCardActive]:
|
|
36
|
+
card.actionType === 'already-installed',
|
|
37
|
+
}}
|
|
38
|
+
style={{ position: 'relative' }}
|
|
39
|
+
>
|
|
40
|
+
{/* New Banner */}
|
|
41
|
+
<Show when={card.metadata?.isNew}>
|
|
42
|
+
<div class={styles().pluginMarketplaceNewBanner}>New</div>
|
|
43
|
+
</Show>
|
|
44
|
+
|
|
45
|
+
<span class={getBadgeClass(card, styles)}>{getBadgeText(card)}</span>
|
|
46
|
+
<div
|
|
47
|
+
class={styles().pluginMarketplaceCardIcon}
|
|
48
|
+
classList={{
|
|
49
|
+
'custom-logo': !!card.metadata?.logoUrl,
|
|
50
|
+
}}
|
|
51
|
+
>
|
|
52
|
+
<Show when={card.metadata?.logoUrl} fallback={<PackageIcon />}>
|
|
53
|
+
<img
|
|
54
|
+
src={card.metadata?.logoUrl}
|
|
55
|
+
alt={card.metadata?.title || card.devtoolsPackage}
|
|
56
|
+
class={styles().pluginMarketplaceCardImage}
|
|
57
|
+
/>
|
|
58
|
+
</Show>
|
|
59
|
+
</div>
|
|
60
|
+
<div class={styles().pluginMarketplaceCardHeader}>
|
|
61
|
+
<h3 class={styles().pluginMarketplaceCardTitle}>
|
|
62
|
+
{card.metadata?.title || card.devtoolsPackage}
|
|
63
|
+
</h3>
|
|
64
|
+
<p class={styles().pluginMarketplaceCardPackageBadge}>
|
|
65
|
+
{card.devtoolsPackage}
|
|
66
|
+
</p>
|
|
67
|
+
<p class={styles().pluginMarketplaceCardDescriptionText}>
|
|
68
|
+
{card.actionType === 'requires-package'
|
|
69
|
+
? `Requires ${card.requiredPackageName}`
|
|
70
|
+
: card.actionType === 'wrong-framework'
|
|
71
|
+
? `For different framework projects`
|
|
72
|
+
: card.actionType === 'already-installed'
|
|
73
|
+
? `Active in your devtools`
|
|
74
|
+
: card.actionType === 'version-mismatch'
|
|
75
|
+
? card.versionInfo?.reason || 'Version incompatible'
|
|
76
|
+
: card.metadata?.description ||
|
|
77
|
+
`For ${card.requiredPackageName}`}
|
|
78
|
+
</p>
|
|
79
|
+
<Show when={card.versionInfo}>
|
|
80
|
+
<p class={styles().pluginMarketplaceCardVersionInfo}>
|
|
81
|
+
<Show
|
|
82
|
+
when={card.versionInfo?.satisfied}
|
|
83
|
+
fallback={
|
|
84
|
+
<span class={styles().pluginMarketplaceCardVersionUnsatisfied}>
|
|
85
|
+
⚠️ v{card.versionInfo?.current} • Requires v
|
|
86
|
+
{card.versionInfo?.required}+
|
|
87
|
+
</span>
|
|
88
|
+
}
|
|
89
|
+
>
|
|
90
|
+
<span class={styles().pluginMarketplaceCardVersionSatisfied}>
|
|
91
|
+
✓ v{card.versionInfo?.current} • Min v
|
|
92
|
+
{card.versionInfo?.required}
|
|
93
|
+
</span>
|
|
94
|
+
</Show>
|
|
95
|
+
</p>
|
|
96
|
+
</Show>
|
|
97
|
+
<Show when={card.metadata?.docsUrl}>
|
|
98
|
+
<a
|
|
99
|
+
href={card.metadata?.docsUrl}
|
|
100
|
+
target="_blank"
|
|
101
|
+
rel="noopener noreferrer"
|
|
102
|
+
class={styles().pluginMarketplaceCardDocsLink}
|
|
103
|
+
>
|
|
104
|
+
Documentation <ExternalLinkIcon />
|
|
105
|
+
</a>
|
|
106
|
+
</Show>
|
|
107
|
+
|
|
108
|
+
{/* Tags */}
|
|
109
|
+
<Show when={card.metadata?.tags && card.metadata.tags.length > 0}>
|
|
110
|
+
<div class={styles().pluginMarketplaceCardTags}>
|
|
111
|
+
<For each={card.metadata?.tags}>
|
|
112
|
+
{(tag) => (
|
|
113
|
+
<span class={styles().pluginMarketplaceCardTag}>{tag}</span>
|
|
114
|
+
)}
|
|
115
|
+
</For>
|
|
116
|
+
</div>
|
|
117
|
+
</Show>
|
|
118
|
+
</div>
|
|
119
|
+
<Show
|
|
120
|
+
when={card.status === 'idle'}
|
|
121
|
+
fallback={
|
|
122
|
+
<div class={styles().pluginMarketplaceCardStatus}>
|
|
123
|
+
<Show when={card.status === 'installing'}>
|
|
124
|
+
<div class={styles().pluginMarketplaceCardSpinner} />
|
|
125
|
+
<span class={styles().pluginMarketplaceCardStatusText}>
|
|
126
|
+
Installing...
|
|
127
|
+
</span>
|
|
128
|
+
</Show>
|
|
129
|
+
<Show when={card.status === 'success'}>
|
|
130
|
+
<CheckCircleIcon />
|
|
131
|
+
<span class={styles().pluginMarketplaceCardStatusText}>
|
|
132
|
+
Installed!
|
|
133
|
+
</span>
|
|
134
|
+
</Show>
|
|
135
|
+
<Show when={card.status === 'error'}>
|
|
136
|
+
<XCircleIcon />
|
|
137
|
+
<span class={styles().pluginMarketplaceCardStatusTextError}>
|
|
138
|
+
{card.error || 'Failed to install'}
|
|
139
|
+
</span>
|
|
140
|
+
</Show>
|
|
141
|
+
</div>
|
|
142
|
+
}
|
|
143
|
+
>
|
|
144
|
+
<Button
|
|
145
|
+
variant={getButtonVariant(card)}
|
|
146
|
+
onClick={() => props.onAction(card)}
|
|
147
|
+
disabled={
|
|
148
|
+
card.status !== 'idle' ||
|
|
149
|
+
card.actionType === 'requires-package' ||
|
|
150
|
+
card.actionType === 'wrong-framework' ||
|
|
151
|
+
card.actionType === 'already-installed' ||
|
|
152
|
+
card.actionType === 'version-mismatch'
|
|
153
|
+
}
|
|
154
|
+
class={
|
|
155
|
+
card.actionType === 'already-installed'
|
|
156
|
+
? styles().pluginMarketplaceButtonInstalled
|
|
157
|
+
: ''
|
|
158
|
+
}
|
|
159
|
+
>
|
|
160
|
+
{getButtonText(card)}
|
|
161
|
+
</Button>
|
|
162
|
+
</Show>
|
|
163
|
+
</div>
|
|
164
|
+
)
|
|
165
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { For, Show } from 'solid-js'
|
|
2
|
+
import { ChevronDownIcon } from '@tanstack/devtools-ui'
|
|
3
|
+
import { useStyles } from '../../styles/use-styles'
|
|
4
|
+
import { PluginCardComponent } from './plugin-card'
|
|
5
|
+
import type { Accessor } from 'solid-js'
|
|
6
|
+
import type { PluginCard, PluginSection } from './types'
|
|
7
|
+
|
|
8
|
+
interface PluginSectionComponentProps {
|
|
9
|
+
section: PluginSection
|
|
10
|
+
isCollapsed: Accessor<boolean>
|
|
11
|
+
onToggleCollapse: () => void
|
|
12
|
+
onCardAction: (card: PluginCard) => void
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const PluginSectionComponent = (props: PluginSectionComponentProps) => {
|
|
16
|
+
const styles = useStyles()
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<div class={styles().pluginMarketplaceSection}>
|
|
20
|
+
<div
|
|
21
|
+
class={styles().pluginMarketplaceSectionHeader}
|
|
22
|
+
onClick={props.onToggleCollapse}
|
|
23
|
+
>
|
|
24
|
+
<div class={styles().pluginMarketplaceSectionHeaderLeft}>
|
|
25
|
+
<div
|
|
26
|
+
class={styles().pluginMarketplaceSectionChevron}
|
|
27
|
+
classList={{
|
|
28
|
+
[styles().pluginMarketplaceSectionChevronCollapsed]:
|
|
29
|
+
props.isCollapsed(),
|
|
30
|
+
}}
|
|
31
|
+
>
|
|
32
|
+
<ChevronDownIcon />
|
|
33
|
+
</div>
|
|
34
|
+
<h3 class={styles().pluginMarketplaceSectionTitle}>
|
|
35
|
+
{props.section.displayName}
|
|
36
|
+
</h3>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<Show when={!props.isCollapsed()}>
|
|
41
|
+
<div class={styles().pluginMarketplaceGrid}>
|
|
42
|
+
<For each={props.section.cards}>
|
|
43
|
+
{(card) => (
|
|
44
|
+
<PluginCardComponent card={card} onAction={props.onCardAction} />
|
|
45
|
+
)}
|
|
46
|
+
</For>
|
|
47
|
+
</div>
|
|
48
|
+
</Show>
|
|
49
|
+
</div>
|
|
50
|
+
)
|
|
51
|
+
}
|