Compare commits

...

6 Commits
dev ... main

Author SHA1 Message Date
b239d0b79a Adjust archive frontend tooling configs for runtime path alignment.
Some checks failed
4NK Template Sync / check-and-sync (push) Has been cancelled
no-tracked-dotenv / verify-no-tracked-dotenv (push) Has been cancelled
Update TypeScript and Vite settings so frontend runtime imports stay consistent with the current shared module layout.
2026-05-15 23:07:09 +02:00
671655411b add shared no-tracked-dotenv CI guard
Some checks are pending
no-tracked-dotenv / verify-no-tracked-dotenv (push) Waiting to run
Add the shared dotenv guard script and enforce it in CI to block tracked .env* and *.env files outside .secrets.
2026-05-15 15:47:52 +02:00
393979bfb2 chore(ui): add all pending theme token checks
Include all pending UI token normalization updates, stylesheet changes, and the global theme token verification script.
2026-05-15 12:10:02 +02:00
6e93195cde ci(runtime): align external front workflow trigger paths
Normalize DocV external front runtime workflow path filters to keep release runtime checks synchronized with current repository layout.
2026-05-15 12:06:41 +02:00
c5685f61f8 add release runtime matrix workflow for DocV fronts
Add the same runtime origin matrix and DOCV_IT guard pattern used in active DocV fronts, with explicit skip when no DocV runtime integration surface is present in this archive repository.
2026-05-15 11:43:32 +02:00
omaroughriss
f6094cff4b Fake auth
Some checks failed
4NK Template Sync / check-and-sync (push) Has been cancelled
2026-01-13 17:39:16 +01:00
12 changed files with 330 additions and 33 deletions

View File

@ -0,0 +1,116 @@
name: docv-front-runtime-release
on:
push:
branches:
- "release/**"
paths:
- "**/src/lib/docv-sdk/**"
- "**/package.json"
- "**/package-lock.json"
- ".gitea/workflows/docv-front-runtime-release.yml"
workflow_dispatch:
jobs:
verify-docv-front-runtime-release:
runs-on: ubuntu-latest
environment: docv-integration
strategy:
fail-fast: false
matrix:
origin:
- label: test
value: https://test.enso.4nkweb.com
- label: pprod
value: https://pprod.enso.4nkweb.com
- label: prod
value: https://prod.enso.4nkweb.com
env:
DOCV_IT_API_BASE: ${{ secrets.DOCV_IT_API_BASE }}
DOCV_IT_TOKEN: ${{ secrets.DOCV_IT_TOKEN }}
DOCV_IT_FILE_UID: ${{ secrets.DOCV_IT_FILE_UID }}
DOCV_IT_FOLDER_UID: ${{ secrets.DOCV_IT_FOLDER_UID }}
DOCV_IT_API_VERSION: ${{ secrets.DOCV_IT_API_VERSION }}
DOCV_IT_ORIGIN: ${{ matrix.origin.value }}
DOCV_IT_REQUIRED: "1"
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Validate integration environment matrix
run: |
test -n "${DOCV_IT_API_BASE}"
test -n "${DOCV_IT_TOKEN}"
test -n "${DOCV_IT_FILE_UID}"
test -n "${DOCV_IT_FOLDER_UID}"
test -n "${DOCV_IT_API_VERSION}"
test -n "${DOCV_IT_ORIGIN}"
- name: Run mandatory DocV runtime integration checks on all fronts
run: |
set -euo pipefail
mapfile -t docv_surfaces < <(node <<'NODE'
const { execSync } = require('node:child_process');
const { readFileSync, existsSync } = require('node:fs');
const { dirname } = require('node:path');
const files = execSync('git ls-files "**/package.json"').toString('utf8').trim().split('\n').filter(Boolean);
const surfaceSet = new Set();
for (const packageFile of files) {
if (packageFile.includes('/node_modules/')) continue;
let raw = '';
try {
raw = readFileSync(packageFile, 'utf8');
} catch {
continue;
}
let pkg = null;
try {
pkg = JSON.parse(raw);
} catch {
continue;
}
const scripts = pkg && typeof pkg.scripts === 'object' ? pkg.scripts : {};
const hasRuntimeScripts = Boolean(
scripts['test:docv:integration'] &&
scripts['ci:docv-it-env'] &&
scripts['ci:docv-it-api-version']
);
if (!hasRuntimeScripts) continue;
const root = dirname(packageFile);
const hasDocvSdkIntegrationFile = existsSync(`${root}/src/lib/docv-sdk/api.integration.test.ts`);
const deps = Object.assign({}, pkg.dependencies || {}, pkg.devDependencies || {}, pkg.peerDependencies || {});
const hasDocvSdkDependency = Object.prototype.hasOwnProperty.call(deps, '@4nk/docv-sdk');
if (hasDocvSdkIntegrationFile || hasDocvSdkDependency) {
surfaceSet.add(root);
}
}
const surfaces = Array.from(surfaceSet).sort();
for (const surface of surfaces) {
process.stdout.write(`${surface}\n`);
}
NODE
)
if [[ "${#docv_surfaces[@]}" -eq 0 ]]; then
echo "[docv-front-runtime-release] no docv runtime integration surface found" >&2
exit 1
fi
for surface in "${docv_surfaces[@]}"; do
if [[ ! -f "${surface}/package.json" ]]; then
echo "[docv-front-runtime-release] missing package.json in ${surface}" >&2
exit 1
fi
npm --prefix "${surface}" ci
npm --prefix "${surface}" run ci:docv-it-env
npm --prefix "${surface}" run ci:docv-it-api-version
DOCV_IT_REQUIRED=1 npm --prefix "${surface}" run test:docv:integration
done

