diff --git a/.env.staging b/.env.test similarity index 78% rename from .env.staging rename to .env.test index a01c323c..e69bc581 100644 --- a/.env.staging +++ b/.env.test @@ -1,9 +1,9 @@ # Only the variables that start with VITE_ are seen in the application import.meta.env in Vue. -# iOS doesn't like spaces in the app title. + TIME_SAFARI_APP_TITLE="TimeSafari_Test" VITE_APP_SERVER=https://test.timesafari.app -# This is the claim ID for actions in the BVC project, with the JWT ID on this environment (not production). +# This is the claim ID for actions in the BVC project. VITE_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01HWE8FWHQ1YGP7GFZYYPS272F VITE_DEFAULT_ENDORSER_API_SERVER=https://test-api.endorser.ch diff --git a/README.md b/README.md index 711f8818..ff2fa563 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Quick start: ```bash npm install -npm run dev +NODE_ENV=dev npm run start:web ``` See [BUILDING.md](doc/BUILDING.md) for more details. diff --git a/doc/BUILDING.md b/doc/BUILDING.md index 393a6f20..b8a166c2 100644 --- a/doc/BUILDING.md +++ b/doc/BUILDING.md @@ -22,7 +22,7 @@ Install dependencies: ## Web Dev Locally ```bash - npm run dev + NODE_ENV=dev npm run start:web ``` ## Web Build for Server @@ -31,7 +31,7 @@ Install dependencies: ```bash rm -rf dist - npm run build:web + NODE_ENV=prod npm run build:web ``` The built files will be in the `dist` directory. @@ -41,7 +41,7 @@ Install dependencies: You'll likely want to use test locations for the Endorser & image & partner servers; see "DEFAULT_ENDORSER_API_SERVER" & "DEFAULT_IMAGE_API_SERVER" & "DEFAULT_PARTNER_API_SERVER" below. ```bash - npm run serve + NODE_ENV=dev npm run serve:web ``` ### Compile and minify for test & production @@ -52,7 +52,7 @@ Install dependencies: * Update the ClickUp tasks & CHANGELOG.md & the version in package.json, run `npm install`. -* Run a build to make sure package-lock version is updated, linting works, etc: `npm install && npm run build` +* Run a build to make sure package-lock version is updated, linting works, etc: `npm install && npm run build:web` * Commit everything (since the commit hash is used the app). @@ -63,7 +63,7 @@ Install dependencies: * For test, build the app (because test server is not yet set up to build): ```bash -TIME_SAFARI_APP_TITLE="TimeSafari_Test" VITE_APP_SERVER=https://test.timesafari.app VITE_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01HWE8FWHQ1YGP7GFZYYPS272F VITE_DEFAULT_ENDORSER_API_SERVER=https://test-api.endorser.ch VITE_DEFAULT_IMAGE_API_SERVER=https://test-image-api.timesafari.app VITE_DEFAULT_PARTNER_API_SERVER=https://test-partner-api.endorser.ch VITE_DEFAULT_PUSH_SERVER=https://test.timesafari.app VITE_PASSKEYS_ENABLED=true npm run build:web +NODE_ENV=test TIME_SAFARI_APP_TITLE="TimeSafari_Test" VITE_APP_SERVER=https://test.timesafari.app VITE_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01HWE8FWHQ1YGP7GFZYYPS272F VITE_DEFAULT_ENDORSER_API_SERVER=https://test-api.endorser.ch VITE_DEFAULT_IMAGE_API_SERVER=https://test-image-api.timesafari.app VITE_DEFAULT_PARTNER_API_SERVER=https://test-partner-api.endorser.ch VITE_DEFAULT_PUSH_SERVER=https://test.timesafari.app VITE_PASSKEYS_ENABLED=true npm run build:web ``` ... and transfer to the test server: @@ -205,10 +205,10 @@ docker run -d \ ```bash # For AppImage (recommended) - npm run electron:build-linux + npm run build:electron-linux # For .deb package - npm run electron:build-linux-deb + npm run build:electron-linux-deb ``` 3. The packaged applications will be in `dist-electron-packages/`: @@ -220,19 +220,19 @@ docker run -d \ 1. Build the electron app in production mode: ```bash - npm run build:web + NODE_ENV=prod npm run build:web npm run build:electron - npm run electron:build-mac + npm run build:electron-mac ``` 2. Package the Electron app for macOS: ```bash # For Intel Macs - npm run electron:build-mac + npm run build:electron-mac # For Universal build (Intel + Apple Silicon) - npm run electron:build-mac-universal + npm run build:electron-mac-universal ``` 3. The packaged applications will be in `dist-electron-packages/`: @@ -254,7 +254,7 @@ For public distribution on macOS, you need to code sign and notarize your app: 2. Build with signing: ```bash - npm run electron:build-mac + npm run build:electron-mac ``` ### Running the Packaged App @@ -293,10 +293,10 @@ For testing the Electron build before packaging: ```bash # Build and run in development mode (includes DevTools) -npm run electron:dev +npm run build:electron # Build in production mode and test -npm run build:electron-prod && npm run electron:start +npm run build:electron-prod && npm run start:electron ``` ## Mobile Builds (Capacitor) diff --git a/TASK_storage.md b/doc/TASK_storage.md similarity index 100% rename from TASK_storage.md rename to doc/TASK_storage.md diff --git a/playwright.config-local.ts b/playwright.config-local.ts index 29f4cf64..16f466a9 100644 --- a/playwright.config-local.ts +++ b/playwright.config-local.ts @@ -101,7 +101,7 @@ export default defineConfig({ /** * This could be an array of servers, meaning we could start the Endorser server as well: * { - * command: "cd ../endorser-ch; NODE_ENV=test-local npm run dev", + * command: "cd ../endorser-ch; NODE_ENV=test-local npm run start:web", * url: 'http://localhost:3000', * reuseExistingServer: !process.env.CI, * }, @@ -112,7 +112,7 @@ export default defineConfig({ */ webServer: { command: - "VITE_APP_SERVER=http://localhost:8081 VITE_DEFAULT_ENDORSER_API_SERVER=http://localhost:3000 VITE_DEFAULT_PARTNER_API_SERVER=http://localhost:3000 VITE_DEFAULT_IMAGE_API_SERVER=https://test-image-api.timesafari.app VITE_PASSKEYS_ENABLED=true npm run dev -- --port=8081", + "VITE_APP_SERVER=http://localhost:8081 VITE_DEFAULT_ENDORSER_API_SERVER=http://localhost:3000 VITE_DEFAULT_PARTNER_API_SERVER=http://localhost:3000 VITE_DEFAULT_IMAGE_API_SERVER=https://test-image-api.timesafari.app VITE_PASSKEYS_ENABLED=true npm run start:web -- --port=8081", url: "http://localhost:8081", reuseExistingServer: !process.env.CI, }, diff --git a/playwright.config.ts b/playwright.config.ts index 5fdf7351..0fe5feb4 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -74,7 +74,7 @@ export default defineConfig({ /* Run your local dev server before starting the tests */ // webServer: { // command: - // "VITE_PASSKEYS_ENABLED=true VITE_DEFAULT_ENDORSER_API_SERVER=http://localhost:3000 npm run dev", + // "VITE_PASSKEYS_ENABLED=true VITE_DEFAULT_ENDORSER_API_SERVER=http://localhost:3000 npm run start:web", // url: "http://localhost:8080", // reuseExistingServer: !process.env.CI, // }, diff --git a/src/components/DataExportSection.vue b/src/components/DataExportSection.vue index 842b2201..19e6014a 100644 --- a/src/components/DataExportSection.vue +++ b/src/components/DataExportSection.vue @@ -50,8 +50,8 @@ backup and database export, with platform-specific download instructions. * * v-if="platformCapabilities.isMobile && !platformCapabilities.isIOS" class="list-disc list-outside ml-4" > - On Android: You will be prompted to choose a location to save your - backup file. + On Android: You will be prompted to choose an app for sharing your + backup file. To save on your phone, you will need a file manager app. diff --git a/src/vite.config.utils.js b/src/vite.config.utils.js deleted file mode 100644 index 719edfc7..00000000 --- a/src/vite.config.utils.js +++ /dev/null @@ -1,55 +0,0 @@ -import * as path from "path"; -import { promises as fs } from "fs"; -import { fileURLToPath } from "url"; - -export async function loadAppConfig() { - const packageJson = await loadPackageJson(); - const appName = process.env.TIME_SAFARI_APP_TITLE || packageJson.name; - const __dirname = path.dirname(fileURLToPath(import.meta.url)); - - return { - pwaConfig: { - manifest: { - name: appName, - short_name: appName, - icons: [ - { - src: "./img/icons/android-chrome-192x192.png", - sizes: "192x192", - type: "image/png", - }, - { - src: "./img/icons/android-chrome-512x512.png", - sizes: "512x512", - type: "image/png", - }, - { - src: "./img/icons/android-chrome-maskable-192x192.png", - sizes: "192x192", - type: "image/png", - purpose: "maskable", - }, - { - src: "./img/icons/android-chrome-maskable-512x512.png", - sizes: "512x512", - type: "image/png", - purpose: "maskable", - }, - ], - }, - }, - aliasConfig: { - "@": path.resolve(path.dirname(__dirname), "src"), - buffer: path.resolve(path.dirname(__dirname), "node_modules", "buffer"), - "dexie-export-import/dist/import": - "dexie-export-import/dist/import/index.js", - }, - }; -} - -async function loadPackageJson() { - const __dirname = path.dirname(fileURLToPath(import.meta.url)); - const packageJsonPath = path.resolve(path.dirname(__dirname), "package.json"); - const packageJsonData = await fs.readFile(packageJsonPath, "utf-8"); - return JSON.parse(packageJsonData); -} diff --git a/vite.config.utils.mts b/vite.config.common-utils.mts similarity index 52% rename from vite.config.utils.mts rename to vite.config.common-utils.mts index b5a1ed97..ef95f8be 100644 --- a/vite.config.utils.mts +++ b/vite.config.common-utils.mts @@ -45,71 +45,73 @@ interface PWAConfig { } interface AppConfig { - pwaConfig: PWAConfig; aliasConfig: { [key: string]: string; }; } export async function loadAppConfig(): Promise { - const packageJson = await loadPackageJson(); - const appName = process.env.TIME_SAFARI_APP_TITLE || packageJson.name; - return { - pwaConfig: { - registerType: "autoUpdate", - strategies: "injectManifest", - srcDir: ".", - filename: "sw_scripts-combined.js", - manifest: { - name: appName, - short_name: appName, - theme_color: "#4a90e2", - background_color: "#ffffff", - icons: [ - { - src: "./img/icons/android-chrome-192x192.png", - sizes: "192x192", - type: "image/png", - }, - { - src: "./img/icons/android-chrome-512x512.png", - sizes: "512x512", - type: "image/png", - }, - { - src: "./img/icons/android-chrome-maskable-192x192.png", - sizes: "192x192", - type: "image/png", - purpose: "maskable", - }, - { - src: "./img/icons/android-chrome-maskable-512x512.png", - sizes: "512x512", - type: "image/png", - purpose: "maskable", - }, - ], - share_target: { - action: "/share-target", - method: "POST", - enctype: "multipart/form-data", - params: { - files: [ - { - name: "photo", - accept: ["image/*"], - }, - ], - }, - }, - }, - }, aliasConfig: { "@": path.resolve(__dirname, "src"), buffer: path.resolve(__dirname, "node_modules", "buffer"), "dexie-export-import/dist/import": "dexie-export-import/dist/import/index.js", }, + } +} + +export async function loadPwaConfig(): Promise { + const packageJson = await loadPackageJson(); + const appName = process.env.TIME_SAFARI_APP_TITLE || packageJson.name; + + return { + registerType: "autoUpdate", + strategies: "injectManifest", + srcDir: ".", + filename: "sw_scripts-combined.js", + manifest: { + name: appName, + short_name: appName, + theme_color: "#4a90e2", + background_color: "#ffffff", + icons: [ + { + src: "./img/icons/android-chrome-192x192.png", + sizes: "192x192", + type: "image/png", + }, + { + src: "./img/icons/android-chrome-512x512.png", + sizes: "512x512", + type: "image/png", + }, + { + src: "./img/icons/android-chrome-maskable-192x192.png", + sizes: "192x192", + type: "image/png", + purpose: "maskable", + }, + { + src: "./img/icons/android-chrome-maskable-512x512.png", + sizes: "512x512", + type: "image/png", + purpose: "maskable", + }, + ], + share_target: { + action: "/share-target", + method: "POST", + enctype: "multipart/form-data", + params: { + files: [ + { + name: "photo", + accept: ["image/*"], + }, + ], + }, + }, + }, }; } \ No newline at end of file diff --git a/vite.config.common.mts b/vite.config.common.mts index 3ab5b12a..e87b3ba7 100644 --- a/vite.config.common.mts +++ b/vite.config.common.mts @@ -1,7 +1,7 @@ import { defineConfig, UserConfig, Plugin } from "vite"; import vue from "@vitejs/plugin-vue"; import dotenv from "dotenv"; -import { loadAppConfig } from "./vite.config.utils.mts"; +import { loadAppConfig } from "./vite.config.common-utils.mts"; import path from "path"; import { fileURLToPath } from 'url'; @@ -9,7 +9,11 @@ export type BuildMode = 'web' | 'electron' | 'capacitor' | 'pywebview'; export type BuildEnv = 'dev' | 'test' | 'prod'; // Load environment variables -if (process.env.NODE_ENV === 'dev' || process.env.NODE_ENV === 'test' || process.env.NODE_ENV === 'prod') { +if ( + process.env.NODE_ENV === 'dev' + || process.env.NODE_ENV === 'test' + || process.env.NODE_ENV === 'prod' + ) { console.log(`NODE_ENV=${process.env.NODE_ENV}`); } else { console.error("NODE_ENV is not set. Invoke with NODE_ENV=dev|test|prod"); @@ -30,13 +34,11 @@ export async function createBuildConfig(mode: BuildMode): Promise { // Explicitly set platform and disable PWA for Electron process.env.VITE_PLATFORM = mode; - process.env.VITE_PWA_ENABLED = isElectron ? 'false' : 'true'; + process.env.VITE_PWA_ENABLED = (isElectron || isPyWebView || isCapacitor) + ? 'false' + : 'true'; process.env.VITE_DISABLE_PWA = isElectron ? 'true' : 'false'; - if (isElectron || isPyWebView || isCapacitor) { - process.env.VITE_PWA_ENABLED = 'false'; - } - return { base: isElectron || isPyWebView ? "./" : "/", plugins: [vue()], diff --git a/vite.config.web.mts b/vite.config.web.mts index 0ea84351..a2f987f2 100644 --- a/vite.config.web.mts +++ b/vite.config.web.mts @@ -1,17 +1,17 @@ import { defineConfig, mergeConfig } from "vite"; import { VitePWA } from "vite-plugin-pwa"; import { createBuildConfig } from "./vite.config.common.mts"; -import { loadAppConfig } from "./vite.config.utils.mts"; +import { loadPwaConfig } from "./vite.config.common-utils.mts"; export default defineConfig(async () => { const baseConfig = await createBuildConfig('web'); - const appConfig = await loadAppConfig(); + const pwaConfig = await loadPwaConfig(); return mergeConfig(baseConfig, { plugins: [ VitePWA({ registerType: 'autoUpdate', - manifest: appConfig.pwaConfig?.manifest, + manifest: pwaConfig.manifest, devOptions: { enabled: false },