Skip to content

Commit

Permalink
Implemented Components page
Browse files Browse the repository at this point in the history
  • Loading branch information
mlhaufe committed Jan 15, 2024
1 parent 9910cb4 commit 22114ee
Show file tree
Hide file tree
Showing 17 changed files with 181 additions and 62 deletions.
3 changes: 0 additions & 3 deletions _old/domain/entities/Assumption.mts

This file was deleted.

3 changes: 0 additions & 3 deletions _old/domain/entities/Behavior.mts

This file was deleted.

3 changes: 0 additions & 3 deletions _old/domain/entities/Component.mts

This file was deleted.

14 changes: 0 additions & 14 deletions _old/domain/entities/Environment.mts

This file was deleted.

30 changes: 0 additions & 30 deletions _old/domain/entities/Project.mts

This file was deleted.

1 change: 0 additions & 1 deletion _old/domain/entities/Requirement.mts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// import { Contract, Contracted, implies, invariant } from '@final-hill/decorator-contracts';
import { type Predicate } from './Predicate.mjs';
import Project from './Project.mjs';

// const requirementContract = new Contract<Requirement>({
// [invariant]: self => implies(
Expand Down
3 changes: 0 additions & 3 deletions _old/domain/entities/UseCase.mts

This file was deleted.

11 changes: 11 additions & 0 deletions src/data/ComponentRepository.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import StorageRepository from './StorageRepository.mjs';
import pkg from '~/../package.json' with { type: 'json' };
import type { SemVerString } from '~/lib/SemVer.mjs';
import { ComponentToJsonMapper } from '~/mappers/ComponentToJsonMapper.mjs';
import type Component from '~/domain/Component.mjs';

export default class BehaviorRepository extends StorageRepository<Component> {
constructor(storage: Storage) {
super('components', storage, new ComponentToJsonMapper(pkg.version as SemVerString));
}
}
26 changes: 26 additions & 0 deletions src/domain/Component.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { Properties } from '~/types/Properties.mjs';
import Requirement from './Requirement.mjs';

