Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🎉 early entity exclusion for all chart types #4583

Draft
wants to merge 1 commit into
base: refactor-entity-ids
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions adminSiteClient/AbstractChartEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,25 @@ export abstract class AbstractChartEditor<
return difference(focusedSeriesNames, availableSeriesNames)
}

@computed get invalidSelectedEntityNames(): SeriesName[] {
const { grapher } = this

// find invalid selected entities
const availableEntityNames = grapher.availableEntities.map(
(e) => e.entityName
)
const selectedEntityNames = grapher.selection.selectedEntityNames
return difference(selectedEntityNames, availableEntityNames)
}

@action.bound removeInvalidFocusedSeriesNames(): void {
this.grapher.focusArray.remove(...this.invalidFocusedSeriesNames)
}

@action.bound removeInvalidSelectedEntityNames(): void {
this.grapher.selection.deselectEntities(this.invalidSelectedEntityNames)
}

abstract get isNewGrapher(): boolean
abstract get availableTabs(): EditorTab[]

Expand Down
177 changes: 177 additions & 0 deletions adminSiteClient/EditorDataTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ import { ColorBox, SelectField, Section, FieldsRow } from "./Forms.js"
import {
faArrowsAltV,
faLink,
faMinus,
faTimes,
faTrash,
faUnlink,
} from "@fortawesome/free-solid-svg-icons"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome/index.js"
Expand Down Expand Up @@ -407,6 +409,180 @@ class MissingDataSection<
}
}

@observer
class EntityFilterSection<
Editor extends AbstractChartEditor,
> extends React.Component<{ editor: Editor }> {
@computed private get editor(): Editor {
return this.props.editor
}

@computed private get grapher(): Grapher {
return this.editor.grapher
}

@computed private get includedEntityNames(): EntityName[] {
return this.grapher.includedEntityNames ?? []
}

@computed private get excludedEntityNames(): EntityName[] {
return this.grapher.excludedEntityNames ?? []
}

@computed private get includedEntityChoices() {
const { inputTable, includedEntityNames = [] } = this.grapher
return inputTable.availableEntityNames
.filter((entityName) => !includedEntityNames.includes(entityName))
.sort()
}

@computed private get excludedEntityChoices() {
const { inputTable, excludedEntityNames = [] } = this.grapher
return inputTable.availableEntityNames
.filter((entityName) => !excludedEntityNames.includes(entityName))
.sort()
}

@action.bound validateSelectionAndFocus() {
this.editor.removeInvalidSelectedEntityNames()
this.editor.removeInvalidFocusedSeriesNames()
}

@action.bound onExcludeEntity(entityName: string) {
const { grapher } = this
if (grapher.excludedEntityNames === undefined) {
grapher.excludedEntityNames = []
}

if (!grapher.excludedEntityNames.includes(entityName))
grapher.excludedEntityNames.push(entityName)

this.validateSelectionAndFocus()
}

@action.bound onUnexcludeEntity(entityName: string) {
const { grapher } = this
if (!grapher.excludedEntityNames) return
grapher.excludedEntityNames = grapher.excludedEntityNames.filter(
(e) => e !== entityName
)

this.validateSelectionAndFocus()
}

@action.bound onIncludeEntity(entityName: string) {
const { grapher } = this
if (grapher.includedEntityNames === undefined) {
grapher.includedEntityNames = []
}

if (!grapher.includedEntityNames.includes(entityName))
grapher.includedEntityNames.push(entityName)

this.validateSelectionAndFocus()
}

@action.bound onUnincludeEntity(entityName: string) {
const { grapher } = this
if (!grapher.includedEntityNames) return
grapher.includedEntityNames = grapher.includedEntityNames.filter(
(e) => e !== entityName
)

this.validateSelectionAndFocus()
}

@action.bound onClearExcludedEntities() {
const { grapher } = this
grapher.excludedEntityNames = []
this.validateSelectionAndFocus()
}

@action.bound onClearIncludedEntities() {
const { grapher } = this
grapher.includedEntityNames = []
this.validateSelectionAndFocus()
}

render() {
const { includedEntityChoices, excludedEntityChoices } = this
return (
<Section name="Manual entity selection">
<SelectField
label={
"Explicit start selection (leave empty to show all entities)"
}
placeholder={"Select an entity to include"}
value={undefined}
onValue={(v) => v && this.onIncludeEntity(v)}
options={includedEntityChoices.map((entry) => ({
value: entry,
}))}
/>
{this.includedEntityNames && (
<ul className="includedEntities">
{this.includedEntityNames.map((entity) => (
<li key={entity}>
<div
className="clickable"
onClick={() =>
this.onUnincludeEntity(entity)
}
>
<FontAwesomeIcon icon={faMinus} />
</div>
{entity}
</li>
))}
</ul>
)}
{this.includedEntityNames && (
<button
className="btn btn-light btn-clear-selection"
onClick={this.onClearIncludedEntities}
>
<FontAwesomeIcon icon={faTrash} /> Clear start selection
</button>
)}
<SelectField
label="Exclude individual entities"
placeholder="Select an entity to exclude"
value={undefined}
onValue={(v) => v && this.onExcludeEntity(v)}
options={excludedEntityChoices.map((entry) => ({
value: entry,
}))}
/>
{this.excludedEntityNames && (
<ul className="excludedEntities">
{this.excludedEntityNames.map((entity) => (
<li key={entity}>
<div
className="clickable"
onClick={() =>
this.onUnexcludeEntity(entity)
}
>
<FontAwesomeIcon icon={faMinus} />
</div>
{entity}
</li>
))}
</ul>
)}
{this.excludedEntityNames && (
<button
className="btn btn-light btn-clear-selection"
onClick={this.onClearExcludedEntities}
>
<FontAwesomeIcon icon={faTrash} /> Clear exclude list
</button>
)}
</Section>
)
}
}

@observer
export class EditorDataTab<
Editor extends AbstractChartEditor,
Expand Down Expand Up @@ -480,6 +656,7 @@ export class EditorDataTab<
{features.canHighlightSeries && (
<FocusSection editor={editor} />
)}
<EntityFilterSection editor={editor} />
{features.canSpecifyMissingDataStrategy && (
<MissingDataSection editor={this.props.editor} />
)}
Expand Down
Loading