From 2e0ed4e96cd556d1cb5ce996d83191d4ce810b92 Mon Sep 17 00:00:00 2001 From: "Jonathan W. Zaleski" Date: Thu, 6 Nov 2025 10:17:05 -0500 Subject: [PATCH 1/3] feat: Add auto-attach project support via `AUTO_ATTACH_PUBSUB_PROJECTS` env-var --- .dockerignore | 3 ++ Dockerfile | 4 ++ scripts/docker/docker-entrypoint.sh | 9 +++++ webapp/src/app/services/pubsub.service.ts | 48 ++++++++++++++++++++++- webapp/src/index.html | 6 +++ 5 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 .dockerignore create mode 100644 scripts/docker/docker-entrypoint.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..75d1314 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +webapp/node_modules + +webapp/package-lock.json diff --git a/Dockerfile b/Dockerfile index a7668fa..a6bd402 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,11 @@ RUN npm run build FROM nginx:stable-alpine-slim AS serve COPY scripts/docker/docker_nginx.conf /etc/nginx/conf.d/default.conf +COPY scripts/docker/docker-entrypoint.sh /docker-entrypoint.sh +RUN chmod +x /docker-entrypoint.sh WORKDIR /usr/share/nginx/html COPY --from=build /app/dist/webapp/browser . EXPOSE 80 + +ENTRYPOINT ["/docker-entrypoint.sh"] diff --git a/scripts/docker/docker-entrypoint.sh b/scripts/docker/docker-entrypoint.sh new file mode 100644 index 0000000..70df94d --- /dev/null +++ b/scripts/docker/docker-entrypoint.sh @@ -0,0 +1,9 @@ +#!/bin/sh +set -e + +# Update runtime variables +envsubst '${AUTO_ATTACH_PUBSUB_PROJECTS}' < /usr/share/nginx/html/index.html > /usr/share/nginx/html/index.html.tmp +mv /usr/share/nginx/html/index.html.tmp /usr/share/nginx/html/index.html + +# Start nginx +exec nginx -g 'daemon off;' diff --git a/webapp/src/app/services/pubsub.service.ts b/webapp/src/app/services/pubsub.service.ts index be9923d..84c9435 100644 --- a/webapp/src/app/services/pubsub.service.ts +++ b/webapp/src/app/services/pubsub.service.ts @@ -3,6 +3,15 @@ import { Injectable, inject } from '@angular/core'; import { BehaviorSubject, EMPTY, map, Observable, ReplaySubject } from 'rxjs'; import { NewSubscriptionRequest } from '../components/subscription-list/new-subscription-dialog/new-subscription-dialog.component'; +// Declare window.APP_CONFIG for runtime configuration +declare global { + interface Window { + APP_CONFIG?: { + autoAttachPubsubProjects?: string; + }; + } +} + @Injectable({ providedIn: 'root' }) @@ -31,13 +40,48 @@ export class PubsubService { const prevProjects = localStorage.getItem("projects") ?? "[]" const projects: string[] = JSON.parse(prevProjects) ?? [] - this._projectList.next(projects) + + // Auto-attach projects from environment variable (idempotent) + const autoAttachProjects = this.getAutoAttachProjects() + const mergedProjects = this.mergeProjectsIdempotently(projects, autoAttachProjects) + + this._projectList.next(mergedProjects) + + // Save merged list to localStorage if auto-attach added new projects + if (mergedProjects.length !== projects.length) { + localStorage.setItem("projects", JSON.stringify(mergedProjects)) + console.log('auto-attached projects:', autoAttachProjects) + } this.currentProject$.subscribe(project => this.topicList$ = this.listTopics(project) ) } + private getAutoAttachProjects(): string[] { + const envVar = window.APP_CONFIG?.autoAttachPubsubProjects || '' + if (!envVar || envVar.trim() === '' || envVar === '${AUTO_ATTACH_PUBSUB_PROJECTS}') { + return [] + } + + return envVar + .split(',') + .map(project => project.trim()) + .filter(project => project.length > 0) + } + + private mergeProjectsIdempotently(existing: string[], autoAttach: string[]): string[] { + const merged = [...existing] + + for (const project of autoAttach) { + if (!merged.includes(project)) { + merged.push(project) + } + } + + return merged + } + setHost(hostUrl: string) { this._currentHost$.next(hostUrl) @@ -141,7 +185,7 @@ export interface ReceivedMessage { } export interface PubsubMessage { - data: string + data: string attributes?: { [key: string]: string } messageId?: string publishTime?: string diff --git a/webapp/src/index.html b/webapp/src/index.html index c403841..28d9232 100644 --- a/webapp/src/index.html +++ b/webapp/src/index.html @@ -15,6 +15,12 @@ + From 3fb2391836e9253985d5ef4078a07caba4ea6522 Mon Sep 17 00:00:00 2001 From: "Jonathan W. Zaleski" Date: Sat, 8 Nov 2025 15:40:26 -0500 Subject: [PATCH 2/3] feat: Add configurable default-host support via `DEFAULT_PUBSUB_EMULATOR_HOST` env-var + clean-up --- scripts/docker/docker-entrypoint.sh | 2 +- webapp/src/app/services/pubsub.service.ts | 17 +++++++++++++---- webapp/src/index.html | 4 ++-- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/scripts/docker/docker-entrypoint.sh b/scripts/docker/docker-entrypoint.sh index 70df94d..431756b 100644 --- a/scripts/docker/docker-entrypoint.sh +++ b/scripts/docker/docker-entrypoint.sh @@ -3,7 +3,7 @@ set -e # Update runtime variables envsubst '${AUTO_ATTACH_PUBSUB_PROJECTS}' < /usr/share/nginx/html/index.html > /usr/share/nginx/html/index.html.tmp -mv /usr/share/nginx/html/index.html.tmp /usr/share/nginx/html/index.html +envsubst '${DEFAULT_PUBSUB_EMULATOR_HOST}' < /usr/share/nginx/html/index.html.tmp > /usr/share/nginx/html/index.html # Start nginx exec nginx -g 'daemon off;' diff --git a/webapp/src/app/services/pubsub.service.ts b/webapp/src/app/services/pubsub.service.ts index 84c9435..630d6e1 100644 --- a/webapp/src/app/services/pubsub.service.ts +++ b/webapp/src/app/services/pubsub.service.ts @@ -8,6 +8,7 @@ declare global { interface Window { APP_CONFIG?: { autoAttachPubsubProjects?: string; + defaultPubsubEmulatorHost?: string; }; } } @@ -18,7 +19,7 @@ declare global { export class PubsubService { private http = inject(HttpClient); - public _currentHost$ = new BehaviorSubject("http://localhost:8681") + public _currentHost$ = new BehaviorSubject("") private _projectList = new BehaviorSubject([]) private _currentProject = new ReplaySubject() @@ -32,10 +33,18 @@ export class PubsubService { public currentSubscription$ = this._currentSubscription.asObservable() constructor() { + let defaultHost = window.APP_CONFIG?.defaultPubsubEmulatorHost || "" + if (!defaultHost || defaultHost === '${DEFAULT_PUBSUB_EMULATOR_HOST}') { + defaultHost = "http://localhost:8681" + } + const prevHost = localStorage.getItem("host") if (prevHost) { console.log('loaded previous host', prevHost) this._currentHost$.next(prevHost) + } else { + console.log('loaded default host', defaultHost) + this._currentHost$.next(defaultHost) } const prevProjects = localStorage.getItem("projects") ?? "[]" @@ -59,12 +68,12 @@ export class PubsubService { } private getAutoAttachProjects(): string[] { - const envVar = window.APP_CONFIG?.autoAttachPubsubProjects || '' - if (!envVar || envVar.trim() === '' || envVar === '${AUTO_ATTACH_PUBSUB_PROJECTS}') { + const autoAttachProjects = window.APP_CONFIG?.autoAttachPubsubProjects || '' + if (!autoAttachProjects || autoAttachProjects === "${AUTO_ATTACH_PUBSUB_PROJECTS}") { return [] } - return envVar + return autoAttachProjects .split(',') .map(project => project.trim()) .filter(project => project.length > 0) diff --git a/webapp/src/index.html b/webapp/src/index.html index 28d9232..db8f058 100644 --- a/webapp/src/index.html +++ b/webapp/src/index.html @@ -16,9 +16,9 @@ From 331d7d015be028642c9102de8ffe4aab6f4f804a Mon Sep 17 00:00:00 2001 From: "Jonathan W. Zaleski" Date: Sat, 8 Nov 2025 15:53:49 -0500 Subject: [PATCH 3/3] fix: Auto-prefix the default-host with "http://" if it is missing the protocol --- webapp/src/app/services/pubsub.service.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/webapp/src/app/services/pubsub.service.ts b/webapp/src/app/services/pubsub.service.ts index 630d6e1..eb4f4b0 100644 --- a/webapp/src/app/services/pubsub.service.ts +++ b/webapp/src/app/services/pubsub.service.ts @@ -38,6 +38,10 @@ export class PubsubService { defaultHost = "http://localhost:8681" } + if (!defaultHost.match(/^http[s]?:\/\//)) { + defaultHost = `http://${defaultHost}` + } + const prevHost = localStorage.getItem("host") if (prevHost) { console.log('loaded previous host', prevHost)