File tree Expand file tree Collapse file tree
components/atom/DemoBanner Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -175,6 +175,16 @@ LLM_MAX_TOKENS_CLARIFY=2000 # cap for follow-up Q&A
175175# DEEPSEEK_TIMEOUT_MS=600000 # optional: raise DeepSeek axios timeout (default: 10 min for reasoner, 4 min for chat)
176176# DEEPSEEK_BASE_URL="https://api.deepseek.com" # optional: override DeepSeek base URL (e.g. for a compatible proxy)
177177
178+ # ─────────────────────────────────────────
179+ # DEMO MODE (public demo instances only)
180+ # When DEMO_MODE=true, the app shows a "you're on the live demo" banner with
181+ # the shared demo credentials and a "deploy your own" link. Leave false for
182+ # real deployments. Only set DEMO_EMAIL/DEMO_PASSWORD on a throwaway demo DB.
183+ # ─────────────────────────────────────────
184+ DEMO_MODE = " false"
185+ DEMO_EMAIL = " "
186+ DEMO_PASSWORD = " "
187+
178188# ─────────────────────────────────────────
179189# MISC
180190# ─────────────────────────────────────────
Original file line number Diff line number Diff line change @@ -91,12 +91,22 @@ exports.makeDefaultBrandSettings = () => {
9191
9292exports . getBrandSettingsData = ( req , res ) => {
9393 try {
94+ // Public demo flag (+ shared demo creds) surfaced on this already-public,
95+ // pre-auth endpoint so the demo banner / login can read it without a
96+ // build-time var. Off unless DEMO_MODE=true in the server env.
97+ const demo = process . env . DEMO_MODE === 'true' ;
98+ const withDemo = ( obj ) => ( {
99+ ...obj ,
100+ demoMode : demo ,
101+ ...( demo ? { demoEmail : process . env . DEMO_EMAIL || '' , demoPassword : process . env . DEMO_PASSWORD || '' } : { } ) ,
102+ } ) ;
103+
94104 const filePath = path . join ( __dirname , '/../../../' , 'brandSettings.json' ) ;
95105
96106 if ( ! fs . existsSync ( filePath ) ) {
97107 exports . makeDefaultBrandSettings ( )
98108 . then ( ( data ) => {
99- res . status ( 200 ) . json ( JSON . parse ( data ) ) ;
109+ res . status ( 200 ) . json ( withDemo ( JSON . parse ( data ) ) ) ;
100110 } )
101111 . catch ( ( error ) => {
102112 res . status ( 404 ) . send ( error ) ;
@@ -107,7 +117,7 @@ exports.getBrandSettingsData = (req, res) => {
107117 logger . error ( 'Error writing file getBrandSettingsData:' , err ) ;
108118 return res . status ( 500 ) . send ( 'Internal Server Error' ) ;
109119 }
110- res . status ( 200 ) . json ( JSON . parse ( data ) ) ;
120+ res . status ( 200 ) . json ( withDemo ( JSON . parse ( data ) ) ) ;
111121 } ) ;
112122 }
113123 } catch ( error ) {
Original file line number Diff line number Diff line change 11<template >
22 <div v-if =" !underMaintainance" >
3+ <DemoBanner />
34 <template v-if =" $route .meta .requiresAuth " >
45 <template v-if =" logged && (rules && Object .keys (rules ).length && companyUserDetail && Object .keys (companyUserDetail ).length ) && socket " >
56 <HeaderComponent v-if =" ! $route .meta .hideHeader " @change =" changeCompany ($event )" @filter =" handleFilter " />
Original file line number Diff line number Diff line change 1+ <template >
2+ <div v-if =" demoMode" class =" demo-banner" >
3+ <span class =" demo-banner__msg" >
4+ 🚀 {{ $t('Demo.banner') }}
5+ <span v-if =" demoEmail" class =" demo-banner__creds" >
6+ {{ $t('Demo.login_with') }} <strong >{{ demoEmail }}</strong ><template v-if =" demoPassword " > / <strong >{{ demoPassword }}</strong ></template >
7+ </span >
8+ </span >
9+ <span class =" demo-banner__links" >
10+ <a :href =" githubUrl" target =" _blank" rel =" noopener noreferrer" >⭐ {{ $t('Demo.star') }}</a >
11+ <a :href =" deployUrl" target =" _blank" rel =" noopener noreferrer" >{{ $t('Demo.deploy') }}</a >
12+ </span >
13+ </div >
14+ </template >
15+
16+ <script setup>
17+ import { computed } from " vue" ;
18+ import { useStore } from " vuex" ;
19+
20+ const store = useStore ();
21+
22+ const GITHUB_URL = ' https://github.com/aliansoftwareteam/AlianHub-Project-Management-System' ;
23+ const DEPLOY_URL = ' https://github.com/aliansoftwareteam/AlianHub-Project-Management-System#quick-start' ;
24+
25+ const brand = computed (() => store .getters [' brandSettingTab/brandSettings' ] || {});
26+ const demoMode = computed (() => brand .value .demoMode === true );
27+ const demoEmail = computed (() => brand .value .demoEmail || ' ' );
28+ const demoPassword = computed (() => brand .value .demoPassword || ' ' );
29+ const githubUrl = GITHUB_URL ;
30+ const deployUrl = DEPLOY_URL ;
31+ </script >
32+
33+ <style scoped>
34+ .demo-banner {
35+ display : flex ;
36+ align-items : center ;
37+ justify-content : center ;
38+ flex-wrap : wrap ;
39+ gap : 6px 16px ;
40+ background : #2f3990 ;
41+ color : #fff ;
42+ font-size : 12.5px ;
43+ line-height : 1.3 ;
44+ padding : 6px 14px ;
45+ text-align : center ;
46+ }
47+ .demo-banner__creds {
48+ opacity : 0.92 ;
49+ margin-left : 6px ;
50+ }
51+ .demo-banner__links {
52+ display : inline-flex ;
53+ gap : 14px ;
54+ white-space : nowrap ;
55+ }
56+ .demo-banner__links a {
57+ color : #fff ;
58+ text-decoration : underline ;
59+ font-weight : 600 ;
60+ }
61+ .demo-banner__links a :hover {
62+ opacity : 0.85 ;
63+ }
64+ </style >
Original file line number Diff line number Diff line change @@ -2655,4 +2655,10 @@ export default {
26552655 load_failed : "Couldn't load the changelog." ,
26562656 retry : "Retry" ,
26572657 } ,
2658+ Demo : {
2659+ banner : "You're on the AlianHub live demo — data may reset periodically." ,
2660+ login_with : "Log in with" ,
2661+ star : "Star on GitHub" ,
2662+ deploy : "Deploy your own" ,
2663+ } ,
26582664} ;
Original file line number Diff line number Diff line change @@ -13,6 +13,7 @@ import { DatePicker } from 'v-calendar';
1313import 'v-calendar/style.css' ;
1414import { i18n } from '@/locales/main' ;
1515import VueApexCharts from "vue3-apexcharts" ;
16+ import DemoBanner from "@/components/atom/DemoBanner/DemoBanner.vue" ;
1617// Plugins Path
1718import registerPlugin from './plugins/register/registerPlugin' ;
1819import createcompanyinsidePlugin from './plugins/createcompanyinside/createcompanyinsidePlugin' ;
@@ -61,6 +62,8 @@ for (let index = 0; index < pluginArray.length; index++) {
6162app . use ( ToastPlugin , { position : 'top-right' } ) ;
6263app . use ( plugin , defaultConfig ( { plugins : [ pro ] } ) )
6364app . use ( i18n ) ;
65+ // Registered before mount so the root App.vue template can resolve it.
66+ app . component ( 'DemoBanner' , DemoBanner ) ;
6467app . mount ( '#app' ) ;
6568// Use plugin defaults (optional)
6669app . component ( 'ApexChart' , VueApexCharts ) ; // Register the apexchart component globally
You can’t perform that action at this time.
0 commit comments