Browse Source

Fix schema filtering.

pull/786/head
Sebastian 4 years ago
parent
commit
20574d0b6d
  1. 3
      frontend/app/features/content/pages/schemas/schemas-page.component.html
  2. 1
      frontend/app/features/schemas/pages/schema/schema-page.component.scss
  3. 4
      frontend/app/features/schemas/pages/schemas/schemas-page.component.scss
  4. 19
      frontend/app/shared/components/schema-category.component.html
  5. 35
      frontend/app/shared/components/schema-category.component.scss
  6. 16
      frontend/app/shared/components/schema-category.component.ts
  7. 7
      frontend/app/shared/services/schemas.service.spec.ts
  8. 333
      frontend/app/shared/state/schemas.state.spec.ts
  9. 94
      frontend/app/shared/state/schemas.state.ts
  10. 2
      frontend/app/theme/_panels2.scss

3
frontend/app/features/content/pages/schemas/schemas-page.component.html

@ -20,7 +20,8 @@
<ng-container>
<sqx-schema-category *ngFor="let category of categories | async; trackBy: trackByCategory"
[schemaCategory]="category" [forContent]="true">
[schemaCategory]="category"
[schemaTarget]="'Contents'">
</sqx-schema-category>
</ng-container>
</ng-container>

1
frontend/app/features/schemas/pages/schema/schema-page.component.scss

@ -6,6 +6,7 @@
}
.cards {
overflow-x: hidden;
overflow-y: auto;
padding: $panel-padding;
}

4
frontend/app/features/schemas/pages/schemas/schemas-page.component.scss

@ -1,4 +0,0 @@
::ng-deep sqx-schemas-page .panel2-main-inner.padded {
padding: .5rem;
padding-left: 0;
}

19
frontend/app/shared/components/schema-category.component.html

@ -1,6 +1,5 @@
<ul [hidden]="forContent && visibleCount == 0" id="cat_{{schemaCategory.name}}" class="nav nav-light flex-column">
<div class="droppable category"
<ul [hidden]="forContent && schemaCategory.countSchemasInSubtree === 0" class="nav nav-light flex-column">
<div class="droppable nav-category"
cdkDropList
cdkDropListSortingDisabled
[cdkDropListData]="schemaCategory.name"
@ -19,8 +18,8 @@
</div>
</div>
<div class="col-auto">
<ng-container *ngIf="visibleCount > 0; else noSchemas">
<span class="badge rounded-pill badge-secondary">{{visibleCount}}</span>
<ng-container *ngIf="schemaCategory.countSchemasInSubtree > 0; else noSchemas">
<span class="badge rounded-pill badge-secondary">{{schemaCategory.countSchemasInSubtreeFiltered}}</span>
</ng-container>
<ng-template #noSchemas>
<button type="button" class="btn btn-sm btn-text-secondary btn-remove" (click)="remove.emit(schemaCategory.name)" *ngIf="schemaCategory.name">
@ -31,7 +30,7 @@
</div>
</li>
<div [hidden]="isCollapsed" @fade [style.height]="getContainerHeight()" class="nav-collapsed">
<div [hidden]="isCollapsed" [style.height]="getContainerHeight()" class="nav-collapsed">
<ng-container *ngIf="!forContent; else simpleMode">
<li *ngFor="let schema of schemas; trackBy: trackBySchema" class="nav-item truncate" [style.height]="getItemHeight()"
cdkDrag
@ -52,8 +51,7 @@
<li *ngFor="let schema of schemas; trackBy: trackBySchema" class="nav-item truncate">
<a class="nav-link truncate drag-none" [routerLink]="schemaRoute(schema)" routerLinkActive="active" sqxStopDrag
title="{{schema.displayName}}"
titlePosition="top-left"
id="schema_{{schema.name}}">
titlePosition="top-left">
{{schema.displayName}}
</a>
</li>
@ -61,13 +59,12 @@
</div>
<div class="drop-indicator"></div>
</div>
<div class="nav nav-panel nav-dark nav-dark-bordered flex-column" [hidden]="isCollapsed" @fade>
<div class="categories" [hidden]="isCollapsed">
<sqx-schema-category *ngFor="let category of schemaCategory.categories; trackBy: trackByCategory"
[schemaCategory]="category"
[forContent]="forContent"
[schemaTarget]="schemaTarget"
(remove)="remove.emit($event)">
</sqx-schema-category>
</div>

