move auth components to auth app

This commit is contained in:
Jacob Overgaard
2023-01-24 10:32:40 +01:00
parent d2e47cf351
commit fdab5f3e32
11 changed files with 53 additions and 14 deletions

View File

@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Umbraco Auth</title>
<script type="module" src="/src/index.ts"></script>
<base href="/" />
</head>
<body class="uui-font uui-text" style="margin: 0; padding: 0; overflow: hidden">
<umb-login></umb-login>
</body>
</html>

View File

@@ -0,0 +1,16 @@
{
"name": "umbraco-backoffice-auth",
"version": "0.0.0",
"license": "MIT",
"author": {
"name": "Umbraco HQ",
"email": "backoffice@umbraco.com"
},
"scripts": {
"dev": "vite",
"build": "vite build",
"build:production": "vite build --mode production",
"preview": "vite preview",
"test": "web-test-runner \"test/**/*.test.ts\" --node-resolve"
}
}

View File

@@ -0,0 +1,72 @@
import { css, CSSResultGroup, html, LitElement } from 'lit';
import { customElement } from 'lit/decorators.js';
@customElement('umb-auth-layout')
export class UmbAuthLayout extends LitElement {
static styles: CSSResultGroup = [
css`
#background {
position: fixed;
overflow: hidden;
background-position: 50%;
background-repeat: no-repeat;
background-size: cover;
background-image: url('login.jpeg');
width: 100vw;
height: 100vh;
}
#logo {
position: fixed;
top: var(--uui-size-space-5);
left: var(--uui-size-space-5);
height: 30px;
}
#logo img {
height: 100%;
}
#container {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 100vw;
height: 100vh;
}
#box {
width: 500px;
padding: var(--uui-size-space-6) var(--uui-size-space-5) var(--uui-size-space-5) var(--uui-size-space-5);
}
#email,
#password {
width: 100%;
}
`,
];
render() {
return html`
<div id="background"></div>
<div id="logo">
<img src="/umbraco_logo_white.svg" alt="Umbraco" />
</div>
<div id="container">
<uui-box id="box">
<slot></slot>
</uui-box>
</div>
`;
}
}
declare global {
interface HTMLElementTagNameMap {
'umb-auth-layout': UmbAuthLayout;
}
}

View File

@@ -0,0 +1,4 @@
export default function() {
sessionStorage.setItem('is-authenticated', 'true');
history.replaceState(null, '', 'section');
}

View File

@@ -0,0 +1,41 @@
import { css, html } from 'lit';
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
import { customElement } from 'lit/decorators.js';
import { UmbLitElement } from '@umbraco-cms/element';
@customElement('umb-external-login-provider-test')
export class UmbExternalLoginProviderTestElement extends UmbLitElement {
static styles = [
UUITextStyles,
css`
:host {
display: flex;
flex-direction: column;
gap: var(--uui-size-space-4);
padding: var(--uui-size-space-5);
border: 1px solid var(--uui-color-border);
background: var(--uui-color-surface-alt);
border-radius: var(--uui-border-radius);
}
p {
margin: 0;
}
`,
];
render() {
return html`
<b>Custom External Login Provider</b>
<p>This is an example of a custom external login provider using the external login provider extension point</p>
<uui-button label="My custom login provider" look="primary"></uui-button>
`;
}
}
export default UmbExternalLoginProviderTestElement;
declare global {
interface HTMLElementTagNameMap {
'umb-external-login-provider-test': UmbExternalLoginProviderTestElement;
}
}

View File

@@ -0,0 +1,54 @@
import { css, html } from 'lit';
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
import { customElement } from 'lit/decorators.js';
import { UmbLitElement } from '@umbraco-cms/element';
@customElement('umb-external-login-provider-test2')
export class UmbExternalLoginProviderTest2Element extends UmbLitElement {
static styles = [
UUITextStyles,
css`
:host {
display: flex;
flex-direction: column;
gap: var(--uui-size-space-4);
padding: var(--uui-size-space-5);
border: 1px solid var(--uui-color-border);
background: var(--uui-color-surface-alt);
border-radius: var(--uui-border-radius);
}
p {
margin: 0;
}
uui-input {
width: 100%;
}
`,
];
render() {
return html`
<b>Another Custom External Login Provider</b>
<p>This is an example of another custom external login provider</p>
<uui-form-layout-item>
<uui-label id="emailLabel" for="email" slot="label" required>Email</uui-label>
<uui-input
type="email"
id="email"
name="email"
placeholder="Enter your email..."
required
required-message="Email is required"></uui-input>
</uui-form-layout-item>
<uui-button label="Custom login" look="primary"></uui-button>
`;
}
}
export default UmbExternalLoginProviderTest2Element;
declare global {
interface HTMLElementTagNameMap {
'umb-external-login-provider-test2': UmbExternalLoginProviderTest2Element;
}
}

View File

