Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"permissions": {
"allow": [
"Bash(grep -l \"$l\" build/assets/*.js)"
]
}
}
1 change: 1 addition & 0 deletions .env.production
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
VITE_PUBLIC_URL=/mlrun
VITE_FEDERATION=false
VITE_MLRUN_API_URL=${MLRUN_API_PROXY_URL}
VITE_MLRUN_V3IO_ACCESS_KEY=${MLRUN_V3IO_ACCESS_KEY}
VITE_IGUAZIO_API_URL=
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

# production
/build
.__mf__temp/
*.tar

# misc
.DS_Store
Expand Down
25 changes: 9 additions & 16 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,7 @@
# limitations under the License.
#
# build stage
# node:20.18.2-alpine used as 20-alpine
FROM quay.io/mlrun/node:20-alpine as build-stage

RUN apk update && \
apk upgrade && \
rm -rf /var/cache/apk/*
FROM quay.io/mlrun/node:20.19.2-slim AS build-stage

WORKDIR /app

Expand All @@ -30,32 +25,30 @@ RUN npm run build

ARG COMMIT_HASH
ARG DATE
RUN echo ${COMMIT_HASH} > ./build/COMMIT_HASH && \
echo ${DATE} > ./build/BUILD_DATE
RUN echo "${COMMIT_HASH}" > ./build/COMMIT_HASH && \
echo "${DATE}" > ./build/BUILD_DATE

# production stage
FROM gcr.io/iguazio/nginx-unprivileged:1.21-alpine as production-stage
FROM gcr.io/iguazio/nginx-unprivileged:1.21-alpine AS production-stage

# align UID & GID with nginx-unprivileged image UID & GID
ARG UID=101
ARG GID=101

USER root
# escalate permissions to update packages
RUN apk update --no-cache && apk upgrade --no-cache
# we are inheriting $UID and $GID from the base image, you can find more information here:
# https://github.com/nginxinc/docker-nginx-unprivileged/blob/main/Dockerfile-alpine.template
RUN apk update --no-cache && apk upgrade --no-cache \
&& rm -f /etc/nginx/conf.d/default.conf

USER $UID

COPY --from=build-stage /app/build /usr/share/nginx/html
COPY config.json.tmpl /usr/share/nginx/html/
RUN rm /etc/nginx/conf.d/default.conf

COPY nginx/nginx.conf.tmpl /etc/nginx/conf.d/
COPY nginx/run_nginx /etc/nginx/

USER root
# update build files permissions so they would be accessible to the running user
RUN chown -R $UID:0 /usr/share/nginx/html && chmod -R g+w /usr/share/nginx/html && chmod 777 /etc/nginx/run_nginx

USER $UID

EXPOSE 8090
Expand Down
67 changes: 67 additions & 0 deletions Dockerfile.mf
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Copyright 2019 Iguazio
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# build stage β€” Module Federation remote
FROM quay.io/mlrun/node:20.19.2-slim AS build-stage

WORKDIR /app

COPY package*.json ./
RUN npm install

COPY . .

RUN echo ">>> Building Module Federation remote" && \
sed -i "/^VITE_FEDERATION=/d" .env.production && \
echo "VITE_FEDERATION=true" >> .env.production && \
sed -i "s|^VITE_PUBLIC_URL=/mlrun|VITE_PUBLIC_URL=|" .env.production && \
echo ">>> Final .env.production:" && grep '^VITE_' .env.production

RUN npm run build

ARG COMMIT_HASH
ARG DATE
RUN echo "${COMMIT_HASH}" > ./build/COMMIT_HASH && \
echo "${DATE}" > ./build/BUILD_DATE

# production stage
FROM gcr.io/iguazio/nginx-unprivileged:1.21-alpine AS production-stage

ARG UID=101
ARG GID=101

USER root
RUN apk update --no-cache && apk upgrade --no-cache \
&& rm -f /etc/nginx/conf.d/default.conf

USER $UID

COPY --from=build-stage /app/build /usr/share/nginx/html
COPY --from=build-stage /app/.env.production /usr/share/nginx/html/

COPY nginx/nginx.conf.mf.tmpl /etc/nginx/conf.d/nginx.conf.tmpl
COPY nginx/run_nginx.mf /etc/nginx/run_nginx

USER root
RUN INDEX=/usr/share/nginx/html/index.html && \
[ -f "$INDEX" ] && sed -i 's|<base href="/mlrun"|<base href="/projects"|g' "$INDEX" && \
chown -R $UID:0 /usr/share/nginx/html && \
chmod -R g+w /usr/share/nginx/html && \
chmod 777 /etc/nginx/run_nginx

USER $UID

EXPOSE 8090

CMD ["/etc/nginx/run_nginx"]
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ Examples:
| `npm run docker` | `mlrun/mlrun-ui:latest` |
| `MLRUN_DOCKER_REGISTRY=quay.io/ MLRUN_DOCKER_REPO=iguazio MLRUN_DOCKER_TAG=0.4.9 npm run docker` | `quay.io/iguazio/mlrun-ui:0.4.9` |

### Docker build argument

The Docker build supports an optional argument:

`--build-arg IS_MF=${npm_config_IS_MF:-false}`

By default, `IS_MF` is `false`, and the image is built as a standard **mlrun-ui** build.<br />
When set to `true`, the image is built in **Module Federation** mode.

### `docker run` environment variables

The Docker container runs a Nginx server, which listens on exposed port number 8090, serves the web-app, and proxies to the backend API.
Expand All @@ -36,6 +45,7 @@ You can pass the following environment variables to the `docker run` command to
| `MLRUN_V3IO_ACCESS_KEY` | Sets the V3IO access key to use for accessing V3IO containers<br />Example: `a7097c94-6e8f-436d-9717-a84abe2861d1` |
| `MLRUN_FUNCTION_CATALOG_URL` | Sets the base URL of the function-template catalog <br />Default: `https://raw.githubusercontent.com` |
| `MLRUN_FUNCTION_CATALOG_PATH` | Sets the base URI of the function-template catalog <br />Default: `/mlrun/functions/master` |
| `MLRUN_IGZ_UI_ALLOWED_ORIGIN` | Allowed origin for Module Federation and CORS<br />Example: `https://igz-ui.pini.vmdev90ig4.lab.iguazeng.com` |

Example:

Expand Down Expand Up @@ -71,6 +81,11 @@ This command is run by the Dockerfile that is used by the command [`npm run dock

Note: `npm install` should be run first.

### `npm run preview:federation`

Builds and serves the **mlrun-ui** application in **Module Federation** mode at `http://localhost:5179/`.<br />
Use this command when developing locally with **igz-ui**, allowing **mlrun-ui** to be consumed as a remote module.

## Development

### Environment variables
Expand Down
3 changes: 2 additions & 1 deletion config.json.tmpl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"betaMode": "${MLRUN_BETA_MODE}",
"nuclioMode": "${MLRUN_NUCLIO_MODE}",
"nuclioUiUrl": "${MLRUN_NUCLIO_UI_URL}"
"nuclioUiUrl": "${MLRUN_NUCLIO_UI_URL}",
"nuclioRemoteEntryUrl": "${MLRUN_NUCLIO_REMOTE_ENTRY_URL}"
}
57 changes: 57 additions & 0 deletions config/loadDevProxyConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
Copyright 2019 Iguazio Systems Ltd.

Licensed under the Apache License, Version 2.0 (the "License") with
an addition restriction as set forth herein. You may not use this
file except in compliance with the License. You may obtain a copy of
the License at http://www.apache.org/licenses/LICENSE-2.0.

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.

In addition, you may not use the software for any purposes that are
illegal under applicable law, and the grant of the foregoing license
under the Apache 2.0 license is conditioned upon your compliance with
such restriction.
*/
/**
* Dynamically loads the Mlrun proxy configuration for development.
*
* Returns an empty proxy in production.
* In development, it imports the shared `mlrunProxyConfig` function
* from the `iguazio.dashboard-react-controls` package and validates its export.
*
* Node cannot use the aliased import
* (`import { mlrunProxyConfig } from 'igz-controls/utils/proxyServerConfig.util'`)
* since Vite path aliases are resolved only at build time,
* not during Node's module execution.
*/
import path from 'path'
import { pathToFileURL } from 'url'

