-
Notifications
You must be signed in to change notification settings - Fork 263
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
Simplify timelines UI/reuse UI elements #2629
Merged
Merged
Changes from all commits
Commits
Show all changes
49 commits
Select commit
Hold shift + click to select a range
b514517
Strip down the timelines screen to minimum
tillprochaska 3648259
Improve color contrast of secondary/muted text
tillprochaska 5d35dda
Implement basic timelines list view
tillprochaska 26e6918
Render descriptive caption for edge entities
tillprochaska e297833
Use temporal extent to render start/end dates
tillprochaska a6ca505
Allow selecting timeline items
tillprochaska 376300f
Display schema and property data for selected timeline items
tillprochaska e50ab1b
Temporarily rename entity viewer to resolve naming clash
tillprochaska 3f69a56
Make timeline list and entity scrollable independently
tillprochaska 8fd8217
Handle updates to timeline state
tillprochaska d636196
Allow users to add properties
tillprochaska 36c2642
Allow users to create new items in timelines
tillprochaska d548c96
Emphasize timeline item color
tillprochaska c5d0770
Allow toggling editing of timeline items
tillprochaska 4cbdd68
Show placeholder/date format hint
tillprochaska 3ac5a93
Handle timelines without layout
tillprochaska f370285
Fix jerky scrollbar in entity select autocomplete
tillprochaska e33f4c2
Allow removing entities from timelines
tillprochaska e4b0fbd
Hook up timeline component to Redux store
tillprochaska d06822c
Improve keyboard navigability
tillprochaska f9d876a
Show loading indicator and disable submit while new entity is being s…
tillprochaska fd6e3cb
Display timeline items as table
tillprochaska cb74955
Extract shared types to remove duplication
tillprochaska 9187c33
Simplify timeline item creation state
tillprochaska 1916710
Unselect timeline item when pressing escape
tillprochaska b24b850
Do not reset properties when changing schema
tillprochaska 29822f5
Add timeline empty state
tillprochaska 10ffaec
Only show end date column if there's at least one item with an end date
tillprochaska 2331d1e
Add utility class to handle FtM’s imprecise dates, e.g. `2022` or `20…
tillprochaska 26fe059
Refactor: Introduce `TimelineItem`, a wrapper class for entities
tillprochaska 59e5cd2
Refactor: Extract keyboard navigation logic into custom hook
tillprochaska caf3d0b
Fix missing hook dependency
tillprochaska 79d3967
Add basic chart renderer for timelines
tillprochaska 533733c
Move timeline renderers into subdirectories
tillprochaska 1aed501
Make timeline item captions sticky
tillprochaska 412e6bc
Unselect timeline items when clicking outside
tillprochaska 4023889
Add popover when hovering timeline chart items
tillprochaska cd882d6
Ensure clicking on an item in timeline charts always focuses the item
tillprochaska 4328b32
Extract logic to fetch entity suggestions into custom hook
tillprochaska 9aa0304
Allow editing entity-type properties
tillprochaska 7361f7b
Wire up update status indicator with actual timeline state
tillprochaska 79b5c44
Refactor: Reduce use of optional props
tillprochaska bbedac2
Use full entity ID when creating new timeline items
tillprochaska 5e6bb5d
Add read-only mode
tillprochaska 87e9156
Translate UI copy
tillprochaska 5409e53
Always display temporal properties in entity viewer, even if they are…
tillprochaska 64f4b11
Add tooltip to remove button
tillprochaska f59e1df
Replace old Timeline component
tillprochaska 3a45add
Hide `incorporationDate`/`dissolutionDate` properties for `Person` sc…
tillprochaska File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
.visually-hidden { | ||
border: 0; | ||
clip: rect(0 0 0 0); | ||
height: auto; | ||
margin: 0; | ||
overflow: hidden; | ||
padding: 0; | ||
position: absolute; | ||
width: 1px; | ||
white-space: nowrap; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
@import 'app/variables.scss'; | ||
|
||
.EntityViewer2 { | ||
display: grid; | ||
gap: 2 * $aleph-grid-size; | ||
padding-top: 5 * $aleph-grid-size; | ||
} | ||
|
||
.EntityViewer2__header { | ||
text-align: center; | ||
} | ||
|
||
.EntityViewer2__caption { | ||
margin-top: 0.5 * $aleph-grid-size; | ||
margin-bottom: 0; | ||
} | ||
|
||
.EntityViewer2__schema { | ||
color: $aleph-greyed-text; | ||
} | ||
|
||
.EntityViewer2__color { | ||
width: 75%; | ||
justify-self: center; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { render, screen } from 'testUtils'; | ||
import { Entity, Model, defaultModel } from '@alephdata/followthemoney'; | ||
import EntityViewer2 from './EntityViewer2'; | ||
|
||
const defaultProps = { | ||
fetchEntitySuggestions: async () => [], | ||
writeable: true, | ||
onVertexChange: () => {}, | ||
onEntityChange: () => {}, | ||
}; | ||
|
||
const model = new Model(defaultModel); | ||
let entity: Entity; | ||
|
||
beforeEach(() => { | ||
entity = model.getEntity({ | ||
id: '1', | ||
schema: 'Company', | ||
properties: { | ||
name: ['ACME, Inc.'], | ||
}, | ||
}); | ||
}); | ||
|
||
it('renders schema name and entity caption', () => { | ||
const vertex = { entityId: '1' }; | ||
render(<EntityViewer2 {...defaultProps} entity={entity} vertex={vertex} />); | ||
expect(screen.getByText('Company')).toBeInTheDocument(); | ||
expect(screen.getByRole('heading', { name: 'ACME, Inc.' })); | ||
}); | ||
|
||
it('renders a color picker', () => { | ||
const vertex = { entityId: '1', color: 'green' }; | ||
render(<EntityViewer2 {...defaultProps} entity={entity} vertex={vertex} />); | ||
const picker = document.querySelector( | ||
'.ColorPicker [style*="background-color: green"]' | ||
); | ||
expect(picker).toBeInTheDocument(); | ||
}); | ||
|
||
it('renders properties', () => { | ||
const vertex = { entityId: '1' }; | ||
render(<EntityViewer2 {...defaultProps} entity={entity} vertex={vertex} />); | ||
expect(screen.getByText('Name')).toBeInTheDocument(); | ||
expect(screen.getByText('Incorporation date')).toBeInTheDocument(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { FC } from 'react'; | ||
import { Entity } from '@alephdata/followthemoney'; | ||
import { Schema } from 'src/react-ftm/types'; | ||
import { DEFAULT_COLOR } from './Timeline'; | ||
import type { Vertex, FetchEntitySuggestions } from './types'; | ||
import EntityViewerProperties from './EntityViewerProperties'; | ||
import { ColorPicker } from 'src/react-ftm'; | ||
|
||
import './EntityViewer2.scss'; | ||
|
||
type EntityViewer2Props = { | ||
entity: Entity; | ||
vertex: Vertex; | ||
fetchEntitySuggestions: FetchEntitySuggestions; | ||
writeable?: boolean; | ||
onVertexChange: (vertex: Vertex) => void; | ||
onEntityChange: (entity: Entity) => void; | ||
}; | ||
|
||
const EntityViewer2: FC<EntityViewer2Props> = ({ | ||
entity, | ||
vertex, | ||
fetchEntitySuggestions, | ||
writeable, | ||
onVertexChange, | ||
onEntityChange, | ||
}) => { | ||
const currentColor = vertex?.color || DEFAULT_COLOR; | ||
|
||
return ( | ||
<article className="EntityViewer2"> | ||
<header className="EntityViewer2__header"> | ||
<div className="EntityViewer2__schema"> | ||
<Schema.Label schema={entity.schema} icon /> | ||
</div> | ||
<h2 className="EntityViewer2__caption">{entity.getCaption()}</h2> | ||
</header> | ||
<div className="EntityViewer2__color"> | ||
{writeable && ( | ||
<ColorPicker | ||
currSelected={currentColor} | ||
onSelect={(color) => onVertexChange({ ...vertex, color })} | ||
/> | ||
)} | ||
</div> | ||
<EntityViewerProperties | ||
entity={entity} | ||
fetchEntitySuggestions={fetchEntitySuggestions} | ||
writeable={writeable} | ||
onChange={(entity) => onEntityChange(entity)} | ||
/> | ||
</article> | ||
); | ||
}; | ||
|
||
export default EntityViewer2; |
71 changes: 71 additions & 0 deletions
71
ui/src/components/Timeline/EntityViewerProperties.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import { render, screen } from 'testUtils'; | ||
import userEvent from '@testing-library/user-event'; | ||
import { Entity, Model, defaultModel } from '@alephdata/followthemoney'; | ||
import EntityViewerProperties from './EntityViewerProperties'; | ||
|
||
const defaultProps = { | ||
fetchEntitySuggestions: async () => [], | ||
writeable: true, | ||
onChange: () => {}, | ||
}; | ||
|
||
const model = new Model(defaultModel); | ||
let entity: Entity; | ||
|
||
beforeEach(() => { | ||
entity = model.getEntity({ | ||
id: '1', | ||
schema: 'Company', | ||
}); | ||
}); | ||
|
||
it('renders featured, temporal, and non-empty properties', () => { | ||
const { rerender } = render( | ||
<EntityViewerProperties {...defaultProps} entity={entity} /> | ||
); | ||
|
||
// Featured | ||
expect(screen.getByText('Name')).toBeInTheDocument(); | ||
expect(screen.getByText('Jurisdiction')).toBeInTheDocument(); | ||
expect(screen.getByText('Registration number')).toBeInTheDocument(); | ||
|
||
// Temporal | ||
expect(screen.getByText('Incorporation date')).toBeInTheDocument(); | ||
expect(screen.getByText('Dissolution date')).toBeInTheDocument(); | ||
|
||
// Non empty | ||
entity.setProperty('wikidataId', 'Q7102061'); | ||
rerender(<EntityViewerProperties {...defaultProps} entity={entity} />); | ||
expect(screen.getByText('Wikidata ID')).toBeInTheDocument(); | ||
}); | ||
|
||
it('can add any other editable property', async () => { | ||
render(<EntityViewerProperties {...defaultProps} entity={entity} />); | ||
|
||
// There is no editor for the Wikidata ID | ||
expect(screen.queryByText('Wikidata ID')).toBeNull(); | ||
|
||
await userEvent.click(screen.getByRole('button', { name: 'Add a property' })); | ||
await userEvent.click(screen.getByRole('menuitem', { name: 'Wikidata ID' })); | ||
|
||
// Now there is an editor for the dissolution date | ||
expect(screen.getByText('Wikidata ID').matches('.EditableProperty *')).toBe( | ||
true | ||
); | ||
|
||
// Can't add a property twice | ||
await userEvent.click(screen.getByRole('button', { name: 'Add a property' })); | ||
expect(screen.queryByRole('menuitem', { name: 'Wikidata ID' })).toBeNull(); | ||
}); | ||
|
||
it('cannot add properties if not writeable', () => { | ||
render( | ||
<EntityViewerProperties | ||
{...defaultProps} | ||
writeable={false} | ||
entity={entity} | ||
/> | ||
); | ||
|
||
expect(screen.queryByRole('button', { name: 'Add a property' })).toBeNull(); | ||
}); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is px is right here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is a utility class to hide elements visually while still keeping it accessible to screen readers: https://css-tricks.com/inclusively-hidden/