Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions .github/workflows/test-e2e-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,29 +114,23 @@ jobs:
azd env set DEPLOY_AZURE_COSMOSDB true
azd env set AZURE_COSMOSDB_ACCOUNT_KIND MongoDB
azd env set DEPLOY_OBSERVABILITY_TOOLS true
azd env set COMPANY_NAME "Contoso"
azd up
env:
AZURE_ENV_NAME: ${{ vars.AZURE_ENV_NAME }}
AZURE_LOCATION: ${{ vars.AZURE_LOCATION }}
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

- name: Get endpoint URLs
id: azd_get_endpoint_urls
run: |
echo "STORE_ADMIN_URL=$(azd env get-value SERVICE_STORE_ADMIN_ENDPOINT_URL)" >> "$GITHUB_OUTPUT"
echo "STORE_FRONT_URL=$(azd env get-value SERVICE_STORE_FRONT_ENDPOINT_URL)" >> "$GITHUB_OUTPUT"

- name: Install Playwright dependencies
run: npm ci
working-directory: tests

- name: Run Playwright tests
run: npx playwright test --config=playwright.service.config.ts --workers=20
run: npx playwright test e2e/store-front/basic.spec.ts e2e/store-admin/basic.spec.ts --config=playwright.service.config.ts --workers=20
working-directory: tests
env:
PLAYWRIGHT_SERVICE_URL: ${{ secrets.PLAYWRIGHT_SERVICE_URL }}
STORE_ADMIN_URL: ${{ steps.azd_get_endpoint_urls.outputs.STORE_ADMIN_URL }}
STORE_FRONT_URL: ${{ steps.azd_get_endpoint_urls.outputs.STORE_FRONT_URL }}
CI: true

- name: Clean up resources
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ jobs:
working-directory: tests

