Skip to content

Commit 45d4294

Browse files
committed
Add model transfer jobs table with BFF mocks
1 parent 236c009 commit 45d4294

21 files changed

+1118
-63
lines changed

clients/ui/bff/internal/api/app.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ const (
7474
ModelCatalogSettingsSourceConfigListPath = ModelCatalogSettingsPathPrefix + "/source_configs"
7575
ModelCatalogSettingsSourceConfigPath = ModelCatalogSettingsSourceConfigListPath + "/:" + CatalogSourceId
7676
CatalogSourcePreviewPath = ModelCatalogSettingsPathPrefix + "/source_preview"
77+
78+
// Model Transfer Jobs
79+
ModelTransferJobListPath = ModelRegistryPath + "/model_transfer_jobs"
7780
)
7881

7982
type App struct {
@@ -231,6 +234,9 @@ func (app *App) Routes() http.Handler {
231234
apiRouter.PATCH(ModelRegistryPath, app.AttachNamespace(app.RequireAccessToMRService(app.AttachModelRegistryRESTClient(app.UpdateModelVersionHandler))))
232235
apiRouter.PATCH(ModelArtifactPath, app.AttachNamespace(app.RequireAccessToMRService(app.AttachModelRegistryRESTClient(app.UpdateModelArtifactHandler))))
233236

237+
// Model Transfer Jobs
238+
apiRouter.GET(ModelTransferJobListPath, app.AttachNamespace(app.RequireAccessToMRService(app.GetAllModelTransferJobsHandler)))
239+
234240
// Model catalog HTTP client routes (requests that we forward to Model Catalog API)
235241
apiRouter.GET(CatalogModelListPath, app.AttachNamespace(app.AttachModelCatalogRESTClient(app.GetAllCatalogModelsAcrossSourcesHandler)))
236242
apiRouter.GET(CatalogSourceListPath, app.AttachNamespace(app.AttachModelCatalogRESTClient(app.GetAllCatalogSourcesHandler)))
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package api
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"net/http"
7+
8+
"github.com/julienschmidt/httprouter"
9+
"github.com/kubeflow/model-registry/ui/bff/internal/constants"
10+
"github.com/kubeflow/model-registry/ui/bff/internal/models"
11+
)
12+
13+
type ModelTransferJobListEnvelope Envelope[*models.ModelTransferJobList, None]
14+
15+
func (app *App) GetAllModelTransferJobsHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
16+
ctx := r.Context()
17+
18+
namespace, ok := ctx.Value(constants.NamespaceHeaderParameterKey).(string)
19+
if !ok || namespace == "" {
20+
app.badRequestResponse(w, r, fmt.Errorf("missing namespace in context"))
21+
return
22+
}
23+
24+
client, err := app.kubernetesClientFactory.GetClient(ctx)
25+
if err != nil {
26+
app.serverErrorResponse(w, r, errors.New("kubernetes client not found"))
27+
return
28+
}
29+
30+
transferJobs, err := app.repositories.ModelRegistry.GetAllModelTransferJobs(ctx, client, namespace)
31+
if err != nil {
32+
app.serverErrorResponse(w, r, err)
33+
return
34+
}
35+
36+
response := ModelTransferJobListEnvelope{
37+
Data: transferJobs,
38+
}
39+
40+
err = app.WriteJSON(w, http.StatusOK, response, nil)
41+
if err != nil {
42+
app.serverErrorResponse(w, r, err)
43+
}
44+
}

