Skip to content

Commit a0ba602

Browse files
committed
feat: enhance Docker and Makefile for Nuxt supervisor management
- Added supervisor management scripts to the Dockerfile for better process control. - Updated Makefile with new commands for checking Nuxt supervisor status, reloading configuration, and managing Nuxt processes (start, stop, restart). - Improved logging in the AcGuard to provide detailed user access information. - Refactored entrypoint script to ensure proper execution of development and production commands.
1 parent 963b501 commit a0ba602

File tree

28 files changed

+271
-103
lines changed

28 files changed

+271
-103
lines changed

Dockerfile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,16 @@ RUN ARCH=$(uname -m) && \
5858
RUN cp /usr/share/zoneinfo/$TZ /etc/localtime \
5959
&& echo $TZ > /etc/timezone
6060

61+
RUN printf '%s\n' \
62+
'#!/bin/sh' \
63+
'exec /bin/sh /etc/supervisor/supervisor-manager.sh "$@"' \
64+
> /usr/local/bin/supervisor-manager \
65+
&& printf '%s\n' \
66+
'#!/bin/sh' \
67+
'exec supervisor-manager "$@"' \
68+
> /usr/local/bin/nuxt-supervisor \
69+
&& chmod +x /usr/local/bin/supervisor-manager /usr/local/bin/nuxt-supervisor
70+
6171
RUN yarn install \
6272
--prefer-offline \
6373
--pure-lockfile \

Makefile

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,22 @@ dbs: ## Start databases
177177
stop: ## Stop the container
178178
@docker stop $(APP_NAME) || true
179179

180+
nuxt-status: ## Show Nuxt supervisor status
181+
@docker exec -it $(APP_NAME) sh /etc/supervisor/supervisor-manager.sh status web
182+
183+
supervisor-reload: ## Reload supervisor config in running container
184+
@docker exec -it $(APP_NAME) sh /etc/supervisor/supervisor-manager.sh reread
185+
@docker exec -it $(APP_NAME) sh /etc/supervisor/supervisor-manager.sh update
186+
187+
nuxt-restart: ## Restart Nuxt only via supervisor
188+
@docker exec -it $(APP_NAME) sh /etc/supervisor/supervisor-manager.sh restart web
189+
190+
nuxt-stop: ## Stop Nuxt only via supervisor
191+
@docker exec -it $(APP_NAME) sh /etc/supervisor/supervisor-manager.sh stop web
192+
193+
nuxt-start: ## Start Nuxt only via supervisor
194+
@docker exec -it $(APP_NAME) sh /etc/supervisor/supervisor-manager.sh start web
195+
180196
stop-all: ## Stop all containers
181197
@docker stop $(APP_NAME) || true
182198
@docker stop $(BASE_NAME)-mongodb || true

apps/api/src/_common/guards/ac.guard.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import { Reflector } from '@nestjs/core';
33
import { ACGuard as AcGuardInternal, RolesBuilder } from 'nest-access-control';
44
import { META_UNPROTECTED } from '~/_common/decorators/public.decorator';
55
import { AC_ADMIN_ROLE, AC_GUEST_ROLE } from '../types/ac-types';
6+
import { ApiSession } from '../data/api-session';
7+
import { ConsoleSession } from '../data/console-session';
8+
import { Request } from 'express';
69

