From 4746d5e671a50fb900ff8c9252c26cca72278dc0 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Wed, 30 Aug 2023 02:12:23 +0200 Subject: feat(frontend): projection dialog --- subprojects/frontend/src/graph/GraphStore.ts | 146 ++++++++++++++++++++++++--- 1 file changed, 130 insertions(+), 16 deletions(-) (limited to 'subprojects/frontend/src/graph/GraphStore.ts') diff --git a/subprojects/frontend/src/graph/GraphStore.ts b/subprojects/frontend/src/graph/GraphStore.ts index b59bfb7d..f81b4db4 100644 --- a/subprojects/frontend/src/graph/GraphStore.ts +++ b/subprojects/frontend/src/graph/GraphStore.ts @@ -6,10 +6,48 @@ import { makeAutoObservable, observable } from 'mobx'; -import type { SemanticsSuccessResult } from '../xtext/xtextServiceResults'; +import type { + RelationMetadata, + SemanticsSuccessResult, +} from '../xtext/xtextServiceResults'; export type Visibility = 'all' | 'must' | 'none'; +export function getDefaultVisibility( + metadata: RelationMetadata | undefined, +): Visibility { + if (metadata === undefined || metadata.arity <= 0 || metadata.arity > 2) { + return 'none'; + } + const { detail } = metadata; + switch (detail.type) { + case 'class': + case 'reference': + case 'opposite': + return 'all'; + case 'predicate': + return detail.error ? 'must' : 'none'; + default: + return 'none'; + } +} + +export function isVisibilityAllowed( + metadata: RelationMetadata | undefined, + visibility: Visibility, +): boolean { + if (metadata === undefined || metadata.arity <= 0 || metadata.arity > 2) { + return visibility === 'none'; + } + const { detail } = metadata; + if (detail.type === 'predicate' && detail.error) { + // We can't display may matches of error predicates, + // because they have none by definition. + return visibility !== 'all'; + } + return true; +} + export default class GraphStore { semantics: SemanticsSuccessResult = { nodes: [], @@ -17,35 +55,111 @@ export default class GraphStore { partialInterpretation: {}, }; + relationMetadata = new Map(); + visibility = new Map(); + abbreviate = true; + constructor() { makeAutoObservable(this, { semantics: observable.ref, }); } - getVisiblity(relation: string): Visibility { - return this.visibility.get(relation) ?? 'none'; + getVisibility(relation: string): Visibility { + const visibilityOverride = this.visibility.get(relation); + if (visibilityOverride !== undefined) { + return visibilityOverride; + } + return this.getDefaultVisibility(relation); + } + + getDefaultVisibility(relation: string): Visibility { + const metadata = this.relationMetadata.get(relation); + return getDefaultVisibility(metadata); + } + + isVisibilityAllowed(relation: string, visibility: Visibility): boolean { + const metadata = this.relationMetadata.get(relation); + return isVisibilityAllowed(metadata, visibility); + } + + setVisibility(relation: string, visibility: Visibility): void { + const metadata = this.relationMetadata.get(relation); + if (metadata === undefined || !isVisibilityAllowed(metadata, visibility)) { + return; + } + const defaultVisiblity = getDefaultVisibility(metadata); + if (defaultVisiblity === visibility) { + this.visibility.delete(relation); + } else { + this.visibility.set(relation, visibility); + } + } + + cycleVisibility(relation: string): void { + const metadata = this.relationMetadata.get(relation); + if (metadata === undefined) { + return; + } + switch (this.getVisibility(relation)) { + case 'none': + if (isVisibilityAllowed(metadata, 'must')) { + this.setVisibility(relation, 'must'); + } + break; + case 'must': + { + const next = isVisibilityAllowed(metadata, 'all') ? 'all' : 'none'; + this.setVisibility(relation, next); + } + break; + default: + this.setVisibility(relation, 'none'); + break; + } + } + + hideAll(): void { + this.relationMetadata.forEach((metadata, name) => { + if (getDefaultVisibility(metadata) === 'none') { + this.visibility.delete(name); + } else { + this.visibility.set(name, 'none'); + } + }); + } + + resetFilter(): void { + this.visibility.clear(); + } + + getName({ name, simpleName }: { name: string; simpleName: string }): string { + return this.abbreviate ? simpleName : name; + } + + toggleAbbrevaite(): void { + this.abbreviate = !this.abbreviate; } setSemantics(semantics: SemanticsSuccessResult) { this.semantics = semantics; - this.visibility.clear(); - const names = new Set(); - this.semantics.relations.forEach(({ name, detail }) => { - names.add(name); - if (!this.visibility.has(name)) { - const newVisibility = detail.type === 'builtin' ? 'none' : 'all'; - this.visibility.set(name, newVisibility); - } + this.relationMetadata.clear(); + this.semantics.relations.forEach((metadata) => { + this.relationMetadata.set(metadata.name, metadata); }); - const oldNames = new Set(); - this.visibility.forEach((_, key) => oldNames.add(key)); - oldNames.forEach((key) => { - if (!names.has(key)) { - this.visibility.delete(key); + const toRemove = new Set(); + this.visibility.forEach((value, key) => { + if ( + !this.isVisibilityAllowed(key, value) || + this.getDefaultVisibility(key) === value + ) { + toRemove.add(key); } }); + toRemove.forEach((key) => { + this.visibility.delete(key); + }); } } -- cgit v1.2.3-70-g09d2