Skip to content

Commit 6d986f0

Browse files
author
smarunich
committed
expanding publishing workflow
1 parent abf858e commit 6d986f0

File tree

3 files changed

+152
-19
lines changed

3 files changed

+152
-19
lines changed

management/ui/src/components/PublishingForm.js

Lines changed: 73 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React, { useState, useEffect } from 'react';
22
import { useApi } from '../contexts/ApiContext';
3+
import { useAuth } from '../contexts/AuthContext';
34
import toast from 'react-hot-toast';
45
import { Globe, Key, Settings, Zap, AlertCircle, CheckCircle, X } from 'lucide-react';
56

@@ -24,15 +25,22 @@ const PublishingForm = ({ modelName, onComplete, onCancel }) => {
2425
const [isPublished, setIsPublished] = useState(false);
2526
const [modelDetails, setModelDetails] = useState(null);
2627
const [tenantInfo, setTenantInfo] = useState(null);
28+
const [tenants, setTenants] = useState([]);
2729
const api = useApi();
30+
const { user } = useAuth();
2831

2932
useEffect(() => {
3033
if (modelName) {
3134
fetchModelDetails();
3235
fetchTenantInfo();
3336
checkIfPublished();
37+
38+
// If user is admin, fetch available tenants
39+
if (user?.isAdmin) {
40+
fetchTenants();
41+
}
3442
}
35-
}, [modelName]);
43+
}, [modelName, user]);
3644