35
frontend/app/shared/components/schema-category.component.scss

@ -74,26 +74,31 @@ $drag-margin: -8px;
}
}
:host {
&:first-child {
.nav-light {
margin-top: 0;
}
}
}
.item-published {
margin-bottom: 1px;
}
ul.nav-light {
margin-left: 1rem;
margin-right: 0;
font-size: 100%;
}
.category,
.nav-category,
.nav-panel,
sqx-schema-category {
max-width: 100%;
}
.categories {
padding: 0;
padding-left: 1rem;
font-size: 1rem;
.nav-light {
margin-left: 0;
margin-right: 0;
}
}
:host {
&:first-child {
.nav-light {
margin-top: 0;
}
}
}

16
frontend/app/shared/components/schema-category.component.ts

@ -28,14 +28,16 @@ export class SchemaCategoryComponent implements OnChanges {
public schemaCategory: SchemaCategory;
@Input()
public forContent?: boolean | null;
public schemaTarget?: 'Schema' | 'Contents';
public isCollapsed = false;
public visibleCount = 0;
public get forContent() {
return this.schemaTarget === 'Contents';
}
public get schemas() {
return this.schemaCategory.schemas;
return this.schemaCategory.schemasFiltered;
}
constructor(
@ -51,19 +53,13 @@ export class SchemaCategoryComponent implements OnChanges {
}
public ngOnChanges() {
this.visibleCount = this.getCount(this.schemaCategory);
if (this.schemaCategory.schemas.length < this.schemaCategory.schemaTotalCount) {
if (this.schemaCategory.countSchemasInSubtreeFiltered < this.schemaCategory.countSchemasInSubtree) {
this.isCollapsed = false;
} else {
this.isCollapsed = this.localStore.getBoolean(this.configKey());
}
}
private getCount(category: SchemaCategory): number {
const childCount = category.categories.reduce((total, child) => total + this.getCount(child), 0);
return childCount + category.schemas.length;
}
public schemaRoute(schema: SchemaDto) {
if (schema.type === 'Singleton' && this.forContent) {
return [schema.name, schema.id, 'history'];

7
frontend/app/shared/services/schemas.service.spec.ts

@ -818,15 +818,12 @@ function createSchemaProperties(id: number, suffix = '') {
);
}
export function createSchema(id: number, suffix = '', category = '') {
export function createSchema(id: number, suffix = '') {
const links: ResourceLinks = {
update: { method: 'PUT', href: `/schemas/${id}` },
};
const key = `${id}${suffix}`;
if (category === '') {
category = `schema-category${key}`;
}
return new SchemaDto(links,
`id${id}`,
@ -834,7 +831,7 @@ export function createSchema(id: number, suffix = '', category = '') {
DateTime.parseISO(`${id % 1000 + 2000}-11-11T10:10:00Z`), `modifier${id}`,
new Version(key),
`schema-name${key}`,
category,
`schema-category${key}`,
id % 2 === 0 ? 'Default' : 'Singleton',
id % 3 === 0,
createSchemaProperties(id, suffix),

333
frontend/app/shared/state/schemas.state.spec.ts

@ -494,14 +494,74 @@ describe('SchemasState', () => {
});
describe('Categories', () => {
it('should be build from schemas', () => {
it('should be build from schemas with undefined categories', () => {
const schemaDefault = createSchema(6);
const schemaComponent = createSchema(7);
(schemaDefault as any)['category'] = '';
(schemaComponent as any)['category'] = '';
(schemaComponent as any)['type'] = 'Component';
const result = getCategoryTree([schemaDefault, schemaComponent], new Set<string>());
expect(result).toEqual([
{
displayName: 'i18n:common.components',
schemas: [schemaComponent],
schemasFiltered: [schemaComponent],
countSchemasInSubtree: 1,
countSchemasInSubtreeFiltered: 1,
categories: [],
},
{
displayName: 'i18n:common.schemas',
schemas: [schemaDefault],
schemasFiltered: [schemaDefault],
countSchemasInSubtree: 1,
countSchemasInSubtreeFiltered: 1,
categories: [],
},
]);
});
it('should be build from schemas with defined categories', () => {
const result = getCategoryTree([schema1, schema2], new Set<string>());
expect(result).toEqual([
{ displayName: 'i18n:common.components', schemas: [], schemaTotalCount: 0, categories: [] },
{ displayName: 'i18n:common.schemas', schemas: [], schemaTotalCount: 0, categories: [] },
{ displayName: 'schema-category1', name: 'schema-category1', schemas: [schema1], schemaTotalCount: 1, categories: [] },
{ displayName: 'schema-category2', name: 'schema-category2', schemas: [schema2], schemaTotalCount: 1, categories: [] },
{
displayName: 'i18n:common.components',
schemas: [],
schemasFiltered: [],
countSchemasInSubtree: 0,
countSchemasInSubtreeFiltered: 0,
categories: [],
},
{
displayName: 'i18n:common.schemas',
schemas: [],
schemasFiltered: [],
countSchemasInSubtree: 0,
countSchemasInSubtreeFiltered: 0,
categories: [],
},
{
displayName: 'schema-category1',
name: 'schema-category1',
schemas: [schema1],
schemasFiltered: [schema1],
countSchemasInSubtree: 1,
countSchemasInSubtreeFiltered: 1,
categories: [],
},
{
displayName: 'schema-category2',
name: 'schema-category2',
schemas: [schema2],
schemasFiltered: [schema2],
countSchemasInSubtree: 1,
countSchemasInSubtreeFiltered: 1,
categories: [],
},
]);
});
@ -509,11 +569,49 @@ describe('SchemasState', () => {
const result = getCategoryTree([schema1, schema2], new Set<string>(['schema-category3']));
expect(result).toEqual([
{ displayName: 'i18n:common.components', schemas: [], schemaTotalCount: 0, categories: [] },
{ displayName: 'i18n:common.schemas', schemas: [], schemaTotalCount: 0, categories: [] },
{ displayName: 'schema-category1', name: 'schema-category1', schemas: [schema1], schemaTotalCount: 1, categories: [] },
{ displayName: 'schema-category2', name: 'schema-category2', schemas: [schema2], schemaTotalCount: 1, categories: [] },
{ displayName: 'schema-category3', name: 'schema-category3', schemas: [], schemaTotalCount: 0, categories: [] },
{
displayName: 'i18n:common.components',
schemas: [],
schemasFiltered: [],
countSchemasInSubtree: 0,
countSchemasInSubtreeFiltered: 0,
categories: [],
},
{
displayName: 'i18n:common.schemas',
schemas: [],
schemasFiltered: [],
countSchemasInSubtree: 0,
countSchemasInSubtreeFiltered: 0,
categories: [],
},
{
displayName: 'schema-category1',
name: 'schema-category1',
schemas: [schema1],
schemasFiltered: [schema1],
countSchemasInSubtree: 1,
countSchemasInSubtreeFiltered: 1,
categories: [],
},
{
displayName: 'schema-category2',
name: 'schema-category2',
schemas: [schema2],
schemasFiltered: [schema2],
countSchemasInSubtree: 1,
countSchemasInSubtreeFiltered: 1,
categories: [],
},
{
displayName: 'schema-category3',
name: 'schema-category3',
schemas: [],
schemasFiltered: [],
countSchemasInSubtree: 0,
countSchemasInSubtreeFiltered: 0,
categories: [],
},
]);
});
@ -521,24 +619,100 @@ describe('SchemasState', () => {
const result = getCategoryTree([schema1, schema2], new Set<string>(), '1');
expect(result).toEqual([
{ displayName: 'i18n:common.components', schemas: [], schemaTotalCount: 0, categories: [] },
{ displayName: 'i18n:common.schemas', schemas: [], schemaTotalCount: 0, categories: [] },
{ displayName: 'schema-category1', name: 'schema-category1', schemas: [schema1], schemaTotalCount: 1, categories: [] },
{ displayName: 'schema-category2', name: 'schema-category2', schemas: [], schemaTotalCount: 1, categories: [] }, // Filtered out
{
displayName: 'i18n:common.components',
schemas: [],
schemasFiltered: [],
countSchemasInSubtree: 0,
countSchemasInSubtreeFiltered: 0,
categories: [],
},
{
displayName: 'i18n:common.schemas',
schemas: [],
schemasFiltered: [],
countSchemasInSubtree: 0,
countSchemasInSubtreeFiltered: 0,
categories: [],
},
{
displayName: 'schema-category1',
name: 'schema-category1',
schemas: [schema1],
schemasFiltered: [schema1],
countSchemasInSubtree: 1,
countSchemasInSubtreeFiltered: 1,
categories: [],
},
{
displayName: 'schema-category2',
name: 'schema-category2',
schemas: [schema2],
schemasFiltered: [],
countSchemasInSubtree: 1,
countSchemasInSubtreeFiltered: 0,
categories: [],
},
]);
});
it('should be build from schemas with nested categories', () => {
const schema3 = createSchema(3, '', 'A');
const schema4 = createSchema(4, '', 'A/B');
const result = getCategoryTree([schema1, schema2, schema3, schema4], new Set<string>());
const schemaA = createSchema(3);
const schemaAB = createSchema(4);
(schemaA as any)['category'] = 'A';
(schemaAB as any)['category'] = 'A/B';
const result = getCategoryTree([schema1, schema2, schemaA, schemaAB], new Set<string>());
expect(result).toEqual([
{ displayName: 'i18n:common.components', schemas: [], schemaTotalCount: 0, categories: [] },
{ displayName: 'i18n:common.schemas', schemas: [], schemaTotalCount: 0, categories: [] },
{ displayName: 'A', name: 'A', schemas: [schema3], schemaTotalCount: 2, categories: [{ displayName: 'B', name: 'A/B', schemas: [schema4], schemaTotalCount: 1, categories: [] }] },
{ displayName: 'schema-category1', name: 'schema-category1', schemas: [schema1], schemaTotalCount: 1, categories: [] },
{ displayName: 'schema-category2', name: 'schema-category2', schemas: [schema2], schemaTotalCount: 1, categories: [] },
{
displayName: 'i18n:common.components',
schemas: [],
schemasFiltered: [],
countSchemasInSubtree: 0,
countSchemasInSubtreeFiltered: 0,
categories: [],
}, {
displayName: 'i18n:common.schemas',
schemas: [],
schemasFiltered: [],
countSchemasInSubtree: 0,
countSchemasInSubtreeFiltered: 0,
categories: [],
}, {
displayName: 'A',
name: 'A',
schemas: [schemaA],
schemasFiltered: [schemaA],
countSchemasInSubtree: 2,
countSchemasInSubtreeFiltered: 2,
categories: [{
displayName: 'B',
name: 'A/B',
schemas: [schemaAB],
schemasFiltered: [schemaAB],
countSchemasInSubtree: 1,
countSchemasInSubtreeFiltered: 1,
categories: [],
}],
}, {
displayName: 'schema-category1',
name: 'schema-category1',
schemas: [schema1],
schemasFiltered: [schema1],
countSchemasInSubtree: 1,
countSchemasInSubtreeFiltered: 1,
categories: [],
}, {
displayName: 'schema-category2',
name: 'schema-category2',
schemas: [schema2],
schemasFiltered: [schema2],
countSchemasInSubtree: 1,
countSchemasInSubtreeFiltered: 1,
categories: [],
},
]);
});
@ -546,26 +720,115 @@ describe('SchemasState', () => {
const result = getCategoryTree([schema1, schema2], new Set<string>(['A/B']));
expect(result).toEqual([
{ displayName: 'i18n:common.components', schemas: [], schemaTotalCount: 0, categories: [] },
{ displayName: 'i18n:common.schemas', schemas: [], schemaTotalCount: 0, categories: [] },
{ displayName: 'A', name: 'A', schemas: [], schemaTotalCount: 0, categories: [{ displayName: 'B', name: 'A/B', schemas: [], schemaTotalCount: 0, categories: [] }] },
{ displayName: 'schema-category1', name: 'schema-category1', schemas: [schema1], schemaTotalCount: 1, categories: [] },
{ displayName: 'schema-category2', name: 'schema-category2', schemas: [schema2], schemaTotalCount: 1, categories: [] },
{
displayName: 'i18n:common.components',
schemas: [],
schemasFiltered: [],
countSchemasInSubtree: 0,
countSchemasInSubtreeFiltered: 0,
categories: [],
}, {
displayName: 'i18n:common.schemas',
schemas: [],
schemasFiltered: [],
countSchemasInSubtree: 0,
countSchemasInSubtreeFiltered: 0,
categories: [],
}, {
displayName: 'A',
name: 'A',
schemas: [],
schemasFiltered: [],
countSchemasInSubtree: 0,
countSchemasInSubtreeFiltered: 0,
categories: [{
displayName: 'B',
name: 'A/B',
schemas: [],
schemasFiltered: [],
countSchemasInSubtree: 0,
countSchemasInSubtreeFiltered: 0,
categories: [],
}],
}, {
displayName: 'schema-category1',
name: 'schema-category1',
schemas: [schema1],
schemasFiltered: [schema1],
countSchemasInSubtree: 1,
countSchemasInSubtreeFiltered: 1,
categories: [],
}, {
displayName: 'schema-category2',
name: 'schema-category2',
schemas: [schema2],
schemasFiltered: [schema2],
countSchemasInSubtree: 1,
countSchemasInSubtreeFiltered: 1,
categories: [],
},
]);
});
});
it('should be build from schemas with nested categories and filter', () => {
const schema3 = createSchema(3, '', 'A');
const schema4 = createSchema(4, '', 'A/B');
const result = getCategoryTree([schema1, schema2, schema3, schema4], new Set<string>(), '4');
const schemaA = createSchema(3);
const schemaAB = createSchema(4);
(schemaA as any)['category'] = 'A';
(schemaAB as any)['category'] = 'A/B';
const result = getCategoryTree([schema1, schema2, schemaA, schemaAB], new Set<string>(), '4');
expect(result).toEqual([
{ displayName: 'i18n:common.components', schemas: [], schemaTotalCount: 0, categories: [] },
{ displayName: 'i18n:common.schemas', schemas: [], schemaTotalCount: 0, categories: [] },
{ displayName: 'A', name: 'A', schemas: [], schemaTotalCount: 2, categories: [{ displayName: 'B', name: 'A/B', schemas: [schema4], schemaTotalCount: 1, categories: [] }] },
{ displayName: 'schema-category1', name: 'schema-category1', schemas: [], schemaTotalCount: 1, categories: [] },
{ displayName: 'schema-category2', name: 'schema-category2', schemas: [], schemaTotalCount: 1, categories: [] },
{
displayName: 'i18n:common.components',
schemas: [],
schemasFiltered: [],
countSchemasInSubtree: 0,
countSchemasInSubtreeFiltered: 0,
categories: [],
}, {
displayName: 'i18n:common.schemas',
schemas: [],
schemasFiltered: [],
countSchemasInSubtree: 0,
countSchemasInSubtreeFiltered: 0,
categories: [],
},
{
displayName: 'A',
name: 'A',
schemas: [schemaA],
schemasFiltered: [],
countSchemasInSubtree: 2,
countSchemasInSubtreeFiltered: 1,
categories: [{
displayName: 'B',
name: 'A/B',
schemas: [schemaAB],
schemasFiltered: [schemaAB],
countSchemasInSubtree: 1,
countSchemasInSubtreeFiltered: 1,
categories: [],
}],
}, {
displayName: 'schema-category1',
name: 'schema-category1',
schemas: [schema1],
schemasFiltered: [],
countSchemasInSubtree: 1,
countSchemasInSubtreeFiltered: 0,
categories: [],
}, {
displayName: 'schema-category2',
name: 'schema-category2',
schemas: [schema2],
schemasFiltered: [],
countSchemasInSubtree: 1,
countSchemasInSubtreeFiltered: 0,
categories: [],
},
]);
});
});

94
frontend/app/shared/state/schemas.state.ts

@ -367,7 +367,9 @@ export type SchemaCategory = {
displayName: string;
name?: string;
schemas: SchemaDto[];
schemaTotalCount: number;
schemasFiltered: SchemaDto[];
countSchemasInSubtree: number;
countSchemasInSubtreeFiltered: number;
categories: SchemaCategory[];
};
@ -394,52 +396,72 @@ export function getCategoryTree(allSchemas: ReadonlyArray<SchemaDto>, categories
const schemas: SchemaCategory = {
displayName: SPECIAL_SCHEMAS,
schemas: [],
schemaTotalCount: 0,
schemasFiltered: [],
countSchemasInSubtree: 0,
countSchemasInSubtreeFiltered: 0,
categories: [],
};
const components: SchemaCategory = {
displayName: SPECIAL_COMPONENTS,
schemas: [],
schemaTotalCount: 0,
schemasFiltered: [],
countSchemasInSubtree: 0,
countSchemasInSubtreeFiltered: 0,
categories: [],
};
const flatCategoryList: SchemaCategory[] = [schemas, components];
const categoryCache: { [name: string]: SchemaCategory } = {};
const categoryRoots: SchemaCategory[] = [];
// Sort the categories so that components and schemas stay top.
for (const name of categories) {
getOrCreateCategory(name);
}
function addSchemaToCategory(schema: SchemaDto, category: SchemaCategory) {
category.schemaTotalCount++;
category.schemas.push(schema);
if (match(schema)) {
category.schemas.push(schema);
category.schemasFiltered.push(schema);
}
}
function getOrCreateCategory(name: string): SchemaCategory {
let category = flatCategoryList.find(x => x.name === name);
let category = categoryCache[name];
if (category) {
return category;
}
const displayName = (name.indexOf(NESTED_CATEGORY_SEPARATOR) === -1) ? name : name.substr(name.lastIndexOf(NESTED_CATEGORY_SEPARATOR) + 1);
let displayName = name;
const lastSeparatorIndex = name.lastIndexOf(NESTED_CATEGORY_SEPARATOR);
if (lastSeparatorIndex >= 0) {
displayName = displayName.substr(lastSeparatorIndex + 1);
}
if (!category) {
category = {
displayName,
name,
schemas: [],
schemaTotalCount: 0,
schemasFiltered: [],
countSchemasInSubtree: 0,
countSchemasInSubtreeFiltered: 0,
categories: [],
};
flatCategoryList.push(category);
categoryCache[name] = category;
if (name.indexOf(NESTED_CATEGORY_SEPARATOR) !== -1) {
if (lastSeparatorIndex >= 0) {
// Recurse back creating all the parents of this category
const parentName = name.substr(0, name.lastIndexOf(NESTED_CATEGORY_SEPARATOR));
getOrCreateCategory(parentName);
}
const parentName = name.substr(0, lastSeparatorIndex);
const parentCategory = getOrCreateCategory(parentName);
parentCategory.categories.push(category);
} else {
categoryRoots.push(category);
}
return category;
@ -449,8 +471,7 @@ export function getCategoryTree(allSchemas: ReadonlyArray<SchemaDto>, categories
const name = schema.category;
if (name) {
const category = getOrCreateCategory(name);
addSchemaToCategory(schema, category);
addSchemaToCategory(schema, getOrCreateCategory(name));
} else if (schema.type === 'Component') {
addSchemaToCategory(schema, components);
} else {
@ -458,28 +479,29 @@ export function getCategoryTree(allSchemas: ReadonlyArray<SchemaDto>, categories
}
}
// Sort by name and than DisplayName so that children get correctly sorted under their parents but component and schema still sort correctly
flatCategoryList.sortByString(x => `${x.name ?? ''} - ${x.displayName}`);
function update(category: SchemaCategory) {
category.countSchemasInSubtree = category.schemas.length;
category.countSchemasInSubtreeFiltered = category.schemasFiltered.length;
const result: SchemaCategory[] = [];
// Child categories by necessity come after their parents alphabetically so processing in reverse lets us roll up all categories into their parents nicely.
// Because we're processing in reverse we unshift rather than push to the results array to get everything in the right order at the end.
for (const category of flatCategoryList.reverse()) {
if (category.name) {
if (category.name?.indexOf(NESTED_CATEGORY_SEPARATOR) !== -1) {
const parentName = category.name?.substr(0, category.name.lastIndexOf(NESTED_CATEGORY_SEPARATOR));
const parentCategory = flatCategoryList.find(x => x.name === parentName);
if (parentCategory) {
parentCategory.categories.unshift(category);
parentCategory.schemaTotalCount += category.schemaTotalCount;
}
} else {
result.unshift(category);
// Add up the total count of the whole tree.
for (const child of category.categories) {
update(child);
category.countSchemasInSubtree += child.countSchemasInSubtree;
category.countSchemasInSubtreeFiltered += child.countSchemasInSubtreeFiltered;
}
} else {
result.unshift(category);
// Sort each category category individually because sorting is O(log N).
category.categories.sortByString(x => x.displayName);
}
// Sort by name and then add components and schemas, so that both categories are on top.
categoryRoots.sortByString(x => x.displayName);
categoryRoots.unshift(components, schemas);
for (const child of categoryRoots) {
update(child);
}
return result;
return categoryRoots;
}

2
frontend/app/theme/_panels2.scss

@ -304,7 +304,7 @@
.nav-heading {
color: $color-text-decent;
margin-bottom: .5rem;
margin-bottom: 0;
margin-top: 1rem;
}
}
Loading…
Cancel
Save