Skip to content

Preview of potential new UI #241

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

Draft
wants to merge 13 commits 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
84 changes: 67 additions & 17 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,55 @@ ARG mode=prod

FROM node:24-alpine AS build-stage

# Add build dependencies and security updates
RUN apk update && \
apk upgrade && \
apk add --no-cache dumb-init

# Use non-root user for security
USER node
WORKDIR /app

# Copy package files first for better layer caching
COPY --chown=1000:1000 package*.json ./
RUN npm ci

# Install dependencies with npm ci for reproducible builds
# Use --no-audit to speed up the build
RUN npm ci --no-audit --no-fund && \
npm cache clean --force

# Copy source code
COPY --chown=1000:1000 . .

# Build the application
RUN npm run build

# Stage 2: Prepare the Node.js API
FROM node:23-alpine AS base-prod
FROM node:24-alpine AS base-prod

# Add security updates and dumb-init for proper process handling
RUN apk update && \
apk upgrade && \
apk add --no-cache dumb-init curl && \
# Add a non-privileged user for running the application
addgroup -g 1001 -S appgroup && \
adduser -u 1001 -S appuser -G appgroup

# Set working directory and copy built application
WORKDIR /app
COPY --chown=1000:1000 --from=build-stage /app/.output /app
COPY --chown=1001:1001 --from=build-stage /app/.output /app

# Create a health check script
RUN echo '#!/bin/sh' > /healthcheck.sh && \
echo 'curl -f http://localhost:${NITRO_PORT:-80}/api/health || exit 1' >> /healthcheck.sh && \
chmod +x /healthcheck.sh

# Expose the port your API will run on
EXPOSE 80

# Set port to 80 for backwards compatibility
ENV NITRO_PORT=80
ENV NITRO_PORT=80 \
NODE_ENV=production

# Re-map the environment variables for the Vue.js app for backwards compatibility
RUN echo '#!/bin/sh' > /entrypoint.sh && \
Expand All @@ -41,34 +71,54 @@ RUN echo '#!/bin/sh' > /entrypoint.sh && \
echo 'export NUXT_SESSION_PASSWORD=${NUXT_SESSION_PASSWORD:-$NUXT_GITHUB_TOKEN$NUXT_GITHUB_TOKEN}' >> /entrypoint.sh && \
echo 'export NUXT_OAUTH_GITHUB_CLIENT_ID=${NUXT_OAUTH_GITHUB_CLIENT_ID:-$GITHUB_CLIENT_ID}' >> /entrypoint.sh && \
echo 'export NUXT_OAUTH_GITHUB_CLIENT_SECRET=${NUXT_OAUTH_GITHUB_CLIENT_SECRET:-$GITHUB_CLIENT_SECRET}' >> /entrypoint.sh && \
# Set default theme to ensure consistent appearance
echo 'export NUXT_PUBLIC_DEFAULT_THEME=${NUXT_PUBLIC_DEFAULT_THEME:-dark}' >> /entrypoint.sh && \
# Conditionally set NUXT_PUBLIC_USING_GITHUB_AUTH if GITHUB_CLIENT_ID is provided
echo 'if [ -n "$GITHUB_CLIENT_ID" ]; then' >> /entrypoint.sh && \
echo 'export NUXT_PUBLIC_USING_GITHUB_AUTH=true' >> /entrypoint.sh && \
echo 'fi' >> /entrypoint.sh && \
echo 'node /app/server/index.mjs' >> /entrypoint.sh && \
echo 'exec dumb-init -- node /app/server/index.mjs' >> /entrypoint.sh && \
chmod +x /entrypoint.sh

# Configure Docker health check
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 CMD ["/healthcheck.sh"]

USER node
ENTRYPOINT [ "/entrypoint.sh" ]
# Set proper permissions and switch to non-root user
RUN chown -R 1001:1001 /app
USER appuser
ENTRYPOINT ["/entrypoint.sh"]

#----------------------------------- PW layer - not used in production
FROM mcr.microsoft.com/playwright:v1.49.1 AS base-playwright

WORKDIR /pw

# Install only necessary packages and clean up to reduce image size
RUN apt-get update && \
apt-get install -y --no-install-recommends gettext-base && \
apt-get install -y --no-install-recommends gettext-base curl dumb-init && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

COPY --chown=1000:1000 --from=base-prod /app /app
COPY --chown=1000:1000 e2e-tests ./e2e-tests
COPY --chown=1000:1000 playwright.config.ts playwright.docker.config.ts tsconfig.json package*.json ./

RUN npm install --only=dev

ENTRYPOINT [ "npx", "playwright", "test", "-c", "playwright.docker.config.ts" ]
rm -rf /var/lib/apt/lists/* && \
# Create a non-root user for running tests
groupadd -g 1001 pwuser && \
useradd -u 1001 -g pwuser -m pwuser

# Copy application and test files
COPY --chown=1001:1001 --from=base-prod /app /app
COPY --chown=1001:1001 e2e-tests ./e2e-tests
COPY --chown=1001:1001 playwright.config.ts playwright.docker.config.ts tsconfig.json package*.json ./

# Install only dev dependencies and clean cache
RUN npm install --only=dev && \
npm cache clean --force

# Create a wrapper script for better process handling
RUN echo '#!/bin/sh' > /entrypoint-pw.sh && \
echo 'exec dumb-init -- npx playwright test -c playwright.docker.config.ts "$@"' >> /entrypoint-pw.sh && \
chmod +x /entrypoint-pw.sh

# Switch to non-root user for security
USER pwuser
ENTRYPOINT ["/entrypoint-pw.sh"]

#-----------------------------------
FROM base-${mode} AS final
147 changes: 147 additions & 0 deletions app/assets/background.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/* Background styling for the entire application */
body.v-theme--dark {
background-color: #121212;
background-image:
radial-gradient(circle at 10% 20%, rgba(100, 216, 203, 0.05) 0%, transparent 30%),
radial-gradient(circle at 90% 80%, rgba(156, 100, 216, 0.05) 0%, transparent 30%),
radial-gradient(circle at 50% 50%, rgba(139, 233, 253, 0.03) 0%, transparent 50%);
background-attachment: fixed;
min-height: 100vh;
}

