Skip to content

Commit

Permalink
Add ability to customize About dialog with callbacks and optionally h…
Browse files Browse the repository at this point in the history
…ide links to data (#3230)

* Consolidate getTrackName into a single util function

* Test out hideUris

* Session wide about detail formatter

* Session wide feature detail formatters

* Update snaps

* Slightly more compact

* Add customizeAbout extension point

* Add getEnv helper that resolves to proper PluginManager typescripting

* Test

* Bump deps

* Update plugins

* Small refactors

* Misc

* Test

* Add examples of extra about panels

* Allow replacing widget

* Conf->config
  • Loading branch information
cmdcolin committed Oct 18, 2022
1 parent 28fcca8 commit cb9159a
Show file tree
Hide file tree
Showing 56 changed files with 1,916 additions and 1,381 deletions.
40 changes: 32 additions & 8 deletions packages/core/BaseFeatureWidget/BaseFeatureDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import {
measureText,
measureGridWidth,
getStr,
getEnv,
getSession,
getUriLink,
isUriLocation,
} from '../util'
Expand Down Expand Up @@ -312,6 +314,7 @@ interface AttributeProps {
formatter?: (val: unknown, key: string) => React.ReactNode
descriptions?: Record<string, React.ReactNode>
prefix?: string[]
hideUris?: boolean
}

export function UriLink({
Expand All @@ -322,6 +325,7 @@ export function UriLink({
const href = getUriLink(value)
return <SanitizedHTML html={`<a href="${href}">${href}</a>`} />
}

const DataGridDetails = ({
value,
prefix,
Expand Down Expand Up @@ -454,6 +458,7 @@ export function Attributes(props: AttributeProps) {
omit = [],
descriptions,
formatter = val => val,
hideUris,
prefix = [],
} = props
const omits = [...omit, ...globalOmit]
Expand Down Expand Up @@ -494,12 +499,14 @@ export function Attributes(props: AttributeProps) {
)
} else if (isObject(value)) {
return isUriLocation(value) ? (
<UriAttribute
key={key}
name={key}
prefix={prefix}
value={value}
/>
hideUris ? null : (
<UriAttribute
key={key}
name={key}
prefix={prefix}
value={value}
/>
)
) : (
<Attributes
{...props}
Expand Down Expand Up @@ -562,13 +569,22 @@ export const FeatureDetails = (props: {
}) => {
const { omit = [], model, feature, depth = 0 } = props
const { name = '', id = '', type = '', subfeatures } = feature

const { pluginManager } = getEnv(model)
const session = getSession(model)

const ExtraPanel = pluginManager?.evaluateExtensionPoint(
'Core-extraFeaturePanel',
null,
{ session, feature, model },
) as { name: string; Component: React.FC<any> } | undefined
return (
<BaseCard title={generateTitle(name, id, type)}>
<Typography>Core details</Typography>
<CoreDetails {...props} />
<Divider />

<Typography>Attributes</Typography>

<Attributes
attributes={feature}
{...props}
Expand All @@ -581,6 +597,15 @@ export const FeatureDetails = (props: {
<SequenceFeatureDetails {...props} />
</ErrorBoundary>

{ExtraPanel ? (
<>
<Divider />
<BaseCard title={ExtraPanel.name}>
<ExtraPanel.Component {...props} />
</BaseCard>
</>
) : null}

{subfeatures?.length ? (
<BaseCard title="Subfeatures" defaultExpanded={depth < 1}>
{subfeatures.map(sub => (
Expand Down Expand Up @@ -613,7 +638,6 @@ const BaseFeatureDetails = observer(({ model }: BaseInputProps) => {
typeof v === 'undefined' ? null : v,
),
)

return isEmpty(feature) ? null : (
<FeatureDetails model={model} feature={feature} />
)
Expand Down
47 changes: 31 additions & 16 deletions packages/core/BaseFeatureWidget/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import { types, addDisposer } from 'mobx-state-tree'
import { autorun } from 'mobx'
import PluginManager from '../PluginManager'
import { getConf, ConfigurationSchema } from '../configuration'
import clone from 'clone'

// locals
import PluginManager from '../PluginManager'
import {
getConf,
ConfigurationSchema,
AnyConfigurationModel,
} from '../configuration'
import { getSession } from '../util'
import { ElementId } from '../util/types/mst'

const configSchema = ConfigurationSchema('BaseFeatureWidget', {})
Expand Down Expand Up @@ -42,8 +49,9 @@ export default function stateModelFactory(pluginManager: PluginManager) {
track: types.safeReference(
pluginManager.pluggableMstType('track', 'stateModel'),
),
trackId: types.maybe(types.string),
trackType: types.maybe(types.string),
})
.volatile(() => ({}))
.actions(self => ({
setFeatureData(featureData: Record<string, unknown>) {
self.unformattedFeatureData = featureData
Expand All @@ -54,33 +62,40 @@ export default function stateModelFactory(pluginManager: PluginManager) {
setFormattedData(feat: Record<string, unknown>) {
self.featureData = feat
},
setExtra(type?: string, trackId?: string) {
self.trackId = trackId
self.trackType = type
},
}))
.actions(self => ({
afterCreate() {
addDisposer(
self,
autorun(() => {
self.setExtra(self.track?.type, self.track?.configuration.trackId)
const { unformattedFeatureData, track } = self
const session = getSession(self)
if (unformattedFeatureData) {
const feature = clone(unformattedFeatureData)

const f = (
obj: { configuration: AnyConfigurationModel },
arg2: string,
) => getConf(obj, ['formatDetails', arg2], { feature })

if (track) {
// eslint-disable-next-line no-underscore-dangle
feature.__jbrowsefmt = getConf(
track,
['formatDetails', 'feature'],
{ feature },
)

feature.__jbrowsefmt = {
...f(session, 'feature'),
...f(track, 'feature'),
}
const depth = getConf(track, ['formatDetails', 'depth'])

formatSubfeatures(feature, depth, subfeature => {
formatSubfeatures(feature, depth, sub => {
// eslint-disable-next-line no-underscore-dangle
subfeature.__jbrowsefmt = getConf(
track,
['formatDetails', 'subfeatures'],
{ feature: subfeature },
)
sub.__jbrowsefmt = {
...f(session, 'subfeature'),
...f(track, 'subfeature'),
}
})
}

Expand Down
3 changes: 2 additions & 1 deletion packages/core/configuration/configurationSlot.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { types, IAnyModelType, IAnyComplexType, getEnv } from 'mobx-state-tree'
import { types, IAnyModelType, IAnyComplexType } from 'mobx-state-tree'
import { stringToJexlExpression } from '../util/jexlStrings'
import { FileLocation } from '../util/types/mst'
import { getEnv } from '../util'

function isValidColorString(/* str */) {
// TODO: check all the crazy cases for whether it's a valid HTML/CSS color string
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { getParent, Instance, types, isRoot, getEnv } from 'mobx-state-tree'
import { getParent, Instance, types, isRoot } from 'mobx-state-tree'
import React from 'react'
import { getConf } from '../../configuration'
import { MenuItem } from '../../ui'
import { getParentRenderProps } from '../../util/tracks'
import { getEnv } from '../../util'
import { ElementId } from '../../util/types/mst'

export const BaseDisplay = types
Expand Down
10 changes: 2 additions & 8 deletions packages/core/pluggableElementTypes/models/BaseTrackModel.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import { transaction } from 'mobx'
import {
getEnv,
getRoot,
resolveIdentifier,
types,
Instance,
} from 'mobx-state-tree'
import { getRoot, resolveIdentifier, types, Instance } from 'mobx-state-tree'
import {
getConf,
AnyConfigurationModel,
Expand All @@ -14,7 +8,7 @@ import {
} from '../../configuration'
import PluginManager from '../../PluginManager'
import { MenuItem } from '../../ui'
import { getContainingView, getSession } from '../../util'
import { getContainingView, getSession, getEnv } from '../../util'
import { isSessionModelWithConfigEditing } from '../../util/types'
import { ElementId } from '../../util/types/mst'

Expand Down
20 changes: 16 additions & 4 deletions packages/core/pluggableElementTypes/models/baseTrackConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,18 @@ export function createBaseTrackConfig(pluginManager: PluginManager) {
description: 'depth to iterate on subfeatures',
},
}),
formatAbout: ConfigurationSchema('FormatAbout', {
config: {
type: 'frozen',
description: 'formats configuration object in about dialog',
defaultValue: {},
contextVariable: ['config'],
},
hideUris: {
type: 'boolean',
defaultValue: false,
},
}),
},
{
preProcessSnapshot: s => {
Expand All @@ -96,18 +108,18 @@ export function createBaseTrackConfig(pluginManager: PluginManager) {
explicitIdentifier: 'trackId',
explicitlyTyped: true,
actions: (self: any) => ({
addDisplayConf(displayConf: { type: string; displayId: string }) {
const { type } = displayConf
addDisplayConf(conf: { type: string; displayId: string }) {
const { type } = conf
if (!type) {
throw new Error(`unknown display type ${type}`)
}
const display = self.displays.find(
(d: any) => d && d.displayId === displayConf.displayId,
(d: any) => d && d.displayId === conf.displayId,
)
if (display) {
return display
}
const length = self.displays.push(displayConf)
const length = self.displays.push(conf)
return self.displays[length - 1]
},
}),
Expand Down
Loading

0 comments on commit cb9159a

Please sign in to comment.