Initial Commit

This commit is contained in:
seedorf_s1
2020-11-13 09:09:21 +01:00
commit 5a56fc26d2
50 changed files with 5038 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
import {getUserInfo} from './utils';
export async function getUserName(): Promise<string> {
const info = await getUserInfo();
return info?.name ?? "No name found!";
}

View File

@@ -0,0 +1,12 @@
// Export setConfig so that the external url can set set automatically
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export {setConfig} from './utils';
import {getUserName} from './SomeModule';
getUserName().then((name) => {
const node = document.createElement('span');
node.innerText = `This user name is fetched with Javascript: ${name}`;
document.getElementsByTagName("body")[0].appendChild(node);
});

View File

@@ -0,0 +1,78 @@
enum ResolvableState {
WAITING,
PENDING,
ERROR,
DONE
}
class FetchOnce<T> {
protected data: T|undefined;
protected error: unknown|undefined;
protected state: ResolvableState = ResolvableState.WAITING;
protected pendings: [(res: Promise<T>|T) => void, (reason: unknown) => void][] = [];
constructor(protected fetchMethod?: () => Promise<T>) { }
public resolve(): Promise<T> {
return new Promise((resolve, reject) => {
switch (this.state) {
case ResolvableState.WAITING:
this.state = ResolvableState.PENDING;
this.pendings.push([resolve, reject]);
if (this.fetchMethod) this.parsePromise(this.fetchMethod());
break;
case ResolvableState.PENDING:
this.pendings.push([resolve, reject]);
break;
case ResolvableState.DONE:
resolve(this.data);
break;
case ResolvableState.ERROR:
reject(this.error);
break;
}
});
}
protected isFinished(): boolean {
return this.state === ResolvableState.DONE || this.state === ResolvableState.ERROR;
}
protected parsePromise(promise: Promise<T>): void {
promise.then((data) => {
this.data = data;
this.state = ResolvableState.DONE;
this.pendings.forEach(pending => pending[0](data));
}).catch(err => {
this.error = err;
this.state = ResolvableState.ERROR;
this.pendings.forEach(pending => pending[1](err));
});
}
}
export class Resolvable<T> extends FetchOnce<T> {
constructor(fetchMethod: () => Promise<T>) {
super(fetchMethod);
}
}
export class WaitForSync<T> extends FetchOnce<T> {
protected state: ResolvableState = ResolvableState.PENDING;
constructor() {
super(undefined);
}
public setData(data: T): void {
if (!this.isFinished()) {
this.parsePromise((async () => data)());
}
}
public setError(error: unknown): void {
if (!this.isFinished()) {
this.parsePromise((async () => { throw error; })());
}
}
}

View File

@@ -0,0 +1,10 @@
type UserInfo = {
email: string,
email_verified: boolean,
family_name: string,
given_name: string,
groups: string[],
name: string,
preferred_username: string,
sub: string,
};

View File

@@ -0,0 +1,23 @@
import {WaitForSync} from './resolvable';
export interface ClientConfig {
EXTERNAL_BASE_URL: string
}
let config: ClientConfig|undefined;
const configWaiter = new WaitForSync<ClientConfig>();
export function setConfig(clientConfig: ClientConfig): void {
config = clientConfig;
configWaiter.setData(config);
}
export function getConfig(): Promise<ClientConfig> {
return configWaiter.resolve();
}
export async function getUserInfo(): Promise<UserInfo|undefined> {
const getBaseUrl = await getConfig();
const res = await fetch(getBaseUrl.EXTERNAL_BASE_URL + "/api/user");
return res.json();
}