Skip to content

Commit a63b477

Browse files
Add YAML preview drawer (kubeflow#2279)
Signed-off-by: Philip Colares Carneiro <philip.colares@gmail.com>
1 parent 82182e4 commit a63b477

18 files changed

Lines changed: 610 additions & 41 deletions

Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,11 @@ else
3838
endif
3939

4040
# Change Dockerfile path depending on IMG_REPO
41+
# UI image uses repo root as context so COPY manifests/... for sample-catalog.yaml works
4142
ifeq ($(IMG_REPO),model-registry/ui)
4243
DOCKERFILE := $(UI_PATH)/Dockerfile
43-
BUILD_PATH := $(UI_PATH)
44+
BUILD_PATH := $(PROJECT_PATH)
45+
ARGS := --build-arg UI_SOURCE_CODE=clients/ui/frontend --build-arg BFF_SOURCE_CODE=clients/ui/bff $(ARGS)
4446
endif
4547

4648
# The BUILD_PATH is still the root

clients/ui/Makefile

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,33 +74,35 @@ dev-bff-federated:
7474

7575
############ Build ############
7676

77+
DOCKER_BUILD_ARGS := --build-arg UI_SOURCE_CODE=clients/ui/frontend --build-arg BFF_SOURCE_CODE=clients/ui/bff
78+
7779
.PHONY: docker-build
7880
docker-build:
79-
$(CONTAINER_TOOL) build --build-arg DEPLOYMENT_MODE=kubeflow --build-arg STYLE_THEME=mui-theme -t ${IMG_UI} .
81+
$(CONTAINER_TOOL) build -f Dockerfile $(DOCKER_BUILD_ARGS) --build-arg DEPLOYMENT_MODE=kubeflow --build-arg STYLE_THEME=mui-theme -t ${IMG_UI} ../..
8082

8183
.PHONY: docker-build-standalone
8284
docker-build-standalone:
83-
$(CONTAINER_TOOL) build -f Dockerfile.standalone --build-arg DEPLOYMENT_MODE=standalone --build-arg STYLE_THEME=mui-theme -t ${IMG_UI_STANDALONE} .
85+
$(CONTAINER_TOOL) build -f Dockerfile.standalone $(DOCKER_BUILD_ARGS) --build-arg DEPLOYMENT_MODE=standalone --build-arg STYLE_THEME=mui-theme -t ${IMG_UI_STANDALONE} ../..
8486

8587
.PHONY: docker-build-standalone-release
8688
docker-build-standalone-release:
87-
$(CONTAINER_TOOL) build -f Dockerfile.standalone --target release --build-arg DEPLOYMENT_MODE=standalone --build-arg STYLE_THEME=mui-theme -t ${IMG_UI_STANDALONE} .
89+
$(CONTAINER_TOOL) build -f Dockerfile.standalone --target release $(DOCKER_BUILD_ARGS) --build-arg DEPLOYMENT_MODE=standalone --build-arg STYLE_THEME=mui-theme -t ${IMG_UI_STANDALONE} ../..
8890

8991
.PHONY: docker-build-federated
9092
docker-build-federated:
91-
$(CONTAINER_TOOL) build --build-arg DEPLOYMENT_MODE=federated --build-arg STYLE_THEME=patternfly -t ${IMG_UI_FEDERATED} .
93+
$(CONTAINER_TOOL) build -f Dockerfile $(DOCKER_BUILD_ARGS) --build-arg DEPLOYMENT_MODE=federated --build-arg STYLE_THEME=patternfly -t ${IMG_UI_FEDERATED} ../..
9294

9395
.PHONY: docker-buildx
9496
docker-buildx:
95-
docker buildx build --build-arg DEPLOYMENT_MODE=kubeflow --build-arg STYLE_THEME=mui-theme --platform ${PLATFORM} -t ${IMG_UI} --push .
97+
docker buildx build -f Dockerfile $(DOCKER_BUILD_ARGS) --build-arg DEPLOYMENT_MODE=kubeflow --build-arg STYLE_THEME=mui-theme --platform ${PLATFORM} -t ${IMG_UI} --push ../..
9698

9799
.PHONY: docker-buildx-standalone
98100
docker-buildx-standalone:
99-
docker buildx build -f Dockerfile.standalone --build-arg DEPLOYMENT_MODE=standalone --build-arg STYLE_THEME=mui-theme --platform ${PLATFORM} -t ${IMG_UI_STANDALONE} --push .
101+
docker buildx build -f Dockerfile.standalone $(DOCKER_BUILD_ARGS) --build-arg DEPLOYMENT_MODE=standalone --build-arg STYLE_THEME=mui-theme --platform ${PLATFORM} -t ${IMG_UI_STANDALONE} --push ../..
100102

101103
.PHONY: docker-buildx-federated
102104
docker-buildx-federated:
103-
docker buildx build --build-arg DEPLOYMENT_MODE=federated --build-arg STYLE_THEME=patternfly --platform ${PLATFORM} -t ${IMG_UI_FEDERATED} --push .
105+
docker buildx build -f Dockerfile $(DOCKER_BUILD_ARGS) --build-arg DEPLOYMENT_MODE=federated --build-arg STYLE_THEME=patternfly --platform ${PLATFORM} -t ${IMG_UI_FEDERATED} --push ../..
104106

105107
############ Push ############
106108

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const fs = require('fs');
2+
3+
module.exports = {
4+
process(_src, filename) {
5+
const content = fs.readFileSync(filename, 'utf8');
6+
return { code: `module.exports = ${JSON.stringify(content)};` };
7+
},
8+
};

clients/ui/frontend/config/webpack.common.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ module.exports = (env) => ({
118118
options: {},
119119
},
120120
},
121+
{
122+
test: /\.ya?ml$/,
123+
use: { loader: 'raw-loader', options: {} },
124+
},
121125
{
122126
test: /\.(jpg|jpeg|png|gif)$/i,
123127
include: [
@@ -165,10 +169,6 @@ module.exports = (env) => ({
165169
'sass-loader',
166170
],
167171
},
168-
{
169-
test: /\.ya?ml$/,
170-
use: 'js-yaml-loader',
171-
},
172172
],
173173
},
174174
output: {
@@ -234,9 +234,15 @@ module.exports = (env) => ({
234234
}),
235235
],
236236
resolve: {
237-
extensions: ['.js', '.ts', '.tsx', '.jsx'],
237+
extensions: ['.js', '.ts', '.tsx', '.jsx', '.yaml'],
238238
alias: {
239239
'~': path.resolve(SRC_DIR),
240+
// Set SAMPLE_CATALOG_YAML_PATH to override the bundled sample YAML with a custom file at build time.
241+
...(process.env.SAMPLE_CATALOG_YAML_PATH && {
242+
'~/app/pages/modelCatalogSettings/sample-catalog.yaml': path.resolve(
243+
process.env.SAMPLE_CATALOG_YAML_PATH,
244+
),
245+
}),
240246
},
241247
symlinks: false,
242248
cacheWithContext: false,

clients/ui/frontend/jest.config.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ module.exports = {
2222
'~/(.*)': '<rootDir>/src/$1',
2323
},
2424

25+
transform: {
26+
'\\.(ts|tsx|js|jsx)$': 'ts-jest',
27+
'\\.yaml$': '<rootDir>/config/transform.yaml.js',
28+
},
29+
2530
// The test environment that will be used for testing.
2631
testEnvironment: 'jest-environment-jsdom',
2732

clients/ui/frontend/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"build:analyze": "run-s build build:bundle-profile build:bundle-analyze",
1515
"build:bundle-profile": "webpack --config ./config/webpack.prod.js --profile --json > ./bundle.stats.json",
1616
"build:bundle-analyze": "webpack-bundle-analyzer ./bundle.stats.json",
17-
"build:prod": "webpack --config ./config/webpack.prod.js",
17+
"build:prod": "npm run sync:sample-catalog && webpack --config ./config/webpack.prod.js",
18+
"sync:sample-catalog": "node scripts/sync-sample-catalog.js",
1819
"build:clean": "rm -rf ./dist",
1920
"start:dev": "webpack serve --hot --color --config ./config/webpack.dev.js",
2021
"test": "run-s test:lint test:type-check test:unit test:cypress-ci",
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* Syncs sample-catalog.yaml from manifests/ (repo root) into the frontend so the UI
3+
* shows the same content. Run before build when building from the full model-registry repo.
4+
* If manifests/ is not present (e.g. frontend used as subtree), this script no-ops.
5+
* To use a different YAML at build time, set SAMPLE_CATALOG_YAML_PATH in webpack build.
6+
*/
7+
const fs = require('fs');
8+
const path = require('path');
9+
10+
const source = path.join(
11+
__dirname,
12+
'../../../manifests/kustomize/options/catalog/base/sample-catalog.yaml',
13+
);
14+
const dest = path.join(
15+
__dirname,
16+
'../src/app/pages/modelCatalogSettings/sample-catalog.yaml',
17+
);
18+
19+
if (!fs.existsSync(source)) {
20+
process.exit(0);
21+
}
22+
fs.copyFileSync(source, dest);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import sampleCatalogYamlContent from '~/app/pages/modelCatalogSettings/sample-catalog.yaml';
2+
3+
describe('sample-catalog.yaml content', () => {
4+
it('exports a non-empty string', () => {
5+
expect(typeof sampleCatalogYamlContent).toBe('string');
6+
expect(sampleCatalogYamlContent.length).toBeGreaterThan(0);
7+
});
8+
9+
it('contains expected YAML structure keys', () => {
10+
expect(sampleCatalogYamlContent).toContain('source:');
11+
expect(sampleCatalogYamlContent).toContain('models:');
12+
});
13+
});
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import * as React from 'react';
2+
import {
3+
CodeBlock,
4+
CodeBlockCode,
5+
DrawerActions,
6+
DrawerCloseButton,
7+
DrawerHead,
8+
DrawerPanelBody,
9+
} from '@patternfly/react-core';
10+
import sampleCatalogYamlContent from '~/app/pages/modelCatalogSettings/sample-catalog.yaml';
11+
import { EXPECTED_YAML_FORMAT_LABEL } from '~/app/pages/modelCatalogSettings/constants';
12+
13+
type ExpectedYamlFormatDrawerPanelProps = {
14+
onClose: () => void;
15+
};
16+
17+
export const ExpectedYamlFormatDrawerPanel: React.FC<ExpectedYamlFormatDrawerPanelProps> = ({
18+
onClose,
19+
}) => (
20+
<>
21+
<DrawerHead>
22+
<span data-testid="expected-format-drawer-title">{EXPECTED_YAML_FORMAT_LABEL}</span>
23+
<DrawerActions>
24+
<DrawerCloseButton
25+
onClose={onClose}
26+
aria-label="Close drawer"
27+
data-testid="expected-format-drawer-close"
28+
/>
29+
</DrawerActions>
30+
</DrawerHead>
31+
<DrawerPanelBody hasNoPadding>
32+
<CodeBlock>
33+
<CodeBlockCode>{sampleCatalogYamlContent}</CodeBlockCode>
34+
</CodeBlock>
35+
</DrawerPanelBody>
36+
</>
37+
);

clients/ui/frontend/src/app/pages/modelCatalogSettings/components/ManageSourceForm.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,13 @@ import ManageSourceFormFooter from './ManageSourceFormFooter';
3333
type ManageSourceFormProps = {
3434
existingSourceConfig?: CatalogSourceConfig;
3535
isEditMode: boolean;
36+
onToggleExpectedFormatDrawer?: () => void;
3637
};
3738

3839
const ManageSourceForm: React.FC<ManageSourceFormProps> = ({
3940
existingSourceConfig,
4041
isEditMode,
42+
onToggleExpectedFormatDrawer,
4143
}) => {
4244
const navigate = useNavigate();
4345
const existingData = existingSourceConfig
@@ -120,7 +122,11 @@ const ManageSourceForm: React.FC<ManageSourceFormProps> = ({
120122

121123
{!formData.isDefault && !isHuggingFaceMode && (
122124
<StackItem>
123-
<YamlSection formData={formData} setData={setData} />
125+
<YamlSection
126+
formData={formData}
127+
setData={setData}
128+
onToggleExpectedFormatDrawer={onToggleExpectedFormatDrawer}
129+
/>
124130
</StackItem>
125131
)}
126132

0 commit comments

Comments
 (0)