3745
const fetchModelDetails = async () => {
3846
try {
@@ -48,12 +56,31 @@ const PublishingForm = ({ modelName, onComplete, onCancel }) => {
4856
try {
4957
const response = await api.getTenantInfo();
5058
setTenantInfo(response.data);
51-
setFormData(prev => ({ ...prev, tenantId: response.data.tenant }));
59+
// Only set the default tenant if admin hasn't selected one
60+
if (!user?.isAdmin) {
61+
setFormData(prev => ({ ...prev, tenantId: response.data.tenant }));
62+
}
5263
} catch (error) {
5364
console.error('Error fetching tenant info:', error);
5465
}
5566
};
5667

68+
const fetchTenants = async () => {
69+
try {
70+
const response = await api.getTenants();
71+
setTenants(response.data.tenants || []);
72+
73+
// Set default tenant for admin (first tenant or current user tenant)
74+
if (response.data.tenants && response.data.tenants.length > 0) {
75+
const defaultTenant = tenantInfo?.tenant || response.data.tenants[0].id;
76+
setFormData(prev => ({ ...prev, tenantId: defaultTenant }));
77+
}
78+
} catch (error) {
79+
console.error('Error fetching tenants:', error);
80+
toast.error('Failed to fetch tenant list');
81+
}
82+
};
83+
5784
const checkIfPublished = async () => {
5885
try {
5986
const response = await api.getPublishedModel(modelName);
@@ -97,9 +124,17 @@ const PublishingForm = ({ modelName, onComplete, onCancel }) => {
97124
setLoading(true);
98125

99126
try {
100-
const response = await api.publishModel(modelName, {
127+
// Add tenant parameter for admin users
128+
const requestBody = {
101129
config: formData
102-
});
130+
};
131+
132+
// If admin is publishing to a different tenant, include tenant in request
133+
if (user?.isAdmin && formData.tenantId !== tenantInfo?.tenant) {
134+
requestBody.config.tenantID = formData.tenantId;
135+
}
136+
137+
const response = await api.publishModel(modelName, requestBody);
103138

104139
toast.success('Model published successfully!');
105140
onComplete(response.data);
@@ -118,7 +153,11 @@ const PublishingForm = ({ modelName, onComplete, onCancel }) => {
118153

119154
try {
120155
setLoading(true);
121-
await api.unpublishModel(modelName);
156+
157+
// Include namespace parameter for admin users
158+
const namespace = user?.isAdmin ? formData.tenantId : null;
159+
await api.unpublishModel(modelName, namespace);
160+
122161
toast.success('Model unpublished successfully!');
123162
onComplete(null);
124163
} catch (error) {
@@ -184,13 +223,35 @@ const PublishingForm = ({ modelName, onComplete, onCancel }) => {
184223

185224
<div className="form-group">
186225
<label>Tenant</label>
187-
<input
188-
type="text"
189-
value={formData.tenantId}
190-
className="form-control"
191-
disabled
192-
style={{ backgroundColor: '#f8fafc', color: '#6b7280' }}
193-
/>
226+
{user?.isAdmin ? (
227+
<select
228+
name="tenantId"
229+
value={formData.tenantId}
230+
onChange={handleInputChange}
231+
className="form-control"
232+
required
233+
>
234+
<option value="">Select a tenant</option>
235+
{tenants.map(tenant => (
236+
<option key={tenant.id} value={tenant.id}>
237+
{tenant.name || tenant.id}
238+
</option>
239+
))}
240+
</select>
241+
) : (
242+
<input
243+
type="text"
244+
value={formData.tenantId}
245+
className="form-control"
246+
disabled
247+
style={{ backgroundColor: '#f8fafc', color: '#6b7280' }}
248+
/>
249+
)}
250+
{user?.isAdmin && (
251+
<div style={{ fontSize: '0.875rem', color: '#6b7280', marginTop: '0.25rem' }}>
252+
Select the tenant namespace where the model should be published
253+
</div>
254+
)}
194255
</div>
195256
</div>
196257

management/ui/src/components/PublishingWorkflow.js

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React, { useState, useEffect } from 'react';
22
import { useApi } from '../contexts/ApiContext';
3+
import { useAuth } from '../contexts/AuthContext';
34
import toast from 'react-hot-toast';
45
import {
56
ArrowRight,
@@ -38,7 +39,9 @@ const PublishingWorkflow = ({ modelName, onComplete, onCancel }) => {
3839
const [publishedModel, setPublishedModel] = useState(null);
3940
const [loading, setLoading] = useState(false);
4041
const [validationErrors, setValidationErrors] = useState([]);
42+
const [tenants, setTenants] = useState([]);
4143
const api = useApi();
44+
const { user } = useAuth();
4245

4346
const steps = [
4447
{ id: 1, title: 'Model Validation', icon: CheckCircle },
@@ -51,8 +54,13 @@ const PublishingWorkflow = ({ modelName, onComplete, onCancel }) => {
5154
if (modelName) {
5255
fetchModelDetails();
5356
fetchTenantInfo();
57+
58+
// If user is admin, fetch available tenants
59+
if (user?.isAdmin) {
60+
fetchTenants();
61+
}
5462
}
55-
}, [modelName]);
63+
}, [modelName, user]);
5664

5765
const fetchModelDetails = async () => {
5866
try {
@@ -68,12 +76,31 @@ const PublishingWorkflow = ({ modelName, onComplete, onCancel }) => {
6876
const fetchTenantInfo = async () => {
6977
try {
7078
const response = await api.getTenantInfo();
71-
setPublishConfig(prev => ({ ...prev, tenantId: response.data.tenant }));
79+
// Only set default tenant if admin hasn't selected one
80+
if (!user?.isAdmin) {
81+
setPublishConfig(prev => ({ ...prev, tenantId: response.data.tenant }));
82+
}
7283
} catch (error) {
7384
console.error('Error fetching tenant info:', error);
7485
}
7586
};
7687

88+
const fetchTenants = async () => {
89+
try {
90+
const response = await api.getTenants();
91+
setTenants(response.data.tenants || []);
92+
93+
// Set default tenant for admin
94+
if (response.data.tenants && response.data.tenants.length > 0) {
95+
const defaultTenant = response.data.tenants[0].id;
96+
setPublishConfig(prev => ({ ...prev, tenantId: defaultTenant }));
97+
}
98+
} catch (error) {
99+
console.error('Error fetching tenants:', error);
100+
toast.error('Failed to fetch tenant list');
101+
}
102+
};
103+
77104
const validateModel = (model) => {
78105
const errors = [];
79106

@@ -125,9 +152,17 @@ const PublishingWorkflow = ({ modelName, onComplete, onCancel }) => {
125152
const handlePublish = async () => {
126153
setLoading(true);
127154
try {
128-
const response = await api.publishModel(modelName, {
155+
// Add tenant parameter for admin users
156+
const requestBody = {
129157
config: publishConfig
130-
});
158+
};
159+
160+
// If admin is publishing to a specific tenant, include tenant in request
161+
if (user?.isAdmin && publishConfig.tenantId) {
162+
requestBody.config.tenantID = publishConfig.tenantId;
163+
}
164+
165+
const response = await api.publishModel(modelName, requestBody);
131166

132167
setPublishedModel(response.data.publishedModel);
133168
setCurrentStep(4);
@@ -301,6 +336,34 @@ const PublishingWorkflow = ({ modelName, onComplete, onCancel }) => {
301336

302337
<div style={{ display: 'flex', flexDirection: 'column', gap: '2rem' }}>
303338

339+
{/* Tenant Selection - Only for admins */}
340+
{user?.isAdmin && (
341+
<div>
342+
<h4 style={{ marginBottom: '1rem', display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
343+
<Settings size={16} />
344+
Target Tenant
345+
</h4>
346+
<div className="form-group">
347+
<select
348+
value={publishConfig.tenantId}
349+
onChange={(e) => handleConfigChange('tenantId', e.target.value)}
350+
className="form-control"
351+
required
352+
>
353+
<option value="">Select a tenant</option>
354+
{tenants.map(tenant => (
355+
<option key={tenant.id} value={tenant.id}>
356+
{tenant.name || tenant.id}
357+
</option>
358+
))}
359+
</select>
360+
<div style={{ fontSize: '0.875rem', color: '#6b7280', marginTop: '0.5rem' }}>
361+
Select the tenant namespace where the model should be published
362+
</div>
363+
</div>
364+
</div>
365+
)}
366+
304367
{/* Model Type Detection */}
305368
<div>
306369
<h4 style={{ marginBottom: '1rem', display: 'flex', alignItems: 'center', gap: '0.5rem' }}>

management/ui/src/contexts/ApiContext.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,19 @@ export const ApiProvider = ({ children }) => {
6060

6161
// Model Publishing
6262
publishModel: (modelName, publishConfig) => api.post(`/models/${modelName}/publish`, publishConfig),
63-
unpublishModel: (modelName) => api.delete(`/models/${modelName}/publish`),
64-
getPublishedModel: (modelName) => api.get(`/models/${modelName}/publish`),
63+
unpublishModel: (modelName, namespace = null) => {
64+
const params = namespace ? { namespace } : {};
65+
return api.delete(`/models/${modelName}/publish`, { params });
66+
},
67+
getPublishedModel: (modelName, namespace = null) => {
68+
const params = namespace ? { namespace } : {};
69+
return api.get(`/models/${modelName}/publish`, { params });
70+
},
6571
getPublishedModels: () => api.get('/published-models'),
66-
rotateAPIKey: (modelName) => api.post(`/models/${modelName}/publish/rotate-key`),
72+
rotateAPIKey: (modelName, namespace = null) => {
73+
const params = namespace ? { namespace } : {};
74+
return api.post(`/models/${modelName}/publish/rotate-key`, {}, { params });
75+
},
6776
validateAPIKey: (apiKey) => api.post('/validate-api-key', { apiKey }),
6877

6978
// Admin endpoints

0 commit comments

Comments
 (0)