diff --git a/.env.example b/.env.example index 460e575..76a74b6 100644 --- a/.env.example +++ b/.env.example @@ -1 +1 @@ -VITE_API_URL=http://localhost:8080 +VITE_API_URL=http://localhost:8090/api diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 8f083de..f6bbbc5 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -5,32 +5,30 @@ module.exports = { browser: true, es2021: true, }, - extends: [ - 'eslint:recommended', - 'plugin:vue/vue3-recommended', - 'plugin:@typescript-eslint/recommended', - 'prettier', - ], - parser: 'vue-eslint-parser', + extends: ["eslint:recommended", "plugin:vue/vue3-recommended", "plugin:@typescript-eslint/recommended", "prettier"], + parser: "vue-eslint-parser", parserOptions: { - ecmaVersion: 'latest', - parser: '@typescript-eslint/parser', - sourceType: 'module', + ecmaVersion: "latest", + parser: "@typescript-eslint/parser", + sourceType: "module", }, - plugins: ['vue', '@typescript-eslint'], + plugins: ["vue", "@typescript-eslint"], rules: { - 'vue/multi-word-component-names': 'off', - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }], - 'vue/max-attributes-per-line': 'off', - 'vue/singleline-html-element-content-newline': 'off', - 'vue/html-self-closing': ['warn', { - html: { void: 'any', normal: 'always', component: 'always' }, - svg: 'always', - math: 'always', - }], - 'vue/attributes-order': 'off', - 'vue/require-default-prop': 'off', - 'vue/use-v-on-exact': 'off', + "vue/multi-word-component-names": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }], + "vue/max-attributes-per-line": "off", + "vue/singleline-html-element-content-newline": "off", + "vue/html-self-closing": [ + "warn", + { + html: { void: "any", normal: "always", component: "always" }, + svg: "always", + math: "always", + }, + ], + "vue/attributes-order": "off", + "vue/require-default-prop": "off", + "vue/use-v-on-exact": "off", }, }; diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3b95a3b..060fc67 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,8 +16,8 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: '20' - cache: 'npm' + node-version: "20" + cache: "npm" - name: Install dependencies run: npm ci @@ -37,8 +37,8 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: '20' - cache: 'npm' + node-version: "20" + cache: "npm" - name: Install dependencies run: npm ci @@ -55,8 +55,8 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: '20' - cache: 'npm' + node-version: "20" + cache: "npm" - name: Install dependencies run: npm ci @@ -74,8 +74,8 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: '20' - cache: 'npm' + node-version: "20" + cache: "npm" - name: Install dependencies run: npm ci diff --git a/README.md b/README.md index 553d36a..591694b 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ FlatRun UI provides a user-friendly dashboard for managing Docker deployments th ## Development ### Prerequisites + - Node.js 18+ and npm ### Setup @@ -75,9 +76,11 @@ Create a `.env.local` file to configure the API connection: ```bash # FlatRun Agent API URL -VITE_API_URL=http://localhost:8090 +VITE_API_URL=http://localhost:8090/api ``` +`VITE_API_URL` must include the `/api` prefix used by the agent routes. + For production deployments: ```bash @@ -101,8 +104,8 @@ If running the UI on a different domain/port than the agent, ensure the agent's api: enable_cors: true allowed_origins: - - http://localhost:5173 # Development - - https://your-ui-domain.com # Production + - http://localhost:5173 # Development + - https://your-ui-domain.com # Production ``` ## Available Scripts @@ -160,16 +163,19 @@ EXPOSE 80 ## Troubleshooting ### Cannot connect to agent + - Verify the agent is running: `systemctl status flatrun-agent` - Check `VITE_API_URL` is correct in your `.env.local` - Ensure CORS is configured if running on different domains ### Authentication fails + - Verify the API key matches the agent's configuration - Check browser console for specific error messages - Ensure JWT secret is properly set in agent config ### UI shows no deployments + - Confirm the agent's `deployments_path` is accessible - Check that deployments have valid `docker-compose.yml` files diff --git a/index.html b/index.html index 058d4b8..8516593 100644 --- a/index.html +++ b/index.html @@ -1,9 +1,9 @@ - + - - - + + + Flatrun - Container Orchestration diff --git a/package-lock.json b/package-lock.json index 6bc5b9e..e30652b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,7 @@ "primevue": "^3.50.0", "vue": "^3.4.21", "vue-codemirror": "^6.1.1", + "vue-i18n": "^9.14.5", "vue-router": "^4.3.0" }, "devDependencies": { @@ -804,6 +805,47 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/@intlify/core-base": { + "version": "9.14.5", + "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.14.5.tgz", + "integrity": "sha512-5ah5FqZG4pOoHjkvs8mjtv+gPKYU0zCISaYNjBNNqYiaITxW8ZtVih3GS/oTOqN8d9/mDLyrjD46GBApNxmlsA==", + "dependencies": { + "@intlify/message-compiler": "9.14.5", + "@intlify/shared": "9.14.5" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@intlify/message-compiler": { + "version": "9.14.5", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.14.5.tgz", + "integrity": "sha512-IHzgEu61/YIpQV5Pc3aRWScDcnFKWvQA9kigcINcCBXN8mbW+vk9SK+lDxA6STzKQsVJxUPg9ACC52pKKo3SVQ==", + "dependencies": { + "@intlify/shared": "9.14.5", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@intlify/shared": { + "version": "9.14.5", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.14.5.tgz", + "integrity": "sha512-9gB+E53BYuAEMhbCAxVgG38EZrk59sxBtv3jSizNL2hEWlgjBjAw1AwpLHtNaeda12pe6W20OGEa0TwuMSRbyQ==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -5182,6 +5224,26 @@ "eslint": ">=6.0.0" } }, + "node_modules/vue-i18n": { + "version": "9.14.5", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.14.5.tgz", + "integrity": "sha512-0jQ9Em3ymWngyiIkj0+c/k7WgaPO+TNzjKSNq9BvBQaKJECqn9cd9fL4tkDhB5G1QBskGl9YxxbDAhgbFtpe2g==", + "deprecated": "v9 and v10 no longer supported. please migrate to v11. about maintenance status, see https://vue-i18n.intlify.dev/guide/maintenance.html", + "dependencies": { + "@intlify/core-base": "9.14.5", + "@intlify/shared": "9.14.5", + "@vue/devtools-api": "^6.5.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, "node_modules/vue-router": { "version": "4.6.3", "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.3.tgz", diff --git a/package.json b/package.json index 005ce5c..d32ef7f 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "primevue": "^3.50.0", "vue": "^3.4.21", "vue-codemirror": "^6.1.1", + "vue-i18n": "^9.14.5", "vue-router": "^4.3.0" }, "devDependencies": { diff --git a/public/flags/de.svg b/public/flags/de.svg new file mode 100644 index 0000000..295d13e --- /dev/null +++ b/public/flags/de.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/flags/es.svg b/public/flags/es.svg new file mode 100644 index 0000000..e143324 --- /dev/null +++ b/public/flags/es.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/flags/fr.svg b/public/flags/fr.svg new file mode 100644 index 0000000..ec311d7 --- /dev/null +++ b/public/flags/fr.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/flags/gb.svg b/public/flags/gb.svg new file mode 100644 index 0000000..91f11d8 --- /dev/null +++ b/public/flags/gb.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/flags/it.svg b/public/flags/it.svg new file mode 100644 index 0000000..be3a5df --- /dev/null +++ b/public/flags/it.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/flags/pt.svg b/public/flags/pt.svg new file mode 100644 index 0000000..99b5fe6 --- /dev/null +++ b/public/flags/pt.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/components/BackupsTab.test.ts b/src/components/BackupsTab.test.ts index 9dd2f09..87627b7 100644 --- a/src/components/BackupsTab.test.ts +++ b/src/components/BackupsTab.test.ts @@ -200,7 +200,7 @@ describe("BackupsTab", () => { const statusBadge = wrapper.find(".backup-status"); expect(statusBadge.exists()).toBe(true); - expect(statusBadge.text()).toBe("completed"); + expect(statusBadge.text().toLowerCase()).toBe("completed"); }); it("displays component badges", async () => { diff --git a/src/components/BackupsTab.vue b/src/components/BackupsTab.vue index cd21c2e..2cc708c 100644 --- a/src/components/BackupsTab.vue +++ b/src/components/BackupsTab.vue @@ -1,28 +1,28 @@ diff --git a/src/components/database/DatabaseHeader.vue b/src/components/database/DatabaseHeader.vue index d0d5776..e807801 100644 --- a/src/components/database/DatabaseHeader.vue +++ b/src/components/database/DatabaseHeader.vue @@ -3,14 +3,16 @@
-

{{ selectedDatabase || connection?.name || "Database Server" }}

+

{{ selectedDatabase || connection?.name || t("databases.manager.header.databaseServer") }}