export const loadMlrunProxyConfig = async mode => {
const modulePath = path.resolve(
'node_modules/iguazio.dashboard-react-controls/dist/utils/proxyServerConfig.util.mjs'
)

try {
const moduleUrl = pathToFileURL(modulePath).href

const { mlrunProxyConfig } = await import(moduleUrl)

if (typeof mlrunProxyConfig !== 'function') {
throw new Error('Invalid export: expected mlrunProxyConfig to be a function.')
}

return mlrunProxyConfig
} catch (error) {
if (process.env.PREVIEW_MODE === 'true' || mode === 'development') {
throw new Error(`Failed to load mlrunProxyConfig: ${error.message}`)
}

return () => ({})
}
}
16 changes: 10 additions & 6 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,28 @@ import react from 'eslint-plugin-react'
import reactHooks from 'eslint-plugin-react-hooks'
import eslintPluginImport from 'eslint-plugin-import'

import { viteGlobals } from './eslint.mlrun-globals.mjs'

export default [
{ ignores: ['dist'] },
{ ignores: ['dist', '.__mf__temp'] },
js.configs.recommended,
eslintConfigPrettier,
{
files: ['**/*.{js,jsx,ts,tsx}'],
files: ['**/*.{js,mjs,jsx,ts,tsx}'],
languageOptions: {
ecmaVersion: 2021,
globals: {
...globals.browser,
...globals.jest,
...globals.node
...globals.node,
...viteGlobals
},
parserOptions: {
ecmaFeatures: {
jsx: true
}
}
},
sourceType: 'module'
},
plugins: {
react: react,
Expand All @@ -49,9 +53,9 @@ export default [
}
},
{
files: ["**/*.test.jsx"],
files: ['**/*.test.jsx'],
rules: {
"import/named": "off"
'import/named': 'off'
}
}
]
9 changes: 9 additions & 0 deletions eslint.mlrun-globals.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const viteGlobals = {
VITE_PUBLIC_URL: 'readonly',
VITE_MLRUN_API_URL: 'readonly',
VITE_NUCLIO_API_URL: 'readonly',
VITE_IGUAZIO_API_URL: 'readonly',
VITE_FUNCTION_CATALOG_URL: 'readonly',
VITE_MLRUN_V3IO_ACCESS_KEY: 'readonly',
VITE_FEDERATION: 'readonly'
}
30 changes: 30 additions & 0 deletions nginx/nginx.conf.mf.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
server {
listen 8090;
server_name localhost;

root /usr/share/nginx/html;

# Basic Gzip as per standard defaults
gzip on;

# CRITICAL: Allow the Global Host (IGZ) to fetch these assets
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, OPTIONS';
add_header Access-Control-Allow-Headers 'Content-Type, Authorization';

location / {
# Show landing page when accessing the remote directly
index landing.html;
try_files $uri $uri/ /landing.html;

# Ensure remote assets are always fresh
if ($request_filename ~* .*\.(?:js|json)$ ) {
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
7 changes: 7 additions & 0 deletions nginx/run_nginx.mf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/sh

# Simply copy the template as the final config
cp /etc/nginx/conf.d/nginx.conf.tmpl /etc/nginx/conf.d/nginx.conf

# Start Nginx in foreground
exec nginx -g 'daemon off;'
Loading
Loading