Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[studio] implement login #1298 #1318

Merged
merged 14 commits into from
Oct 20, 2024
Merged
10 changes: 9 additions & 1 deletion .github/workflows/agdb_studio.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ jobs:
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run test:unit
working-directory: agdb_api/typescript
- run: npm run build
working-directory: agdb_api/typescript
- run: npm ci
- run: npm run test
- uses: actions/upload-artifact@v4
if: always()
with:
Expand All @@ -57,6 +61,10 @@ jobs:
working-directory: agdb_studio
steps:
- uses: actions/checkout@v4
- run: npm ci
working-directory: agdb_api/typescript
- run: npm run build
working-directory: agdb_api/typescript
- run: npm ci
- run: npx playwright install --with-deps
- run: npm run build
Expand Down
21 changes: 21 additions & 0 deletions .vscode/terminals.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,27 @@
"open": true,
"focus": false,
"commands": ["cd agdb_web"]
},
{
"name": "studio SERVER",
"description": "For running web studio server",
"open": true,
"focus": false,
"commands": ["cd agdb_studio", "npm run dev"]
},
{
"name": "studio SCRIPTS",
"description": "For running studio scripts",
"open": true,
"focus": false,
"commands": ["cd agdb_studio"]
},
{
"name": "api SCRIPTS",
"description": "For running api/typescript scripts",
"open": true,
"focus": false,
"commands": ["cd agdb_api/typescript"]
}
]
}
26 changes: 16 additions & 10 deletions agdb_api/typescript/src/client.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { OpenAPIClientAxios } from "openapi-client-axios";
import { AxiosRequestConfig, OpenAPIClientAxios } from "openapi-client-axios";
import type { Client } from "./openapi";

type AgdbApi = {
token: string;
token: string | undefined;
login: (username: string, password: string) => Promise<string>; // eslint-disable-line no-unused-vars
logout: () => Promise<void>;
get_token: () => string;
get_token: () => string | undefined;
set_token: (token: string) => void; // eslint-disable-line no-unused-vars
reset_token: () => void;
};

