Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 73b60f14a9 | |||
| b3f43c421f | |||
| a2339f7106 | |||
| e83a76f111 | |||
| 0096c18098 | |||
| 3284931f84 | |||
| 28517a3558 | |||
| 3b9f10ec98 | |||
| 65fd248993 | |||
| ebd9ab132c | |||
| ddaeb2c3ca | |||
| ad1a8c4fbf | |||
| 013b0259b2 |
7
.changeset/resilient-build-scripts.md
Normal file
7
.changeset/resilient-build-scripts.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@mintel/monorepo": patch
|
||||
"acquisition-manager": patch
|
||||
"feedback-commander": patch
|
||||
---
|
||||
|
||||
fix: make directus extension build scripts more resilient
|
||||
@@ -1,5 +1,5 @@
|
||||
# Project
|
||||
IMAGE_TAG=v1.7.3
|
||||
IMAGE_TAG=v1.7.9
|
||||
PROJECT_NAME=sample-website
|
||||
PROJECT_COLOR=#82ed20
|
||||
|
||||
|
||||
44
.gitea/workflows/maintenance.yml
Normal file
44
.gitea/workflows/maintenance.yml
Normal file
@@ -0,0 +1,44 @@
|
||||
name: 🏥 Server Maintenance
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 3 * * *' # Every day at 3:00 AM
|
||||
workflow_dispatch: # Allow manual trigger
|
||||
|
||||
jobs:
|
||||
maintenance:
|
||||
name: 🧹 Prune & Clean
|
||||
runs-on: docker
|
||||
container:
|
||||
image: catthehacker/ubuntu:act-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 🚀 Execute Maintenance via SSH
|
||||
run: |
|
||||
mkdir -p ~/.ssh
|
||||
echo "${{ secrets.SSH_KEY }}" > ~/.ssh/id_ed25519
|
||||
chmod 600 ~/.ssh/id_ed25519
|
||||
ssh-keyscan -H ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts 2>/dev/null
|
||||
|
||||
# Run the prune script on the host
|
||||
# We transfer the script and execute it to ensure it matches the repo version
|
||||
scp packages/infra/scripts/prune-registry.sh root@${{ secrets.SSH_HOST }}:/tmp/prune-registry.sh
|
||||
ssh root@${{ secrets.SSH_HOST }} "bash /tmp/prune-registry.sh && rm /tmp/prune-registry.sh"
|
||||
|
||||
- name: 🔔 Notification - Success
|
||||
if: success()
|
||||
run: |
|
||||
curl -s -k -X POST "${{ secrets.GOTIFY_URL }}/message?token=${{ secrets.GOTIFY_TOKEN }}" \
|
||||
-F "title=🏥 Maintenance Complete" \
|
||||
-F "message=Server-Wartung erfolgreich ausgeführt.\nRegistry & Docker Ressourcen bereinigt." \
|
||||
-F "priority=2" || true
|
||||
|
||||
- name: 🔔 Notification - Failure
|
||||
if: failure()
|
||||
run: |
|
||||
curl -s -k -X POST "${{ secrets.GOTIFY_URL }}/message?token=${{ secrets.GOTIFY_TOKEN }}" \
|
||||
-F "title=❌ Maintenance FAILED" \
|
||||
-F "message=Die automatische Server-Wartung ist fehlgeschlagen!\nBitte Logs prüfen." \
|
||||
-F "priority=8" || true
|
||||
@@ -29,28 +29,34 @@ jobs:
|
||||
run: |
|
||||
echo "🔎 Debug: Event=$EVENT, Ref=$REF, RefName=$REF_NAME, RunId=$RUN_ID"
|
||||
|
||||
if [[ "$REF" == refs/tags/v* ]]; then
|
||||
echo "🚀 Release detected ($REF_NAME). Cancelling non-tag runs..."
|
||||
|
||||
# Fetch all runs
|
||||
RUNS=$(curl -s -H "Authorization: token $GITEA_TOKEN" "https://git.infra.mintel.me/api/v1/repos/$REPO/actions/runs")
|
||||
|
||||
# Identify runs to cancel: in_progress/queued, NOT this run, and NOT a tag run
|
||||
echo "$RUNS" | jq -c '.workflow_runs[] | select(.status == "in_progress" or .status == "queued") | select(.id | tostring != "'$RUN_ID'")' | while read -r run; do
|
||||
ID=$(echo "$run" | jq -r '.id')
|
||||
RUN_REF=$(echo "$run" | jq -r '.ref')
|
||||
TITLE=$(echo "$run" | jq -r '.display_title')
|
||||
case "$REF" in
|
||||
refs/tags/v*)
|
||||
echo "🚀 Release detected ($REF_NAME). Cancelling non-tag runs..."
|
||||
|
||||
if [[ "$RUN_REF" != refs/tags/v* ]]; then
|
||||
echo "🛑 Cancelling redundant branch run $ID ($TITLE) on $RUN_REF..."
|
||||
curl -X POST -s -H "Authorization: token $GITEA_TOKEN" "https://git.infra.mintel.me/api/v1/repos/$REPO/actions/runs/$ID/cancel"
|
||||
else
|
||||
echo "⏭️ Skipping parallel release run $ID ($TITLE) on $RUN_REF"
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "ℹ️ Regular push. No prioritazation needed."
|
||||
fi
|
||||
# Fetch all runs
|
||||
RUNS=$(curl -s -H "Authorization: token $GITEA_TOKEN" "https://git.infra.mintel.me/api/v1/repos/$REPO/actions/runs")
|
||||
|
||||
# Identify runs to cancel: in_progress/queued, NOT this run, and NOT a tag run
|
||||
echo "$RUNS" | jq -c '.workflow_runs[] | select(.status == "in_progress" or .status == "queued") | select(.id | tostring != "'$RUN_ID'")' | while read -r run; do
|
||||
ID=$(echo "$run" | jq -r '.id')
|
||||
RUN_REF=$(echo "$run" | jq -r '.ref')
|
||||
TITLE=$(echo "$run" | jq -r '.display_title')
|
||||
|
||||
case "$RUN_REF" in
|
||||
refs/tags/v*)
|
||||
echo "⏭️ Skipping parallel release run $ID ($TITLE) on $RUN_REF"
|
||||
;;
|
||||
*)
|
||||
echo "🛑 Cancelling redundant branch run $ID ($TITLE) on $RUN_REF..."
|
||||
curl -X POST -s -H "Authorization: token $GITEA_TOKEN" "https://git.infra.mintel.me/api/v1/repos/$REPO/actions/runs/$ID/cancel"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
;;
|
||||
*)
|
||||
echo "ℹ️ Regular push. No prioritization needed."
|
||||
;;
|
||||
esac
|
||||
|
||||
lint:
|
||||
name: 🧹 Lint
|
||||
|
||||
56
Dockerfile.template
Normal file
56
Dockerfile.template
Normal file
@@ -0,0 +1,56 @@
|
||||
# Stage 1: Builder
|
||||
FROM registry.infra.mintel.me/mintel/nextjs:latest AS builder
|
||||
WORKDIR /app
|
||||
|
||||
# Clean the workspace in case the base image is dirty
|
||||
RUN rm -rf ./*
|
||||
|
||||
# Arguments for build-time configuration
|
||||
ARG NEXT_PUBLIC_BASE_URL
|
||||
ARG NEXT_PUBLIC_TARGET
|
||||
ARG DIRECTUS_URL
|
||||
ARG NPM_TOKEN
|
||||
|
||||
# Environment variables for Next.js build
|
||||
ENV NEXT_PUBLIC_BASE_URL=$NEXT_PUBLIC_BASE_URL
|
||||
ENV NEXT_PUBLIC_TARGET=$NEXT_PUBLIC_TARGET
|
||||
ENV DIRECTUS_URL=$DIRECTUS_URL
|
||||
ENV SKIP_RUNTIME_ENV_VALIDATION=true
|
||||
ENV CI=true
|
||||
|
||||
# Enable pnpm
|
||||
RUN corepack enable
|
||||
|
||||
# Copy lockfile and manifest for dependency installation caching
|
||||
COPY pnpm-lock.yaml package.json .npmrc* ./
|
||||
|
||||
# Install dependencies with cache mount
|
||||
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
|
||||
--mount=type=secret,id=NPM_TOKEN \
|
||||
export NPM_TOKEN=$(cat /run/secrets/NPM_TOKEN 2>/dev/null || echo $NPM_TOKEN) && \
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
# Copy source code
|
||||
COPY . .
|
||||
|
||||
# Build application
|
||||
RUN pnpm build
|
||||
|
||||
# Stage 2: Runner
|
||||
FROM registry.infra.mintel.me/mintel/runtime:latest AS runner
|
||||
WORKDIR /app
|
||||
|
||||
ENV HOSTNAME="0.0.0.0"
|
||||
ENV PORT=3000
|
||||
ENV NODE_ENV=production
|
||||
|
||||
# Copy standalone output and static files
|
||||
# Adjust paths if using a monorepo structure (e.g., /app/apps/web/public)
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/cache ./.next/cache
|
||||
|
||||
USER nextjs
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "sample-website",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.9",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
"pino-pretty": "^13.1.3",
|
||||
"require-in-the-middle": "^8.0.1"
|
||||
},
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.10",
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"next": "16.1.6",
|
||||
|
||||
1
packages/acquisition-manager/index.js
Normal file
1
packages/acquisition-manager/index.js
Normal file
@@ -0,0 +1 @@
|
||||
import{defineModule as e}from"@directus/extensions-sdk";import{defineComponent as t,resolveComponent as n,openBlock as a,createBlock as i,withCtx as r,createElementVNode as o}from"vue";var s=t({__name:"module",setup:e=>(e,t)=>{const s=n("private-view");return a(),i(s,{title:"Acquisition Manager"},{default:r(()=>[...t[0]||(t[0]=[o("div",{class:"acquisition-manager"},[o("h1",null,"Acquisition Manager"),o("p",null,"Modern Industrial Acquisition Management Interface")],-1)])]),_:1})}}),u=[],c=[];!function(e,t){if(e&&"undefined"!=typeof document){var n,a=!0===t.prepend?"prepend":"append",i=!0===t.singleTag,r="string"==typeof t.container?document.querySelector(t.container):document.getElementsByTagName("head")[0];if(i){var o=u.indexOf(r);-1===o&&(o=u.push(r)-1,c[o]={}),n=c[o]&&c[o][a]?c[o][a]:c[o][a]=s()}else n=s();65279===e.charCodeAt(0)&&(e=e.substring(1)),n.styleSheet?n.styleSheet.cssText+=e:n.appendChild(document.createTextNode(e))}function s(){var e=document.createElement("style");if(e.setAttribute("type","text/css"),t.attributes)for(var n=Object.keys(t.attributes),i=0;i<n.length;i++)e.setAttribute(n[i],t.attributes[n[i]]);var o="prepend"===a?"afterbegin":"beforeend";return r.insertAdjacentElement(o,e),e}}("\n.acquisition-manager[data-v-19f4e937] {\n\tpadding: 20px;\n}\n",{});var d=e({id:"acquisition-manager",name:"Acquisition Manager",icon:"account_balance_wallet",routes:[{path:"",component:((e,t)=>{const n=e.__vccOpts||e;for(const[e,a]of t)n[e]=a;return n})(s,[["__scopeId","data-v-19f4e937"],["__file","module.vue"]])}]});export{d as default};
|
||||
30
packages/acquisition-manager/package.json
Normal file
30
packages/acquisition-manager/package.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "acquisition-manager",
|
||||
"description": "Custom High-Fidelity Acquisition Management for Directus",
|
||||
"icon": "account_balance_wallet",
|
||||
"version": "1.7.9",
|
||||
"type": "module",
|
||||
"keywords": [
|
||||
"directus",
|
||||
"directus-extension",
|
||||
"directus-extension-module"
|
||||
],
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"directus:extension": {
|
||||
"type": "module",
|
||||
"path": "index.js",
|
||||
"source": "src/index.ts",
|
||||
"host": "*",
|
||||
"name": "Acquisition Manager"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "directus-extension build && (cp -f dist/index.js index.js 2>/dev/null || true)",
|
||||
"dev": "directus-extension build -w"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@directus/extensions-sdk": "11.0.2",
|
||||
"vue": "^3.4.0"
|
||||
}
|
||||
}
|
||||
14
packages/acquisition-manager/src/index.ts
Normal file
14
packages/acquisition-manager/src/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { defineModule } from '@directus/extensions-sdk';
|
||||
import ModuleComponent from './module.vue';
|
||||
|
||||
export default defineModule({
|
||||
id: 'acquisition-manager',
|
||||
name: 'Acquisition Manager',
|
||||
icon: 'account_balance_wallet',
|
||||
routes: [
|
||||
{
|
||||
path: '',
|
||||
component: ModuleComponent,
|
||||
},
|
||||
],
|
||||
});
|
||||
18
packages/acquisition-manager/src/module.vue
Normal file
18
packages/acquisition-manager/src/module.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<private-view title="Acquisition Manager">
|
||||
<div class="acquisition-manager">
|
||||
<h1>Acquisition Manager</h1>
|
||||
<p>Modern Industrial Acquisition Management Interface</p>
|
||||
</div>
|
||||
</private-view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// Logic will be added here
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.acquisition-manager {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
44
packages/acquisition/build.js
Normal file
44
packages/acquisition/build.js
Normal file
@@ -0,0 +1,44 @@
|
||||
import { build } from 'esbuild';
|
||||
import { resolve, dirname } from 'path';
|
||||
import { mkdirSync } from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
const entryPoint = resolve(__dirname, 'src/index.ts');
|
||||
const outfile = resolve(__dirname, 'index.js');
|
||||
|
||||
try {
|
||||
mkdirSync(dirname(outfile), { recursive: true });
|
||||
} catch (e) { }
|
||||
|
||||
console.log(`Building from ${entryPoint} to ${outfile}...`);
|
||||
|
||||
build({
|
||||
entryPoints: [entryPoint],
|
||||
bundle: true,
|
||||
platform: 'node',
|
||||
target: 'node18',
|
||||
outfile: outfile,
|
||||
format: 'esm',
|
||||
external: [],
|
||||
plugins: [{
|
||||
name: 'mock-jquery',
|
||||
setup(build) {
|
||||
build.onResolve({ filter: /^jquery$/ }, args => ({ path: args.path, namespace: 'mock-jquery' }));
|
||||
build.onLoad({ filter: /.*/, namespace: 'mock-jquery' }, () => ({ contents: 'export default {};', loader: 'js' }));
|
||||
}
|
||||
}, {
|
||||
name: 'mock-canvas',
|
||||
setup(build) {
|
||||
build.onResolve({ filter: /^canvas$/ }, args => ({ path: args.path, namespace: 'mock-canvas' }));
|
||||
build.onLoad({ filter: /.*/, namespace: 'mock-canvas' }, () => ({ contents: 'export default {};', loader: 'js' }));
|
||||
}
|
||||
}]
|
||||
}).then(() => {
|
||||
console.log("Build succeeded!");
|
||||
}).catch((e) => {
|
||||
console.error("Build failed:", e);
|
||||
process.exit(1);
|
||||
});
|
||||
3845
packages/acquisition/index.js
Normal file
3845
packages/acquisition/index.js
Normal file
File diff suppressed because it is too large
Load Diff
25
packages/acquisition/package.json
Normal file
25
packages/acquisition/package.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "acquisition",
|
||||
"version": "1.7.9",
|
||||
"type": "module",
|
||||
"directus:extension": {
|
||||
"type": "endpoint",
|
||||
"path": "index.js",
|
||||
"source": "src/index.ts",
|
||||
"host": "^11.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "node build.js",
|
||||
"dev": "node build.js --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@directus/extensions-sdk": "11.0.2",
|
||||
"esbuild": "^0.25.0",
|
||||
"typescript": "^5.6.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"jquery": "^3.7.1",
|
||||
"react": "^19.2.4",
|
||||
"react-dom": "^19.2.4"
|
||||
}
|
||||
}
|
||||
5
packages/acquisition/src/index.ts
Normal file
5
packages/acquisition/src/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { defineEndpoint } from '@directus/extensions-sdk';
|
||||
|
||||
export default defineEndpoint((router) => {
|
||||
router.get('/ping', (req, res) => res.send('pong'));
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mintel/cli",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.9",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://npm.infra.mintel.me"
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
import{defineModule as e}from"@directus/extensions-sdk";import{defineComponent as t,resolveComponent as n,openBlock as a,createBlock as i,withCtx as r,createElementVNode as o}from"vue";var s=t({__name:"module",setup:e=>(e,t)=>{const s=n("private-view");return a(),i(s,{title:"Acquisition Manager"},{default:r(()=>[...t[0]||(t[0]=[o("div",{class:"acquisition-manager"},[o("h1",null,"Acquisition Manager"),o("p",null,"Modern Industrial Acquisition Management Interface")],-1)])]),_:1})}}),u=[],c=[];!function(e,t){if(e&&"undefined"!=typeof document){var n,a=!0===t.prepend?"prepend":"append",i=!0===t.singleTag,r="string"==typeof t.container?document.querySelector(t.container):document.getElementsByTagName("head")[0];if(i){var o=u.indexOf(r);-1===o&&(o=u.push(r)-1,c[o]={}),n=c[o]&&c[o][a]?c[o][a]:c[o][a]=s()}else n=s();65279===e.charCodeAt(0)&&(e=e.substring(1)),n.styleSheet?n.styleSheet.cssText+=e:n.appendChild(document.createTextNode(e))}function s(){var e=document.createElement("style");if(e.setAttribute("type","text/css"),t.attributes)for(var n=Object.keys(t.attributes),i=0;i<n.length;i++)e.setAttribute(n[i],t.attributes[n[i]]);var o="prepend"===a?"afterbegin":"beforeend";return r.insertAdjacentElement(o,e),e}}("\n.acquisition-manager[data-v-19f4e937] {\n\tpadding: 20px;\n}\n",{});var d=e({id:"acquisition-manager",name:"Acquisition Manager",icon:"account_balance_wallet",routes:[{path:"",component:((e,t)=>{const n=e.__vccOpts||e;for(const[e,a]of t)n[e]=a;return n})(s,[["__scopeId","data-v-19f4e937"],["__file","module.vue"]])}]});export{d as default};
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "acquisition-manager",
|
||||
"description": "Custom High-Fidelity Acquisition Management for Directus",
|
||||
"icon": "account_balance_wallet",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"keywords": [
|
||||
"directus",
|
||||
"directus-extension",
|
||||
"directus-extension-module"
|
||||
],
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"directus:extension": {
|
||||
"type": "module",
|
||||
"path": "index.js",
|
||||
"source": "src/index.ts",
|
||||
"host": "*",
|
||||
"name": "Acquisition Manager"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "directus-extension build && (cp -f dist/index.js index.js 2>/dev/null || true)",
|
||||
"dev": "directus-extension build -w"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@directus/extensions-sdk": "11.0.2",
|
||||
"vue": "^3.4.0"
|
||||
}
|
||||
}
|
||||
3845
packages/cms-infra/extensions/acquisition/index.js
Normal file
3845
packages/cms-infra/extensions/acquisition/index.js
Normal file
File diff suppressed because it is too large
Load Diff
25
packages/cms-infra/extensions/acquisition/package.json
Normal file
25
packages/cms-infra/extensions/acquisition/package.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "acquisition",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"directus:extension": {
|
||||
"type": "endpoint",
|
||||
"path": "index.js",
|
||||
"source": "src/index.ts",
|
||||
"host": "^11.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "node build.js",
|
||||
"dev": "node build.js --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@directus/extensions-sdk": "11.0.2",
|
||||
"esbuild": "^0.25.0",
|
||||
"typescript": "^5.6.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"jquery": "^3.7.1",
|
||||
"react": "^19.2.4",
|
||||
"react-dom": "^19.2.4"
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,29 +1,30 @@
|
||||
{
|
||||
"name": "customer-manager",
|
||||
"description": "Custom High-Fidelity Customer & Company Management for Directus",
|
||||
"icon": "supervisor_account",
|
||||
"version": "1.0.0",
|
||||
"keywords": [
|
||||
"directus",
|
||||
"directus-extension",
|
||||
"directus-extension-module"
|
||||
],
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"directus:extension": {
|
||||
"type": "module",
|
||||
"path": "index.js",
|
||||
"source": "src/index.ts",
|
||||
"host": "*",
|
||||
"name": "Customer Manager"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "directus-extension build",
|
||||
"dev": "directus-extension build -w"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@directus/extensions-sdk": "11.0.2",
|
||||
"vue": "^3.4.0"
|
||||
}
|
||||
"name": "customer-manager",
|
||||
"description": "Custom High-Fidelity Customer & Company Management for Directus",
|
||||
"icon": "supervisor_account",
|
||||
"version": "1.7.3",
|
||||
"type": "module",
|
||||
"keywords": [
|
||||
"directus",
|
||||
"directus-extension",
|
||||
"directus-extension-module"
|
||||
],
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"directus:extension": {
|
||||
"type": "module",
|
||||
"path": "index.js",
|
||||
"source": "src/index.ts",
|
||||
"host": "*",
|
||||
"name": "Customer Manager"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "directus-extension build && (cp -f dist/index.js index.js 2>/dev/null || true)",
|
||||
"dev": "directus-extension build -w"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@directus/extensions-sdk": "11.0.2",
|
||||
"vue": "^3.4.0"
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,30 @@
|
||||
{
|
||||
"name": "feedback-commander",
|
||||
"description": "Custom High-Fidelity Feedback Management Extension for Directus",
|
||||
"icon": "view_kanban",
|
||||
"version": "1.0.0",
|
||||
"keywords": [
|
||||
"directus",
|
||||
"directus-extension",
|
||||
"directus-extension-module"
|
||||
],
|
||||
"files": [
|
||||
"index.js"
|
||||
],
|
||||
"directus:extension": {
|
||||
"type": "module",
|
||||
"path": "index.js",
|
||||
"source": "src/index.ts",
|
||||
"host": "*",
|
||||
"name": "Feedback Commander"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "directus-extension build",
|
||||
"dev": "directus-extension build -w"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@directus/extensions-sdk": "11.0.2",
|
||||
"vue": "^3.4.0"
|
||||
}
|
||||
}
|
||||
"name": "feedback-commander",
|
||||
"description": "Custom High-Fidelity Feedback Management Extension for Directus",
|
||||
"icon": "view_kanban",
|
||||
"version": "1.7.3",
|
||||
"type": "module",
|
||||
"keywords": [
|
||||
"directus",
|
||||
"directus-extension",
|
||||
"directus-extension-module"
|
||||
],
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"directus:extension": {
|
||||
"type": "module",
|
||||
"path": "index.js",
|
||||
"source": "src/index.ts",
|
||||
"host": "*",
|
||||
"name": "Feedback Commander"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "directus-extension build && (cp -f dist/index.js index.js 2>/dev/null || true)",
|
||||
"dev": "directus-extension build -w"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@directus/extensions-sdk": "11.0.2",
|
||||
"vue": "^3.4.0"
|
||||
}
|
||||
}
|
||||
|
||||
1
packages/cms-infra/extensions/people-manager/index.js
Normal file
1
packages/cms-infra/extensions/people-manager/index.js
Normal file
@@ -0,0 +1 @@
|
||||
import{defineModule as e}from"@directus/extensions-sdk";import{defineComponent as t,resolveComponent as n,openBlock as a,createBlock as r,withCtx as o,createElementVNode as p}from"vue";var s=t({__name:"module",setup:e=>(e,t)=>{const s=n("private-view");return a(),r(s,{title:"People Manager"},{default:o(()=>[...t[0]||(t[0]=[p("div",{class:"people-manager"},[p("h1",null,"People Manager"),p("p",null,"Modern Industrial People Management Interface")],-1)])]),_:1})}}),d=[],i=[];!function(e,t){if(e&&"undefined"!=typeof document){var n,a=!0===t.prepend?"prepend":"append",r=!0===t.singleTag,o="string"==typeof t.container?document.querySelector(t.container):document.getElementsByTagName("head")[0];if(r){var p=d.indexOf(o);-1===p&&(p=d.push(o)-1,i[p]={}),n=i[p]&&i[p][a]?i[p][a]:i[p][a]=s()}else n=s();65279===e.charCodeAt(0)&&(e=e.substring(1)),n.styleSheet?n.styleSheet.cssText+=e:n.appendChild(document.createTextNode(e))}function s(){var e=document.createElement("style");if(e.setAttribute("type","text/css"),t.attributes)for(var n=Object.keys(t.attributes),r=0;r<n.length;r++)e.setAttribute(n[r],t.attributes[n[r]]);var p="prepend"===a?"afterbegin":"beforeend";return o.insertAdjacentElement(p,e),e}}("\n.people-manager[data-v-da2952f8] {\n\tpadding: 20px;\n}\n",{});var u=e({id:"people-manager",name:"People Manager",icon:"person",routes:[{path:"",component:((e,t)=>{const n=e.__vccOpts||e;for(const[e,a]of t)n[e]=a;return n})(s,[["__scopeId","data-v-da2952f8"],["__file","module.vue"]])}]});export{u as default};
|
||||
30
packages/cms-infra/extensions/people-manager/package.json
Normal file
30
packages/cms-infra/extensions/people-manager/package.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "people-manager",
|
||||
"description": "Custom High-Fidelity People Management for Directus",
|
||||
"icon": "person",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"keywords": [
|
||||
"directus",
|
||||
"directus-extension",
|
||||
"directus-extension-module"
|
||||
],
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"directus:extension": {
|
||||
"type": "module",
|
||||
"path": "index.js",
|
||||
"source": "src/index.ts",
|
||||
"host": "*",
|
||||
"name": "People Manager"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "directus-extension build && (cp -f dist/index.js index.js 2>/dev/null || true)",
|
||||
"dev": "directus-extension build -w"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@directus/extensions-sdk": "11.0.2",
|
||||
"vue": "^3.4.0"
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
{
|
||||
"name": "@mintel/cms-infra",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.9",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"up": "docker compose up -d",
|
||||
"up": "npm run build:extensions && docker compose up -d",
|
||||
"down": "docker compose down",
|
||||
"logs": "docker compose logs -f"
|
||||
"logs": "docker compose logs -f",
|
||||
"build:extensions": "../../scripts/sync-extensions.sh"
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -2,7 +2,8 @@
|
||||
"name": "customer-manager",
|
||||
"description": "Custom High-Fidelity Customer & Company Management for Directus",
|
||||
"icon": "supervisor_account",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.9",
|
||||
"type": "module",
|
||||
"keywords": [
|
||||
"directus",
|
||||
"directus-extension",
|
||||
@@ -19,7 +20,7 @@
|
||||
"name": "Customer Manager"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "directus-extension build",
|
||||
"build": "directus-extension build && (cp -f dist/index.js index.js 2>/dev/null || true)",
|
||||
"dev": "directus-extension build -w"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mintel/eslint-config",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.9",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://npm.infra.mintel.me"
|
||||
|
||||
1
packages/feedback-commander/index.js
Normal file
1
packages/feedback-commander/index.js
Normal file
File diff suppressed because one or more lines are too long
@@ -1,8 +1,9 @@
|
||||
{
|
||||
"name": "@mintel/extension-feedback-commander",
|
||||
"name": "feedback-commander",
|
||||
"description": "Custom High-Fidelity Feedback Management Extension for Directus",
|
||||
"icon": "view_kanban",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.9",
|
||||
"type": "module",
|
||||
"keywords": [
|
||||
"directus",
|
||||
"directus-extension",
|
||||
@@ -13,13 +14,13 @@
|
||||
],
|
||||
"directus:extension": {
|
||||
"type": "module",
|
||||
"path": "dist/index.js",
|
||||
"path": "index.js",
|
||||
"source": "src/index.ts",
|
||||
"host": "*",
|
||||
"name": "Feedback Commander"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "directus-extension build",
|
||||
"build": "directus-extension build && (cp -f dist/index.js index.js 2>/dev/null || true)",
|
||||
"dev": "directus-extension build -w"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mintel/gatekeeper",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.9",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mintel/husky-config",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.9",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://npm.infra.mintel.me"
|
||||
|
||||
@@ -1,38 +1,13 @@
|
||||
# Step 1: Builder image
|
||||
FROM node:20-alpine AS builder
|
||||
# Step 1: Base image for Next.js builds
|
||||
FROM node:20-alpine
|
||||
RUN apk add --no-cache libc6-compat curl
|
||||
|
||||
# Enable pnpm
|
||||
RUN corepack enable pnpm && \
|
||||
corepack prepare pnpm@10.2.0 --activate
|
||||
|
||||
WORKDIR /app
|
||||
RUN corepack enable pnpm
|
||||
|
||||
# Step 2: Install dependencies
|
||||
ENV NPM_TOKEN=placeholder
|
||||
# Copy manifest files specifically for better layer caching
|
||||
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json .npmrc ./
|
||||
# Copy package manifest files individually to preserve directory structure
|
||||
COPY packages/cli/package.json ./packages/cli/
|
||||
COPY packages/cms-infra/package.json ./packages/cms-infra/
|
||||
COPY packages/customer-manager/package.json ./packages/customer-manager/
|
||||
COPY packages/eslint-config/package.json ./packages/eslint-config/
|
||||
COPY packages/feedback-commander/package.json ./packages/feedback-commander/
|
||||
COPY packages/gatekeeper/package.json ./packages/gatekeeper/
|
||||
COPY packages/husky-config/package.json ./packages/husky-config/
|
||||
COPY packages/infra/package.json ./packages/infra/
|
||||
COPY packages/mail/package.json ./packages/mail/
|
||||
COPY packages/next-config/package.json ./packages/next-config/
|
||||
COPY packages/next-feedback/package.json ./packages/next-feedback/
|
||||
COPY packages/next-observability/package.json ./packages/next-observability/
|
||||
COPY packages/next-utils/package.json ./packages/next-utils/
|
||||
COPY packages/observability/package.json ./packages/observability/
|
||||
COPY packages/tsconfig/package.json ./packages/tsconfig/
|
||||
# packages/ui does not have a package.json
|
||||
|
||||
# Use a secret for NPM_TOKEN and a standardized cache mount
|
||||
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
|
||||
--mount=type=secret,id=NPM_TOKEN \
|
||||
export NPM_TOKEN=$(cat /run/secrets/NPM_TOKEN) && \
|
||||
pnpm config set store-dir /pnpm/store && \
|
||||
pnpm i --frozen-lockfile
|
||||
|
||||
# Step 3: Build shared packages
|
||||
COPY . .
|
||||
RUN pnpm --filter "./packages/*" -r build
|
||||
# Final environment
|
||||
ENV NODE_ENV=production
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
@@ -275,6 +275,10 @@ jobs:
|
||||
docker system prune -f --filter "until=24h"
|
||||
EOF
|
||||
|
||||
- name: 🧹 Post-Deploy Cleanup (Runner)
|
||||
if: always()
|
||||
run: docker builder prune -f --filter "until=1h"
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────────────────
|
||||
# JOB 5: Notifications
|
||||
# ──────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mintel/infra",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.9",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://npm.infra.mintel.me"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
set -e
|
||||
|
||||
# Configuration
|
||||
REGISTRY_DATA="/opt/infra/registry/data/docker/registry/v2"
|
||||
REGISTRY_DATA="/mnt/HC_Volume_104575103/registry-data/docker/registry/v2"
|
||||
KEEP_TAGS=3
|
||||
|
||||
echo "🏥 Starting Aggressive Registry & Docker Maintenance..."
|
||||
@@ -15,31 +15,26 @@ for repo_dir in "$REGISTRY_DATA/repositories/mintel/"*; do
|
||||
if [ -d "$tags_dir" ]; then
|
||||
echo "🔍 Processing repository: mintel/$repo_name"
|
||||
|
||||
# Prune main-* tags
|
||||
echo " 📦 Pruning main tags..."
|
||||
main_tags=$(ls -dt "$tags_dir"/main-* 2>/dev/null || true)
|
||||
count=0
|
||||
for tag_path in $main_tags; do
|
||||
((++count))
|
||||
if [ $count -gt $KEEP_TAGS ]; then
|
||||
echo " 🗑️ Deleting old main tag: $(basename "$tag_path")"
|
||||
rm -rf "$tag_path"
|
||||
fi
|
||||
# Prune various tag patterns
|
||||
PATTERNS=("main-*" "testing-*" "branch-*" "v*" "rc*" "[0-9a-f]*")
|
||||
|
||||
for pattern in "${PATTERNS[@]}"; do
|
||||
echo " 📦 Pruning $pattern tags..."
|
||||
tags=$(ls -dt "$tags_dir"/${pattern} 2>/dev/null || true)
|
||||
count=0
|
||||
for tag_path in $tags; do
|
||||
tag_name=$(basename "$tag_path")
|
||||
if [[ "$tag_name" == "latest" ]]; then continue; fi
|
||||
|
||||
((++count))
|
||||
if [ $count -gt $KEEP_TAGS ]; then
|
||||
echo " 🗑️ Deleting old tag: $tag_name"
|
||||
rm -rf "$tag_path"
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
# Prune version tags (v* and rc*)
|
||||
echo " 🏷️ Pruning version tags..."
|
||||
version_tags=$(ls -dt "$tags_dir"/v1* 2>/dev/null || true)
|
||||
count=0
|
||||
for tag_path in $version_tags; do
|
||||
((++count))
|
||||
if [ $count -gt $KEEP_TAGS ]; then
|
||||
echo " 🗑️ Deleting old version tag: $(basename "$tag_path")"
|
||||
rm -rf "$tag_path"
|
||||
fi
|
||||
done
|
||||
|
||||
# Always prune buildcache (as it rebuilds quickly)
|
||||
# Always prune buildcache
|
||||
if [ -d "$tags_dir/buildcache" ]; then
|
||||
echo " 🧹 Deleting buildcache tag"
|
||||
rm -rf "$tags_dir/buildcache"
|
||||
@@ -49,7 +44,7 @@ done
|
||||
|
||||
# 2. Run Garbage Collection
|
||||
echo "♻️ Running Registry Garbage Collection..."
|
||||
docker exec registry-registry-1 bin/registry garbage-collect /etc/docker/registry/config.yml
|
||||
docker exec registry-registry-1 bin/registry garbage-collect /etc/docker/registry/config.yml --delete-untagged
|
||||
|
||||
# 3. Prune Host Docker resources (Shorter window: 24h)
|
||||
echo "🧹 Pruning Host Docker resources..."
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mintel/mail",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.9",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mintel/next-config",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.9",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://npm.infra.mintel.me"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mintel/next-feedback",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.9",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://npm.infra.mintel.me"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mintel/next-observability",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.9",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://npm.infra.mintel.me"
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"name": "@mintel/next-utils",
|
||||
"version": "1.7.8",
|
||||
"version": "1.7.9",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://npm.infra.mintel.me"
|
||||
},
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "tsup src/index.ts --format cjs,esm --dts",
|
||||
"dev": "tsup src/index.ts --format cjs,esm --watch --dts",
|
||||
"build": "tsup src/index.ts --format esm --dts --clean",
|
||||
"dev": "tsup src/index.ts --format esm --watch --dts",
|
||||
"lint": "eslint src/",
|
||||
"test": "vitest run"
|
||||
},
|
||||
|
||||
@@ -7,20 +7,21 @@ import {
|
||||
AuthenticationClient,
|
||||
} from "@directus/sdk";
|
||||
|
||||
export type MintelDirectusClient = DirectusClient<any> &
|
||||
RestClient<any> &
|
||||
AuthenticationClient<any>;
|
||||
export type MintelDirectusClient<Schema extends object = any> =
|
||||
DirectusClient<Schema> & RestClient<Schema> & AuthenticationClient<Schema>;
|
||||
|
||||
/**
|
||||
* Creates a Directus client configured with Mintel standards.
|
||||
* Automatically handles internal vs. external URLs based on environment.
|
||||
*/
|
||||
export function createMintelDirectusClient(url?: string): MintelDirectusClient {
|
||||
export function createMintelDirectusClient<Schema extends object = any>(
|
||||
url?: string,
|
||||
): MintelDirectusClient<Schema> {
|
||||
const isServer = typeof window === "undefined";
|
||||
|
||||
// 1. If an explicit URL is provided, use it.
|
||||
if (url) {
|
||||
return createDirectus(url).with(rest()).with(authentication());
|
||||
return createDirectus<Schema>(url).with(rest()).with(authentication());
|
||||
}
|
||||
|
||||
// 2. On server: Prioritize INTERNAL_DIRECTUS_URL, fallback to DIRECTUS_URL
|
||||
@@ -29,7 +30,9 @@ export function createMintelDirectusClient(url?: string): MintelDirectusClient {
|
||||
process.env.INTERNAL_DIRECTUS_URL ||
|
||||
process.env.DIRECTUS_URL ||
|
||||
"http://localhost:8055";
|
||||
return createDirectus(directusUrl).with(rest()).with(authentication());
|
||||
return createDirectus<Schema>(directusUrl)
|
||||
.with(rest())
|
||||
.with(authentication());
|
||||
}
|
||||
|
||||
// 3. In browser: Use a proxy path if we are on a different origin,
|
||||
@@ -40,7 +43,7 @@ export function createMintelDirectusClient(url?: string): MintelDirectusClient {
|
||||
? `${window.location.origin}${proxyPath}`
|
||||
: proxyPath;
|
||||
|
||||
return createDirectus(browserUrl).with(rest()).with(authentication());
|
||||
return createDirectus<Schema>(browserUrl).with(rest()).with(authentication());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -50,14 +50,51 @@ export const mintelEnvSchema = {
|
||||
INTERNAL_DIRECTUS_URL: z.string().url().optional(),
|
||||
};
|
||||
|
||||
/**
|
||||
* Standard Mintel refinements for environment variables.
|
||||
* Enforces mandatory requirements for non-development environments.
|
||||
*/
|
||||
export const withMintelRefinements = <T extends z.ZodTypeAny>(schema: T) => {
|
||||
return schema.superRefine((data: any, ctx) => {
|
||||
const skipValidation =
|
||||
process.env.SKIP_ENV_VALIDATION === "true" ||
|
||||
process.env.SKIP_RUNTIME_ENV_VALIDATION === "true";
|
||||
|
||||
if (skipValidation) return;
|
||||
|
||||
const target = data.TARGET || data.NEXT_PUBLIC_TARGET || "development";
|
||||
|
||||
// Strict validation for non-development environments
|
||||
if (target !== "development") {
|
||||
if (!data.MAIL_HOST) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: "MAIL_HOST is required in non-development environments",
|
||||
path: ["MAIL_HOST"],
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export type MintelEnv<T extends z.ZodRawShape = Record<string, never>> =
|
||||
z.infer<
|
||||
ReturnType<
|
||||
typeof withMintelRefinements<z.ZodObject<typeof mintelEnvSchema & T>>
|
||||
>
|
||||
>;
|
||||
|
||||
export function validateMintelEnv<
|
||||
T extends z.ZodRawShape = Record<string, never>,
|
||||
>(schemaExtension: T = {} as T) {
|
||||
const fullSchema = z.object(mintelEnvSchema).extend(schemaExtension);
|
||||
>(schemaExtension: T = {} as T): MintelEnv<T> {
|
||||
const fullSchema = withMintelRefinements(
|
||||
z.object(mintelEnvSchema).extend(schemaExtension),
|
||||
);
|
||||
|
||||
const isBuildTime =
|
||||
process.env.NEXT_PHASE === "phase-production-build" ||
|
||||
process.env.SKIP_ENV_VALIDATION === "true";
|
||||
process.env.SKIP_ENV_VALIDATION === "true" ||
|
||||
process.env.SKIP_RUNTIME_ENV_VALIDATION === "true";
|
||||
|
||||
const result = fullSchema.safeParse(process.env);
|
||||
|
||||
@@ -77,5 +114,5 @@ export function validateMintelEnv<
|
||||
throw new Error("Invalid environment variables");
|
||||
}
|
||||
|
||||
return result.data;
|
||||
return result.data as MintelEnv<T>;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mintel/observability",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.9",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://npm.infra.mintel.me"
|
||||
|
||||
1
packages/people-manager/index.js
Normal file
1
packages/people-manager/index.js
Normal file
@@ -0,0 +1 @@
|
||||
import{defineModule as e}from"@directus/extensions-sdk";import{defineComponent as t,resolveComponent as n,openBlock as a,createBlock as r,withCtx as o,createElementVNode as p}from"vue";var s=t({__name:"module",setup:e=>(e,t)=>{const s=n("private-view");return a(),r(s,{title:"People Manager"},{default:o(()=>[...t[0]||(t[0]=[p("div",{class:"people-manager"},[p("h1",null,"People Manager"),p("p",null,"Modern Industrial People Management Interface")],-1)])]),_:1})}}),d=[],i=[];!function(e,t){if(e&&"undefined"!=typeof document){var n,a=!0===t.prepend?"prepend":"append",r=!0===t.singleTag,o="string"==typeof t.container?document.querySelector(t.container):document.getElementsByTagName("head")[0];if(r){var p=d.indexOf(o);-1===p&&(p=d.push(o)-1,i[p]={}),n=i[p]&&i[p][a]?i[p][a]:i[p][a]=s()}else n=s();65279===e.charCodeAt(0)&&(e=e.substring(1)),n.styleSheet?n.styleSheet.cssText+=e:n.appendChild(document.createTextNode(e))}function s(){var e=document.createElement("style");if(e.setAttribute("type","text/css"),t.attributes)for(var n=Object.keys(t.attributes),r=0;r<n.length;r++)e.setAttribute(n[r],t.attributes[n[r]]);var p="prepend"===a?"afterbegin":"beforeend";return o.insertAdjacentElement(p,e),e}}("\n.people-manager[data-v-da2952f8] {\n\tpadding: 20px;\n}\n",{});var u=e({id:"people-manager",name:"People Manager",icon:"person",routes:[{path:"",component:((e,t)=>{const n=e.__vccOpts||e;for(const[e,a]of t)n[e]=a;return n})(s,[["__scopeId","data-v-da2952f8"],["__file","module.vue"]])}]});export{u as default};
|
||||
30
packages/people-manager/package.json
Normal file
30
packages/people-manager/package.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "people-manager",
|
||||
"description": "Custom High-Fidelity People Management for Directus",
|
||||
"icon": "person",
|
||||
"version": "1.7.9",
|
||||
"type": "module",
|
||||
"keywords": [
|
||||
"directus",
|
||||
"directus-extension",
|
||||
"directus-extension-module"
|
||||
],
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"directus:extension": {
|
||||
"type": "module",
|
||||
"path": "index.js",
|
||||
"source": "src/index.ts",
|
||||
"host": "*",
|
||||
"name": "People Manager"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "directus-extension build && (cp -f dist/index.js index.js 2>/dev/null || true)",
|
||||
"dev": "directus-extension build -w"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@directus/extensions-sdk": "11.0.2",
|
||||
"vue": "^3.4.0"
|
||||
}
|
||||
}
|
||||
14
packages/people-manager/src/index.ts
Normal file
14
packages/people-manager/src/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { defineModule } from '@directus/extensions-sdk';
|
||||
import ModuleComponent from './module.vue';
|
||||
|
||||
export default defineModule({
|
||||
id: 'people-manager',
|
||||
name: 'People Manager',
|
||||
icon: 'person',
|
||||
routes: [
|
||||
{
|
||||
path: '',
|
||||
component: ModuleComponent,
|
||||
},
|
||||
],
|
||||
});
|
||||
18
packages/people-manager/src/module.vue
Normal file
18
packages/people-manager/src/module.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<private-view title="People Manager">
|
||||
<div class="people-manager">
|
||||
<h1>People Manager</h1>
|
||||
<p>Modern Industrial People Management Interface</p>
|
||||
</div>
|
||||
</private-view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// Logic will be added here
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.people-manager {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mintel/tsconfig",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.9",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://npm.infra.mintel.me"
|
||||
|
||||
5013
pnpm-lock.yaml
generated
5013
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
69
scripts/sync-extensions.sh
Executable file
69
scripts/sync-extensions.sh
Executable file
@@ -0,0 +1,69 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Configuration
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
EXTENSIONS_ROOT="$REPO_ROOT/packages"
|
||||
TARGET_DIR="$REPO_ROOT/packages/cms-infra/extensions"
|
||||
|
||||
# List of extensions to sync - including modules and endpoints
|
||||
EXTENSIONS=(
|
||||
"acquisition"
|
||||
"acquisition-manager"
|
||||
"customer-manager"
|
||||
"feedback-commander"
|
||||
"people-manager"
|
||||
)
|
||||
|
||||
echo "🚀 Starting extension sync..."
|
||||
|
||||
# Ensure target directory exists
|
||||
mkdir -p "$TARGET_DIR"
|
||||
|
||||
for EXT in "${EXTENSIONS[@]}"; do
|
||||
EXT_PATH="$EXTENSIONS_ROOT/$EXT"
|
||||
|
||||
if [ -d "$EXT_PATH" ]; then
|
||||
echo "📦 Building $EXT..."
|
||||
|
||||
# Build the extension
|
||||
# We use --if-present to avoid errors if build script is missing
|
||||
(cd "$EXT_PATH" && pnpm build)
|
||||
|
||||
# Create target directory for this extension
|
||||
# Directus expects extensions to be in subdirectories matching their name
|
||||
mkdir -p "$TARGET_DIR/$EXT"
|
||||
|
||||
echo "🚚 Syncing $EXT to $TARGET_DIR/$EXT..."
|
||||
|
||||
# Clean target first to avoid ghost files
|
||||
rm -rf "${TARGET_DIR:?}/$EXT"/*
|
||||
|
||||
# Copy build artifacts and package metadata
|
||||
# Some extensions have index.js in root after build, some use dist/
|
||||
# We check for index.js and package.json
|
||||
if [ -f "$EXT_PATH/index.js" ]; then
|
||||
cp "$EXT_PATH/index.js" "$TARGET_DIR/$EXT/"
|
||||
fi
|
||||
|
||||
if [ -f "$EXT_PATH/package.json" ]; then
|
||||
cp "$EXT_PATH/package.json" "$TARGET_DIR/$EXT/"
|
||||
fi
|
||||
|
||||
if [ -d "$EXT_PATH/dist" ]; then
|
||||
cp -r "$EXT_PATH/dist" "$TARGET_DIR/$EXT/"
|
||||
fi
|
||||
|
||||
# Sync node_modules if they exist (sometimes needed if not everything is bundled)
|
||||
if [ -d "$EXT_PATH/node_modules" ]; then
|
||||
echo "📚 Syncing node_modules for $EXT..."
|
||||
rsync -a --delete "$EXT_PATH/node_modules/" "$TARGET_DIR/$EXT/node_modules/"
|
||||
fi
|
||||
|
||||
echo "✅ $EXT synced."
|
||||
else
|
||||
echo "❌ Extension source not found: $EXT_PATH"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "✨ Extension sync complete!"
|
||||
Reference in New Issue
Block a user