idp.global
-
Your permanent identity on the web
+
Open identity infrastructure
+
One Identity. Any Scale. Yours Forever.
-
+
Open Source
@@ -273,7 +300,7 @@ export class IdpCenterContainer extends DeesElement {
-
+
Always Free
@@ -283,7 +310,7 @@ export class IdpCenterContainer extends DeesElement {
-
+
Permanent Identity
@@ -293,10 +320,14 @@ export class IdpCenterContainer extends DeesElement {
- window.open('https://about.idp.global', '_blank')}
- >Learn more
+ >Learn more
+ window.open('https://code.foss.global/idp.global/app', '_blank')}
+ >Source code
diff --git a/ts_web/elements/idp-loginprompt.ts b/ts_web/elements/idp-loginprompt.ts
index 7187e6c..9d0521f 100644
--- a/ts_web/elements/idp-loginprompt.ts
+++ b/ts_web/elements/idp-loginprompt.ts
@@ -14,8 +14,6 @@ import {
import '@uptime.link/webwidget';
-import '@design.estate/dees-catalog';
-import { DeesForm, DeesFormSubmit, DeesInputText } from '@design.estate/dees-catalog';
import { IdpState } from '../states/idp.state.js';
declare global {
@@ -146,7 +144,7 @@ export class IdpLoginPrompt extends DeesElement {
return false;
}
- const loginForm = this.shadowRoot.querySelector('#loginForm') as DeesForm | null;
+ const loginForm = this.shadowRoot.querySelector('#loginForm') as plugins.idpCatalog.IdpForm | null;
loginForm?.setStatus('pending', 'preparing application authorization...');
this.oidcConsentError = '';
@@ -177,7 +175,7 @@ export class IdpLoginPrompt extends DeesElement {
}
const idpState = await IdpState.getSingletonInstance();
- const loginForm = this.shadowRoot.querySelector('#loginForm') as DeesForm | null;
+ const loginForm = this.shadowRoot.querySelector('#loginForm') as plugins.idpCatalog.IdpForm | null;
loginForm?.setStatus('pending', 'authorizing application...');
this.oidcConsentError = '';
@@ -233,7 +231,7 @@ export class IdpLoginPrompt extends DeesElement {
margin: 0;
}
- dees-form {
+ idp-form {
display: flex;
flex-direction: column;
gap: 16px;
@@ -318,25 +316,6 @@ export class IdpLoginPrompt extends DeesElement {
gap: 12px;
}
- .consent-button {
- border: none;
- border-radius: 999px;
- padding: 12px 18px;
- font: inherit;
- cursor: pointer;
- }
-
- .consent-button-secondary {
- background: rgba(255, 255, 255, 0.08);
- color: var(--foreground);
- }
-
- .consent-button-primary {
- background: linear-gradient(135deg, #9b7bff, #5fd1ff);
- color: #0a0a0a;
- font-weight: 600;
- }
-
.consent-error {
color: #ff9a9a;
font-size: 14px;
@@ -370,16 +349,16 @@ export class IdpLoginPrompt extends DeesElement {
${this.oidcConsentError ? html`
${this.oidcConsentError}
` : null}
-
-
+
@@ -404,29 +383,31 @@ export class IdpLoginPrompt extends DeesElement {
Sign in to your account
Enter your credentials to continue
-
{
+ @idp-submit=${(eventArg: CustomEvent) => {
this.login({
- emailAddress: eventArg.detail.data.emailAddress,
- passwordArg: eventArg.detail.data.password,
+ emailAddress: String(eventArg.detail.data.emailAddress || ''),
+ passwordArg: String(eventArg.detail.data.password || ''),
});
}}
>
-
-
-
-
+ autocomplete="username"
+ >
+
+
+
-
{
+ @idp-submit=${(eventArg: CustomEvent) => {
this.register({
- emailAddress: eventArg.detail.data.emailAddress,
+ emailAddress: String(eventArg.detail.data.emailAddress || ''),
});
- }}"
+ }}
>
-
-
- Send Verification Email
-
+ type="email"
+ autocomplete="email"
+ >
+
+
Send Verification Email
+
- {
const idpState = await IdpState.getSingletonInstance();
- idpState.domtools.router.pushUrl('/account');
+ idpState.domtools.router.pushUrl('/dash/overview');
}}
- >Manage your account
- Open dashboard
+ {
const idpState = await IdpState.getSingletonInstance();
idpState.domtools.router.pushUrl('/logout');
}}
- >Sign out
+ >Sign out
`;
}
@@ -124,29 +125,30 @@ export class IdpWelcome extends DeesElement {
Sign in to your account or create a new one
- {
const idpState = await IdpState.getSingletonInstance();
idpState.domtools.router.pushUrl('/login');
}}
- >Sign In
- Sign In
+ {
const idpState = await IdpState.getSingletonInstance();
idpState.domtools.router.pushUrl('/register');
}}
- >Create Account
+ >Create Account
`;
})}
- {
- window.open('https://code.foss.global/idp.global/idp.global', '_blank');
+ window.open('https://code.foss.global/idp.global/app', '_blank');
}}
- >View Source Code
+ >View Source Code
`;
diff --git a/ts_web/index.ts b/ts_web/index.ts
index 78a572e..ea061c6 100644
--- a/ts_web/index.ts
+++ b/ts_web/index.ts
@@ -15,24 +15,26 @@ const run = async () => {
'Your permanent identity on the web',
canonicalDomain: 'https://idp.global',
ldCompany: {
+ type: 'company',
name: 'Task Venture Capital GmbH',
- status: 'active',
- contact: {
- address: {
- name: 'Task Venture Capital GmbH',
- city: 'Grasberg',
- country: 'Germany',
- houseNumber: '24',
- postalCode: '28879',
- streetName: 'Eickedorfer Vorweide',
- },
- description: 'work',
+ description: 'work',
+ address: {
name: 'Task Venture Capital GmbH',
- type: 'company',
- website: 'https://task.vc',
- phone: '+49 421 16767 548',
+ city: 'Grasberg',
+ country: 'Germany',
+ countryCode: 'DE',
+ houseNumber: '24',
+ postalCode: '28879',
+ streetName: 'Eickedorfer Vorweide',
},
- closedDate: null,
+ website: 'https://task.vc',
+ phone: '+49 421 16767 548',
+ registrationDetails: {
+ vatId: '',
+ registrationId: 'HRB 35230 HB',
+ registrationName: 'District court Bremen',
+ },
+ status: 'active',
foundedDate: {
day: 1,
month: 1,
diff --git a/ts_web/plugins.ts b/ts_web/plugins.ts
index 5b6590d..565b9ea 100644
--- a/ts_web/plugins.ts
+++ b/ts_web/plugins.ts
@@ -1,10 +1,11 @@
// node native
// project native
-import * as idpInterfaces from '../dist_ts_interfaces/index.js';
+import * as idpCatalog from '@idp.global/catalog';
+import * as idpInterfaces from '@idp.global/interfaces';
import * as leleReceptionclient from '../dist_ts_idpclient/index.js';
-export { idpInterfaces, leleReceptionclient as idpClient };
+export { idpCatalog, idpInterfaces, leleReceptionclient as idpClient };
// @api.global scope
import * as typedrequest from '@api.global/typedrequest';
diff --git a/ts_web/readme.md b/ts_web/readme.md
index 7696cbf..8ff0738 100644
--- a/ts_web/readme.md
+++ b/ts_web/readme.md
@@ -1,6 +1,6 @@
# `ts_web/` Web App Module
-The `ts_web/` folder contains the frontend for `idp.global`: login, registration, account management, org management, billing, and admin UI.
+The `ts_web/` folder contains the frontend for `idp.global`: login, logout, registration, account management, org management, billing, and admin UI.
It is built with `@design.estate/dees-element`, `@design.estate/dees-domtools`, and the shared `idp.global` client and interface packages.
@@ -42,6 +42,7 @@ The module currently includes:
| `register` | `/register` |
| `finishregistration` | `/finishregistration` |
| `account` | `/account` |
+| `logout` | `/logout` |
## Build And Run
@@ -60,6 +61,7 @@ pnpm watch
- The app metadata in `ts_web/index.ts` identifies the site as `idp.global`.
- The frontend uses the shared client package for auth state and backend communication.
- Account-related UI is split into reusable elements plus state containers in `states/`.
+- The router treats `/account{/*path}` as the signed-in account area, so account subroutes can stay in the SPA shell.
## License and Legal Information
diff --git a/ts_web/states/idp.state.ts b/ts_web/states/idp.state.ts
index 02935c8..6d0a653 100644
--- a/ts_web/states/idp.state.ts
+++ b/ts_web/states/idp.state.ts
@@ -19,7 +19,7 @@ export class IdpState {
public idpClient = new plugins.idpClient.IdpClient(this.receptionUrl);
public domtools: domtools.DomTools;
public mainStatePart: plugins.deesDomtools.plugins.smartstate.StatePart<'main', {
- view: 'welcome' | 'login' | 'register' | 'finishregistration' | 'account' | 'logout';
+ view: 'welcome' | 'login' | 'register' | 'finishregistration' | 'dash' | 'logout';
}>
public async init() {
@@ -38,6 +38,12 @@ export class IdpState {
});
this.domtools.router.on('/login', async () => {
+ const isOauthLogin = new URL(window.location.href).searchParams.get('oauth') === 'true';
+ if (!isOauthLogin && await this.idpClient.determineLoginStatus(false)) {
+ this.domtools.router.pushUrl('/dash/overview');
+ return;
+ }
+
await this.mainStatePart.setState({
...this.mainStatePart.getState(),
view: 'login',
@@ -53,6 +59,11 @@ export class IdpState {
});
this.domtools.router.on('/register', async () => {
+ if (await this.idpClient.determineLoginStatus(false)) {
+ this.domtools.router.pushUrl('/dash/overview');
+ return;
+ }
+
await this.mainStatePart.setState({
...this.mainStatePart.getState(),
view: 'register',
@@ -66,13 +77,18 @@ export class IdpState {
})
});
- this.domtools.router.on('/account{/*path}', async () => {
+ this.domtools.router.on('/dash{/*path}', async () => {
+ if (!await this.idpClient.determineLoginStatus(false)) {
+ this.domtools.router.pushUrl('/login');
+ return;
+ }
+
await this.mainStatePart.setState({
...this.mainStatePart.getState(),
- view: 'account',
+ view: 'dash',
})
});
this.domtools.router._handleRouteState();
}
-}
\ No newline at end of file
+}
diff --git a/ts_web/views/viewcontainer.ts b/ts_web/views/viewcontainer.ts
index ad6d0ff..218c884 100644
--- a/ts_web/views/viewcontainer.ts
+++ b/ts_web/views/viewcontainer.ts
@@ -114,8 +114,8 @@ export class IdpViewcontainer extends DeesElement {
case 'finishregistration':
await this.loadElement(elements.IdpRegistrationStepper);
break;
- case 'account':
- console.log('now on /account');
+ case 'dash':
+ console.log('now on /dash');
await this.loadElement(elements.IdpAccountContent);
break;
}