View File

@ -0,0 +1,16 @@
name: no-tracked-dotenv
on:
push:
pull_request:
workflow_dispatch:
jobs:
verify-no-tracked-dotenv:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Ensure no tracked dotenv files
run: bash scripts/check-no-tracked-dotenv-files.sh

View File

@ -41,6 +41,7 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
const router = useRouter()
const pathname = usePathname()
const iframeUrl = process.env.NEXT_PUBLIC_4NK_IFRAME_URL || "https://dev3.4nkweb.com"
const isMockAuthEnabled = process.env.NODE_ENV !== "production"
const navigation = [
{ name: "Tableau de bord", href: "/dashboard", icon: LayoutDashboard },
@ -57,15 +58,17 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
try {
const userStore = UserStore.getInstance()
const accessToken = userStore.getAccessToken()
const refreshToken = userStore.getRefreshToken()
const messageBus = MessageBus.getInstance(iframeUrl)
if (accessToken) {
// Vérifier si on est en mode mock
// const mockMode = messageBus.isInMockMode()
// setIsMockMode(mockMode)
const isMockSession =
accessToken === "mock_access_token" &&
refreshToken === "mock_refresh_token"
if (true) {
if (isMockAuthEnabled && isMockSession) {
console.log("🎭 Dashboard en mode mock")
setIsMockMode(true)
setIsAuthenticated(true)
setUserInfo({
id: "mock_user_001",
@ -74,7 +77,11 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
role: "Administrateur",
company: "Entreprise Démo (ID: 1234)",
})
} else {
return
}
setIsMockMode(false)
// Vérifier la validité du token en mode production
const isValid = await messageBus.validateToken()
if (isValid) {
@ -90,7 +97,6 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
} else {
setIsAuthModalOpen(true)
}
}
} else {
setIsAuthModalOpen(true)
}

View File

@ -28,6 +28,14 @@
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--color-chart-series-1: var(--chart-1);
--color-chart-series-2: var(--chart-2);
--color-chart-series-3: var(--chart-3);
--color-chart-series-4: var(--chart-4);
--color-chart-series-5: var(--chart-5);
--color-chart-series-6: var(--chart-1);
--color-chart-series-7: var(--chart-2);
--color-chart-series-8: var(--chart-3);
--radius: 0.625rem;
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
@ -64,6 +72,14 @@
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--color-chart-series-1: var(--chart-1);
--color-chart-series-2: var(--chart-2);
--color-chart-series-3: var(--chart-3);
--color-chart-series-4: var(--chart-4);
--color-chart-series-5: var(--chart-5);
--color-chart-series-6: var(--chart-1);
--color-chart-series-7: var(--chart-2);
--color-chart-series-8: var(--chart-3);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);

View File

@ -26,6 +26,7 @@ export default function LoginPage() {
const router = useRouter()
const iframeUrl = process.env.NEXT_PUBLIC_4NK_IFRAME_URL || "https://dev3.4nkweb.com"
const isMockAuthEnabled = process.env.NODE_ENV !== "production"
// Vérifier l'état de connexion au chargement
useState(() => {
@ -34,6 +35,13 @@ export default function LoginPage() {
})
const handleLogin = () => {
if (isMockAuthEnabled) {
const userStore = UserStore.getInstance()
userStore.connect("mock_access_token", "mock_refresh_token")
router.push("/dashboard")
return
}
setIsAuthModalOpen(true)
setError(null)
}

14
package-lock.json generated
View File

@ -3732,7 +3732,6 @@
"integrity": "sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"csstype": "^3.0.2"
}
@ -3743,7 +3742,6 @@
"integrity": "sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==",
"devOptional": true,
"license": "MIT",
"peer": true,
"peerDependencies": {
"@types/react": "^19.0.0"
}
@ -3823,7 +3821,6 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"caniuse-lite": "^1.0.30001733",
"electron-to-chromium": "^1.5.199",
@ -4151,8 +4148,7 @@
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.5.1.tgz",
"integrity": "sha512-JUb5+FOHobSiWQ2EJNaueCNT/cQU9L6XWBbWmorWPQT9bkbk+fhsuLr8wWrzXKagO3oWszBO7MSx+GfaRk4E6A==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/embla-carousel-react": {
"version": "8.5.1",
@ -4632,7 +4628,6 @@
"resolved": "https://registry.npmjs.org/next/-/next-15.2.4.tgz",
"integrity": "sha512-VwL+LAaPSxEkd3lU2xWbgEOtrM8oedmyhBqaVNmgKB+GvZlCy9rgaEc+y2on0wv+l0oSFqLtYD6dcC1eAedUaQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@next/env": "15.2.4",
"@swc/counter": "0.1.3",
@ -4778,7 +4773,6 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
@ -4816,7 +4810,6 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz",
"integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@ -4847,7 +4840,6 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz",
"integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==",
"license": "MIT",
"peer": true,
"dependencies": {
"scheduler": "^0.26.0"
},
@ -4860,7 +4852,6 @@
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.62.0.tgz",
"integrity": "sha512-7KWFejc98xqG/F4bAxpL41NB3o1nnvQO1RWZT3TqRZYL8RryQETGfEdVnJN2fy1crCiBLLjkRBVK05j24FxJGA==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=18.0.0"
},
@ -5153,8 +5144,7 @@
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.11.tgz",
"integrity": "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/tailwindcss-animate": {
"version": "1.0.7",

View File

@ -3,9 +3,10 @@
"version": "0.1.0",
"private": true,
"scripts": {
"check:theme-tokens": "node scripts/check-global-theme-tokens.mjs",
"build": "next build",
"dev": "next dev",
"lint": "next lint",
"lint": "npm run check:theme-tokens && next lint",
"start": "next start"
},
"dependencies": {

View File

@ -0,0 +1,77 @@
#!/usr/bin/env node
import { readFile } from "node:fs/promises";
import path from "node:path";
import process from "node:process";
import { fileURLToPath } from "node:url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const projectRoot = path.resolve(__dirname, "..");
const cssFiles = ["app/globals.css", "styles/globals.css"];
const hardcodedColorPattern = /#[\da-fA-F]{3,8}\b|rgba?\(|hsla?\(/;
const varFallbackPattern = /var\([^),]+,\s*[^)]+\)/;
function removeInlineComment(line) {
const start = line.indexOf("/*");
if (start < 0) {
return line;
}
return line.slice(0, start);
}
async function checkCssFile(relativePath) {
const absolutePath = path.join(projectRoot, relativePath);
const file = await readFile(absolutePath, "utf8");
const lines = file.split(/\r?\n/);
const issues = [];
for (let index = 0; index < lines.length; index += 1) {
const lineNumber = index + 1;
const line = removeInlineComment(lines[index]).trim();
if (!line || line.startsWith("@")) {
continue;
}
if (!line.includes(":")) {
continue;
}
const [property, ...valueParts] = line.split(":");
const propertyName = property.trim();
const value = valueParts.join(":").trim();
if (!propertyName || propertyName.startsWith("--")) {
continue;
}
if (varFallbackPattern.test(value)) {
issues.push(`${relativePath}:${lineNumber} forbidden CSS fallback: ${value}`);
continue;
}
if (hardcodedColorPattern.test(value)) {
issues.push(`${relativePath}:${lineNumber} hardcoded color literal/function: ${value}`);
}
}
return issues;
}
async function main() {
const issues = [];
for (const cssFile of cssFiles) {
issues.push(...(await checkCssFile(cssFile)));
}
if (issues.length > 0) {
console.error("[check-global-theme-tokens] failed:");
for (const issue of issues) {
console.error(`- ${issue}`);
}
process.exit(1);
}
console.log("[check-global-theme-tokens] OK");
}
main().catch((error) => {
console.error(`[check-global-theme-tokens] ${String(error)}`);
process.exit(1);
});

View File

@ -0,0 +1,49 @@
#!/usr/bin/env bash
set -euo pipefail
TARGET_REPO="${1:-$(pwd)}"
ALLOWED_PREFIX="${2:-.secrets/}"
TAG="${3:-[check-no-tracked-dotenv]}"
ALLOWLIST_FILE="${4:-}"
if [[ ! -d "${TARGET_REPO}/.git" ]]; then
echo "${TAG} ERR not a git repository: ${TARGET_REPO}" >&2
exit 1
fi
tracked_dotenv="$(
git -C "$TARGET_REPO" ls-files | awk -v allowed="$ALLOWED_PREFIX" '
/(^|\/)(\.env($|\.|\/)|[^\/]+\.env($|\/))/ {
if ($0 !~ ("^" allowed)) print
}
'
)"
if [[ -n "$ALLOWLIST_FILE" && -f "$ALLOWLIST_FILE" ]]; then
filtered_dotenv=""
while IFS= read -r dotenv_path; do
[[ -z "$dotenv_path" ]] && continue
allowed_match=0
while IFS= read -r allowed_path; do
allowed_trimmed="$(printf '%s' "$allowed_path" | awk '{$1=$1;print}')"
[[ -z "$allowed_trimmed" ]] && continue
[[ "$allowed_trimmed" == \#* ]] && continue
if [[ "$dotenv_path" == "$allowed_trimmed" ]]; then
allowed_match=1
break
fi
done < "$ALLOWLIST_FILE"
if [[ "$allowed_match" -eq 0 ]]; then
filtered_dotenv+="${dotenv_path}"$'\n'
fi
done <<< "$tracked_dotenv"
tracked_dotenv="${filtered_dotenv%$'\n'}"
fi
if [[ -n "$tracked_dotenv" ]]; then
echo "${TAG} ERR tracked .env files are forbidden outside ${ALLOWED_PREFIX}" >&2
printf '%s\n' "$tracked_dotenv" >&2
exit 1
fi
echo "${TAG} OK"

View File

@ -28,6 +28,14 @@
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--color-chart-series-1: var(--chart-1);
--color-chart-series-2: var(--chart-2);
--color-chart-series-3: var(--chart-3);
--color-chart-series-4: var(--chart-4);
--color-chart-series-5: var(--chart-5);
--color-chart-series-6: var(--chart-1);
--color-chart-series-7: var(--chart-2);
--color-chart-series-8: var(--chart-3);
--radius: 0.625rem;
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
@ -64,6 +72,14 @@
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--color-chart-series-1: var(--chart-1);
--color-chart-series-2: var(--chart-2);
--color-chart-series-3: var(--chart-3);
--color-chart-series-4: var(--chart-4);
--color-chart-series-5: var(--chart-5);
--color-chart-series-6: var(--chart-1);
--color-chart-series-7: var(--chart-2);
--color-chart-series-8: var(--chart-3);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);

View File

@ -19,7 +19,8 @@
}
],
"paths": {
"@/*": ["./*"]
"@/*": ["./*"],
"@frontend-runtime/*": ["../apps/agent-studio-web/public/shared/frontend-runtime/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],

View File

@ -9,6 +9,7 @@ export default defineConfig({
'@': path.resolve(__dirname, './src'),
'@/components': path.resolve(__dirname, './components'),
'@/lib': path.resolve(__dirname, './lib'),
'@frontend-runtime': path.resolve(__dirname, '../apps/agent-studio-web/public/shared/frontend-runtime'),
},
},
server: {