Files
registry/ts_web/elements/sg-view-organizations.ts

154 lines
4.3 KiB
TypeScript
Raw Normal View History

import * as appstate from '../appstate.js';
import * as shared from './shared/index.js';
import { appRouter } from '../router.js';
import {
css,
cssManager,
customElement,
DeesElement,
html,
state,
type TemplateResult,
} from '@design.estate/dees-element';
@customElement('sg-view-organizations')
export class SgViewOrganizations extends DeesElement {
@state()
accessor organizationsState: appstate.IOrganizationsState = {
organizations: [],
currentOrg: null,
repositories: [],
members: [],
};
@state()
accessor uiState: appstate.IUiState = { activeView: 'organizations' };
@state()
accessor detailOrgId: string | null = null;
constructor() {
super();
const orgSub = appstate.organizationsStatePart
.select((s) => s)
.subscribe((s) => {
this.organizationsState = s;
});
this.rxSubscriptions.push(orgSub);
const uiSub = appstate.uiStatePart
.select((s) => s)
.subscribe((s) => {
this.uiState = s;
});
this.rxSubscriptions.push(uiSub);
}
public static styles = [
cssManager.defaultStyles,
shared.viewHostCss,
];
async connectedCallback() {
super.connectedCallback();
await appstate.organizationsStatePart.dispatchAction(appstate.fetchOrganizationsAction, null);
// If there's an entity ID from the URL, copy it to internal state
if (this.uiState.activeEntityId) {
this.detailOrgId = this.uiState.activeEntityId;
await this.loadOrgDetail(this.detailOrgId);
}
}
private async loadOrgDetail(orgId: string) {
await appstate.organizationsStatePart.dispatchAction(
appstate.fetchOrganizationAction,
{ organizationId: orgId },
);
await appstate.organizationsStatePart.dispatchAction(
appstate.fetchRepositoriesAction,
{ organizationId: orgId },
);
await appstate.organizationsStatePart.dispatchAction(
appstate.fetchMembersAction,
{ organizationId: orgId },
);
}
public render(): TemplateResult {
if (this.detailOrgId && this.organizationsState.currentOrg) {
return html`
<sg-organization-detail-view
.organization="${this.organizationsState.currentOrg}"
.repositories="${this.organizationsState.repositories}"
.members="${this.organizationsState.members}"
@back="${() => this.goBack()}"
@select-repo="${(e: CustomEvent) => this.selectRepo(e.detail.repositoryId)}"
@create-repo="${() => {/* TODO: create repo modal */}}"
@edit="${(e: CustomEvent) => this.handleEditOrg(e.detail)}"
@delete="${(e: CustomEvent) => this.handleDeleteOrg(e.detail.organizationId)}"
></sg-organization-detail-view>
`;
}
return html`
<sg-organizations-list-view
.organizations="${this.organizationsState.organizations}"
@select="${(e: CustomEvent) => this.selectOrg(e.detail.organizationId)}"
@create="${(e: CustomEvent) => this.createOrg(e.detail)}"
></sg-organizations-list-view>
`;
}
private selectOrg(orgId: string) {
this.detailOrgId = orgId;
this.loadOrgDetail(orgId);
}
private selectRepo(repoId: string) {
// Navigate to repository within org context
// For now, we could switch to packages view
}
private goBack() {
this.detailOrgId = null;
appstate.organizationsStatePart.setState({
...appstate.organizationsStatePart.getState(),
currentOrg: null,
repositories: [],
members: [],
});
}
private async handleEditOrg(data: {
organizationId: string;
displayName?: string;
description?: string;
website?: string;
isPublic?: boolean;
}) {
await appstate.organizationsStatePart.dispatchAction(
appstate.updateOrganizationAction,
data,
);
// Re-load detail to reflect changes
if (this.detailOrgId) {
await this.loadOrgDetail(this.detailOrgId);
}
}
private async handleDeleteOrg(organizationId: string) {
await appstate.organizationsStatePart.dispatchAction(
appstate.deleteOrganizationAction,
{ organizationId },
);
this.goBack();
}
private async createOrg(data: { name: string; displayName?: string; description?: string }) {
await appstate.organizationsStatePart.dispatchAction(
appstate.createOrganizationAction,
data,
);
}
}