@orsetra/shared-ui 1.1.8 → 1.1.9
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.
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
} from "./dialog"
|
|
11
11
|
import { Button } from "./button"
|
|
12
12
|
import { Label } from "./label"
|
|
13
|
+
import { Input } from "./input"
|
|
13
14
|
import {
|
|
14
15
|
Select,
|
|
15
16
|
SelectContent,
|
|
@@ -29,11 +30,12 @@ export interface ProjectSelectorModalProps {
|
|
|
29
30
|
open: boolean
|
|
30
31
|
onOpenChange?: (open: boolean) => void
|
|
31
32
|
getProjects: () => Promise<Project[]>
|
|
33
|
+
createProject: (name: string) => Promise<Project>
|
|
32
34
|
storage: {
|
|
33
35
|
getItem: (key: string) => string | null
|
|
34
36
|
setItem: (key: string, value: string) => void
|
|
35
37
|
}
|
|
36
|
-
storageKey
|
|
38
|
+
storageKey: string
|
|
37
39
|
doInit: () => void | Promise<void>
|
|
38
40
|
title?: string
|
|
39
41
|
description?: string
|
|
@@ -43,15 +45,17 @@ export function ProjectSelectorModal({
|
|
|
43
45
|
open,
|
|
44
46
|
onOpenChange,
|
|
45
47
|
getProjects,
|
|
48
|
+
createProject,
|
|
46
49
|
storage,
|
|
47
|
-
storageKey
|
|
50
|
+
storageKey,
|
|
48
51
|
doInit,
|
|
49
|
-
title = "Select
|
|
50
|
-
description = "Choose a
|
|
52
|
+
title = "Select Business Unit",
|
|
53
|
+
description = "Choose a business unit to continue. This will be used for all operations in this application.",
|
|
51
54
|
}: ProjectSelectorModalProps) {
|
|
52
55
|
const [projects, setProjects] = React.useState<Project[]>([])
|
|
53
56
|
const [loading, setLoading] = React.useState(true)
|
|
54
57
|
const [selectedProject, setSelectedProject] = React.useState<string>("")
|
|
58
|
+
const [newProjectName, setNewProjectName] = React.useState<string>("")
|
|
55
59
|
const [submitting, setSubmitting] = React.useState(false)
|
|
56
60
|
const [error, setError] = React.useState<string | null>(null)
|
|
57
61
|
|
|
@@ -88,6 +92,36 @@ export function ProjectSelectorModal({
|
|
|
88
92
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
89
93
|
e.preventDefault()
|
|
90
94
|
|
|
95
|
+
// If no projects exist, create a new one
|
|
96
|
+
if (projects.length === 0) {
|
|
97
|
+
if (!newProjectName.trim()) {
|
|
98
|
+
setError("Please enter a business unit name")
|
|
99
|
+
return
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
setSubmitting(true)
|
|
103
|
+
setError(null)
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
// Create the new project
|
|
107
|
+
const newProject = await createProject(newProjectName.trim())
|
|
108
|
+
|
|
109
|
+
// Save to storage
|
|
110
|
+
storage.setItem(storageKey, newProject.name)
|
|
111
|
+
|
|
112
|
+
// Call doInit
|
|
113
|
+
await Promise.resolve(doInit())
|
|
114
|
+
|
|
115
|
+
// Close modal
|
|
116
|
+
onOpenChange?.(false)
|
|
117
|
+
} catch (err) {
|
|
118
|
+
console.error("Failed to create project:", err)
|
|
119
|
+
setError(err instanceof Error ? err.message : "Failed to create business unit")
|
|
120
|
+
setSubmitting(false)
|
|
121
|
+
}
|
|
122
|
+
return
|
|
123
|
+
}
|
|
124
|
+
|
|
91
125
|
if (!selectedProject) {
|
|
92
126
|
setError("Please select a project")
|
|
93
127
|
return
|
|
@@ -127,54 +161,78 @@ export function ProjectSelectorModal({
|
|
|
127
161
|
{loading ? (
|
|
128
162
|
<div className="flex items-center justify-center py-8">
|
|
129
163
|
<Loader2 className="h-6 w-6 animate-spin text-ibm-blue-60" />
|
|
130
|
-
<span className="ml-2 text-
|
|
131
|
-
</div>
|
|
132
|
-
) : error ? (
|
|
133
|
-
<div className="rounded-none border border-red-200 bg-red-50 p-3 text-sm text-red-800">
|
|
134
|
-
{error}
|
|
164
|
+
<span className="ml-2 text-ibm-gray-70">Loading business units...</span>
|
|
135
165
|
</div>
|
|
136
166
|
) : projects.length === 0 ? (
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
167
|
+
<>
|
|
168
|
+
{error && (
|
|
169
|
+
<div className="rounded-none border border-red-200 bg-red-50 p-3 text-sm text-red-800">
|
|
170
|
+
{error}
|
|
171
|
+
</div>
|
|
172
|
+
)}
|
|
173
|
+
<div className="space-y-2">
|
|
174
|
+
<Label htmlFor="new-project">
|
|
175
|
+
Business Unit Name <span className="text-red-600">*</span>
|
|
176
|
+
</Label>
|
|
177
|
+
<Input
|
|
178
|
+
id="new-project"
|
|
179
|
+
type="text"
|
|
180
|
+
placeholder="Enter business unit name"
|
|
181
|
+
value={newProjectName}
|
|
182
|
+
onChange={(e) => setNewProjectName(e.target.value)}
|
|
183
|
+
className="rounded-none"
|
|
184
|
+
autoFocus
|
|
185
|
+
/>
|
|
186
|
+
<p className="text-xs text-ibm-gray-60">
|
|
187
|
+
No business units found. Create your first one to continue.
|
|
188
|
+
</p>
|
|
189
|
+
</div>
|
|
190
|
+
</>
|
|
140
191
|
) : (
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
192
|
+
<>
|
|
193
|
+
{error && (
|
|
194
|
+
<div className="rounded-none border border-red-200 bg-red-50 p-3 text-sm text-red-800">
|
|
195
|
+
{error}
|
|
196
|
+
</div>
|
|
197
|
+
)}
|
|
198
|
+
<div className="space-y-2">
|
|
199
|
+
<Label htmlFor="project">
|
|
200
|
+
Business Unit <span className="text-red-600">*</span>
|
|
201
|
+
</Label>
|
|
202
|
+
<Select value={selectedProject} onValueChange={setSelectedProject}>
|
|
203
|
+
<SelectTrigger id="project" className="rounded-none">
|
|
204
|
+
<SelectValue placeholder="Select a business unit" />
|
|
205
|
+
</SelectTrigger>
|
|
206
|
+
<SelectContent className="rounded-none">
|
|
207
|
+
{projects.map((project) => (
|
|
208
|
+
<SelectItem key={project.name} value={project.name} className="rounded-none">
|
|
209
|
+
<div className="flex flex-col">
|
|
210
|
+
<span className="font-medium">{project.alias || project.name}</span>
|
|
211
|
+
{project.description && (
|
|
212
|
+
<span className="text-xs text-ibm-gray-60">{project.description}</span>
|
|
213
|
+
)}
|
|
214
|
+
</div>
|
|
215
|
+
</SelectItem>
|
|
216
|
+
))}
|
|
217
|
+
</SelectContent>
|
|
218
|
+
</Select>
|
|
219
|
+
</div>
|
|
220
|
+
</>
|
|
163
221
|
)}
|
|
164
222
|
|
|
165
223
|
<div className="flex items-center justify-end gap-3 pt-2">
|
|
166
224
|
<Button
|
|
167
225
|
type="submit"
|
|
168
226
|
className="rounded-none"
|
|
169
|
-
disabled={submitting || loading ||
|
|
227
|
+
disabled={submitting || loading || (projects.length === 0 ? !newProjectName.trim() : !selectedProject)}
|
|
170
228
|
>
|
|
171
229
|
{submitting ? (
|
|
172
230
|
<>
|
|
173
231
|
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
174
|
-
Initializing...
|
|
232
|
+
{projects.length === 0 ? "Creating..." : "Initializing..."}
|
|
175
233
|
</>
|
|
176
234
|
) : (
|
|
177
|
-
"Continue"
|
|
235
|
+
projects.length === 0 ? "Create & Continue" : "Continue"
|
|
178
236
|
)}
|
|
179
237
|
</Button>
|
|
180
238
|
</div>
|