Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce Nativelink Web UI #1449

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
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
4 changes: 4 additions & 0 deletions .github/styles/config/vocabularies/TraceMachina/accept.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,7 @@ Wainer
Gert
Bruer
Eagan
Vue
Vite
VSCode
Vetur
3 changes: 3 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,8 @@
};
};

nativelink-ui = pkgs.callPackage ./web/ui/image.nix {inherit buildImage pullImage pkgs;};

nativelink-worker-init = pkgs.callPackage ./tools/nativelink-worker-init.nix {inherit buildImage self nativelink-image;};

rbe-autogen = pkgs.callPackage ./local-remote-execution/rbe-autogen.nix {
Expand Down Expand Up @@ -419,6 +421,7 @@
nativelink-worker-init
nativelink-x86_64-linux
publish-ghcr
nativelink-ui # not working yet
;
default = nativelink;

Expand Down
1 change: 1 addition & 0 deletions tools/pre-commit-hooks.nix
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ in {

# Bun binary lockfile
"web/platform/bun.lockb"
"web/ui/bun.lockb"
];
enable = true;
types = ["binary"];
Expand Down
1 change: 1 addition & 0 deletions web/ui/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
BRIDGE_URL=
30 changes: 30 additions & 0 deletions web/ui/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
.DS_Store
dist
dist-ssr
coverage
*.local

/cypress/videos/
/cypress/screenshots/

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

*.tsbuildinfo
38 changes: 38 additions & 0 deletions web/ui/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# NativeLink Web UI

This template should help get you started developing with Vue 3 in Vite.

## Recommended IDE Setup

[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).

## Type Support for `.vue` Imports in TS

TypeScript can't handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.

## Customize configuration

See [Vite Configuration Reference](https://vite.dev/config/).

## Project Setup

```sh
bun install
```

### Compile and Hot-Reload for Development

```sh
bun dev
```

### Type-Check, Compile and Minify for Production

```sh
bun run build
```

### Preview the build
```sh
bun preview
```
Binary file added web/ui/bun.lockb
Binary file not shown.
1 change: 1 addition & 0 deletions web/ui/env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="vite/client" />
96 changes: 96 additions & 0 deletions web/ui/image.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
{
pkgs,
buildImage,
pullImage,
...
}: let
# Base image configuration for nginx:mainline-alpine-slim
imageParams = {
imageName = "nginx";
imageDigest = "sha256:e9293c9bedb0db866e7d2b69e58131db4c2478e6cd216cdd99b134830703983a";
sha256 = "sha256:63f36d95235a84d401bd3e061ffb0c25f72ca1d7b0ad154e583b7e25479d424f";
description = "Nginx mainline Alpine slim image for serving Vue3 applications.";
title = "Nginx Alpine Slim for Vue3";
};

# Derivation to build the Vue3 web UI using Bun
webUi = pkgs.stdenv.mkDerivation {
pname = "nativelink-web-ui";
version = "1.0.0"; # Update as necessary

src = ./.; # Path to your Vue3 project

buildInputs = [pkgs.bun];

# Ensure Bun is available in the build environment
buildPhase = ''
bun install
bun run build
'';

# Install the built files and nginx configuration
installPhase = ''
mkdir -p $out/dist
cp -r dist/* $out/dist/

mkdir -p $out/etc/nginx
cat > $out/etc/nginx/nginx.conf <<EOF
events {}
http {
server {
listen 80;
server_name localhost;

root /dist;
index index.html;

location / {
try_files \$uri \$uri/ /index.html;
}
}
}
EOF
'';

# Specify that only the /dist and /etc/nginx directories are output
meta = {
description = "Builds the Vue3 application and prepares Nginx configuration.";
};
};
in
buildImage {
name = "nativelink-ui";

# Base image configuration using nginx:mainline-alpine-slim
fromImage = pullImage {
inherit (imageParams) imageName imageDigest sha256;
tlsVerify = true;
os = "linux";
};

# Container configuration
config = {
# Set the working directory to /dist where the built files are located
WorkingDir = "/dist";

# Define the entrypoint to start Nginx in the foreground
Entrypoint = ["nginx" "-g" "daemon off;"];

# Expose port 80 for HTTP traffic
ExposedPorts = {
"80/tcp" = {};
};

# Define volumes to copy built files and nginx configuration
Volumes = {
"/dist" = "${webUi}/dist";
"/etc/nginx/nginx.conf" = "${webUi}/etc/nginx/nginx.conf";
};

# Add descriptive labels
Labels = {
"org.opencontainers.image.description" = imageParams.description;
"org.opencontainers.image.title" = imageParams.title;
};
};
}
14 changes: 14 additions & 0 deletions web/ui/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- <link rel="icon" href="/favicon.ico"> -->
<link rel="icon" sizes="192x192" type="image/png" href="https://nativelink-cdn.s3.us-east-1.amazonaws.com/nativelink_favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Nativelink | Dashboard</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
31 changes: 31 additions & 0 deletions web/ui/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "nativelink-dashboard",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --build --force"
},
"dependencies": {
"pinia": "^2.2.4",
"vue": "^3.5.12",
"vue-router": "^4.4.5"
},
"devDependencies": {
"@tailwindcss/vite": "^4.0.0-alpha",
"@tsconfig/node20": "^20.1.4",
"@types/node": "^20.17.0",
"@vitejs/plugin-vue": "^5.1.4",
"@vitejs/plugin-vue-jsx": "^4.0.1",
"@vue/tsconfig": "^0.5.1",
"npm-run-all2": "^7.0.1",
"tailwindcss": "^4.0.0-alpha",
"typescript": "~5.6.0",
"vite": "^5.4.10",
"vue-tsc": "^2.1.6"
}
}
28 changes: 28 additions & 0 deletions web/ui/src/App.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<script setup lang="ts">
import AsideView from './views/AsideView.vue';
</script>

<template>
<div class="min-h-screen w-full bg-background bg-radial-gradient font-sans antialiased">
<div class="flex overflow-y-auto">
<!-- Sidebar -->
<AsideView />
<!-- Main Content -->
<transition name="fade" mode="out-in">
<RouterView />
</transition>
</div>
</div>
</template>

<style scoped>
.fade-enter-active, .fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter-from, .fade-leave-to {
opacity: 0;
}
.fade-enter-to, .fade-leave-from {
opacity: 1;
}
</style>
86 changes: 86 additions & 0 deletions web/ui/src/assets/base.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/* color palette from <https://github.com/vuejs/theme> */
:root {
--vt-c-white: #ffffff;
--vt-c-white-soft: #f8f8f8;
--vt-c-white-mute: #f2f2f2;

--vt-c-black: #181818;
--vt-c-black-soft: #222222;
--vt-c-black-mute: #282828;

--vt-c-indigo: #2c3e50;

--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);

--vt-c-text-light-1: var(--vt-c-indigo);
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
--vt-c-text-dark-1: var(--vt-c-white);
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
}

/* semantic color variables for this project */
:root {
--color-background: var(--vt-c-white);
--color-background-soft: var(--vt-c-white-soft);
--color-background-mute: var(--vt-c-white-mute);

--color-border: var(--vt-c-divider-light-2);
--color-border-hover: var(--vt-c-divider-light-1);

--color-heading: var(--vt-c-text-light-1);
--color-text: var(--vt-c-text-light-1);

--section-gap: 160px;
}

@media (prefers-color-scheme: dark) {
:root {
--color-background: var(--vt-c-black);
--color-background-soft: var(--vt-c-black-soft);
--color-background-mute: var(--vt-c-black-mute);

--color-border: var(--vt-c-divider-dark-2);
--color-border-hover: var(--vt-c-divider-dark-1);

--color-heading: var(--vt-c-text-dark-1);
--color-text: var(--vt-c-text-dark-2);
}
}

*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
font-weight: normal;
}

body {
min-height: 100vh;
color: var(--color-text);
background: var(--color-background);
transition:
color 0.5s,
background-color 0.5s;
line-height: 1.6;
font-family:
Inter,
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Roboto,
Oxygen,
Ubuntu,
Cantarell,
'Fira Sans',
'Droid Sans',
'Helvetica Neue',
sans-serif;
font-size: 15px;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
Loading
Loading