removed Login component

This commit is contained in:
Markus Thielen 2023-03-01 10:24:10 +01:00
parent b6841591c4
commit ca4480b122
Signed by: markus
GPG Key ID: 3D4980D3EC9C8E26
5 changed files with 177 additions and 59 deletions

View File

@ -1,50 +0,0 @@
<script setup>
import { ref } from "vue";
let username = ref("");
let password = ref("");
let errorTxt = ref("");
/**
* Perform login.
*/
function login() {
if (!username.value || !password.value) {
errorTxt.value = "Please fill in both fields.";
return;
}
}
</script>
<template>
<div id="login-form">
<form>
<h3>Please log in:</h3>
<div class="form-group">
<label>Username</label>
<input type="text" name="username" v-bind="username">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" name="password" v-bind="password">
</div>
<div v-if="errorTxt" class="error">{{ errorTxt }}</div>
<div class="form-buttons">
<button class="btn btn-primary" @click="login" type="button">Login</button>
</div>
</form>
</div>
</template>
<style lang="scss" scoped>
#login-form {
padding: 2rem;
border: 1px solid var(--color-border);
border-radius: 10px;
}
</style>

View File

@ -2,7 +2,7 @@
import AboutItem from './AboutItem.vue'
import DocumentationIcon from './icons/IconDocumentation.vue'
import ToolingIcon from './icons/IconTooling.vue'
import EcosystemIcon from './icons/IconEcosystem.vue'
import QuestionIcon from './icons/IconQuestion.vue'
import CommunityIcon from './icons/IconCommunity.vue'
</script>
@ -30,16 +30,21 @@ import CommunityIcon from './icons/IconCommunity.vue'
<AboutItem>
<template #icon>
<EcosystemIcon />
<CommunityIcon />
</template>
<template #heading>Client Framework</template>
This demo todo app is based on <a href="https://vuejs.org">Vue 3</a>. We will (or already have)
provide more samples based on other frameworks, e.g. React - although the basic idea stays the same.
<template #heading>Feedback</template>
<p><b>We are so eager to hear from you!</b></p>
<ul>
<li>Are you missing something?</li>
<li>Any suggestion?</li>
<li>Any question?</li>
</ul>
<p>We'd be REALLY happy to <a href="https://basebox.tech/open-a-aticket">hear from you</a>!</p>
</AboutItem>
<AboutItem>
<template #icon>
<CommunityIcon />
<QuestionIcon />
</template>
<template #heading>Support</template>

View File

@ -0,0 +1,6 @@
<template>
<svg width="100%" height="100%" viewBox="0 0 320 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(0.649422,0,0,0.681212,64.305,69.5171)">
<path d="M64,160C64,124.7 105.744,95.67 141.044,95.67C176.344,95.67 224,124.7 224,160L224,163.6C224,185.4 212.9,205.7 194.6,217.4L152.4,244.5C127.2,260.7 112,288.6 112,318.5L112,320C112,337.7 126.3,352 144,352C161.7,352 176,337.7 176,320L176,318.6C176,310.4 180.2,302.8 187,298.4L229.2,271.3C265.8,247.7 288,207.2 288,163.6L288,160C288,89.3 211.781,31.042 141.081,31.042C70.381,31.042 0,89.3 0,160C0,177.7 14.3,192 32,192C49.7,192 64,177.7 64,160ZM144,480C165.943,480 184,461.943 184,440C184,418.057 165.943,400 144,400C122.057,400 104,418.057 104,440C104,461.943 122.057,480 144,480Z" style="fill-rule:nonzero;" fill="currentColor"/>
</g>
</svg></template>

159
src/util/net.js Normal file
View File

@ -0,0 +1,159 @@
/**
* Network related functions.
*
* markus.thielen@basebox.health
*/
import store from '@/store'
import router from '@/router'
/**
* GqlError - custom error thrown by the gqlQuery function.
*
* Since the GraphQL server might through multiple errors at once,
* this error class uses a message array.
*/
class GqlError extends Error {
/**
* Construct a GqlError.
*
* GqlError handles errors received from the GraphQL server as well as
* JavaScript errors thrown by the fetch API etc.
*
* @param {*} error JSON server response or Error instance or just a string.
*/
constructor(error) {
/* create array of error message strings */
const errorMessages = [];
if (error instanceof Error) {
/* JavaScript Error instance */
let msg = error.toString();
if (msg.indexOf("Failed to fetch") > 0) {
/* convert to a user-friendly message */
msg = "Failed to connect to basebox server.";
}
errorMessages.push(msg);
} else if (error instanceof String) {
errorMessages.push(error);
} else {
/* assume this is a GraphQL server response (JSON) */
try {
for (const e of error.errors) {
let s = e.message;
/* add info from extension, if available */
if (e.extensions) {
if (e.code) {
s += ` - ${e.extensions.code}`;
}
if (e.reason) {
s += ` - ${e.extensions.reason}`;
}
}
errorMessages.push(s);
}
} catch(e) {
errorMessages.push("Failed to interpret error: " + e.toString());
errorMessages.push(error.toString());
}
}
/* concat errors into a single message for the parent classes */
super(errorMessages.join(" / "));
this.errors = error.errors;
this.messages = errorMessages;
this.name = "GqlError";
}
/**
* Check if this error is an authentication error (401).
*/
is401() {
/* check if one of the server errors has a 401 extension */
for (const error of this.errors) {
if (error.extensions && error.extensions.code.toString() === "401") {
return true;
}
}
return false;
}
}
/**
* Send GraphQL request to the configured server.
*
* @param {String} query the GraphQL query/mutation to send
* @returns Promise with response JSON's data member on success,
* Error with error message array on failure
*/
export function gqlQuery(query)
{
/* prepare fetch options */
const fetchOpt = {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ query: query }),
};
/* if we're logged in, we add the authorization header */
if (store.getters.isLoggedIn) {
fetchOpt.headers["Authorization"] = store.getters.authData.token;
}
console.info(fetchOpt);
return fetch(store.getters.gqlUrl, fetchOpt).then(
/* fetch success */
async response => {
if (response.ok) {
/* convert to JSON */
const rspJson = await response.json();
if (rspJson.data) {
/* success */
return new Promise((resolve, reject) => {
resolve(rspJson.data);
});
} else {
/* some errors... */
return new Promise((resolve, reject) => {
const error = new GqlError(rspJson);
/* if this is a 401, we redirect to the login page */
if (error.is401()) {
router.push({
name: "Login",
query: {
next: router.currentRoute.fullPath,
}
});
}
reject(new GqlError(rspJson));
});
}
} else {
/* low level/network error */
return new Promise((resolve, reject) => {
reject(new GqlError(response.statusText));
});
}
},
/* fetch failure */
reason => {
return new Promise((resolve, reject) => {
reject(new GqlError(reason));
});
}
);
}

View File

@ -1,13 +1,11 @@
<script setup>
import TheWelcome from '../components/TheAbout.vue'
import { store } from "../store";
import Login from "../components/Login.vue";
</script>
<template>
<main>
<!-- Force user to log in before he/she can see tasks. -->
<Login v-if="!store.loggedIn"/>
</main>
</template>