710
export function AcGuard(): Type<CanActivate> {
811
@Injectable()
@@ -24,18 +27,20 @@ export function AcGuard(): Type<CanActivate> {
2427
}
2528

2629
public async canActivate(context: ExecutionContext): Promise<boolean> {
30+
const request = context.switchToHttp().getRequest<Request & { user: Express.User & (ApiSession | ConsoleSession) }>();
2731
const roleOrRoles = await this.getUserRoles(context)
2832
const roles = Array.isArray(roleOrRoles) ? roleOrRoles : [roleOrRoles]
29-
//console.log('canActivate', roles)
33+
3034
if (roles.includes(AC_ADMIN_ROLE)) {
35+
this.logger.verbose(`User <${request.user._id}, ${request.user.username}> wants to access <${request.method}::${request.route.path}>. Roles: [${roles.join(', ')}] -> [is allowed]`);
3136
return true;
3237
}
3338

3439
const result = this.isUnProtected(context) || await super.canActivate(context);
3540

36-
const path = context.switchToHttp().getRequest().route.path;
37-
const method = context.switchToHttp().getRequest().method;
38-
this.logger.verbose(`User wants to access <${method}::${path}>. Roles: [${roles.join(', ')}] -> [${result ? 'is allowed' : 'is not allowed'}]`);
41+
if (request.user) {
42+
this.logger.verbose(`User <${request.user._id}, ${request.user.username}> wants to access <${request.method}::${request.route.path}>. Roles: [${roles.join(', ')}] -> [${result ? 'is allowed' : 'is not allowed'}]`);
43+
}
3944

4045
return result;
4146
}

apps/web/entrypoint.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
./scripts/checkinstall.sh
44
if [ "$DEV" = "1" ];then
5-
yarn dev
5+
exec yarn dev
66
else
7-
yarn run start:prod
7+
exec yarn run start:prod
88
fi
99

apps/web/nuxt.config.ts

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ export default defineNuxtConfig({
8080
modules: [
8181
'@sentry/nuxt/module',
8282
'@nuxt-alt/auth',
83-
'@nuxt-alt/proxy',
8483
'@nuxt-alt/http',
8584
'@pinia/nuxt',
8685
'nuxt-quasar-ui',
@@ -141,28 +140,6 @@ export default defineNuxtConfig({
141140
},
142141
},
143142
},
144-
proxy: {
145-
https: false,
146-
proxies: {
147-
'/api': {
148-
rewrite: (path: string) => path.replace(/^\/api/, ''),
149-
target: SESAME_APP_API_URL,
150-
secure: false,
151-
changeOrigin: true,
152-
xfwd: true,
153-
configure: (proxy, options) => {
154-
proxy.on('proxyReq', (proxyReq, req, res) => {
155-
// Disable timeout for SSE endpoints
156-
if (req.url?.includes('/backends/sse')) {
157-
proxyReq.setTimeout(0);
158-
res.setTimeout(0);
159-
}
160-
});
161-
},
162-
}
163-
},
164-
cors: false,
165-
},
166143
http: {
167144
debug: /true|on|yes|1/i.test(`${process.env.DEBUG}`),
168145
browserBaseURL: '/api',
@@ -176,7 +153,7 @@ export default defineNuxtConfig({
176153
},
177154
quasar: {
178155
iconSet: 'mdi-v7',
179-
plugins: ['Notify', 'Dialog'],
156+
plugins: ['Notify', 'Dialog', 'LoadingBar'],
180157
config: {
181158
dark: SESAME_APP_DARK_MODE,
182159
brand: {
@@ -195,6 +172,11 @@ export default defineNuxtConfig({
195172
position: 'top-right',
196173
actions: [{ icon: 'mdi-close', color: 'white' }],
197174
},
175+
loadingBar: {
176+
color: 'primary',
177+
size: '3px',
178+
position: 'top',
179+
},
198180
},
199181
extras: {
200182
animations: IS_DEV ? 'all' : [],
@@ -212,6 +194,31 @@ export default defineNuxtConfig({
212194
server: {
213195
allowedHosts: ['localhost', ...SESAME_ALLOWED_HOSTS],
214196
},
197+
build: {
198+
rollupOptions: {
199+
output: {
200+
manualChunks: (id: string) => {
201+
if (!id.includes('node_modules')) return
202+
203+
if (id.includes('monaco-editor') || id.includes('nuxt-monaco-editor')) {
204+
return 'vendor-monaco'
205+
}
206+
207+
if (id.includes('@jsonforms/') || id.includes('@tacxou/jsonforms_builder')) {
208+
return 'vendor-jsonforms'
209+
}
210+
211+
if (id.includes('quasar') || id.includes('@quasar/')) {
212+
return 'vendor-quasar'
213+
}
214+
215+
if (id.includes('@sentry/')) {
216+
return 'vendor-sentry'
217+
}
218+
},
219+
},
220+
},
221+
},
215222
define: {
216223
'process.env.DEBUG': process.env.NODE_ENV === 'development',
217224
},
@@ -241,7 +248,11 @@ export default defineNuxtConfig({
241248
websocket: false,
242249
},
243250
routeRules: {
251+
'/api/**': {
252+
proxy: `${SESAME_APP_API_URL}/**`,
253+
},
244254
'/api/core/backends/sse': {
255+
proxy: `${SESAME_APP_API_URL}/core/backends/sse`,
245256
// Disable compression and caching for SSE
246257
headers: {
247258
'Cache-Control': 'no-cache, no-transform',

apps/web/src/components/core/jsonforms-renderer.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
<script lang="ts">
2626
import { JsonForms } from '@jsonforms/vue'
27-
import { quasarRenderers } from '~/jsonforms'
27+
import { quasarRenderers } from '~/jsonforms/renderers'
2828
import { createAjv } from '~/jsonforms/utils/validator'
2929
import type { ErrorObject } from 'ajv'
3030
// import localize from 'ajv-i18n/localize'

apps/web/src/jsonforms/advanced/media-picker.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ import { determineClearValue } from '../utils'
185185
import { useMediaPickerControl } from '../composables'
186186
import { QInput, QAvatar, QIcon, QBtn, QCard, QImg, QSpinner, QPopupProxy, QSeparator, QSpace, QChip, QBar } from 'quasar'
187187
import { fileTypeFromBuffer } from 'file-type'
188-
import mime from 'mime'
188+
import { getMimeTypeFromExtension } from '~/utils/mime'
189189
190190
const controlRenderer = defineComponent({
191191
name: 'MediaPickerControl',
@@ -242,7 +242,7 @@ const controlRenderer = defineComponent({
242242
const ext = getFileExtension(src)
243243
if (!ext) return ''
244244
245-
return mime.getType(ext) || ''
245+
return getMimeTypeFromExtension(ext)
246246
}
247247
248248
const getMimeIcon = (item: any) => {

apps/web/src/jsonforms/common/file-preview.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ q-dialog(
5959
<script lang="ts">
6060
import { defineComponent, computed, ref, watch, type PropType } from 'vue'
6161
import { QDialog, QBar, QBtn, QImg, QIcon } from 'quasar'
62-
import mime from 'mime'
62+
import { getMimeTypeFromExtension } from '~/utils/mime'
6363
6464
export default defineComponent({
6565
name: 'FilePreview',
@@ -115,7 +115,7 @@ export default defineComponent({
115115
const src = item?.thumbnail || item?.value || ''
116116
const ext = getFileExtension(typeof src === 'string' ? src : '')
117117
if (!ext) return ''
118-
return mime.getType(ext) || ''
118+
return getMimeTypeFromExtension(ext)
119119
}
120120
121121
const isDataUrl = (v: unknown): v is string => typeof v === 'string' && v.startsWith('data:')

apps/web/src/jsonforms/controls/file-upload.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ import { determineClearValue } from '../utils'
9090
import { useMediaPickerControl } from '../composables'
9191
import { QField, QAvatar, QIcon, QBtn, QChip } from 'quasar'
9292
import { fileTypeFromBuffer } from 'file-type'
93-
import mime from 'mime'
93+
import { getMimeTypeFromExtension } from '~/utils/mime'
9494
9595
const controlRenderer = defineComponent({
9696
name: 'FileUploadControl',
@@ -222,7 +222,7 @@ const controlRenderer = defineComponent({
222222
const src = item?.thumbnail || item?.value || ''
223223
const ext = getFileExtension(typeof src === 'string' ? src : '')
224224
if (!ext) return ''
225-
return mime.getType(ext) || ''
225+
return getMimeTypeFromExtension(ext)
226226
}
227227
228228
const getMimeIcon = (item: any) => {
Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
import { additionalsRenderers } from './additional'
22
import { controlsRenderers } from './controls'
33
import { layoutsRenderers } from './layouts'
4-
import { advancedRenderers } from './advanced'
5-
6-
export { advancedRenderers }
74

85
export const quasarRenderers = [
96
...controlsRenderers,
107
...layoutsRenderers,
118
...additionalsRenderers,
129
]
1310

14-
export const allRenderers = [
15-
...quasarRenderers,
16-
...advancedRenderers,
17-
]
11+
export const loadAdvancedRenderers = async () => {
12+
const module = await import('./advanced')
13+
return module.advancedRenderers
14+
}

0 commit comments

Comments
 (0)