@@ -0,0 +1,29 @@
// TODO: could these be renamed as login providers?
import type { ManifestExternalLoginProvider } from '@umbraco-cms/models';
export const manifests: Array<ManifestExternalLoginProvider> = [
{
type: 'externalLoginProvider',
alias: 'Umb.ExternalLoginProvider.Test',
name: 'Test External Login Provider',
elementName: 'umb-external-login-provider-test',
loader: () => import('./external-login-provider-test.element'),
weight: 2,
meta: {
label: 'Test External Login Provider',
pathname: 'test/test/test',
},
},
{
type: 'externalLoginProvider',
alias: 'Umb.ExternalLoginProvider.Test2',
name: 'Test External Login Provider 2',
elementName: 'umb-external-login-provider-test2',
loader: () => import('./external-login-provider-test2.element'),
weight: 1,
meta: {
label: 'Test External Login Provider 2',
pathname: 'test/test/test',
},
},
];

View File

@@ -0,0 +1,13 @@
import { ManifestTypes, umbExtensionsRegistry } from '@umbraco-cms/extensions-registry';
import { manifests as externalLoginProviders } from './external-login-providers/manifests';
import './login.element';
const registerExtensions = (manifests: Array<ManifestTypes>) => {
manifests.forEach((manifest) => {
if (umbExtensionsRegistry.isRegistered(manifest.alias)) return;
umbExtensionsRegistry.register(manifest);
});
};
registerExtensions([...externalLoginProviders]);

View File

@@ -0,0 +1,118 @@
import { UUITextStyles } from '@umbraco-ui/uui-css';
import { css, CSSResultGroup, html, LitElement } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import './auth-layout.element';
@customElement('umb-login')
export default class UmbLogin extends LitElement {
static styles: CSSResultGroup = [
UUITextStyles,
css`
#email,
#password {
width: 100%;
}
`,
];
@state()
private _loggingIn = false;
private _handleSubmit = (e: SubmitEvent) => {
e.preventDefault();
const form = e.target as HTMLFormElement;
if (!form) return;
const isValid = form.checkValidity();
if (!isValid) return;
const formData = new FormData(form);
const username = formData.get('email') as string;
const password = formData.get('password') as string;
const persist = formData.has('persist');
this._login(username, password, persist);
};
private async _login(username: string, password: string, persist: boolean) {
// TODO: Move login to new login app
this._loggingIn = true;
try {
this._loggingIn = false;
alert('go back to the backoffice');
} catch (error) {
console.log(error);
this._loggingIn = false;
}
}
private _greetings: Array<string> = [
'Happy super Sunday',
'Happy marvelous Monday',
'Happy tubular Tuesday',
'Happy wonderful Wednesday',
'Happy thunderous Thursday',
'Happy funky Friday',
'Happy Saturday',
];
@state()
private _greeting: string = this._greetings[new Date().getDay()];
render() {
return html`
<umb-auth-layout>
<div class="uui-text">
<h1 class="uui-h3">${this._greeting}</h1>
<uui-form>
<form id="LoginForm" name="login" @submit="${this._handleSubmit}">
<uui-form-layout-item>
<uui-label id="emailLabel" for="email" slot="label" required>Email</uui-label>
<uui-input
type="email"
id="email"
name="email"
placeholder="Enter your email..."
required
required-message="Email is required"></uui-input>
</uui-form-layout-item>
<uui-form-layout-item>
<uui-label id="passwordLabel" for="password" slot="label" required>Password</uui-label>
<uui-input-password
id="password"
name="password"
placeholder="Enter your password..."
required
required-message="Password is required"></uui-input-password>
</uui-form-layout-item>
<uui-form-layout-item>
<uui-checkbox name="persist" label="Remember me"> Remember me </uui-checkbox>
</uui-form-layout-item>
<uui-button
type="submit"
label="Login"
look="primary"
color="positive"
state=${ifDefined(this._loggingIn ? 'waiting' : undefined)}></uui-button>
<uui-button type="button" label="Forgot Password?"></uui-button>
</form>
</uui-form>
</div>
</umb-auth-layout>
`;
}
}
declare global {
interface HTMLElementTagNameMap {
'umb-login': UmbLogin;
}
}

View File

@@ -0,0 +1,19 @@
import { expect, fixture, html } from '@open-wc/testing';
import { defaultA11yConfig } from '@umbraco-cms/test-utils';
import UmbLogin from './login.element';
describe('UmbLogin', () => {
let element: UmbLogin;
beforeEach(async () => {
element = await fixture(html`<umb-login></umb-login>`);
});
it('is defined with its own instance', () => {
expect(element).to.be.instanceOf(UmbLogin);
});
it('passes the a11y audit', async () => {
await expect(element).to.be.accessible(defaultA11yConfig);
});
});

View File

@@ -0,0 +1,15 @@
import { defineConfig } from 'vite';
import viteTSConfigPaths from 'vite-tsconfig-paths';
// https://vitejs.dev/config/
export default defineConfig({
build: {
lib: {
entry: 'src/index.ts',
formats: ['es'],
fileName: 'main',
},
sourcemap: true,
},
plugins: [viteTSConfigPaths()],
});