move auth components to auth app
This commit is contained in:
15
src/Umbraco.Web.UI.Client/apps/auth/index.html
Normal file
15
src/Umbraco.Web.UI.Client/apps/auth/index.html
Normal 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>
|
||||
16
src/Umbraco.Web.UI.Client/apps/auth/package.json
Normal file
16
src/Umbraco.Web.UI.Client/apps/auth/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
4
src/Umbraco.Web.UI.Client/apps/auth/src/auth.ts
Normal file
4
src/Umbraco.Web.UI.Client/apps/auth/src/auth.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export default function() {
|
||||
sessionStorage.setItem('is-authenticated', 'true');
|
||||
history.replaceState(null, '', 'section');
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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',
|
||||
},
|
||||
},
|
||||
];
|
||||
13
src/Umbraco.Web.UI.Client/apps/auth/src/index.ts
Normal file
13
src/Umbraco.Web.UI.Client/apps/auth/src/index.ts
Normal 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]);
|
||||
118
src/Umbraco.Web.UI.Client/apps/auth/src/login.element.ts
Normal file
118
src/Umbraco.Web.UI.Client/apps/auth/src/login.element.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
19
src/Umbraco.Web.UI.Client/apps/auth/src/login.test.ts
Normal file
19
src/Umbraco.Web.UI.Client/apps/auth/src/login.test.ts
Normal 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);
|
||||
});
|
||||
});
|
||||
15
src/Umbraco.Web.UI.Client/apps/auth/vite.config.ts
Normal file
15
src/Umbraco.Web.UI.Client/apps/auth/vite.config.ts
Normal 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()],
|
||||
});
|
||||
Reference in New Issue
Block a user