clients/ui/bff/internal/mocks/static_data_mock.go

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2267,3 +2267,129 @@ func CreateCatalogSourcePreviewMockWithFilter(filterStatus string, pageSize int,
22672267
Size: int32(len(pagedModels)),
22682268
}
22692269
}
2270+
2271+
// Model Transfer Job Mocks
2272+
2273+
func GetModelTransferJobMocks() []models.ModelTransferJob {
2274+
job1 := models.ModelTransferJob{
2275+
Id: "1",
2276+
Name: "my-registry-my-model-3-v1",
2277+
Description: "Sample description for version",
2278+
Source: models.ModelTransferJobSource{
2279+
Type: models.ModelTransferJobSourceTypeS3,
2280+
Bucket: "source-bucket",
2281+
Key: "models/my-model-3/v1",
2282+
Region: "us-east-1",
2283+
},
2284+
Destination: models.ModelTransferJobDestination{
2285+
Type: models.ModelTransferJobDestinationTypeS3,
2286+
Bucket: "destination-bucket",
2287+
Key: "models/my-model-3/v1",
2288+
Region: "us-west-2",
2289+
},
2290+
UploadIntent: models.ModelTransferJobUploadIntentCreateVersion,
2291+
RegisteredModelId: "1",
2292+
RegisteredModelName: "my-model-3",
2293+
ModelVersionId: "1",
2294+
ModelVersionName: "v1",
2295+
Project: "project - 1",
2296+
Author: "alice",
2297+
Status: models.ModelTransferJobStatusRunning,
2298+
CreateTimeSinceEpoch: "1725282249921",
2299+
LastUpdateTimeSinceEpoch: "1725282249921",
2300+
}
2301+
2302+
job2 := models.ModelTransferJob{
2303+
Id: "2",
2304+
Name: "my-registry-my-model-2-version-2",
2305+
Description: "Sample description for version",
2306+
Source: models.ModelTransferJobSource{
2307+
Type: models.ModelTransferJobSourceTypeOCI,
2308+
URI: "quay.io/ml-models/my-model-2:v2",
2309+
Registry: "quay.io",
2310+
},
2311+
Destination: models.ModelTransferJobDestination{
2312+
Type: models.ModelTransferJobDestinationTypeOCI,
2313+
URI: "registry.internal.io/models/my-model-2:v2",
2314+
Registry: "registry.internal.io",
2315+
},
2316+
UploadIntent: models.ModelTransferJobUploadIntentCreateVersion,
2317+
RegisteredModelId: "2",
2318+
RegisteredModelName: "my-model-2",
2319+
ModelVersionId: "2",
2320+
ModelVersionName: "Version-2",
2321+
Project: "my project",
2322+
Author: "bob",
2323+
Status: models.ModelTransferJobStatusCompleted,
2324+
CreateTimeSinceEpoch: "1725282189921",
2325+
LastUpdateTimeSinceEpoch: "1725282219921",
2326+
}
2327+
2328+
job3 := models.ModelTransferJob{
2329+
Id: "3",
2330+
Name: "my-registry-demo-model-version-1",
2331+
Description: "Sample description for version",
2332+
Source: models.ModelTransferJobSource{
2333+
Type: models.ModelTransferJobSourceTypeURI,
2334+
URI: "https://huggingface.co/models/demo-model/resolve/main/model.safetensors",
2335+
},
2336+
Destination: models.ModelTransferJobDestination{
2337+
Type: models.ModelTransferJobDestinationTypeS3,
2338+
Bucket: "model-storage",
2339+
Key: "demo-model/version-1",
2340+
Region: "us-east-1",
2341+
},
2342+
UploadIntent: models.ModelTransferJobUploadIntentCreateVersion,
2343+
RegisteredModelId: "3",
2344+
RegisteredModelName: "demo-model",
2345+
ModelVersionId: "3",
2346+
ModelVersionName: "Version-1",
2347+
Project: "my project - 2",
2348+
Author: "alice",
2349+
Status: models.ModelTransferJobStatusRunning,
2350+
CreateTimeSinceEpoch: "1725282069921",
2351+
LastUpdateTimeSinceEpoch: "1725282129921",
2352+
}
2353+
2354+
job4 := models.ModelTransferJob{
2355+
Id: "4",
2356+
Name: "my-registry-demo-model-demo",
2357+
Description: "Sample description for version",
2358+
Source: models.ModelTransferJobSource{
2359+
Type: models.ModelTransferJobSourceTypeS3,
2360+
Bucket: "source-bucket",
2361+
Key: "models/demo-model/demo",
2362+
Region: "us-east-1",
2363+
},
2364+
Destination: models.ModelTransferJobDestination{
2365+
Type: models.ModelTransferJobDestinationTypeS3,
2366+
Bucket: "destination-bucket",
2367+
Key: "models/demo-model/demo",
2368+
Region: "us-west-2",
2369+
},
2370+
UploadIntent: models.ModelTransferJobUploadIntentCreateVersion,
2371+
RegisteredModelId: "3",
2372+
RegisteredModelName: "demo-model",
2373+
ModelVersionId: "4",
2374+
ModelVersionName: "demo",
2375+
Project: "demo project",
2376+
Author: "alice",
2377+
Status: models.ModelTransferJobStatusFailed,
2378+
ErrorMessage: "Short reason for failure",
2379+
CreateTimeSinceEpoch: "1724504649921",
2380+
LastUpdateTimeSinceEpoch: "1724504749921",
2381+
}
2382+
2383+
return []models.ModelTransferJob{job1, job2, job3, job4}
2384+
}
2385+
2386+
func GetModelTransferJobListMock() models.ModelTransferJobList {
2387+
jobs := GetModelTransferJobMocks()
2388+
2389+
return models.ModelTransferJobList{
2390+
Items: jobs,
2391+
Size: len(jobs),
2392+
PageSize: 10,
2393+
NextPageToken: "",
2394+
}
2395+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package models
2+
3+
// ModelTransferJobSourceType represents the type of source for a transfer job
4+
type ModelTransferJobSourceType string
5+
6+
const (
7+
ModelTransferJobSourceTypeS3 ModelTransferJobSourceType = "s3"
8+
ModelTransferJobSourceTypeOCI ModelTransferJobSourceType = "oci"
9+
ModelTransferJobSourceTypeURI ModelTransferJobSourceType = "uri"
10+
)
11+
12+
// ModelTransferJobDestinationType represents the type of destination for a transfer job
13+
type ModelTransferJobDestinationType string
14+
15+
const (
16+
ModelTransferJobDestinationTypeS3 ModelTransferJobDestinationType = "s3"
17+
ModelTransferJobDestinationTypeOCI ModelTransferJobDestinationType = "oci"
18+
)
19+
20+
// ModelTransferJobStatus represents the status of a transfer job
21+
type ModelTransferJobStatus string
22+
23+
const (
24+
ModelTransferJobStatusPending ModelTransferJobStatus = "PENDING"
25+
ModelTransferJobStatusRunning ModelTransferJobStatus = "RUNNING"
26+
ModelTransferJobStatusCompleted ModelTransferJobStatus = "COMPLETED"
27+
ModelTransferJobStatusFailed ModelTransferJobStatus = "FAILED"
28+
ModelTransferJobStatusCancelled ModelTransferJobStatus = "CANCELLED"
29+
)
30+
31+
// ModelTransferJobUploadIntent represents the intent of the upload
32+
type ModelTransferJobUploadIntent string
33+
34+
const (
35+
ModelTransferJobUploadIntentCreateModel ModelTransferJobUploadIntent = "create_model"
36+
ModelTransferJobUploadIntentCreateVersion ModelTransferJobUploadIntent = "create_version"
37+
ModelTransferJobUploadIntentUpdateArtifact ModelTransferJobUploadIntent = "update_artifact"
38+
)
39+
40+
// ModelTransferJobSource represents the source configuration for a transfer job
41+
type ModelTransferJobSource struct {
42+
Type ModelTransferJobSourceType `json:"type"`
43+
Bucket string `json:"bucket,omitempty"`
44+
Key string `json:"key,omitempty"`
45+
Region string `json:"region,omitempty"`
46+
Endpoint string `json:"endpoint,omitempty"`
47+
URI string `json:"uri,omitempty"`
48+
Registry string `json:"registry,omitempty"`
49+
}
50+
51+
// ModelTransferJobDestination represents the destination configuration for a transfer job
52+
type ModelTransferJobDestination struct {
53+
Type ModelTransferJobDestinationType `json:"type"`
54+
Bucket string `json:"bucket,omitempty"`
55+
Key string `json:"key,omitempty"`
56+
Region string `json:"region,omitempty"`
57+
Endpoint string `json:"endpoint,omitempty"`
58+
URI string `json:"uri,omitempty"`
59+
Registry string `json:"registry,omitempty"`
60+
}
61+
62+
// ModelTransferJob represents a model transfer job
63+
type ModelTransferJob struct {
64+
Id string `json:"id"`
65+
Name string `json:"name"`
66+
Description string `json:"description,omitempty"`
67+
Source ModelTransferJobSource `json:"source"`
68+
Destination ModelTransferJobDestination `json:"destination"`
69+
UploadIntent ModelTransferJobUploadIntent `json:"uploadIntent"`
70+
RegisteredModelId string `json:"registeredModelId,omitempty"`
71+
RegisteredModelName string `json:"registeredModelName,omitempty"`
72+
ModelVersionId string `json:"modelVersionId,omitempty"`
73+
ModelVersionName string `json:"modelVersionName,omitempty"`
74+
ModelArtifactId string `json:"modelArtifactId,omitempty"`
75+
ModelArtifactName string `json:"modelArtifactName,omitempty"`
76+
Project string `json:"project,omitempty"`
77+
Author string `json:"author,omitempty"`
78+
Status ModelTransferJobStatus `json:"status"`
79+
CreateTimeSinceEpoch string `json:"createTimeSinceEpoch"`
80+
LastUpdateTimeSinceEpoch string `json:"lastUpdateTimeSinceEpoch"`
81+
ErrorMessage string `json:"errorMessage,omitempty"`
82+
}
83+
84+
// ModelTransferJobList represents a list of model transfer jobs
85+
type ModelTransferJobList struct {
86+
Items []ModelTransferJob `json:"items"`
87+
Size int `json:"size"`
88+
PageSize int `json:"pageSize"`
89+
NextPageToken string `json:"nextPageToken"`
90+
}

clients/ui/bff/internal/repositories/model_registry.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"github.com/kubeflow/model-registry/ui/bff/internal/constants"
88
helper "github.com/kubeflow/model-registry/ui/bff/internal/helpers"
99
k8s "github.com/kubeflow/model-registry/ui/bff/internal/integrations/kubernetes"
10-
10+
"github.com/kubeflow/model-registry/ui/bff/internal/mocks"
1111
"github.com/kubeflow/model-registry/ui/bff/internal/models"
1212
)
1313

@@ -133,3 +133,12 @@ func (m *ModelRegistryRepository) ResolveServerAddress(clusterIP string, httpPor
133133
url := fmt.Sprintf("%s://%s:%d/api/model_registry/v1alpha3", protocol, clusterIP, httpPort)
134134
return url
135135
}
136+
137+
// GetAllModelTransferJobs returns all model transfer jobs for the given namespace
138+
// TODO: Replace with actual implementation when backend API is available
139+
func (m *ModelRegistryRepository) GetAllModelTransferJobs(_ context.Context, _ k8s.KubernetesClientInterface, _ string) (*models.ModelTransferJobList, error) {
140+
// TODO: Implement actual API call to fetch transfer jobs
141+
// For now, return mock data for development/testing
142+
mockData := mocks.GetModelTransferJobListMock()
143+
return &mockData, nil
144+
}

clients/ui/frontend/src/__mocks__/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ export * from './mockCatalogSourceList';
66
export * from './mockCatalogSourceConfigList';
77
export * from './mockCatalogModelList';
88
export * from './mockCatalogModelArtifactList';
9+
export * from './mockModelTransferJob';

0 commit comments

Comments
 (0)