body.v-theme--light {
background-color: #F5F7FA;
background-image:
radial-gradient(circle at 10% 20%, rgba(38, 166, 154, 0.05) 0%, transparent 30%),
radial-gradient(circle at 90% 80%, rgba(123, 31, 162, 0.05) 0%, transparent 30%),
radial-gradient(circle at 50% 50%, rgba(77, 208, 225, 0.03) 0%, transparent 50%);
background-attachment: fixed;
min-height: 100vh;
}

/* Add subtle animated gradient to the main content area */
.v-main {
position: relative;
overflow: hidden;
}

.v-theme--dark .v-main::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg,
rgba(100, 216, 203, 0.02) 0%,
rgba(139, 233, 253, 0.02) 50%,
rgba(156, 100, 216, 0.02) 100%);
background-size: 400% 400%;
animation: gradientAnimation 15s ease infinite;
z-index: -1;
}

.v-theme--light .v-main::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg,
rgba(38, 166, 154, 0.02) 0%,
rgba(77, 208, 225, 0.02) 50%,
rgba(123, 31, 162, 0.02) 100%);
background-size: 400% 400%;
animation: gradientAnimation 15s ease infinite;
z-index: -1;
}

@keyframes gradientAnimation {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}

/* Add subtle grid pattern overlay */
.v-theme--dark .v-main::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image:
linear-gradient(rgba(255, 255, 255, 0.01) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.01) 1px, transparent 1px);
background-size: 20px 20px;
z-index: -1;
}

.v-theme--light .v-main::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image:
linear-gradient(rgba(0, 0, 0, 0.01) 1px, transparent 1px),
linear-gradient(90deg, rgba(0, 0, 0, 0.01) 1px, transparent 1px);
background-size: 20px 20px;
z-index: -1;
}

/* Add glow effects to cards and important elements */
.v-theme--dark .v-card {
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.25) !important;
}

.v-theme--dark .v-card:hover {
box-shadow: 0 8px 30px rgba(100, 216, 203, 0.15) !important;
}

.v-theme--light .v-card {
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1) !important;
}

.v-theme--light .v-card:hover {
box-shadow: 0 8px 30px rgba(38, 166, 154, 0.15) !important;
}

/* Custom scrollbar for the entire site */
.v-theme--dark ::-webkit-scrollbar {
width: 10px;
height: 10px;
}

.v-theme--dark ::-webkit-scrollbar-track {
background: #1a1a1a;
}

.v-theme--dark ::-webkit-scrollbar-thumb {
background: linear-gradient(to bottom, #64D8CB, #9C64D8);
border-radius: 5px;
}

.v-theme--dark ::-webkit-scrollbar-thumb:hover {
background: linear-gradient(to bottom, #8BE9FD, #64D8CB);
}

.v-theme--light ::-webkit-scrollbar {
width: 10px;
height: 10px;
}

.v-theme--light ::-webkit-scrollbar-track {
background: #f1f1f1;
}

.v-theme--light ::-webkit-scrollbar-thumb {
background: linear-gradient(to bottom, #26A69A, #7B1FA2);
border-radius: 5px;
}

.v-theme--light ::-webkit-scrollbar-thumb:hover {
background: linear-gradient(to bottom, #4DD0E1, #26A69A);
}
69 changes: 69 additions & 0 deletions app/assets/data-table-fix-v2.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/* Target the specific white background in the dropdown */
.v-list-item__underlay {
background-color: transparent !important;
display: none !important;
}

/* Target all possible elements that could have a white background */
.v-list-item__bg {
background-color: transparent !important;
display: none !important;
}

/* Target the ripple effect which might be causing the white background */
.v-ripple__container {
display: none !important;
}

/* Target any other potential elements */
.v-list-item .v-overlay__content,
.v-list-item .v-overlay,
.v-list-item .v-ripple,
.v-list-item .v-ripple__animation {
background-color: transparent !important;
display: none !important;
}

/* Force all list items to have the correct background */
.v-list-item {
background-color: #1E1E1E !important;
}

/* Force selected items to have the correct background */
.v-list-item--active {
background-color: #333333 !important;
}

/* Target the specific element that might be causing the white background */
.v-list-item__overlay {
background-color: transparent !important;
display: none !important;
}

/* Target the v-select dropdown specifically */
.v-select__content .v-list,
.v-select__content .v-list-item,
.v-select__content .v-list-item__overlay,
.v-select__content .v-list-item__underlay {
background-color: #1E1E1E !important;
}

.v-select__content .v-list-item--active,
.v-select__content .v-list-item--active .v-list-item__overlay,
.v-select__content .v-list-item--active .v-list-item__underlay {
background-color: #333333 !important;
}

/* Target the white box specifically */
.v-theme--light.v-list-item .v-list-item__overlay {
background-color: transparent !important;
display: none !important;
}

/* Target the white box in the data table footer */
.v-data-table-footer .v-list-item__overlay,
.v-data-table-footer .v-list-item__underlay,
.v-data-table-footer .v-list-item__bg {
background-color: transparent !important;
display: none !important;
}
Loading