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..431756b --- /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 +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 be9923d..eb4f4b0 100644 --- a/webapp/src/app/services/pubsub.service.ts +++ b/webapp/src/app/services/pubsub.service.ts @@ -3,13 +3,23 @@ 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; + defaultPubsubEmulatorHost?: string; + }; + } +} + @Injectable({ providedIn: 'root' }) 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() @@ -23,21 +33,68 @@ 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" + } + + if (!defaultHost.match(/^http[s]?:\/\//)) { + defaultHost = `http://${defaultHost}` + } + 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") ?? "[]" 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 autoAttachProjects = window.APP_CONFIG?.autoAttachPubsubProjects || '' + if (!autoAttachProjects || autoAttachProjects === "${AUTO_ATTACH_PUBSUB_PROJECTS}") { + return [] + } + + return autoAttachProjects + .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 +198,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..db8f058 100644 --- a/webapp/src/index.html +++ b/webapp/src/index.html @@ -15,6 +15,12 @@ +