From 8130aa07a3fb4094c3224728a0dcafe0fe53736a Mon Sep 17 00:00:00 2001 From: alexpaxton Date: Mon, 13 Apr 2020 15:38:03 -0700 Subject: [PATCH] feat(ui): resource sorting dropdowns (#17321) * feat(ui): replace sortable dashboard table headers with sort dropdown * refactor(ui): remove unecessary components * refactor(ui): add testIDs to dropdown * refactor(ui): move tasks filter to page control bar * fix(ui): remove unused import * feat(ui): replace tasks sortable headers with sort dropdown * fix(ui): make search widget more responsive * fix(ui): make dashboard sort dropdown maintain size * refactor(ui): consolidate resource sorting into a single component * refactor(ui): standardize tabbed page headers * fix: use correct import paths * refactor(ui): implement resource sorting dropdown for variables * refactor(ui): implement sorting dropdown on labels list * chore: delete unused stylesheet * refactor: implement sort dropdown for templates list * refactor: implement sort dropdown on buckets list * refactor: update design of "what is a bucket?" card * refactor: implement sort dropdowns in telegrafs list * fix: appease linter * refactor: implement sort dropdown on scrapers list * chore: add testIDs to resource sorter * fix: remove unused code * fix: update buckets and telegraf e2e tests * fix: update labels e2e test * fix: update variables e2e test * refactor: move dashboards list empty state into own component * fix: oops derp ayyyy * chore: changelog * refactor: use more resource specific types for sort keys --- CHANGELOG.md | 3 +- ui/cypress/e2e/buckets.test.ts | 12 +- ui/cypress/e2e/collectors.test.ts | 5 +- ui/cypress/e2e/labels.test.ts | 39 ++- ui/cypress/e2e/variables.test.ts | 2 +- .../authorizations/components/TokensTab.tsx | 32 +- .../components/BucketAddDataButton.scss | 9 - ui/src/buckets/components/BucketExplainer.tsx | 4 +- ui/src/buckets/components/BucketList.tsx | 38 +-- ui/src/buckets/components/BucketsTab.tsx | 89 ++++-- .../dashboard_index/DashboardsIndex.tsx | 33 +- .../DashboardsIndexContents.tsx | 19 +- .../dashboard_index/DashboardsTableEmpty.tsx | 48 +++ .../components/dashboard_index/Table.tsx | 127 ++------ ui/src/labels/components/LabelCard.scss | 19 ++ ui/src/labels/components/LabelCard.tsx | 50 ++- ui/src/labels/components/LabelList.tsx | 19 -- ui/src/labels/components/LabelsTab.tsx | 61 ++-- .../labels/components/RandomLabelColor.scss | 18 -- ui/src/members/components/Members.tsx | 18 +- ui/src/pageLayout/components/TabbedPage.scss | 56 ++++ ui/src/scrapers/components/ScraperList.tsx | 41 +-- ui/src/scrapers/components/Scrapers.tsx | 49 ++- .../components/SettingsTabbedPageHeader.tsx | 23 -- .../ResourceSortDropdown.tsx | 90 ++++++ .../generateSortItems.ts | 298 ++++++++++++++++++ .../search_widget/SearchWidget.scss | 3 + .../components/search_widget/SearchWidget.tsx | 5 +- .../tabbed_page/TabbedPageHeader.tsx | 27 +- ui/src/style/chronograf.scss | 5 +- ui/src/tasks/components/TasksHeader.tsx | 52 ++- ui/src/tasks/components/TasksList.tsx | 39 +-- ui/src/tasks/containers/TasksPage.tsx | 40 +-- ui/src/telegrafs/components/CollectorList.tsx | 16 +- ui/src/telegrafs/components/Collectors.scss | 21 -- ui/src/telegrafs/components/Collectors.tsx | 76 +++-- .../components/TelegrafExplainer.tsx | 6 +- .../components/StaticTemplatesList.tsx | 21 +- ui/src/templates/components/TemplatesList.tsx | 21 +- ui/src/templates/components/TemplatesPage.tsx | 105 +++--- ui/src/variables/components/VariableList.tsx | 23 +- ui/src/variables/components/VariablesTab.tsx | 57 ++-- 42 files changed, 1083 insertions(+), 636 deletions(-) create mode 100644 ui/src/dashboards/components/dashboard_index/DashboardsTableEmpty.tsx create mode 100644 ui/src/labels/components/LabelCard.scss delete mode 100644 ui/src/labels/components/RandomLabelColor.scss create mode 100644 ui/src/pageLayout/components/TabbedPage.scss delete mode 100644 ui/src/settings/components/SettingsTabbedPageHeader.tsx create mode 100644 ui/src/shared/components/resource_sort_dropdown/ResourceSortDropdown.tsx create mode 100644 ui/src/shared/components/resource_sort_dropdown/generateSortItems.ts create mode 100644 ui/src/shared/components/search_widget/SearchWidget.scss delete mode 100644 ui/src/telegrafs/components/Collectors.scss diff --git a/CHANGELOG.md b/CHANGELOG.md index 1167048791..6e457323dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## v2.0.0-beta.9 +## v2.0.0-beta.9 [unreleased] ### Features @@ -7,6 +7,7 @@ ### UI Improvements 1. [17714](https://github.com/influxdata/influxdb/pull/17714): Cloud environments no longer render markdown images, for security reasons. +1. [17321](https://github.com/influxdata/influxdb/pull/17321): Improve UI for sorting resources ## v2.0.0-beta.8 [2020-04-10] diff --git a/ui/cypress/e2e/buckets.test.ts b/ui/cypress/e2e/buckets.test.ts index b41f9383b5..ea50bd14c0 100644 --- a/ui/cypress/e2e/buckets.test.ts +++ b/ui/cypress/e2e/buckets.test.ts @@ -75,8 +75,11 @@ describe('Buckets', () => { describe('Searching and Sorting', () => { it('can sort by name and retention', () => { const buckets = ['defbuck', '_tasks', '_monitoring'] - cy.getByTestID('name-sorter') + cy.getByTestID('resource-sorter--button') .click() + .then(() => { + cy.getByTestID('resource-sorter--name-desc').click() + }) .then(() => { cy.get('[data-testid*="bucket-card"]').each((val, index) => { const testID = val.attr('data-testid') @@ -84,8 +87,13 @@ describe('Buckets', () => { }) }) - cy.getByTestID('name-sorter') + cy.getByTestID('resource-sorter--button') .click() + .then(() => { + cy.getByTestID( + 'resource-sorter--retentionRules[0].everySeconds-desc' + ).click() + }) .then(() => { const asc_buckets = buckets.slice().sort() cy.get('[data-testid*="bucket-card"]').each((val, index) => { diff --git a/ui/cypress/e2e/collectors.test.ts b/ui/cypress/e2e/collectors.test.ts index e58ce04db2..c0d0ab85dd 100644 --- a/ui/cypress/e2e/collectors.test.ts +++ b/ui/cypress/e2e/collectors.test.ts @@ -225,8 +225,11 @@ describe('Collectors', () => { }) }) - cy.getByTestID('name-sorter') + cy.getByTestID('resource-sorter--button') .click() + .then(() => { + cy.getByTestID('resource-sorter--name-desc').click() + }) .then(() => { // NOTE: this then is just here to let me scope this variable (alex) const teletubbies = telegrafs diff --git a/ui/cypress/e2e/labels.test.ts b/ui/cypress/e2e/labels.test.ts index d92a249fbb..ef3ac5b69b 100644 --- a/ui/cypress/e2e/labels.test.ts +++ b/ui/cypress/e2e/labels.test.ts @@ -284,7 +284,11 @@ describe('labels', () => { } }) - cy.getByTestID('sorter--name').click() + cy.getByTestID('resource-sorter--button') + .click() + .then(() => { + cy.getByTestID('resource-sorter--name-desc').click() + }) // check sort desc cy.getByTestIDSubStr('label--pill').then(labels => { @@ -296,7 +300,11 @@ describe('labels', () => { }) // reset to asc - cy.getByTestID('sorter--name').click() + cy.getByTestID('resource-sorter--button') + .click() + .then(() => { + cy.getByTestID('resource-sorter--name-asc').click() + }) cy.getByTestIDSubStr('label--pill').then(labels => { for (let i = 0; i < labels.length; i++) { @@ -332,27 +340,32 @@ describe('labels', () => { a.description < b.description ? -1 : a.description > b.description ? 1 : 0 ) // check sort asc - cy.getByTestID('sorter--desc').click() + cy.getByTestID('resource-sorter--button') + .click() + .then(() => { + cy.getByTestID('resource-sorter--properties.description-asc').click() + }) - cy.getByTestIDSubStr('resource-card').then(labels => { + cy.getByTestID('label-card').then(labels => { for (let i = 0; i < labels.length; i++) { - cy.getByTestIDSubStr('resource-card') + cy.getByTestID('label-card--description') .eq(i) - .should('have.text', 'Description: ' + names[i].description) + .should('have.text', names[i].description) } }) // check sort desc - cy.getByTestID('sorter--desc').click() + cy.getByTestID('resource-sorter--button') + .click() + .then(() => { + cy.getByTestID('resource-sorter--properties.description-desc').click() + }) - cy.getByTestIDSubStr('resource-card').then(labels => { + cy.getByTestID('label-card').then(labels => { for (let i = 0; i < labels.length; i++) { - cy.getByTestIDSubStr('resource-card') + cy.getByTestID('label-card--description') .eq(i) - .should( - 'have.text', - 'Description: ' + names[labels.length - (i + 1)].description - ) + .should('have.text', names[labels.length - (i + 1)].description) } }) }) diff --git a/ui/cypress/e2e/variables.test.ts b/ui/cypress/e2e/variables.test.ts index 64125540a7..8674c822c3 100644 --- a/ui/cypress/e2e/variables.test.ts +++ b/ui/cypress/e2e/variables.test.ts @@ -42,7 +42,7 @@ describe('Variables', () => { }) it('keeps user input in text area when attempting to import invalid JSON', () => { - cy.get('.tabbed-page-section--header').within(() => { + cy.getByTestID('tabbed-page--header').within(() => { cy.contains('Create').click() }) diff --git a/ui/src/authorizations/components/TokensTab.tsx b/ui/src/authorizations/components/TokensTab.tsx index 32d8d8d08b..2a346d2bbe 100644 --- a/ui/src/authorizations/components/TokensTab.tsx +++ b/ui/src/authorizations/components/TokensTab.tsx @@ -55,20 +55,28 @@ class TokensTab extends PureComponent { const {searchTerm, sortKey, sortDirection, sortType} = this.state const {tokens} = this.props + const leftHeaderItems = ( + + ) + + const rightHeaderItems = ( + + ) + return ( <> - - - - + ( - +
What is a Bucket?
diff --git a/ui/src/buckets/components/BucketList.tsx b/ui/src/buckets/components/BucketList.tsx index 51701c7f0d..92b06c7bf6 100644 --- a/ui/src/buckets/components/BucketList.tsx +++ b/ui/src/buckets/components/BucketList.tsx @@ -18,8 +18,6 @@ import {Sort} from '@influxdata/clockface' // Utils import {SortTypes} from 'src/shared/utils/sort' -type SortKey = keyof Bucket | 'retentionRules[0].everySeconds' - interface Props { buckets: Bucket[] emptyState: JSX.Element @@ -29,9 +27,6 @@ interface Props { sortKey: string sortDirection: Sort sortType: SortTypes - onClickColumn: ( - sortType: SortTypes - ) => (nextSort: Sort, sortKey: SortKey) => void } class BucketList extends PureComponent { @@ -40,38 +35,15 @@ class BucketList extends PureComponent { ) public render() { - const {sortKey, sortDirection, onClickColumn} = this.props return ( - <> - - - - - - - {this.listBuckets} - - - + + + {this.listBuckets} + + ) } - private get headerKeys(): SortKey[] { - return ['name', 'retentionRules[0].everySeconds'] - } - private get listBuckets(): JSX.Element[] { const { buckets, diff --git a/ui/src/buckets/components/BucketsTab.tsx b/ui/src/buckets/components/BucketsTab.tsx index 0c56d0831a..1d1d894e16 100644 --- a/ui/src/buckets/components/BucketsTab.tsx +++ b/ui/src/buckets/components/BucketsTab.tsx @@ -18,13 +18,15 @@ import { Overlay, } from '@influxdata/clockface' import SearchWidget from 'src/shared/components/search_widget/SearchWidget' -import SettingsTabbedPageHeader from 'src/settings/components/SettingsTabbedPageHeader' +import TabbedPageHeader from 'src/shared/components/tabbed_page/TabbedPageHeader' import FilterList from 'src/shared/components/FilterList' import BucketList from 'src/buckets/components/BucketList' import CreateBucketOverlay from 'src/buckets/components/CreateBucketOverlay' import AssetLimitAlert from 'src/cloud/components/AssetLimitAlert' import BucketExplainer from 'src/buckets/components/BucketExplainer' import DemoDataDropdown from 'src/buckets/components/DemoDataDropdown' +import {FeatureFlag} from 'src/shared/utils/featureFlag' +import ResourceSortDropdown from 'src/shared/components/resource_sort_dropdown/ResourceSortDropdown' // Actions import { @@ -58,6 +60,7 @@ import { ResourceType, OwnBucket, } from 'src/types' +import {BucketSortKey} from 'src/shared/components/resource_sort_dropdown/generateSortItems' interface StateProps { org: Organization @@ -78,15 +81,13 @@ interface DispatchProps { interface State { searchTerm: string overlayState: OverlayState - sortKey: SortKey + sortKey: BucketSortKey sortDirection: Sort sortType: SortTypes } type Props = DispatchProps & StateProps -type SortKey = keyof Bucket - const FilterBuckets = FilterList() @ErrorHandling @@ -126,6 +127,46 @@ class BucketsTab extends PureComponent { sortType, } = this.state + const leftHeaderItems = ( + <> + + + + ) + + const rightHeaderItems = ( + <> + + {demoDataBuckets.length > 0 && ( + + )} + +