- name: Run Playwright tests
run: npx playwright test --config=playwright.service.config.ts --workers=20
run: npx playwright test e2e/store-front/basic.spec.ts e2e/store-admin/basic.spec.ts --config=playwright.service.config.ts --workers=20
working-directory: tests
env:
PLAYWRIGHT_SERVICE_URL: ${{ secrets.PLAYWRIGHT_SERVICE_URL }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-playwright.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
working-directory: tests

- name: Run Playwright tests
run: npx playwright test --config=playwright.service.config.ts --workers=20
run: npx playwright test e2e/store-front/basic.spec.ts e2e/store-admin/basic.spec.ts --config=playwright.service.config.ts --workers=20
working-directory: tests
env:
PLAYWRIGHT_SERVICE_URL: ${{ secrets.PLAYWRIGHT_SERVICE_URL }}
Expand Down
7 changes: 7 additions & 0 deletions azure.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ services:
dir: ../../kustomize/overlays/azd/product-service
edits:
- set image product-service=${SERVICE_PRODUCT_SERVICE_IMAGE_NAME}
env:
AI_SERVICE_URL: "http://ai-service:5001/"
COMPANY_NAME: ${COMPANY_NAME}
hooks:
postdeploy:
posix:
Expand Down Expand Up @@ -141,6 +144,8 @@ services:
dir: ../../kustomize/overlays/azd/store-front
edits:
- set image store-front=${SERVICE_STORE_FRONT_IMAGE_NAME}
env:
COMPANY_NAME: ${COMPANY_NAME}
hooks:
postdeploy:
posix:
Expand All @@ -166,6 +171,8 @@ services:
dir: ../../kustomize/overlays/azd/store-admin
edits:
- set image store-admin=${SERVICE_STORE_ADMIN_IMAGE_NAME}
env:
COMPANY_NAME: ${COMPANY_NAME}
hooks:
postdeploy:
posix:
Expand Down
6 changes: 3 additions & 3 deletions kustomize/overlays/azd/product-service/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ spec:
image: product-service:latest
ports:
- containerPort: 3002
env:
- name: AI_SERVICE_URL
value: "http://ai-service:5001/"
envFrom:
- configMapRef:
name: product-service
resources:
requests:
cpu: 1m
Expand Down
4 changes: 4 additions & 0 deletions kustomize/overlays/azd/product-service/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@ kind: Kustomization
resources:
- deployment.yaml
- service.yaml
configMapGenerator:
- envs:
- .env
name: product-service
3 changes: 3 additions & 0 deletions kustomize/overlays/azd/store-admin/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ spec:
ports:
- containerPort: 8081
name: store-admin # container images hosted on ghcr.io and will be removed in future releases
envFrom:
- configMapRef:
name: store-admin
resources:
requests:
cpu: 1m
Expand Down
4 changes: 4 additions & 0 deletions kustomize/overlays/azd/store-admin/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@ kind: Kustomization
resources:
- deployment.yaml
- service.yaml
configMapGenerator:
- envs:
- .env
name: store-admin
3 changes: 3 additions & 0 deletions kustomize/overlays/azd/store-front/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ spec:
ports:
- containerPort: 8080
name: store-front
envFrom:
- configMapRef:
name: store-front
resources:
requests:
cpu: 1m
Expand Down
4 changes: 4 additions & 0 deletions kustomize/overlays/azd/store-front/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@ kind: Kustomization
resources:
- deployment.yaml
- service.yaml
configMapGenerator:
- envs:
- .env
name: store-front
4 changes: 4 additions & 0 deletions src/product-service/src/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub struct Settings {
pub wasm_bin_path: PathBuf,
tcp_listener: Option<TcpListener>,
pub ai_service_url: String,
pub company_name: String,
}

impl Settings {
Expand All @@ -17,6 +18,8 @@ impl Settings {
var("WASM_RULE_ENGINE_PATH").unwrap_or_else(|_| "./tests/rule_engine.wasm".to_string());
let ai_service_url =
std::env::var("AI_SERVICE_URL").unwrap_or_else(|_| "http://127.0.0.1:5001".to_string());
let company_name =
std::env::var("COMPANY_NAME").unwrap_or_else(|_| "Contoso".to_string());
Settings {
max_size: 262_144,
log_level: "info".to_string(),
Expand All @@ -25,6 +28,7 @@ impl Settings {
wasm_bin_path: PathBuf::from(wasm_bin_path_env),
tcp_listener: None,
ai_service_url: ai_service_url.trim_end_matches('/').to_string(),
company_name,
}
}

Expand Down
10 changes: 5 additions & 5 deletions src/product-service/src/data.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use crate::configuration::Settings;
use crate::model::Product;

pub fn fetch_products(_settings: &Settings) -> Vec<Product> {
pub fn fetch_products(settings: &Settings) -> Vec<Product> {
vec![
Product {
id: 1,
name: "Contoso Catnip's Friend".to_string(),
name: format!("{} Catnip's Friend", settings.company_name),
price: 9.99,
description: "Watch your feline friend embark on a fishing adventure with Contoso Catnip's Friend toy. Packed with irresistible catnip and dangling fish lure.".to_string(),
description: format!("Watch your feline friend embark on a fishing adventure with {} Catnip's Friend toy. Packed with irresistible catnip and dangling fish lure.", settings.company_name),
image: "/catnip.jpg".to_string()
},
Product {
Expand Down Expand Up @@ -61,9 +61,9 @@ pub fn fetch_products(_settings: &Settings) -> Vec<Product> {
},
Product {
id: 9,
name: "Contoso Claw's Crabby Cat Toy".to_string(),
name: format!("{} Claw's Crabby Cat Toy", settings.company_name),
price: 3.99,
description: "Watch your cat go crazy for Contoso Claw's Crabby Cat Toy. This crinkly and catnip-filled toy will awaken their hunting instincts and provide endless entertainment.".to_string(),
description: format!("Watch your cat go crazy for {} Claw's Crabby Cat Toy. This crinkly and catnip-filled toy will awaken their hunting instincts and provide endless entertainment.", settings.company_name),
image: "/crabby.jpg".to_string()
},
Product {
Expand Down
18 changes: 14 additions & 4 deletions src/store-admin/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,25 @@ EXPOSE 8081
# Set the build argument for the app version number
ARG APP_VERSION=0.1.0

# Set the environment variable for the app version number
# Set the environment variables
ENV APP_VERSION=$APP_VERSION
ENV COMPANY_NAME=Contoso
ENV PRODUCT_SERVICE_URL=http://product-service:3002/
ENV MAKELINE_SERVICE_URL=http://makeline-service:3001/

# Copy the nginx configuration template to the container
COPY nginx.conf /etc/nginx/conf.d/nginx.conf.template

# Update the nginx configuration to use the app version number
# and Copy the nginx configuration template to the container
RUN envsubst '${APP_VERSION}' < /etc/nginx/conf.d/nginx.conf.template > /etc/nginx/conf.d/default.conf
# Create a startup script to substitute environment variables in both nginx config and HTML
RUN echo '#!/bin/sh' > /docker-entrypoint.d/30-substitute-env.sh && \
echo 'envsubst '"'"'${APP_VERSION} ${COMPANY_NAME} ${PRODUCT_SERVICE_URL} ${MAKELINE_SERVICE_URL}'"'"' < /etc/nginx/conf.d/nginx.conf.template > /etc/nginx/conf.d/default.conf' >> /docker-entrypoint.d/30-substitute-env.sh && \
echo '# Update the page title based on company name' >> /docker-entrypoint.d/30-substitute-env.sh && \
echo 'if [ "$COMPANY_NAME" = "Zava" ]; then' >> /docker-entrypoint.d/30-substitute-env.sh && \
echo ' sed -i "s/<title>Pet Store Admin Portal<\/title>/<title>Zava Pet Store Admin Portal<\/title>/g" /usr/share/nginx/html/index.html' >> /docker-entrypoint.d/30-substitute-env.sh && \
echo 'elif [ "$COMPANY_NAME" = "Contoso" ]; then' >> /docker-entrypoint.d/30-substitute-env.sh && \
echo ' sed -i "s/<title>Pet Store Admin Portal<\/title>/<title>Contoso Pet Store Admin Portal<\/title>/g" /usr/share/nginx/html/index.html' >> /docker-entrypoint.d/30-substitute-env.sh && \
echo 'fi' >> /docker-entrypoint.d/30-substitute-env.sh && \
chmod +x /docker-entrypoint.d/30-substitute-env.sh

# Start the app
CMD ["nginx", "-g", "daemon off;"]
81 changes: 81 additions & 0 deletions src/store-admin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,84 @@ When the app is running, you should see output similar to the following:
```

Open a browser and navigate to `http://localhost:8081/`. You should see the store admin app running.

# Store Admin - Dynamic Theming

This store admin application supports dynamic theming based on the `COMPANY_NAME` environment variable.

## Supported Themes

- **contoso**: Contoso Pet Store theme (default) - Uses blue accents and Contoso branding
- **zava**: Zava theme - Uses black and white color scheme with Zava branding

## Environment Variables

- `COMPANY_NAME`: Set to either "Contoso" or "Zava" to determine the theme (proper casing)
- `VITE_COMPANY_NAME`: Alternative environment variable for development
- `PRODUCT_SERVICE_URL`: URL for the product service
- `MAKELINE_SERVICE_URL`: URL for the makeline service

## Usage

### Development

```bash
# Use Contoso theme (default)
npm run dev

# Use Zava theme
COMPANY_NAME=Zava npm run dev

# Or using Vite environment variable
VITE_COMPANY_NAME=Zava npm run dev
```

### Docker

```bash
# Build with Contoso theme
docker build -t store-admin .

# Run with Zava theme
docker run -p 8081:8081 -e COMPANY_NAME=Zava store-admin

# Run with Contoso theme
docker run -p 8081:8081 -e COMPANY_NAME=Contoso store-admin
```

### Kubernetes

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: store-admin
spec:
template:
spec:
containers:
- name: store-admin
image: store-admin:latest
env:
- name: COMPANY_NAME
value: "Zava" # or "Contoso"
```

## Theme Configuration

Themes are configured in `src/config/themes.ts`. Each theme defines:

- Logo image and alt text
- Color scheme (primary, secondary, accent colors, etc.)
- Company name
- Page title

The theme system uses CSS custom properties to dynamically apply colors throughout the application.

### Supported Values

The `COMPANY_NAME` environment variable accepts the following values:
- `Contoso` - Applies the Contoso Pet Store theme
- `Zava` - Applies the Zava theme

Values are case-sensitive and should use proper capitalization as shown above. The system will convert these to lowercase internally to match theme configuration keys.
2 changes: 1 addition & 1 deletion src/store-admin/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Contoso Pet Store Admin Portal</title>
<title>Pet Store Admin Portal</title>
</head>
<body>
<div id="app"></div>
Expand Down
32 changes: 18 additions & 14 deletions src/store-admin/nginx.conf
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
server {
listen 8081;
listen [::]:8081;
server_name localhost;

#access_log /var/log/nginx/host.access.log main;
listen 8081;
server_name localhost;
root /usr/share/nginx/html;
index index.html index.htm;

location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html; # for spa routing
try_files $uri $uri/ /index.html;
}

# Provide runtime configuration endpoint
location /api/config {
add_header Content-Type application/json;
return 200 '{"companyName":"${COMPANY_NAME}"}';
}

# Health check endpoint
location /health {
add_header Content-Type application/json;
return 200 '{"status":"ok","version":"${APP_VERSION}"}';
}

#error_page 404 /404.html;
#error_page 404 /404.html;

# redirect server error pages to the static page /50x.html
#
Expand All @@ -20,11 +29,6 @@ server {
root /usr/share/nginx/html;
}

location /health {
default_type application/json;
return 200 '{"status":"ok","version":"${APP_VERSION}"}';
}

location ~ ^/api/makeline/order/(?<id>\w+) {
proxy_pass http://makeline-service:3001/order/$id;
proxy_http_version 1.1;
Expand Down
8 changes: 3 additions & 5 deletions src/store-admin/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added src/store-admin/public/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/store-admin/public/zava-logo-black.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/store-admin/public/zava-logo-white.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading