Compare commits
1 commit
main
...
feat/dashb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dcafd036fa |
2 changed files with 228 additions and 3 deletions
|
|
@ -144,6 +144,9 @@ func (m *Manager) ensureSidebar(ctx context.Context, crd *cozyv1alpha1.Applicati
|
|||
// Add sidebar for backups.cozystack.io Backup resource
|
||||
keysAndTags["backups"] = []any{"backup-sidebar"}
|
||||
|
||||
// Add sidebar for backups.cozystack.io RestoreJob resource
|
||||
keysAndTags["restorejobs"] = []any{"restorejob-sidebar"}
|
||||
|
||||
// 3) Sort items within each category by Weight (desc), then Label (A→Z)
|
||||
for cat := range categories {
|
||||
sort.Slice(categories[cat], func(i, j int) bool {
|
||||
|
|
@ -215,6 +218,11 @@ func (m *Manager) ensureSidebar(ctx context.Context, crd *cozyv1alpha1.Applicati
|
|||
"label": "Backups",
|
||||
"link": "/openapi-ui/{cluster}/{namespace}/api-table/backups.cozystack.io/v1alpha1/backups",
|
||||
},
|
||||
map[string]any{
|
||||
"key": "restorejobs",
|
||||
"label": "RestoreJobs",
|
||||
"link": "/openapi-ui/{cluster}/{namespace}/api-table/backups.cozystack.io/v1alpha1/restorejobs",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
|
|
@ -258,6 +266,7 @@ func (m *Manager) ensureSidebar(ctx context.Context, crd *cozyv1alpha1.Applicati
|
|||
"stock-project-factory-plan-details",
|
||||
"stock-project-factory-backupjob-details",
|
||||
"stock-project-factory-backup-details",
|
||||
"stock-project-factory-restorejob-details",
|
||||
"stock-project-factory-external-ips",
|
||||
"stock-project-api-form",
|
||||
"stock-project-api-table",
|
||||
|
|
|
|||
|
|
@ -411,6 +411,14 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid
|
|||
createTimestampColumn("Taken At", ".spec.takenAt"),
|
||||
createTimestampColumn("Created", ".metadata.creationTimestamp"),
|
||||
}),
|
||||
|
||||
// Stock namespace backups cozystack io v1alpha1 restorejobs
|
||||
createCustomColumnsOverride("stock-namespace-/backups.cozystack.io/v1alpha1/restorejobs", []any{
|
||||
createCustomColumnWithJsonPath("Name", ".metadata.name", "RestoreJob", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/restorejob-details/{reqsJsonPath[0]['.metadata.name']['-']}"),
|
||||
createStringColumn("Phase", ".status.phase"),
|
||||
createStringColumn("Backup", ".spec.backupRef.name"),
|
||||
createTimestampColumn("Created", ".metadata.creationTimestamp"),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -533,6 +541,31 @@ func CreateAllCustomFormsOverrides() []*dashboardv1alpha1.CustomFormsOverride {
|
|||
"backupClassName": listInputScemaItemBackupClass(),
|
||||
}),
|
||||
}),
|
||||
|
||||
// RestoreJobs form override - backups.cozystack.io/v1alpha1
|
||||
createCustomFormsOverride("default-/backups.cozystack.io/v1alpha1/restorejobs", map[string]any{
|
||||
"formItems": []any{
|
||||
createFormItem("metadata.name", "Name", "text"),
|
||||
createFormItem("metadata.namespace", "Namespace", "text"),
|
||||
createFormItem("spec.backupRef.name", "Backup", "text"),
|
||||
// Target application: leave empty to restore into the same application
|
||||
// as referenced by the selected Backup. Fill all three only to rename
|
||||
// or restore into a different application.
|
||||
createFormItem("spec.targetApplicationRef.apiGroup", "Target Application API Group (optional, only for rename)", "text"),
|
||||
createFormItem("spec.targetApplicationRef.kind", "Target Application Kind (optional, only for rename)", "text"),
|
||||
createFormItem("spec.targetApplicationRef.name", "Target Application Name (optional, only for rename)", "text"),
|
||||
// Driver-specific options (key-value editor). Known keys for VMInstance:
|
||||
// targetNamespace, failIfTargetExists, keepOriginalPVC, keepOriginalIpAndMac.
|
||||
createFormItem("spec.options", "Options (VMInstance keys: targetNamespace, failIfTargetExists, keepOriginalPVC, keepOriginalIpAndMac)", "object"),
|
||||
},
|
||||
"schema": createSchema(map[string]any{
|
||||
"backupRef": map[string]any{
|
||||
"properties": map[string]any{
|
||||
"name": listInputSchemaItemBackup(),
|
||||
},
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1923,6 +1956,174 @@ func CreateAllFactories() []*dashboardv1alpha1.Factory {
|
|||
}
|
||||
backupSpec := createUnifiedFactory(backupConfig, backupTabs, []any{"/api/clusters/{2}/k8s/apis/backups.cozystack.io/v1alpha1/namespaces/{3}/backups/{6}"})
|
||||
|
||||
// RestoreJob details factory using unified approach
|
||||
restoreJobConfig := UnifiedResourceConfig{
|
||||
Name: "restorejob-details",
|
||||
ResourceType: "factory",
|
||||
Kind: "RestoreJob",
|
||||
Plural: "restorejobs",
|
||||
Title: "restorejob",
|
||||
}
|
||||
restoreJobTabs := []any{
|
||||
map[string]any{
|
||||
"key": "details",
|
||||
"label": "Details",
|
||||
"children": []any{
|
||||
contentCard("details-card", map[string]any{
|
||||
"marginBottom": "24px",
|
||||
}, []any{
|
||||
antdText("details-title", true, "RestoreJob details", map[string]any{
|
||||
"fontSize": 20,
|
||||
"marginBottom": "12px",
|
||||
}),
|
||||
spacer("details-spacer", 16),
|
||||
antdRow("details-grid", []any{48, 12}, []any{
|
||||
antdCol("col-left", 12, []any{
|
||||
antdFlexVertical("col-left-stack", 24, []any{
|
||||
antdFlexVertical("meta-name-block", 4, []any{
|
||||
antdText("meta-name-label", true, "Name", nil),
|
||||
parsedText("meta-name-value", "{reqsJsonPath[0]['.metadata.name']['-']}", nil),
|
||||
}),
|
||||
antdFlexVertical("meta-namespace-block", 8, []any{
|
||||
antdText("meta-namespace-label", true, "Namespace", nil),
|
||||
antdFlex("header-row", 6, []any{
|
||||
map[string]any{
|
||||
"type": "antdText",
|
||||
"data": map[string]any{
|
||||
"id": "header-badge",
|
||||
"text": "NS",
|
||||
"title": "namespace",
|
||||
"style": map[string]any{
|
||||
"backgroundColor": "#a25792ff",
|
||||
"borderRadius": "20px",
|
||||
"color": "#fff",
|
||||
"display": "inline-block",
|
||||
"fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif",
|
||||
"fontSize": "15px",
|
||||
"fontWeight": 400,
|
||||
"lineHeight": "24px",
|
||||
"minWidth": 24,
|
||||
"padding": "0 9px",
|
||||
"textAlign": "center",
|
||||
"whiteSpace": "nowrap",
|
||||
},
|
||||
},
|
||||
},
|
||||
map[string]any{
|
||||
"type": "antdLink",
|
||||
"data": map[string]any{
|
||||
"id": "namespace-link",
|
||||
"text": "{reqsJsonPath[0]['.metadata.namespace']['-']}",
|
||||
"href": "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/marketplace",
|
||||
},
|
||||
},
|
||||
}),
|
||||
}),
|
||||
antdFlexVertical("meta-created-block", 4, []any{
|
||||
antdText("time-label", true, "Created", nil),
|
||||
antdFlex("time-block", 6, []any{
|
||||
map[string]any{
|
||||
"type": "antdText",
|
||||
"data": map[string]any{
|
||||
"id": "time-icon",
|
||||
"text": "🌐",
|
||||
},
|
||||
},
|
||||
map[string]any{
|
||||
"type": "parsedText",
|
||||
"data": map[string]any{
|
||||
"formatter": "timestamp",
|
||||
"id": "time-value",
|
||||
"text": "{reqsJsonPath[0]['.metadata.creationTimestamp']['-']}",
|
||||
},
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
antdCol("col-right", 12, []any{
|
||||
antdFlexVertical("col-right-stack", 24, []any{
|
||||
antdFlexVertical("status-phase-block", 4, []any{
|
||||
antdText("phase-label", true, "Phase", nil),
|
||||
parsedText("phase-value", "{reqsJsonPath[0]['.status.phase']['-']}", nil),
|
||||
}),
|
||||
antdFlexVertical("spec-backup-ref-block", 4, []any{
|
||||
antdText("backup-ref-label", true, "Backup Ref", nil),
|
||||
parsedText("backup-ref-value", "{reqsJsonPath[0]['.spec.backupRef.name']['-']}", nil),
|
||||
}),
|
||||
antdFlexVertical("spec-target-application-ref-block", 4, []any{
|
||||
antdText("target-application-ref-label", true, "Target Application", nil),
|
||||
parsedText("target-application-ref-value", "{reqsJsonPath[0]['.spec.targetApplicationRef.kind']['-']}.{reqsJsonPath[0]['.spec.targetApplicationRef.apiGroup']['-']}/{reqsJsonPath[0]['.spec.targetApplicationRef.name']['-']}", nil),
|
||||
}),
|
||||
antdFlexVertical("spec-options-target-namespace-block", 4, []any{
|
||||
antdText("options-target-namespace-label", true, "Target Namespace", nil),
|
||||
parsedText("options-target-namespace-value", "{reqsJsonPath[0]['.spec.options.targetNamespace']['-']}", nil),
|
||||
}),
|
||||
antdFlexVertical("spec-options-fail-if-target-exists-block", 4, []any{
|
||||
antdText("options-fail-if-target-exists-label", true, "Fail If Target Exists", nil),
|
||||
parsedText("options-fail-if-target-exists-value", "{reqsJsonPath[0]['.spec.options.failIfTargetExists']['-']}", nil),
|
||||
}),
|
||||
antdFlexVertical("spec-options-keep-original-pvc-block", 4, []any{
|
||||
antdText("options-keep-original-pvc-label", true, "Keep Original PVC", nil),
|
||||
parsedText("options-keep-original-pvc-value", "{reqsJsonPath[0]['.spec.options.keepOriginalPVC']['-']}", nil),
|
||||
}),
|
||||
antdFlexVertical("spec-options-keep-original-ip-mac-block", 4, []any{
|
||||
antdText("options-keep-original-ip-mac-label", true, "Keep Original IP/MAC", nil),
|
||||
parsedText("options-keep-original-ip-mac-value", "{reqsJsonPath[0]['.spec.options.keepOriginalIpAndMac']['-']}", nil),
|
||||
}),
|
||||
antdFlexVertical("status-started-at-block", 4, []any{
|
||||
antdText("started-at-label", true, "Started At", nil),
|
||||
antdFlex("time-block", 6, []any{
|
||||
map[string]any{
|
||||
"type": "antdText",
|
||||
"data": map[string]any{
|
||||
"id": "time-icon",
|
||||
"text": "🌐",
|
||||
},
|
||||
},
|
||||
map[string]any{
|
||||
"type": "parsedText",
|
||||
"data": map[string]any{
|
||||
"formatter": "timestamp",
|
||||
"id": "time-value",
|
||||
"text": "{reqsJsonPath[0]['.status.startedAt']['-']}",
|
||||
},
|
||||
},
|
||||
}),
|
||||
}),
|
||||
antdFlexVertical("status-completed-at-block", 4, []any{
|
||||
antdText("completed-at-label", true, "Completed At", nil),
|
||||
antdFlex("time-block", 6, []any{
|
||||
map[string]any{
|
||||
"type": "antdText",
|
||||
"data": map[string]any{
|
||||
"id": "time-icon",
|
||||
"text": "🌐",
|
||||
},
|
||||
},
|
||||
map[string]any{
|
||||
"type": "parsedText",
|
||||
"data": map[string]any{
|
||||
"formatter": "timestamp",
|
||||
"id": "time-value",
|
||||
"text": "{reqsJsonPath[0]['.status.completedAt']['-']}",
|
||||
},
|
||||
},
|
||||
}),
|
||||
}),
|
||||
antdFlexVertical("status-message-block", 4, []any{
|
||||
antdText("message-label", true, "Message", nil),
|
||||
parsedText("message-value", "{reqsJsonPath[0]['.status.message']['-']}", nil),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
},
|
||||
},
|
||||
}
|
||||
restoreJobSpec := createUnifiedFactory(restoreJobConfig, restoreJobTabs, []any{"/api/clusters/{2}/k8s/apis/backups.cozystack.io/v1alpha1/namespaces/{3}/restorejobs/{6}"})
|
||||
|
||||
// External IPs factory (filtered services)
|
||||
externalIPsTabs := []any{
|
||||
map[string]any{
|
||||
|
|
@ -1975,6 +2176,7 @@ func CreateAllFactories() []*dashboardv1alpha1.Factory {
|
|||
createFactory("plan-details", planSpec),
|
||||
createFactory("backupjob-details", backupJobSpec),
|
||||
createFactory("backup-details", backupSpec),
|
||||
createFactory("restorejob-details", restoreJobSpec),
|
||||
createFactory("external-ips", externalIPsSpec),
|
||||
}
|
||||
}
|
||||
|
|
@ -1994,9 +2196,10 @@ func CreateAllNavigations() []*dashboardv1alpha1.Navigation {
|
|||
"base-factory-namespaced-api-networking.k8s.io-v1-ingresses": "kube-ingress-details",
|
||||
"base-factory-namespaced-api-cozystack.io-v1alpha1-workloadmonitors": "workloadmonitor-details",
|
||||
// Backup resources (not ApplicationDefinitions, so ensureNavigation doesn't cover them)
|
||||
"base-factory-namespaced-api-backups.cozystack.io-v1alpha1-plans": "plan-details",
|
||||
"base-factory-namespaced-api-backups.cozystack.io-v1alpha1-backupjobs": "backupjob-details",
|
||||
"base-factory-namespaced-api-backups.cozystack.io-v1alpha1-backups": "backup-details",
|
||||
"base-factory-namespaced-api-backups.cozystack.io-v1alpha1-plans": "plan-details",
|
||||
"base-factory-namespaced-api-backups.cozystack.io-v1alpha1-backupjobs": "backupjob-details",
|
||||
"base-factory-namespaced-api-backups.cozystack.io-v1alpha1-backups": "backup-details",
|
||||
"base-factory-namespaced-api-backups.cozystack.io-v1alpha1-restorejobs": "restorejob-details",
|
||||
}
|
||||
|
||||
return []*dashboardv1alpha1.Navigation{
|
||||
|
|
@ -2121,6 +2324,19 @@ func listInputScemaItemBackupClass() map[string]any {
|
|||
}
|
||||
}
|
||||
|
||||
// listInputSchemaItemBackup returns a listInput schema overlay for selecting a Backup
|
||||
// from the current namespace (used by RestoreJob form for spec.backupRef.name).
|
||||
func listInputSchemaItemBackup() map[string]any {
|
||||
return map[string]any{
|
||||
"type": "listInput",
|
||||
"customProps": map[string]any{
|
||||
"valueUri": "/api/clusters/{cluster}/k8s/apis/backups.cozystack.io/v1alpha1/namespaces/{namespace}/backups",
|
||||
"keysToValue": []any{"metadata", "name"},
|
||||
"keysToLabel": []any{"metadata", "name"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// backupClassSchema returns the schema for spec.backupClassName as listInput (BackupJob/Plan).
|
||||
func createSchema(customProps map[string]any) map[string]any {
|
||||
return map[string]any{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue