Skip to content

Commit

Permalink
Merge branch 'dev' into 230-initiative-filtering-ui
Browse files Browse the repository at this point in the history
  • Loading branch information
rogup committed Jun 3, 2024
2 parents b3a9544 + e333c07 commit 5747de6
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 69 deletions.
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
**
18 changes: 15 additions & 3 deletions CONFIG.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,18 @@ Set whether the sidebar is by default open on starting the app.



### `defaultPanel`

- *type:* `{SidebarId}` One of these strings: "diretory", "initiatives", "about" or "datasets"
- *in string context:* parsed as-is
- *default:* If unset, the default is 'directory'
- *settable?:* yes

Defines which panel opens by default.




### `dialogueSize`

- *type:* `{DialogueSize}` An object containing only string values.
Expand Down Expand Up @@ -479,7 +491,7 @@ Preset location of the data source script(s).
- *default:* `true`
- *settable?:* yes

If true this will load the datasets panel
If true this will load the about panel



Expand All @@ -503,7 +515,7 @@ If true this will load the datasets panel
- *default:* `true`
- *settable?:* yes

If true this will load the datasets panel
If true this will load the directory panel



Expand All @@ -515,7 +527,7 @@ If true this will load the datasets panel
- *default:* `true`
- *settable?:* yes

If true this will load the datasets panel
If true this will load the initiatives (i.e. search) panel



Expand Down
54 changes: 39 additions & 15 deletions src/map-app/app/model/config-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import type {

import { Initiative, InitiativeObj } from './initiative';
import { isIso6391Code, Iso6391Code } from '../../localisations';
import { SidebarId } from '../presenter/sidebar';

class TypeDef<T> {
constructor(params: {
Expand All @@ -54,7 +55,7 @@ class TypeDef<T> {
stringDescr?: string;
// A string-parsing function
parseString?: (val: string) => T;
};
}


export interface VocabSource {
Expand Down Expand Up @@ -84,7 +85,7 @@ export interface DataSource {
id: string;
type: string;
label: string;
};
}

export interface HostSparqlDataSource extends DataSource {
type: 'hostSparql';
Expand Down Expand Up @@ -135,6 +136,7 @@ export interface ReadableConfig {
getShowDatasetsPanel(): boolean;
getShowDirectoryPanel(): boolean;
getShowSearchPanel(): boolean;
getDefaultPanel(): SidebarId;
getSidebarButtonColour(): string;
getSoftwareGitCommit(): string;
getSoftwareTimestamp(): string;
Expand All @@ -144,7 +146,7 @@ export interface ReadableConfig {
htmlTitle(): string;
logo(): string | undefined;
vocabularies(): AnyVocabSource[];
};
}

export interface WritableConfig {
setDefaultLatLng(val: Point2d): void;
Expand All @@ -166,7 +168,8 @@ export interface WritableConfig {
setShowDatasetsPanel(val: boolean): void;
setShowDirectoryPanel(val: boolean): void;
setShowSearchPanel(val: boolean): void;
};
setDefaultPanel(val: SidebarId): void;
}

export interface ConfigSchema<T> {
// An identifier string
Expand All @@ -187,7 +190,7 @@ export interface DialogueSize {
width?: string;
height?: string;
descriptionRatio?: number;
};
}

export type InitiativeRenderFunction =
(initiative: Initiative, model: DataServices) => string;
Expand Down Expand Up @@ -235,6 +238,7 @@ export class ConfigData {
showDatasetsPanel: boolean = true;
showDirectoryPanel: boolean = true;
showSearchPanel: boolean = true;
defaultPanel: SidebarId = 'directory';
sidebarButtonColour: string = '#39cccc';
tileUrl?: string;
timestamp: string = '2000-01-01T00:00:00.000Z';
Expand All @@ -247,12 +251,12 @@ export class ConfigData {
constructor(params: Partial<ConfigData> = {}) {
Object.assign(this, params);
}
};
}

// This type is constrained to have the same keys as ConfigData, and
// values which are ConfigSchema of the appropriate type for the
// ConfigData property in question.
export type ConfigSchemas = { [K in keyof ConfigData]: ConfigSchema<ConfigData[K]> };
export type ConfigSchemas = { [K in keyof ConfigData]: ConfigSchema<ConfigData[K]> }


// Validates/normalises a language code.
Expand Down Expand Up @@ -406,6 +410,14 @@ const types = {
name: '{InitiativeRenderFunction}',
descr: 'A function which accepts an Initiative instance and returns an HTML string',
}),
sidebarId: new TypeDef<SidebarId>({
name: '{SidebarId}',
// Would be sensible to generate this from the keys of a `new SidebarPanels()`
// - except if we import that we hit ERR_REQUIRE_ESM because d3 is a pure ESM module.
// And this module is currently not pure ESM. Argh. And it's not trivial to switch!
// See, for example https://commerce.nearform.com/blog/2022/victory-esm/
descr: 'One of these strings: "diretory", "initiatives", "about" or "datasets"'
}),
vocabSources: new TypeDef<AnyVocabSource[]>({
name: '{AnyVocabSource[]}',
descr: 'An array of vocab source definitions, defining a SPARQL endpoint URL, '+
Expand All @@ -417,7 +429,7 @@ const types = {
descr: 'An array of data source definitions, defining the type, ID, and in certain cases '+
'other source-secific parameters needed for the source type',
}),
};
}



Expand Down Expand Up @@ -724,7 +736,7 @@ export class Config implements ReadableConfig, WritableConfig {
},
showAboutPanel: {
id: 'showAboutPanel',
descr: `If true this will load the datasets panel`,
descr: `If true this will load the about panel`,
getter: 'getShowAboutPanel',
setter: 'setShowAboutPanel',
type: types.boolean,
Expand All @@ -738,18 +750,26 @@ export class Config implements ReadableConfig, WritableConfig {
},
showDirectoryPanel: {
id: 'showDirectoryPanel',
descr: `If true this will load the datasets panel`,
descr: `If true this will load the directory panel`,
getter: 'getShowDirectoryPanel',
setter: 'setShowDirectoryPanel',
type: types.boolean,
},
showSearchPanel: {
id: 'showSearchPanel',
descr: `If true this will load the datasets panel`,
descr: `If true this will load the initiatives (i.e. search) panel`,
getter: 'getShowSearchPanel',
setter: 'setShowSearchPanel',
type: types.boolean,
},
defaultPanel: {
id: "defaultPanel",
descr: "Defines which panel opens by default.",
defaultDescr: "If unset, the default is 'directory'",
getter: "getDefaultPanel",
setter: "setDefaultPanel",
type: types.sidebarId,
},
sidebarButtonColour: {
id: "sidebarButtonColour",
descr: 'Set the css background-colour attribute for the open sidebar button. Defaults to teal',
Expand Down Expand Up @@ -1150,6 +1170,9 @@ ${def.descr}
getShowSearchPanel(): boolean {
return this.data.showSearchPanel;
}
getDefaultPanel(): SidebarId {
return this.data.defaultPanel;
}
getSidebarButtonColour(): string {
return this.data.sidebarButtonColour;
}
Expand Down Expand Up @@ -1251,8 +1274,9 @@ ${def.descr}
setShowSearchPanel(val: boolean): void {
this.data.showSearchPanel = val;
}
setDefaultPanel(val: SidebarId): void {
this.data.defaultPanel = val;
}

// [id: string]: Getter | Setter;
};


// [id: string]: Getter | Setter;
}
125 changes: 77 additions & 48 deletions src/map-app/app/presenter/sidebar.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,50 @@
import { Dictionary } from '../../common-types';
import { EventBus } from '../../eventbus';
import { MapUI } from '../map-ui';
import { Initiative } from '../model/initiative';
import { SidebarView } from '../view/sidebar';
import { BasePresenter } from './base';
import { AboutSidebarPresenter } from './sidebar/about';
import { BaseSidebarPresenter } from './sidebar/base';
import { DatasetsSidebarPresenter } from './sidebar/datasets';
import { DirectorySidebarPresenter } from './sidebar/directory';
import { InitiativesSidebarPresenter } from './sidebar/initiatives';

/// A collection of sidebar panels, by name
export class SidebarPanels {
directory?: DirectorySidebarPresenter = undefined;
initiatives?: InitiativesSidebarPresenter = undefined;
about?: AboutSidebarPresenter = undefined;
datasets?: DatasetsSidebarPresenter = undefined;

// A list of the IDs as a convenience
static readonly ids = Object.keys(new SidebarPanels()) as SidebarId[];
}

/// This type can contain only sidebar ID names
export type SidebarId = keyof SidebarPanels;

export class SidebarPresenter extends BasePresenter {
readonly view: SidebarView;
readonly showDirectoryPanel: boolean;
readonly showSearchPanel: boolean;
readonly showAboutPanel: boolean;
readonly showDatasetsPanel: boolean;
private children: Dictionary<BaseSidebarPresenter> = {};
private sidebarName?: string;
private readonly children = new SidebarPanels();

private sidebarName?: SidebarId;

constructor(readonly mapui: MapUI) {
super();
this.showDirectoryPanel = mapui.config.getShowDirectoryPanel();
this.showSearchPanel = mapui.config.getShowSearchPanel();
this.showAboutPanel = mapui.config.getShowAboutPanel();
this.showDatasetsPanel = mapui.config.getShowDatasetsPanel();
this.view = new SidebarView(this, mapui.dataServices.getSidebarButtonColour());
const defaultPanel = mapui.config.getDefaultPanel();
this.view = new SidebarView(
this,
mapui.dataServices.getSidebarButtonColour()
);
this._eventbusRegister();

this.createSidebars();
this.changeSidebar();
}

createSidebars() {
this.children = {};

if(this.showingDirectory())
this.children.directory = new DirectorySidebarPresenter(this);

Expand All @@ -46,61 +56,80 @@ export class SidebarPresenter extends BasePresenter {

if(this.showingDatasets())
this.children.datasets = new DatasetsSidebarPresenter(this);

this.changeSidebar(defaultPanel);
}

/**
* Changes the sidebar
* @param name the sidebar to change (needs to be one of the keys of this.sidebar)
*/
changeSidebar(name?: string) {
if (name !== undefined) {
// Validate name
if (!(name in this.children)) {
console.warn(`ignoring request to switch to non-existant sidebar '${name}'`);
name = undefined;
changeSidebar(name?: SidebarId): void {
if (!name) {
if (this.sidebarName) {
// Just refresh the currently showing sidebar.
this.children[this.sidebarName]?.refreshView(false);
}
else {
// If no sidebar is set, pick the first one
let key: SidebarId;
for(key in this.children) {
const child = this.children[key];
if (!child)
continue;

this.sidebarName = key;
child.refreshView(true);
break;
}
console.warn('No sidebars to show');
}
return;
}

if (name !== undefined) {
// If name is set, change the current sidebar and then refresh
this.sidebarName = name;
this.children[this.sidebarName]?.refreshView(true);
}
else {
// Just refresh the currently showing sidebar.
// If nothing is showing, show the first. Or nothing, if none.
if (!this.sidebarName) {
const names = Object.keys(this.children);
if (names.length > 0) {
this.sidebarName = names[0];
this.children[this.sidebarName]?.refreshView(true);
} else {
console.warn('No sidebars to show');
return; // No sidebars? Can't do anything.
}
} else {
this.children[this.sidebarName]?.refreshView(false);
if (name in this.children) {
// A valid SidebarId. If it's present, change the current sidebar to that, and then refresh
const child = this.children[name];
if (child !== undefined) {
this.sidebarName = name;
child.refreshView(true);
}
return;
}

// If we get here it's not a valid sidebar (possibly it wasn't configured)
console.warn(
"Attempting to call SidebarPresenter.changeSidebar() with a "+
`non-existant sidebar '${name}' - ignoring.`
);
}

/**
* Fully refresh the sidebar
*/
refreshSidebar() {
if (!this.sidebarName) {
if (this.sidebarName) {
this.children[this.sidebarName]?.refreshView(true);
} else {
// If no sidebar is set, pick the first one
const names = Object.keys(this.children);
if (names.length > 0) {
this.sidebarName = names[0];
this.children[this.sidebarName]?.refreshView(true);
} else {
console.warn('No sidebars to show');
return; // No sidebars? Can't do anything.
let key: SidebarId;
for(key in this.children) {
const child = this.children[key];
if (!child)
continue;

this.sidebarName = key;
child.refreshView(true);
break;
}
} else {
this.children[this.sidebarName]?.refreshView(true);
console.warn('No sidebars to show');
}

// If we get here it's not a valid sidebar (possibly it wasn't configured)
console.warn(
"Attempting to call SidebarPresenter.changeSidebar() with a "+
`non-existant sidebar '${name}' - ignoring.`
);
}

showSidebar() {
Expand Down
Loading

0 comments on commit 5747de6

Please sign in to comment.