async function login(username: string, password: string): Promise<string> {
Expand All @@ -19,26 +20,30 @@ async function login(username: string, password: string): Promise<string> {
return token.data;
}

function get_token(): string {
function get_token(): string | undefined {
return this.token;
}

async function logout(): Promise<void> {
await this.user_logout();
this.token = "";
this.interceptors.request.use((config) => {
return config;
});
this.reset_token();
}

function set_token(token: string) {
function set_token(token: string): void {
this.token = token;
this.interceptors.request.use((config) => {
this.interceptors.request.use((config: AxiosRequestConfig) => {
config.headers.Authorization = `Bearer ${token}`;
return config;
});
}

function reset_token(): void {
this.token = undefined;
this.interceptors.request.use((config: AxiosRequestConfig) => {
return config;
});
}

export type AgdbApiClient = Client & AgdbApi;

export async function client(address: String): Promise<AgdbApiClient> {
Expand All @@ -51,5 +56,6 @@ export async function client(address: String): Promise<AgdbApiClient> {
client.logout = logout;
client.set_token = set_token;
client.get_token = get_token;
client.reset_token = reset_token;
return client;
}
2 changes: 1 addition & 1 deletion agdb_api/typescript/tests/api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ describe("openapi test", () => {
let client = await AgdbApi.client("http://localhost:3000");
await client.login("admin", "admin");
await client.logout();
expect(client.get_token()).toEqual("");
expect(client.get_token()).toEqual(undefined);

await expect(client.db_list()).rejects.toThrowError(
"Request failed with status code 401",
Expand Down
2 changes: 1 addition & 1 deletion agdb_studio/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ npm run build
### Run Unit Tests with [Vitest](https://vitest.dev/)

```sh
npm run test:unit
npm run test
```

### Run End-to-End Tests with [Playwright](https://playwright.dev)
Expand Down
4 changes: 2 additions & 2 deletions agdb_studio/e2e/vue.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ import { test, expect } from "@playwright/test";
// See here how to get started:
// https://playwright.dev/docs/intro
test("visits the app root url", async ({ page }) => {
await page.goto("/");
await expect(page.locator("div.main-wrapper")).toBeVisible();
await page.goto("/login");
await expect(page.locator("div.login-form")).toBeVisible();
});
49 changes: 49 additions & 0 deletions agdb_studio/package-lock.json

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

6 changes: 4 additions & 2 deletions agdb_studio/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,18 @@
"dev": "vite",
"build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"test:unit": "vitest run --coverage",
"test": "vitest run --coverage",
"test:e2e": "playwright test",
"build-only": "vite build",
"type-check": "vue-tsc --noEmit -p tsconfig.vitest.json --composite false",
"lint": "eslint --max-warnings=0 . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"format": "prettier --write src/ e2e/ tests/",
"format:check": "prettier --check src/ e2e/ tests/",
"before-commit": "npm run format && npm run lint && npm run test:unit && npm run test:e2e"
"before-commit": "npm run format && npm run lint && npm run test && npm run test:e2e"
},
"dependencies": {
"@kalimahapps/vue-icons": "^1.7.1",
"agdb_api": "file:../agdb_api/typescript",
"openapi-client-axios": "^7.5.1",
"pinia": "^2.1.7",
"vue": "^3.3.4",
Expand Down
50 changes: 25 additions & 25 deletions agdb_studio/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,32 +53,32 @@ const config: PlaywrightTestConfig = {
...devices["Desktop Chrome"],
},
},
{
name: "firefox",
use: {
...devices["Desktop Firefox"],
},
},
{
name: "webkit",
use: {
...devices["Desktop Safari"],
},
},
// {
// name: "firefox",
// use: {
// ...devices["Desktop Firefox"],
// },
// },
// {
// name: "webkit",
// use: {
// ...devices["Desktop Safari"],
// },
// },

/* Test against mobile viewports. */
{
name: "Mobile Chrome",
use: {
...devices["Pixel 5"],
},
},
{
name: "Mobile Safari",
use: {
...devices["iPhone 12"],
},
},
// /* Test against mobile viewports. */
// {
// name: "Mobile Chrome",
// use: {
// ...devices["Pixel 5"],
// },
// },
// {
// name: "Mobile Safari",
// use: {
// ...devices["iPhone 12"],
// },
// },

/* Test against branded browsers. */
// {
Expand Down
4 changes: 2 additions & 2 deletions agdb_studio/src/assets/button.less
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
}

.button-warning {
background-color: #ffc107;
color: #212529;
background-color: #ff9f2c;
color: #181818;
}

.button-danger {
Expand Down
34 changes: 30 additions & 4 deletions agdb_studio/src/components/auth/LoginForm.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,37 @@
<script lang="ts" setup>
import { ref } from "vue";
import { login } from "@/services/auth.service";
import { CgSpinnerTwo } from "@kalimahapps/vue-icons";
import router from "@/router";

const username = ref("");
const password = ref("");

const login = async () => {
// todo - handle login
const loading = ref(false);
const error = ref("");

const clearError = () => {
error.value = "";
};

const onLogin = async () => {
loading.value = true;
clearError();
login(username.value, password.value)
.then(() => {
loading.value = false;
router.push({ name: "home" });
})
.catch((e) => {
loading.value = false;
error.value = e.message;
});
};
</script>

<template>
<div class="base-form login-form">
<form @submit.prevent="login">
<form @submit.prevent="onLogin">
<div>
<label for="username">Username:</label>
<input type="text" id="username" v-model="username" required />
Expand All @@ -25,7 +45,10 @@ const login = async () => {
required
/>
</div>
<button type="submit" class="button button-success">Login</button>
<button type="submit" class="button button-success">
<CgSpinnerTwo v-if="loading" />
Login
</button>
</form>
</div>
</template>
Expand All @@ -38,5 +61,8 @@ const login = async () => {
font-size: 1.2rem;
margin-top: 0.6rem;
}
input {
border-radius: 0.2rem;
}
}
</style>
Loading