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

157 lines
4.3 KiB
TypeScript

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-packages')
export class SgViewPackages extends DeesElement {
@state()
accessor packagesState: appstate.IPackagesState = {
packages: [],
currentPackage: null,
versions: [],
total: 0,
query: '',
protocolFilter: '',
};
@state()
accessor uiState: appstate.IUiState = { activeView: 'packages' };
@state()
accessor detailPackageId: string | null = null;
constructor() {
super();
const pkgSub = appstate.packagesStatePart
.select((s) => s)
.subscribe((s) => {
this.packagesState = s;
});
this.rxSubscriptions.push(pkgSub);
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();
// If there's an entity ID from the URL, copy it to internal state
if (this.uiState.activeEntityId) {
this.detailPackageId = this.uiState.activeEntityId;
await this.loadPackageDetail(this.detailPackageId);
} else {
await appstate.packagesStatePart.dispatchAction(
appstate.searchPackagesAction,
{ offset: 0 },
);
}
}
private async loadPackageDetail(packageId: string) {
await appstate.packagesStatePart.dispatchAction(
appstate.fetchPackageAction,
{ packageId },
);
await appstate.packagesStatePart.dispatchAction(
appstate.fetchPackageVersionsAction,
{ packageId },
);
}
public render(): TemplateResult {
if (this.detailPackageId && this.packagesState.currentPackage) {
return html`
<sg-package-detail-view
.package="${this.packagesState.currentPackage}"
.versions="${this.packagesState.versions}"
@back="${() => this.goBack()}"
@delete="${(e: CustomEvent) => this.deletePackage(e.detail.packageId)}"
@delete-version="${(e: CustomEvent) => this.deleteVersion(e.detail)}"
></sg-package-detail-view>
`;
}
return html`
<sg-packages-list-view
.packages="${this.packagesState.packages}"
.total="${this.packagesState.total}"
.query="${this.packagesState.query}"
.protocols="${['npm', 'oci', 'maven', 'cargo', 'pypi', 'composer', 'rubygems']}"
@search="${(e: CustomEvent) => this.search(e.detail.query)}"
@filter="${(e: CustomEvent) => this.filter(e.detail.protocol)}"
@select="${(e: CustomEvent) => this.selectPackage(e.detail.packageId)}"
@page="${(e: CustomEvent) => this.paginate(e.detail.offset)}"
></sg-packages-list-view>
`;
}
private selectPackage(packageId: string) {
this.detailPackageId = packageId;
this.loadPackageDetail(packageId);
}
private goBack() {
this.detailPackageId = null;
appstate.packagesStatePart.setState({
...appstate.packagesStatePart.getState(),
currentPackage: null,
versions: [],
});
}
private async search(query: string) {
await appstate.packagesStatePart.dispatchAction(
appstate.searchPackagesAction,
{ query, protocol: this.packagesState.protocolFilter, offset: 0 },
);
}
private async filter(protocol: string) {
await appstate.packagesStatePart.dispatchAction(
appstate.searchPackagesAction,
{ query: this.packagesState.query, protocol, offset: 0 },
);
}
private async paginate(offset: number) {
await appstate.packagesStatePart.dispatchAction(
appstate.searchPackagesAction,
{
query: this.packagesState.query,
protocol: this.packagesState.protocolFilter,
offset,
},
);
}
private async deletePackage(packageId: string) {
await appstate.packagesStatePart.dispatchAction(
appstate.deletePackageAction,
{ packageId },
);
this.goBack();
}
private async deleteVersion(detail: { packageId: string; version: string }) {
// TODO: implement deletePackageVersion action
}
}