mirror of
https://github.com/AppFlowy-IO/AppFlowy-Web.git
synced 2025-12-01 20:08:10 +08:00
24
.github/workflows/web_ci.yaml
vendored
24
.github/workflows/web_ci.yaml
vendored
@@ -82,15 +82,15 @@ jobs:
|
|||||||
set -e
|
set -e
|
||||||
echo "Testing container fails without environment variables..."
|
echo "Testing container fails without environment variables..."
|
||||||
OUTPUT=$(docker run --rm appflowy-web-test:ci 2>&1 || true)
|
OUTPUT=$(docker run --rm appflowy-web-test:ci 2>&1 || true)
|
||||||
echo "$OUTPUT" | grep -q "ERROR: AF_BASE_URL environment variable is required" || (echo "ERROR: Container should fail without env vars" && exit 1)
|
echo "$OUTPUT" | grep -q "ERROR: APPFLOWY_BASE_URL environment variable is required" || (echo "ERROR: Container should fail without env vars" && exit 1)
|
||||||
echo "✓ Container correctly fails without required env vars"
|
echo "✓ Container correctly fails without required env vars"
|
||||||
|
|
||||||
- name: Run container with injected env vars
|
- name: Run container with injected env vars
|
||||||
run: |
|
run: |
|
||||||
docker run -d --rm --name appflowy-web-test -p 8080:80 \
|
docker run -d --rm --name appflowy-web-test -p 8080:80 \
|
||||||
-e AF_BASE_URL=https://ci-backend.example.com \
|
-e APPFLOWY_BASE_URL=https://ci-backend.example.com \
|
||||||
-e AF_GOTRUE_URL=https://ci-backend.example.com/gotrue \
|
-e APPFLOWY_GOTRUE_BASE_URL=https://ci-backend.example.com/gotrue \
|
||||||
-e AF_WS_V2_URL=wss://ci-backend.example.com/ws/v2 \
|
-e APPFLOWY_WS_BASE_URL=wss://ci-backend.example.com/ws/v2 \
|
||||||
appflowy-web-test:ci
|
appflowy-web-test:ci
|
||||||
|
|
||||||
- name: Wait for server to be ready
|
- name: Wait for server to be ready
|
||||||
@@ -111,15 +111,15 @@ jobs:
|
|||||||
echo "✓ Found window.__APP_CONFIG__"
|
echo "✓ Found window.__APP_CONFIG__"
|
||||||
|
|
||||||
echo "Verifying injected values..."
|
echo "Verifying injected values..."
|
||||||
# Note: The config is injected as a single line with format: {AF_BASE_URL:'value',AF_GOTRUE_URL:'value',AF_WS_V2_URL:'value'}
|
# Note: The config is injected as a single line with format: {APPFLOWY_BASE_URL:'value',APPFLOWY_GOTRUE_BASE_URL:'value',APPFLOWY_WS_BASE_URL:'value'}
|
||||||
echo "$HTML" | grep -q "AF_BASE_URL:'https://ci-backend.example.com'" || (echo "ERROR: AF_BASE_URL not correctly injected" && exit 1)
|
echo "$HTML" | grep -q "APPFLOWY_BASE_URL:'https://ci-backend.example.com'" || (echo "ERROR: APPFLOWY_BASE_URL not correctly injected" && exit 1)
|
||||||
echo "✓ AF_BASE_URL correctly injected"
|
echo "✓ APPFLOWY_BASE_URL correctly injected"
|
||||||
|
|
||||||
echo "$HTML" | grep -q "AF_GOTRUE_URL:'https://ci-backend.example.com/gotrue'" || (echo "ERROR: AF_GOTRUE_URL not correctly injected" && exit 1)
|
echo "$HTML" | grep -q "APPFLOWY_GOTRUE_BASE_URL:'https://ci-backend.example.com/gotrue'" || (echo "ERROR: APPFLOWY_GOTRUE_BASE_URL not correctly injected" && exit 1)
|
||||||
echo "✓ AF_GOTRUE_URL correctly injected"
|
echo "✓ APPFLOWY_GOTRUE_BASE_URL correctly injected"
|
||||||
|
|
||||||
echo "$HTML" | grep -q "AF_WS_V2_URL:'wss://ci-backend.example.com/ws/v2'" || (echo "ERROR: AF_WS_V2_URL not correctly injected" && exit 1)
|
echo "$HTML" | grep -q "APPFLOWY_WS_BASE_URL:'wss://ci-backend.example.com/ws/v2'" || (echo "ERROR: APPFLOWY_WS_BASE_URL not correctly injected" && exit 1)
|
||||||
echo "✓ AF_WS_V2_URL correctly injected"
|
echo "✓ APPFLOWY_WS_BASE_URL correctly injected"
|
||||||
|
|
||||||
echo "All runtime configuration values verified successfully!"
|
echo "All runtime configuration values verified successfully!"
|
||||||
|
|
||||||
@@ -133,7 +133,7 @@ jobs:
|
|||||||
echo "Extracted config: $CONFIG"
|
echo "Extracted config: $CONFIG"
|
||||||
|
|
||||||
# Verify it's a valid JavaScript object format
|
# Verify it's a valid JavaScript object format
|
||||||
echo "$CONFIG" | grep -q "window.__APP_CONFIG__={AF_BASE_URL:'[^']*',AF_GOTRUE_URL:'[^']*',AF_WS_V2_URL:'[^']*'}" || \
|
echo "$CONFIG" | grep -q "window.__APP_CONFIG__={APPFLOWY_BASE_URL:'[^']*',APPFLOWY_GOTRUE_BASE_URL:'[^']*',APPFLOWY_WS_BASE_URL:'[^']*'}" || \
|
||||||
(echo "ERROR: Config format is invalid" && exit 1)
|
(echo "ERROR: Config format is invalid" && exit 1)
|
||||||
|
|
||||||
echo "✓ Configuration format and structure verified"
|
echo "✓ Configuration format and structure verified"
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
AF_BASE_URL=http://localhost
|
APPFLOWY_BASE_URL=http://localhost
|
||||||
AF_GOTRUE_URL=http://localhost/gotrue
|
APPFLOWY_GOTRUE_BASE_URL=http://localhost/gotrue
|
||||||
AF_WS_V2_URL=ws://localhost/ws/v2
|
APPFLOWY_WS_BASE_URL=ws://localhost/ws/v2
|
||||||
6
dev.env
6
dev.env
@@ -1,3 +1,3 @@
|
|||||||
AF_BASE_URL=http://localhost:8000
|
APPFLOWY_BASE_URL=http://localhost:8000
|
||||||
AF_GOTRUE_URL=http://localhost:9999
|
APPFLOWY_GOTRUE_BASE_URL=http://localhost:9999
|
||||||
AF_WS_V2_URL=ws://localhost:8000/ws/v2
|
APPFLOWY_WS_BASE_URL=ws://localhost:8000/ws/v2
|
||||||
@@ -8,7 +8,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
# REQUIRED: Configure these to match your AppFlowy backend URLs
|
# REQUIRED: Configure these to match your AppFlowy backend URLs
|
||||||
# The container will fail to start if these are not set
|
# The container will fail to start if these are not set
|
||||||
- AF_BASE_URL=https://your-backend.example.com
|
- APPFLOWY_BASE_URL=https://your-backend.example.com
|
||||||
- AF_GOTRUE_URL=https://your-backend.example.com/gotrue
|
- APPFLOWY_GOTRUE_BASE_URL=https://your-backend.example.com/gotrue
|
||||||
- AF_WS_V2_URL=wss://your-backend.example.com/ws/v2
|
- APPFLOWY_WS_BASE_URL=wss://your-backend.example.com/ws/v2
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
@@ -1,35 +1,72 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Check required environment variables
|
# Backward compatibility: Map old environment variable names to new ones
|
||||||
if [ -z "${AF_BASE_URL}" ]; then
|
if [ -n "${AF_BASE_URL}" ] && [ -z "${APPFLOWY_BASE_URL}" ]; then
|
||||||
echo "ERROR: AF_BASE_URL environment variable is required but not set"
|
echo "⚠️ WARNING: AF_BASE_URL is deprecated. Please use APPFLOWY_BASE_URL instead."
|
||||||
echo "Please set AF_BASE_URL to your AppFlowy backend URL (e.g., https://your-backend.example.com)"
|
APPFLOWY_BASE_URL="${AF_BASE_URL}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "${AF_GOTRUE_URL}" ] && [ -z "${APPFLOWY_GOTRUE_BASE_URL}" ]; then
|
||||||
|
echo "⚠️ WARNING: AF_GOTRUE_URL is deprecated. Please use APPFLOWY_GOTRUE_BASE_URL instead."
|
||||||
|
APPFLOWY_GOTRUE_BASE_URL="${AF_GOTRUE_URL}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Support both AF_WS_V2_URL and AF_WS_URL for backward compatibility
|
||||||
|
if [ -n "${AF_WS_V2_URL}" ] && [ -z "${APPFLOWY_WS_BASE_URL}" ]; then
|
||||||
|
echo "⚠️ WARNING: AF_WS_V2_URL is deprecated. Please use APPFLOWY_WS_BASE_URL instead."
|
||||||
|
APPFLOWY_WS_BASE_URL="${AF_WS_V2_URL}"
|
||||||
|
elif [ -n "${AF_WS_URL}" ] && [ -z "${APPFLOWY_WS_BASE_URL}" ]; then
|
||||||
|
echo "⚠️ WARNING: AF_WS_URL is deprecated. Please use APPFLOWY_WS_BASE_URL instead."
|
||||||
|
APPFLOWY_WS_BASE_URL="${AF_WS_URL}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check required environment variables (after mapping)
|
||||||
|
if [ -z "${APPFLOWY_BASE_URL}" ]; then
|
||||||
|
echo "ERROR: APPFLOWY_BASE_URL environment variable is required but not set"
|
||||||
|
echo "Please set APPFLOWY_BASE_URL to your AppFlowy backend URL (e.g., https://your-backend.example.com)"
|
||||||
|
echo "Note: You can also use the deprecated AF_BASE_URL for backward compatibility"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "${AF_GOTRUE_URL}" ]; then
|
if [ -z "${APPFLOWY_GOTRUE_BASE_URL}" ]; then
|
||||||
echo "ERROR: AF_GOTRUE_URL environment variable is required but not set"
|
echo "ERROR: APPFLOWY_GOTRUE_BASE_URL environment variable is required but not set"
|
||||||
echo "Please set AF_GOTRUE_URL to your GoTrue authentication service URL (e.g., https://your-backend.example.com/gotrue)"
|
echo "Please set APPFLOWY_GOTRUE_BASE_URL to your GoTrue authentication service URL (e.g., https://your-backend.example.com/gotrue)"
|
||||||
|
echo "Note: You can also use the deprecated AF_GOTRUE_URL for backward compatibility"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "${AF_WS_V2_URL}" ]; then
|
if [ -z "${APPFLOWY_WS_BASE_URL}" ]; then
|
||||||
echo "ERROR: AF_WS_V2_URL environment variable is required but not set"
|
echo "ERROR: APPFLOWY_WS_BASE_URL environment variable is required but not set"
|
||||||
echo "Please set AF_WS_V2_URL to your WebSocket v2 URL (e.g., wss://your-backend.example.com/ws/v2)"
|
echo "Please set APPFLOWY_WS_BASE_URL to your WebSocket URL (e.g., wss://your-backend.example.com/ws/v2)"
|
||||||
|
echo "Note: You can also use the deprecated AF_WS_V2_URL or AF_WS_URL for backward compatibility"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create inline config script
|
# Show deprecation summary if any old variables were used
|
||||||
CONFIG_SCRIPT="<script>window.__APP_CONFIG__={AF_BASE_URL:'${AF_BASE_URL}',AF_GOTRUE_URL:'${AF_GOTRUE_URL}',AF_WS_V2_URL:'${AF_WS_V2_URL}'};</script>"
|
if [ -n "${AF_BASE_URL}" ] || [ -n "${AF_GOTRUE_URL}" ] || [ -n "${AF_WS_V2_URL}" ] || [ -n "${AF_WS_URL}" ]; then
|
||||||
|
echo ""
|
||||||
|
echo "════════════════════════════════════════════════════════════════════"
|
||||||
|
echo "⚠️ DEPRECATION NOTICE: Old environment variable names detected!"
|
||||||
|
echo "Please update your configuration to use the new names:"
|
||||||
|
echo " AF_BASE_URL → APPFLOWY_BASE_URL"
|
||||||
|
echo " AF_GOTRUE_URL → APPFLOWY_GOTRUE_BASE_URL"
|
||||||
|
echo " AF_WS_V2_URL → APPFLOWY_WS_BASE_URL"
|
||||||
|
echo " AF_WS_URL → APPFLOWY_WS_BASE_URL"
|
||||||
|
echo "════════════════════════════════════════════════════════════════════"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create inline config script (always use new names internally)
|
||||||
|
CONFIG_SCRIPT="<script>window.__APP_CONFIG__={APPFLOWY_BASE_URL:'${APPFLOWY_BASE_URL}',APPFLOWY_GOTRUE_BASE_URL:'${APPFLOWY_GOTRUE_BASE_URL}',APPFLOWY_WS_BASE_URL:'${APPFLOWY_WS_BASE_URL}'};</script>"
|
||||||
|
|
||||||
# Inject the config script into index.html right before </head>
|
# Inject the config script into index.html right before </head>
|
||||||
sed -i "s|</head>|${CONFIG_SCRIPT}</head>|g" /usr/share/nginx/html/index.html
|
sed -i "s|</head>|${CONFIG_SCRIPT}</head>|g" /usr/share/nginx/html/index.html
|
||||||
|
|
||||||
echo "Runtime configuration injected:"
|
echo "Runtime configuration injected:"
|
||||||
echo " AF_BASE_URL: ${AF_BASE_URL}"
|
echo " APPFLOWY_BASE_URL: ${APPFLOWY_BASE_URL}"
|
||||||
echo " AF_GOTRUE_URL: ${AF_GOTRUE_URL}"
|
echo " APPFLOWY_GOTRUE_BASE_URL: ${APPFLOWY_GOTRUE_BASE_URL}"
|
||||||
echo " AF_WS_V2_URL: ${AF_WS_V2_URL}"
|
echo " APPFLOWY_WS_BASE_URL: ${APPFLOWY_WS_BASE_URL}"
|
||||||
|
|
||||||
# Start nginx
|
# Start nginx
|
||||||
exec nginx -g 'daemon off;'
|
exec nginx -g 'daemon off;'
|
||||||
@@ -102,7 +102,7 @@ function GalleryPreview({ images, open, onClose, previewIndex, workspaceId }: Ga
|
|||||||
|
|
||||||
const fileId = images[index].src;
|
const fileId = images[index].src;
|
||||||
|
|
||||||
return getConfigValue('AF_BASE_URL', '') + '/api/file_storage/' + workspaceId + '/v1/blob/' + fileId;
|
return getConfigValue('APPFLOWY_BASE_URL', '') + '/api/file_storage/' + workspaceId + '/v1/blob/' + fileId;
|
||||||
}, [images, index, workspaceId]);
|
}, [images, index, workspaceId]);
|
||||||
|
|
||||||
if (!open) {
|
if (!open) {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ function PreviewImage({ file, onClick }: { file: FileMediaCellDataItem; onClick:
|
|||||||
let fileUrl = file.url;
|
let fileUrl = file.url;
|
||||||
|
|
||||||
if (!isURL(file.url)) {
|
if (!isURL(file.url)) {
|
||||||
fileUrl = getConfigValue('AF_BASE_URL', '') + '/api/file_storage/' + workspaceId + '/v1/blob/' + file.url;
|
fileUrl = getConfigValue('APPFLOWY_BASE_URL', '') + '/api/file_storage/' + workspaceId + '/v1/blob/' + file.url;
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = new URL(fileUrl);
|
const url = new URL(fileUrl);
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ function UnPreviewFile({ file }: { file: FileMediaCellDataItem }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const fileId = file.url;
|
const fileId = file.url;
|
||||||
const newUrl = getConfigValue('AF_BASE_URL', '') + '/api/file_storage/' + workspaceId + '/v1/blob/' + fileId;
|
const newUrl = getConfigValue('APPFLOWY_BASE_URL', '') + '/api/file_storage/' + workspaceId + '/v1/blob/' + fileId;
|
||||||
|
|
||||||
void openUrl(newUrl, '_blank');
|
void openUrl(newUrl, '_blank');
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ function FileMediaItem({
|
|||||||
|
|
||||||
const fileId = file.url;
|
const fileId = file.url;
|
||||||
|
|
||||||
return getConfigValue('AF_BASE_URL', '') + '/api/file_storage/' + workspaceId + '/v1/blob/' + fileId;
|
return getConfigValue('APPFLOWY_BASE_URL', '') + '/api/file_storage/' + workspaceId + '/v1/blob/' + fileId;
|
||||||
}, [file.url, workspaceId]);
|
}, [file.url, workspaceId]);
|
||||||
|
|
||||||
const [hover, setHover] = useState(false);
|
const [hover, setHover] = useState(false);
|
||||||
@@ -71,7 +71,7 @@ function FileMediaItem({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const fileId = file.url;
|
const fileId = file.url;
|
||||||
const newUrl = getConfigValue('AF_BASE_URL', '') + '/api/file_storage/' + workspaceId + '/v1/blob/' + fileId;
|
const newUrl = getConfigValue('APPFLOWY_BASE_URL', '') + '/api/file_storage/' + workspaceId + '/v1/blob/' + fileId;
|
||||||
|
|
||||||
void openUrl(newUrl, '_blank');
|
void openUrl(newUrl, '_blank');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export const FileBlock = memo(
|
|||||||
|
|
||||||
const fileId = dataUrl;
|
const fileId = dataUrl;
|
||||||
|
|
||||||
return getConfigValue('AF_BASE_URL', '') + '/api/file_storage/' + workspaceId + '/v1/blob/' + fileId;
|
return getConfigValue('APPFLOWY_BASE_URL', '') + '/api/file_storage/' + workspaceId + '/v1/blob/' + fileId;
|
||||||
}, [dataUrl, workspaceId]);
|
}, [dataUrl, workspaceId]);
|
||||||
|
|
||||||
const className = useMemo(() => {
|
const className = useMemo(() => {
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ const GalleryBlock = memo(
|
|||||||
let imageUrl = image.url;
|
let imageUrl = image.url;
|
||||||
|
|
||||||
if (!isURL(image.url)) {
|
if (!isURL(image.url)) {
|
||||||
imageUrl = getConfigValue('AF_BASE_URL', '') + '/api/file_storage/' + workspaceId + '/v1/blob/' + image.url;
|
imageUrl = getConfigValue('APPFLOWY_BASE_URL', '') + '/api/file_storage/' + workspaceId + '/v1/blob/' + image.url;
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = new URL(imageUrl);
|
const url = new URL(imageUrl);
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ export const ImageBlock = memo(
|
|||||||
|
|
||||||
const fileId = dataUrl;
|
const fileId = dataUrl;
|
||||||
|
|
||||||
return getConfigValue('AF_BASE_URL', '') + '/api/file_storage/' + workspaceId + '/v1/blob/' + fileId;
|
return getConfigValue('APPFLOWY_BASE_URL', '') + '/api/file_storage/' + workspaceId + '/v1/blob/' + fileId;
|
||||||
}, [dataUrl, workspaceId]);
|
}, [dataUrl, workspaceId]);
|
||||||
|
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import { User } from '@/application/types';
|
|||||||
import { getConfigValue } from '@/utils/runtime-config';
|
import { getConfigValue } from '@/utils/runtime-config';
|
||||||
import { createContext, useContext } from 'react';
|
import { createContext, useContext } from 'react';
|
||||||
|
|
||||||
const baseURL = getConfigValue('AF_BASE_URL', 'https://test.appflowy.cloud');
|
const baseURL = getConfigValue('APPFLOWY_BASE_URL', 'https://test.appflowy.cloud');
|
||||||
const gotrueURL = getConfigValue('AF_GOTRUE_URL', 'https://test.appflowy.cloud/gotrue');
|
const gotrueURL = getConfigValue('APPFLOWY_GOTRUE_BASE_URL', 'https://test.appflowy.cloud/gotrue');
|
||||||
|
|
||||||
export const defaultConfig: AFServiceConfig = {
|
export const defaultConfig: AFServiceConfig = {
|
||||||
cloudConfig: {
|
cloudConfig: {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { getTokenParsed } from '@/application/session/token';
|
|||||||
import { getConfigValue } from '@/utils/runtime-config';
|
import { getConfigValue } from '@/utils/runtime-config';
|
||||||
import { messages } from '@/proto/messages';
|
import { messages } from '@/proto/messages';
|
||||||
|
|
||||||
const wsURL = getConfigValue('AF_WS_V2_URL', 'ws://localhost:8000/ws/v2');
|
const wsURL = getConfigValue('APPFLOWY_WS_BASE_URL', 'ws://localhost:8000/ws/v2');
|
||||||
|
|
||||||
// WebSocket close code enum
|
// WebSocket close code enum
|
||||||
enum CloseCode {
|
enum CloseCode {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
interface RuntimeConfig {
|
interface RuntimeConfig {
|
||||||
AF_BASE_URL?: string;
|
APPFLOWY_BASE_URL?: string;
|
||||||
AF_GOTRUE_URL?: string;
|
APPFLOWY_GOTRUE_BASE_URL?: string;
|
||||||
AF_WS_V2_URL?: string;
|
APPFLOWY_WS_BASE_URL?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ export default defineConfig({
|
|||||||
cors: false,
|
cors: false,
|
||||||
sourcemapIgnoreList: false,
|
sourcemapIgnoreList: false,
|
||||||
},
|
},
|
||||||
envPrefix: ['AF'],
|
envPrefix: ['APPFLOWY'],
|
||||||
esbuild: {
|
esbuild: {
|
||||||
keepNames: true,
|
keepNames: true,
|
||||||
sourcesContent: true,
|
sourcesContent: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user