added support for grouping
This commit is contained in:
@@ -50,9 +50,6 @@ export default class CardList extends StatefulVue {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
font-family: $main-font;
|
||||
.card {
|
||||
|
||||
}
|
||||
}
|
||||
.error {
|
||||
width: 100%;
|
||||
|
||||
@@ -12,19 +12,19 @@
|
||||
</div>
|
||||
<div class="card__expander" v-on:click.stop>
|
||||
<font-awesome-icon :icon="['fas', 'times']" class="close-button" v-on:click="onSelected(false)"/>
|
||||
<CardListItemScripts :categoryId="categoryId"></CardListItemScripts>
|
||||
<ScriptsTree :categoryId="categoryId"></ScriptsTree>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue, Watch, Emit } from 'vue-property-decorator';
|
||||
import CardListItemScripts from './CardListItemScripts.vue';
|
||||
import ScriptsTree from '@/presentation/Scripts/ScriptsTree/ScriptsTree.vue';
|
||||
import { StatefulVue } from '@/presentation/StatefulVue';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
CardListItemScripts,
|
||||
ScriptsTree,
|
||||
},
|
||||
})
|
||||
export default class CardListItem extends StatefulVue {
|
||||
@@ -124,10 +124,6 @@ export default class CardListItem extends StatefulVue {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
text-transform: uppercase;
|
||||
color: $light-gray;
|
||||
font-size: 1.5em;
|
||||
|
||||
.close-button {
|
||||
font-size: 0.75em;
|
||||
position: absolute;
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
<template>
|
||||
<span>
|
||||
<span v-if="nodes != null && nodes.length > 0">
|
||||
<SelectableTree
|
||||
:nodes="nodes"
|
||||
:selectedNodeIds="selectedNodeIds"
|
||||
:filterPredicate="filterPredicate"
|
||||
:filterText="filterText"
|
||||
v-on:nodeSelected="checkNodeAsync($event)">
|
||||
</SelectableTree>
|
||||
</span>
|
||||
<span v-else>Nooo 😢</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
|
||||
import { StatefulVue } from '@/presentation/StatefulVue';
|
||||
import { Category } from '@/domain/Category';
|
||||
import { IRepository } from '@/infrastructure/Repository/IRepository';
|
||||
import { IScript } from '@/domain/IScript';
|
||||
import { IApplicationState, IUserSelection } from '@/application/State/IApplicationState';
|
||||
import { IFilterMatches } from '@/application/State/Filter/IFilterMatches';
|
||||
import { ScriptNodeParser } from './ScriptNodeParser';
|
||||
import SelectableTree, { FilterPredicate } from './../SelectableTree/SelectableTree.vue';
|
||||
import { INode } from './../SelectableTree/INode';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
SelectableTree,
|
||||
},
|
||||
})
|
||||
export default class CardListItemScripts extends StatefulVue {
|
||||
@Prop() public categoryId!: number;
|
||||
|
||||
public nodes?: INode[] = null;
|
||||
public selectedNodeIds?: string[] = null;
|
||||
public filterText?: string = null;
|
||||
|
||||
private matches?: IFilterMatches;
|
||||
|
||||
public async mounted() {
|
||||
// React to state changes
|
||||
const state = await this.getCurrentStateAsync();
|
||||
this.reactToChanges(state);
|
||||
// Update initial state
|
||||
await this.updateNodesAsync(this.categoryId);
|
||||
}
|
||||
|
||||
public async checkNodeAsync(node: INode) {
|
||||
if (node.children != null && node.children.length > 0) {
|
||||
return; // only interested in script nodes
|
||||
}
|
||||
const state = await this.getCurrentStateAsync();
|
||||
if (node.selected) {
|
||||
state.selection.addSelectedScript(node.id);
|
||||
} else {
|
||||
state.selection.removeSelectedScript(node.id);
|
||||
}
|
||||
}
|
||||
|
||||
@Watch('categoryId')
|
||||
public async updateNodesAsync(categoryId: |number) {
|
||||
this.nodes = categoryId ?
|
||||
await ScriptNodeParser.parseNodes(categoryId, await this.getCurrentStateAsync())
|
||||
: undefined;
|
||||
}
|
||||
|
||||
public filterPredicate(node: INode): boolean {
|
||||
return this.matches.scriptMatches.some((script: IScript) => script.id === node.id);
|
||||
}
|
||||
|
||||
private reactToChanges(state: IApplicationState) {
|
||||
// Update selection data
|
||||
const updateNodeSelection = (node: INode, selectedScripts: ReadonlyArray<IScript>): INode => {
|
||||
return {
|
||||
id: node.id,
|
||||
text: node.text,
|
||||
selected: selectedScripts.some((script) => script.id === node.id),
|
||||
children: node.children ? node.children.map((child) => updateNodeSelection(child, selectedScripts)) : [],
|
||||
documentationUrls: node.documentationUrls,
|
||||
};
|
||||
};
|
||||
state.selection.changed.on(
|
||||
(selectedScripts: ReadonlyArray<IScript>) =>
|
||||
this.nodes = this.nodes.map((node: INode) => updateNodeSelection(node, selectedScripts)),
|
||||
);
|
||||
// Update search / filter data
|
||||
state.filter.filterRemoved.on(() =>
|
||||
this.filterText = '');
|
||||
state.filter.filtered.on((matches: IFilterMatches) => {
|
||||
this.filterText = matches.query;
|
||||
this.matches = matches;
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
@@ -1,43 +0,0 @@
|
||||
import { ICategory } from './../../../domain/ICategory';
|
||||
import { IApplicationState, IUserSelection } from '@/application/State/IApplicationState';
|
||||
import { INode } from './../SelectableTree/INode';
|
||||
|
||||
export class ScriptNodeParser {
|
||||
public static parseNodes(categoryId: number, state: IApplicationState): INode[] | undefined {
|
||||
const category = state.app.findCategory(categoryId);
|
||||
if (!category) {
|
||||
throw new Error(`Category with id ${categoryId} does not exist`);
|
||||
}
|
||||
const tree = this.parseNodesRecursively(category, state.selection);
|
||||
return tree;
|
||||
}
|
||||
|
||||
private static parseNodesRecursively(parentCategory: ICategory, selection: IUserSelection): INode[] {
|
||||
const nodes = new Array<INode>();
|
||||
if (parentCategory.subCategories && parentCategory.subCategories.length > 0) {
|
||||
for (const subCategory of parentCategory.subCategories) {
|
||||
const subCategoryNodes = this.parseNodesRecursively(subCategory, selection);
|
||||
nodes.push(
|
||||
{
|
||||
id: `cat${subCategory.id}`,
|
||||
text: subCategory.name,
|
||||
selected: false,
|
||||
children: subCategoryNodes,
|
||||
documentationUrls: subCategory.documentationUrls,
|
||||
});
|
||||
}
|
||||
}
|
||||
if (parentCategory.scripts && parentCategory.scripts.length > 0) {
|
||||
for (const script of parentCategory.scripts) {
|
||||
nodes.push( {
|
||||
id: script.id,
|
||||
text: script.name,
|
||||
selected: selection.isSelected(script),
|
||||
children: undefined,
|
||||
documentationUrls: script.documentationUrls,
|
||||
});
|
||||
}
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user