/**
* A Component is a self-contained element in the Environment that provides an interface
* which can be used by a System to interact with.
*/
export default class Component extends Requirement {
name: string;
description: string;

constructor(properties: Omit<Properties<Component>, 'interfaceDefinition'>) {
super(properties);

this.name = properties.name;
this.description = properties.description;
}

get interfaceDefinition(): string {
return this.statement;
}

set interfaceDefinition(value: string) {
this.statement = value;
}
}
2 changes: 2 additions & 0 deletions src/domain/Environment.mts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export default class Environment extends Entity {
invariantIds: Uuid[];
assumptionIds: Uuid[];
effectIds: Uuid[];
componentIds: Uuid[];

constructor(options: Properties<Environment>) {
super(options);
Expand All @@ -23,5 +24,6 @@ export default class Environment extends Entity {
this.invariantIds = options.invariantIds;
this.assumptionIds = options.assumptionIds;
this.effectIds = options.effectIds;
this.componentIds = options.componentIds;
}
}
28 changes: 28 additions & 0 deletions src/mappers/ComponentToJsonMapper.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import SemVer from '~/lib/SemVer.mjs';
import type { RequirementJson } from './RequirementToJsonMapper.mjs';
import RequirementToJsonMapper from './RequirementToJsonMapper.mjs';
import Component from '~/domain/Component.mjs';

export interface ComponentJson extends RequirementJson {
name: string;
description: string;
}

export class ComponentToJsonMapper extends RequirementToJsonMapper {
override mapFrom(target: ComponentJson): Component {
const version = new SemVer(target.serializationVersion);

if (version.gte('0.4.0'))
return new Component(target);

throw new Error(`Unsupported serialization version: ${version}`);
}

override mapTo(source: Component): ComponentJson {
return {
...super.mapTo(source),
name: source.name,
description: source.description,
};
}
}
7 changes: 5 additions & 2 deletions src/mappers/EnvironmentToJsonMapper.mts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface EnvironmentJson extends EntityJson {
invariantIds: Uuid[];
assumptionIds: Uuid[];
effectIds: Uuid[];
componentIds: Uuid[];
}

export default class EnvironmentToJsonMapper extends EntityToJsonMapper {
Expand All @@ -21,7 +22,8 @@ export default class EnvironmentToJsonMapper extends EntityToJsonMapper {
constraintIds: target.constraintIds ?? [],
invariantIds: target.invariantIds ?? [],
assumptionIds: target.assumptionIds ?? [],
effectIds: target.effectIds ?? []
effectIds: target.effectIds ?? [],
componentIds: target.componentIds ?? []
});

throw new Error(`Unsupported serialization version: ${version}`);
Expand All @@ -34,7 +36,8 @@ export default class EnvironmentToJsonMapper extends EntityToJsonMapper {
constraintIds: source.constraintIds,
invariantIds: source.invariantIds,
assumptionIds: source.assumptionIds,
effectIds: source.effectIds
effectIds: source.effectIds,
componentIds: source.componentIds
};
}
}
1 change: 1 addition & 0 deletions src/presentation/Application.mts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export default class Application extends Container {
(await import('./pages/solution/environment/InvariantsPage.mjs')).default,
(await import('./pages/solution/environment/AssumptionsPage.mjs')).default,
(await import('./pages/solution/environment/EffectsPage.mjs')).default,
(await import('./pages/solution/environment/ComponentsPage.mjs')).default,
(await import('./pages/solution/goals/GoalsIndexPage.mjs')).default,
(await import('./pages/solution/goals/RationalePage.mjs')).default,
(await import('./pages/solution/goals/FunctionalityPage.mjs')).default,
Expand Down
18 changes: 16 additions & 2 deletions src/presentation/components/DataTable.mts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ interface BaseDataColumn {
}

interface TextHiddenDataColumn {
formType: 'text' | 'hidden';
formType: 'text' | 'hidden' | 'textarea';
}

interface NumberRangeDataColumn {
Expand Down Expand Up @@ -47,7 +47,7 @@ const show = ((item: HTMLElement) => item.hidden = false),
hide = ((item: HTMLElement) => item.hidden = true),
disable = ((item: HTMLInputElement | HTMLSelectElement) => item.disabled = true),
enable = ((item: HTMLInputElement | HTMLSelectElement) => item.disabled = false),
{ button, caption, form, input, option, select, span, table, tbody, td, template, th, thead, tr } = html;
{ button, caption, form, input, option, select, span, table, textarea, tbody, td, template, th, thead, tr } = html;

export class DataTable<T extends Entity> extends Component {
static {
Expand Down Expand Up @@ -332,6 +332,12 @@ export class DataTable<T extends Entity> extends Component {
`${col.step}` : '1',
form: this.#frmDataTableCreate,
[renderIf]: col.formType == 'number' || col.formType == 'range'
}),
textarea({
name: id,
form: this.#frmDataTableCreate,
required: col.required,
[renderIf]: col.formType == 'textarea'
})
]))
);
Expand Down Expand Up @@ -362,6 +368,14 @@ export class DataTable<T extends Entity> extends Component {
name: id,
defaultValue: (item as any)[id]
}, []),
textarea({
[renderIf]: col.formType == 'textarea',
form: this.#frmDataTableUpdate,
name: id,
disabled: true,
required: col.required,
defaultValue: (item as any)[id]
}, []),
input({
form: this.#frmDataTableUpdate,
type: col.formType,
Expand Down
3 changes: 2 additions & 1 deletion src/presentation/pages/solution/NewSolutionPage.mts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ export default class NewSolutionPage extends Page {
constraintIds: [],
invariantIds: [],
assumptionIds: [],
effectIds: []
effectIds: [],
componentIds: []
}),
goals = new Goals({
id: solution.goalsId,
Expand Down
85 changes: 85 additions & 0 deletions src/presentation/pages/solution/environment/ComponentsPage.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import type { Uuid } from '~/types/Uuid.mjs';
import type Environment from '~/domain/Environment.mjs';
import Component from '~/domain/Component.mjs';
import SolutionRepository from '~/data/SolutionRepository.mjs';
import EnvironmentRepository from '~/data/EnvironmentRepository.mjs';
import ComponentRepository from '~/data/ComponentRepository.mjs';
import Page from '~/presentation/pages/Page.mjs';
import { DataTable } from '~/presentation/components/DataTable.mjs';
import html from '~/presentation/lib/html.mjs';

const { p } = html;

export default class ComponentsPage extends Page {
static override route = '/:solution/environment/components';
static {
customElements.define('x-page-components', this);
}

#solutionRepository = new SolutionRepository(localStorage);
#environmentRepository = new EnvironmentRepository(localStorage);
#componentRepository = new ComponentRepository(localStorage);
#environment?: Environment;

constructor() {
super({ title: 'Components' }, []);

const dataTable = new DataTable<Component>({
columns: {
id: { headerText: 'ID', readonly: true, formType: 'hidden', unique: true },
name: { headerText: 'Name', required: true, formType: 'text', unique: true },
description: { headerText: 'Description', formType: 'text' },
interfaceDefinition: { headerText: 'Interface Definition', formType: 'textarea' }
},
select: async () => {
if (!this.#environment)
return [];

return await this.#componentRepository.getAll(t => this.#environment!.componentIds.includes(t.id));
},
onCreate: async item => {
const component = new Component({
id: self.crypto.randomUUID(),
name: item.name,
description: item.description,
statement: item.interfaceDefinition
});
this.#environment!.componentIds.push(component.id);
await Promise.all([
this.#componentRepository.add(component),
this.#environmentRepository.update(this.#environment!)
]);
},
onUpdate: async item => {
await this.#componentRepository.update(new Component({
...item
}));
},
onDelete: async id => {
this.#environment!.componentIds = this.#environment!.componentIds.filter(x => x !== id);
await Promise.all([
this.#componentRepository.delete(id),
this.#environmentRepository.update(this.#environment!)
]);
}
});

this.append(
p(`
Components are self-contained elements in the Environment that provide
an interface which can be used by a System to interact with.
`),
dataTable
);

this.#environmentRepository.addEventListener('update', () => dataTable.renderData());
this.#componentRepository.addEventListener('update', () => dataTable.renderData());
const solutionId = this.urlParams['solution'] as Uuid;
this.#solutionRepository.getBySlug(solutionId).then(solution => {
this.#environmentRepository.get(solution!.environmentId).then(environment => {
this.#environment = environment;
dataTable.renderData();
});
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ export default class EnvironmentsIndexPage extends Page {
icon: 'anchor',
href: `${location.pathname}/constraints`
}),
new MiniCard({
title: 'Components',
icon: 'grid',
href: `${location.pathname}/components`
}),
new MiniCard({
title: 'Invariants',
icon: 'lock',
Expand Down

0 comments on commit 22114ee

Please sign in to comment.