Merge branch 'feat/dashboards-container-org' of github.com:influxdata/influxdb into feat/dashboards-container-org
commit
5655a06be2
|
@ -15,9 +15,8 @@
|
|||
1. [11700](https://github.com/influxdata/influxdb/pull/11700): Update Tasks tab on Org page to look like Tasks Page
|
||||
1. [11740](https://github.com/influxdata/influxdb/pull/11740): Add view button to view the telegraf config toml
|
||||
1. [11522](https://github.com/influxdata/influxdb/pull/11522): Add plugin information step to allow for config naming and configure one plugin at a time
|
||||
|
||||
### Bug Fixes
|
||||
1. [11758](https://github.com/influxdata/influxdb/pull/11758): Update Dashboards tab on Org page to look like Dashboards Page
|
||||
|
||||
## Bug Fixes
|
||||
1. [11678](https://github.com/influxdata/influxdb/pull/11678): Update the System Telegraf Plugin bundle to include the swap plugin
|
||||
1. [11722](https://github.com/influxdata/influxdb/pull/11722): Revert behavior allowing users to create authorizations on behalf of another user
|
||||
|
|
|
@ -207,9 +207,3 @@
|
|||
.index-list--row-cell .index-list--cell a {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.index-list--resource-name {
|
||||
margin-left: 6px;
|
||||
margin-right: $ix-marg-a + $ix-marg-b;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import {downloadTextFile} from 'src/shared/utils/download'
|
|||
import _ from 'lodash'
|
||||
|
||||
// Components
|
||||
import DashboardsContents from 'src/dashboards/components/dashboard_index/Contents'
|
||||
import DashboardsIndexContents from 'src/dashboards/components/dashboard_index/DashboardsIndexContents'
|
||||
import {Page} from 'src/pageLayout'
|
||||
import SearchWidget from 'src/shared/components/search_widget/SearchWidget'
|
||||
import {
|
||||
|
@ -132,7 +132,8 @@ class DashboardIndex extends PureComponent<Props, State> {
|
|||
</Page.Header.Right>
|
||||
</Page.Header>
|
||||
<Page.Contents fullWidth={false} scrollable={true}>
|
||||
<DashboardsContents
|
||||
<div className="col-md-12">
|
||||
<DashboardsIndexContents
|
||||
dashboards={dashboards}
|
||||
orgs={orgs}
|
||||
onSetDefaultDashboard={this.handleSetDefaultDashboard}
|
||||
|
@ -145,7 +146,9 @@ class DashboardIndex extends PureComponent<Props, State> {
|
|||
onEditLabels={this.handleStartEditingLabels}
|
||||
notify={notify}
|
||||
searchTerm={searchTerm}
|
||||
showOwnerColumn={true}
|
||||
/>
|
||||
</div>
|
||||
</Page.Contents>
|
||||
</Page>
|
||||
{this.renderImportOverlay}
|
||||
|
|
|
@ -25,7 +25,7 @@ interface Props {
|
|||
onEditLabels: (dashboard: Dashboard) => void
|
||||
notify: (message: Notification) => void
|
||||
searchTerm: string
|
||||
showInlineEdit?: boolean
|
||||
showOwnerColumn: boolean
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
|
@ -42,11 +42,10 @@ export default class DashboardsIndexContents extends Component<Props> {
|
|||
onEditLabels,
|
||||
searchTerm,
|
||||
orgs,
|
||||
showInlineEdit,
|
||||
showOwnerColumn,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<div className="col-md-12">
|
||||
<Table
|
||||
searchTerm={searchTerm}
|
||||
dashboards={this.filteredDashboards}
|
||||
|
@ -59,9 +58,8 @@ export default class DashboardsIndexContents extends Component<Props> {
|
|||
onUpdateDashboard={onUpdateDashboard}
|
||||
onEditLabels={onEditLabels}
|
||||
orgs={orgs}
|
||||
showInlineEdit={showInlineEdit}
|
||||
showOwnerColumn={showOwnerColumn}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -20,6 +20,10 @@ import SortingHat from 'src/shared/components/sorting_hat/SortingHat'
|
|||
import {Sort} from 'src/clockface'
|
||||
import {Dashboard, Organization} from 'src/types/v2'
|
||||
|
||||
// Constants
|
||||
const OWNER_COL_WIDTH = 17
|
||||
const NAME_COL_WIDTH = 63
|
||||
|
||||
interface Props {
|
||||
searchTerm: string
|
||||
dashboards: Dashboard[]
|
||||
|
@ -32,7 +36,7 @@ interface Props {
|
|||
onSetDefaultDashboard: (dashboardLink: string) => void
|
||||
onEditLabels: (dashboard: Dashboard) => void
|
||||
orgs: Organization[]
|
||||
showInlineEdit?: boolean
|
||||
showOwnerColumn: boolean
|
||||
}
|
||||
|
||||
interface DatedDashboard extends Dashboard {
|
||||
|
@ -57,29 +61,22 @@ class DashboardsTable extends PureComponent<Props & WithRouterProps, State> {
|
|||
|
||||
public render() {
|
||||
const {sortKey, sortDirection} = this.state
|
||||
const headerKeys: SortKey[] = ['name', 'owner', 'modified', 'default']
|
||||
|
||||
return (
|
||||
<IndexList>
|
||||
<IndexList.Header>
|
||||
<IndexList.HeaderCell
|
||||
columnName={headerKeys[0]}
|
||||
sortKey={headerKeys[0]}
|
||||
sort={sortKey === headerKeys[0] ? sortDirection : Sort.None}
|
||||
width="62%"
|
||||
columnName={this.headerKeys[0]}
|
||||
sortKey={this.headerKeys[0]}
|
||||
sort={sortKey === this.headerKeys[0] ? sortDirection : Sort.None}
|
||||
width={this.nameColWidth}
|
||||
onClick={this.handleClickColumn}
|
||||
/>
|
||||
{this.ownerColumnHeader}
|
||||
<IndexList.HeaderCell
|
||||
columnName={headerKeys[1]}
|
||||
sortKey={headerKeys[1]}
|
||||
sort={sortKey === headerKeys[1] ? sortDirection : Sort.None}
|
||||
width="17%"
|
||||
onClick={this.handleClickColumn}
|
||||
/>
|
||||
<IndexList.HeaderCell
|
||||
columnName={headerKeys[2]}
|
||||
sortKey={headerKeys[2]}
|
||||
sort={sortKey === headerKeys[2] ? sortDirection : Sort.None}
|
||||
columnName={this.headerKeys[2]}
|
||||
sortKey={this.headerKeys[2]}
|
||||
sort={sortKey === this.headerKeys[2] ? sortDirection : Sort.None}
|
||||
width="11%"
|
||||
onClick={this.handleClickColumn}
|
||||
/>
|
||||
|
@ -96,6 +93,37 @@ class DashboardsTable extends PureComponent<Props & WithRouterProps, State> {
|
|||
)
|
||||
}
|
||||
|
||||
private get headerKeys(): SortKey[] {
|
||||
return ['name', 'owner', 'modified', 'default']
|
||||
}
|
||||
|
||||
private get ownerColumnHeader(): JSX.Element {
|
||||
const {showOwnerColumn} = this.props
|
||||
const {sortKey, sortDirection} = this.state
|
||||
|
||||
if (showOwnerColumn) {
|
||||
return (
|
||||
<IndexList.HeaderCell
|
||||
columnName={this.headerKeys[1]}
|
||||
sortKey={this.headerKeys[1]}
|
||||
sort={sortKey === this.headerKeys[1] ? sortDirection : Sort.None}
|
||||
width={`${OWNER_COL_WIDTH}%`}
|
||||
onClick={this.handleClickColumn}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private get nameColWidth(): string {
|
||||
const {showOwnerColumn} = this.props
|
||||
|
||||
if (showOwnerColumn) {
|
||||
return `${NAME_COL_WIDTH}%`
|
||||
}
|
||||
|
||||
return `${NAME_COL_WIDTH + OWNER_COL_WIDTH}%`
|
||||
}
|
||||
|
||||
private handleClickColumn = (nextSort: Sort, sortKey: SortKey) => {
|
||||
this.setState({sortKey, sortDirection: nextSort})
|
||||
}
|
||||
|
@ -109,7 +137,7 @@ class DashboardsTable extends PureComponent<Props & WithRouterProps, State> {
|
|||
onUpdateDashboard,
|
||||
onEditLabels,
|
||||
orgs,
|
||||
showInlineEdit,
|
||||
showOwnerColumn,
|
||||
} = this.props
|
||||
|
||||
const {sortKey, sortDirection} = this.state
|
||||
|
@ -130,7 +158,7 @@ class DashboardsTable extends PureComponent<Props & WithRouterProps, State> {
|
|||
onUpdateDashboard={onUpdateDashboard}
|
||||
onEditLabels={onEditLabels}
|
||||
orgs={orgs}
|
||||
showInlineEdit={showInlineEdit}
|
||||
showOwnerColumn={showOwnerColumn}
|
||||
/>
|
||||
)}
|
||||
</SortingHat>
|
||||
|
|
|
@ -18,6 +18,7 @@ const setup = (override = {}) => {
|
|||
onExportDashboard: jest.fn(),
|
||||
onUpdateDashboard: jest.fn(),
|
||||
onEditLabels: jest.fn(),
|
||||
showOwnerColumn: true,
|
||||
...override,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
import {Link} from 'react-router'
|
||||
import classnames from 'classnames'
|
||||
|
||||
// Components
|
||||
import {
|
||||
|
@ -37,7 +36,7 @@ interface Props {
|
|||
onExportDashboard: (dashboard: Dashboard) => void
|
||||
onUpdateDashboard: (dashboard: Dashboard) => void
|
||||
onEditLabels: (dashboard: Dashboard) => void
|
||||
showInlineEdit?: boolean
|
||||
showOwnerColumn: boolean
|
||||
}
|
||||
|
||||
export default class DashboardsIndexTableRow extends PureComponent<Props> {
|
||||
|
@ -67,7 +66,7 @@ export default class DashboardsIndexTableRow extends PureComponent<Props> {
|
|||
/>
|
||||
</ComponentSpacer>
|
||||
</IndexList.Cell>
|
||||
<IndexList.Cell>{this.ownerName}</IndexList.Cell>
|
||||
{this.ownerCell}
|
||||
{this.lastModifiedCell}
|
||||
<IndexList.Cell alignment={Alignment.Right} revealOnHover={true}>
|
||||
<ComponentSpacer align={Alignment.Left} stackChildren={Stack.Columns}>
|
||||
|
@ -91,23 +90,26 @@ export default class DashboardsIndexTableRow extends PureComponent<Props> {
|
|||
)
|
||||
}
|
||||
|
||||
private get ownerCell(): JSX.Element {
|
||||
const {showOwnerColumn} = this.props
|
||||
|
||||
if (showOwnerColumn) {
|
||||
return <IndexList.Cell>{this.ownerName}</IndexList.Cell>
|
||||
}
|
||||
}
|
||||
|
||||
private get resourceNames(): JSX.Element {
|
||||
const {showInlineEdit, dashboard} = this.props
|
||||
if (showInlineEdit) {
|
||||
const {dashboard} = this.props
|
||||
|
||||
return (
|
||||
<EditableName
|
||||
onUpdate={this.handleUpdateDashboard}
|
||||
name={dashboard.name}
|
||||
hrefValue={`/dashboards/${dashboard.id}`}
|
||||
noNameString={DEFAULT_DASHBOARD_NAME}
|
||||
/>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Link className={this.nameClassName} to={`/dashboards/${dashboard.id}`}>
|
||||
{this.name}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
private handleUpdateDashboard = (name: string) => {
|
||||
this.props.onUpdateDashboard({...this.props.dashboard, name})
|
||||
|
@ -120,7 +122,6 @@ export default class DashboardsIndexTableRow extends PureComponent<Props> {
|
|||
return (
|
||||
<Label.Container
|
||||
limitChildCount={4}
|
||||
className="index-list--labels"
|
||||
onEdit={this.handleEditLabels}
|
||||
resourceName="this Dashboard"
|
||||
/>
|
||||
|
@ -167,12 +168,6 @@ export default class DashboardsIndexTableRow extends PureComponent<Props> {
|
|||
onEditLabels(dashboard)
|
||||
}
|
||||
|
||||
private get name(): string {
|
||||
const {dashboard} = this.props
|
||||
|
||||
return dashboard.name || DEFAULT_DASHBOARD_NAME
|
||||
}
|
||||
|
||||
private get ownerName(): JSX.Element {
|
||||
const {dashboard, orgs} = this.props
|
||||
const ownerOrg = orgs.find(o => o.id === dashboard.orgID)
|
||||
|
@ -184,17 +179,6 @@ export default class DashboardsIndexTableRow extends PureComponent<Props> {
|
|||
)
|
||||
}
|
||||
|
||||
private get nameClassName(): string {
|
||||
const {dashboard} = this.props
|
||||
|
||||
const dashboardIsUntitled =
|
||||
dashboard.name === '' || dashboard.name === DEFAULT_DASHBOARD_NAME
|
||||
|
||||
return classnames('index-list--resource-name', {
|
||||
'untitled-name': dashboardIsUntitled,
|
||||
})
|
||||
}
|
||||
|
||||
private handleUpdateDescription = (description: string): void => {
|
||||
const {onUpdateDashboard} = this.props
|
||||
const dashboard = {...this.props.dashboard, description}
|
||||
|
|
|
@ -15,7 +15,7 @@ interface Props {
|
|||
onUpdateDashboard: (dashboard: Dashboard) => void
|
||||
onEditLabels: (dashboard: Dashboard) => void
|
||||
orgs: Organization[]
|
||||
showInlineEdit?: boolean
|
||||
showOwnerColumn: boolean
|
||||
}
|
||||
|
||||
export default class DashboardsIndexTableRows extends PureComponent<Props> {
|
||||
|
@ -28,7 +28,7 @@ export default class DashboardsIndexTableRows extends PureComponent<Props> {
|
|||
onUpdateDashboard,
|
||||
onEditLabels,
|
||||
orgs,
|
||||
showInlineEdit,
|
||||
showOwnerColumn,
|
||||
} = this.props
|
||||
|
||||
return dashboards.map(d => (
|
||||
|
@ -41,7 +41,7 @@ export default class DashboardsIndexTableRows extends PureComponent<Props> {
|
|||
onUpdateDashboard={onUpdateDashboard}
|
||||
onEditLabels={onEditLabels}
|
||||
orgs={orgs}
|
||||
showInlineEdit={showInlineEdit}
|
||||
showOwnerColumn={showOwnerColumn}
|
||||
/>
|
||||
))
|
||||
}
|
||||
|
|
|
@ -89,6 +89,10 @@ type NewDefaultDashboard = Pick<
|
|||
>
|
||||
export const DEFAULT_CELL_NAME = 'Name this Cell'
|
||||
export const DEFAULT_DASHBOARD_NAME = 'Name this Dashboard'
|
||||
export const DEFAULT_BUCKET_NAME = 'Name this Bucket'
|
||||
export const DEFAULT_COLLECTOR_NAME = 'Name this Collector'
|
||||
export const DEFAULT_TASK_NAME = 'Name this Task'
|
||||
export const DEFAULT_SCRAPER_NAME = 'Name this Scraper'
|
||||
export const NEW_DASHBOARD: NewDefaultDashboard = {
|
||||
name: DEFAULT_DASHBOARD_NAME,
|
||||
cells: [NEW_DEFAULT_DASHBOARD_CELL],
|
||||
|
|
|
@ -12,6 +12,9 @@ import {
|
|||
ComponentColor,
|
||||
} from 'src/clockface'
|
||||
|
||||
// Constants
|
||||
import {DEFAULT_BUCKET_NAME} from 'src/dashboards/constants'
|
||||
|
||||
// Types
|
||||
import {Bucket} from '@influxdata/influx'
|
||||
import {DataLoaderType} from 'src/types/v2/dataLoaders'
|
||||
|
@ -40,6 +43,7 @@ export default class BucketRow extends PureComponent<Props> {
|
|||
onUpdate={this.handleUpdateBucketName}
|
||||
name={bucket.name}
|
||||
onEditName={this.handleEditBucket}
|
||||
noNameString={DEFAULT_BUCKET_NAME}
|
||||
/>
|
||||
</IndexList.Cell>
|
||||
<IndexList.Cell>{bucket.ruleString}</IndexList.Cell>
|
||||
|
|
|
@ -14,6 +14,9 @@ import {
|
|||
import {Telegraf} from '@influxdata/influx'
|
||||
import EditableName from 'src/shared/components/EditableName'
|
||||
|
||||
// Constants
|
||||
import {DEFAULT_COLLECTOR_NAME} from 'src/dashboards/constants'
|
||||
|
||||
interface Props {
|
||||
collector: Telegraf
|
||||
bucket: string
|
||||
|
@ -33,6 +36,7 @@ export default class CollectorRow extends PureComponent<Props> {
|
|||
<EditableName
|
||||
onUpdate={this.handleUpdateConfig}
|
||||
name={collector.name}
|
||||
noNameString={DEFAULT_COLLECTOR_NAME}
|
||||
/>
|
||||
</IndexList.Cell>
|
||||
<IndexList.Cell>{bucket}</IndexList.Cell>
|
||||
|
|
|
@ -6,13 +6,11 @@ import _ from 'lodash'
|
|||
import {ComponentSize, EmptyState, IconFont, Input} from 'src/clockface'
|
||||
import MemberList from 'src/organizations/components/MemberList'
|
||||
import FilterList from 'src/shared/components/Filter'
|
||||
import TabbedPageHeader from 'src/shared/components/tabbed_page/TabbedPageHeader'
|
||||
|
||||
// Types
|
||||
import {ResourceOwner} from '@influxdata/influx'
|
||||
|
||||
// Constants
|
||||
import TabbedPageHeader from 'src/shared/components/tabbed_page/TabbedPageHeader'
|
||||
|
||||
interface Props {
|
||||
members: ResourceOwner[]
|
||||
orgName: string
|
||||
|
|
|
@ -6,8 +6,7 @@ import {downloadTextFile} from 'src/shared/utils/download'
|
|||
import _ from 'lodash'
|
||||
|
||||
// Components
|
||||
import DashboardsContents from 'src/dashboards/components/dashboard_index/Contents'
|
||||
import {Page} from 'src/pageLayout'
|
||||
import DashboardsIndexContents from 'src/dashboards/components/dashboard_index/DashboardsIndexContents'
|
||||
import {
|
||||
OverlayTechnology,
|
||||
Button,
|
||||
|
@ -17,6 +16,7 @@ import {
|
|||
} from 'src/clockface'
|
||||
import ImportDashboardOverlay from 'src/dashboards/components/ImportDashboardOverlay'
|
||||
import EditLabelsOverlay from 'src/shared/components/EditLabelsOverlay'
|
||||
import TabbedPageHeader from 'src/shared/components/tabbed_page/TabbedPageHeader'
|
||||
|
||||
// Utils
|
||||
import {getDeep} from 'src/utils/wrappers'
|
||||
|
@ -116,9 +116,7 @@ class OrgDashboardIndex extends PureComponent<Props, State> {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Page titleTag="Dashboards">
|
||||
<Page.Header fullWidth={false}>
|
||||
<Page.Header.Left>
|
||||
<TabbedPageHeader>
|
||||
<Input
|
||||
icon={IconFont.Search}
|
||||
placeholder="Filter tasks..."
|
||||
|
@ -127,8 +125,6 @@ class OrgDashboardIndex extends PureComponent<Props, State> {
|
|||
onChange={this.handleFilterChange}
|
||||
onBlur={this.handleFilterBlur}
|
||||
/>
|
||||
</Page.Header.Left>
|
||||
<Page.Header.Right>
|
||||
<Button
|
||||
color={ComponentColor.Primary}
|
||||
onClick={this.handleCreateDashboard}
|
||||
|
@ -136,10 +132,8 @@ class OrgDashboardIndex extends PureComponent<Props, State> {
|
|||
text="Create Dashboard"
|
||||
titleText="Create a new dashboard"
|
||||
/>
|
||||
</Page.Header.Right>
|
||||
</Page.Header>
|
||||
<Page.Contents fullWidth={false} scrollable={true}>
|
||||
<DashboardsContents
|
||||
</TabbedPageHeader>
|
||||
<DashboardsIndexContents
|
||||
dashboards={dashboards}
|
||||
orgs={orgs}
|
||||
onSetDefaultDashboard={this.handleSetDefaultDashboard}
|
||||
|
@ -152,10 +146,8 @@ class OrgDashboardIndex extends PureComponent<Props, State> {
|
|||
onEditLabels={this.handleStartEditingLabels}
|
||||
notify={notify}
|
||||
searchTerm={searchTerm}
|
||||
showInlineEdit={true}
|
||||
showOwnerColumn={false}
|
||||
/>
|
||||
</Page.Contents>
|
||||
</Page>
|
||||
{this.renderImportOverlay}
|
||||
{this.renderLabelEditorOverlay}
|
||||
</>
|
||||
|
|
|
@ -11,6 +11,9 @@ import {
|
|||
import {ScraperTargetResponse} from '@influxdata/influx'
|
||||
import EditableName from 'src/shared/components/EditableName'
|
||||
|
||||
// Constants
|
||||
import {DEFAULT_SCRAPER_NAME} from 'src/dashboards/constants'
|
||||
|
||||
interface Props {
|
||||
scraper: ScraperTargetResponse
|
||||
onDeleteScraper: (scraper) => void
|
||||
|
@ -27,6 +30,7 @@ export default class ScraperRow extends PureComponent<Props> {
|
|||
<EditableName
|
||||
onUpdate={this.handleUpdateScraper}
|
||||
name={scraper.url}
|
||||
noNameString={DEFAULT_SCRAPER_NAME}
|
||||
/>
|
||||
</IndexList.Cell>
|
||||
<IndexList.Cell>{scraper.bucket}</IndexList.Cell>
|
||||
|
|
|
@ -5,82 +5,78 @@
|
|||
|
||||
@import 'src/style/modules';
|
||||
|
||||
$rename-dash-title-padding: 5px;
|
||||
$resource-name-font-size: 17px;
|
||||
$resource-name-font-wight: 600;
|
||||
$rename-dash-title-padding: 6px;
|
||||
|
||||
.editable-name {
|
||||
height: $form-xs-height;
|
||||
width: 100%;
|
||||
margin-top: -3px;
|
||||
}
|
||||
|
||||
.editable-name--preview,
|
||||
.editable-name > a,
|
||||
.input.editable-name--input > input {
|
||||
font-size: $form-xs-font;
|
||||
font-weight: 400;
|
||||
font-size: $resource-name-font-size;
|
||||
font-weight: $resource-name-font-wight;
|
||||
font-family: $ix-text-font;
|
||||
padding: 0 $rename-dash-title-padding;
|
||||
}
|
||||
|
||||
.editable-name--preview,
|
||||
.editable-name--input {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
.editable-name > a {
|
||||
white-space: nowrap;
|
||||
line-height: $resource-name-font-size;
|
||||
padding-left: ($rename-dash-title-padding + $ix-border);
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.editable-name--preview {
|
||||
display: inline-flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
border-radius: $radius;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@include no-user-select();
|
||||
color: $g13-mist;
|
||||
transition: color 0.25s ease, background-color 0.25s ease, border-color 0.25s ease;
|
||||
border: $ix-border solid transparent;
|
||||
.editable-name {
|
||||
height: $form-xs-height;
|
||||
line-height: $form-xs-height - ($ix-border * 2);
|
||||
|
||||
.icon {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.editable-name--toggle {
|
||||
font-size: $resource-name-font-size * 0.75;
|
||||
transform: translateY(-10%);
|
||||
padding: $ix-marg-a;
|
||||
display: inline-block;
|
||||
margin-left: $ix-marg-b;
|
||||
opacity: 0;
|
||||
transition: opacity 0.25s ease;
|
||||
color: $g11-sidewalk;
|
||||
}
|
||||
|
||||
&:hover .icon {
|
||||
transition: color 0.25s ease, opacity 0.25s ease;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.untitled {
|
||||
color: $g9-mountain;
|
||||
font-style: italic;
|
||||
}
|
||||
color: $g11-sidewalk;
|
||||
|
||||
&:hover {
|
||||
cursor: text;
|
||||
color: $g20-white;
|
||||
// background-color: $g3-castle;
|
||||
// border-color: $g3-castle;
|
||||
cursor: pointer;
|
||||
color: $g15-platinum;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.input.editable-name--input {
|
||||
position: absolute;
|
||||
top: -1px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Ensure placeholder text matches font weight of title */
|
||||
.input.editable-name--input > input {
|
||||
&::-webkit-input-placeholder {
|
||||
font-weight: $page-title-weight !important;
|
||||
font-weight: $resource-name-font-wight !important;
|
||||
}
|
||||
&::-moz-placeholder {
|
||||
font-weight: $page-title-weight !important;
|
||||
font-weight: $resource-name-font-wight !important;
|
||||
}
|
||||
&:-ms-input-placeholder {
|
||||
font-weight: $page-title-weight !important;
|
||||
font-weight: $resource-name-font-wight !important;
|
||||
}
|
||||
&:-moz-placeholder {
|
||||
font-weight: $page-title-weight !important;
|
||||
font-weight: $resource-name-font-wight !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* When used inside an index list, hide edit button until row hover */
|
||||
|
||||
.index-list--row .editable-name--toggle {
|
||||
opacity: 0;
|
||||
}
|
||||
.index-list--row:hover .editable-name--toggle {
|
||||
opacity: 1;
|
||||
}
|
|
@ -12,14 +12,20 @@ import {ErrorHandling} from 'src/shared/decorators/errors'
|
|||
// Styles
|
||||
import 'src/shared/components/EditableName.scss'
|
||||
|
||||
interface Props {
|
||||
interface PassedProps {
|
||||
onUpdate: (name: string) => void
|
||||
name: string
|
||||
onEditName: (e?: MouseEvent<HTMLAnchorElement>) => void
|
||||
hrefValue?: string
|
||||
onEditName?: (e?: MouseEvent<HTMLAnchorElement>) => void
|
||||
placeholder?: string
|
||||
noNameString: string
|
||||
}
|
||||
|
||||
interface DefaultProps {
|
||||
hrefValue?: string
|
||||
}
|
||||
|
||||
type Props = PassedProps & DefaultProps
|
||||
|
||||
interface State {
|
||||
isEditing: boolean
|
||||
workingName: string
|
||||
|
@ -27,9 +33,10 @@ interface State {
|
|||
|
||||
@ErrorHandling
|
||||
class EditableName extends Component<Props, State> {
|
||||
public static defaultProps: Partial<Props> = {
|
||||
public static defaultProps: DefaultProps = {
|
||||
hrefValue: '#',
|
||||
}
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
|
||||
|
@ -40,41 +47,31 @@ class EditableName extends Component<Props, State> {
|
|||
}
|
||||
|
||||
public render() {
|
||||
const {name, onEditName, hrefValue} = this.props
|
||||
const {isEditing} = this.state
|
||||
|
||||
if (isEditing) {
|
||||
return (
|
||||
<div className="editable-name">
|
||||
<ClickOutside onClickOutside={this.handleStopEditing}>
|
||||
{this.input}
|
||||
</ClickOutside>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
const {name, onEditName, hrefValue, noNameString} = this.props
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={this.className}>
|
||||
<a href={hrefValue} onClick={onEditName}>
|
||||
<span>{name || 'No name'}</span>
|
||||
<span>{name || noNameString}</span>
|
||||
</a>
|
||||
<div className="editable-name">
|
||||
<div
|
||||
className={this.previewClassName}
|
||||
className="editable-name--toggle"
|
||||
onClick={this.handleStartEditing}
|
||||
>
|
||||
<span className="icon pencil" />
|
||||
</div>
|
||||
{this.input}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
private get input(): JSX.Element {
|
||||
const {placeholder} = this.props
|
||||
const {workingName} = this.state
|
||||
const {workingName, isEditing} = this.state
|
||||
|
||||
if (isEditing) {
|
||||
return (
|
||||
<ClickOutside onClickOutside={this.handleStopEditing}>
|
||||
<Input
|
||||
size={ComponentSize.ExtraSmall}
|
||||
maxLength={90}
|
||||
|
@ -87,8 +84,10 @@ class EditableName extends Component<Props, State> {
|
|||
customClass="editable-name--input"
|
||||
value={workingName}
|
||||
/>
|
||||
</ClickOutside>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private handleStartEditing = (): void => {
|
||||
this.setState({isEditing: true})
|
||||
|
@ -127,11 +126,11 @@ class EditableName extends Component<Props, State> {
|
|||
e.currentTarget.select()
|
||||
}
|
||||
|
||||
private get previewClassName(): string {
|
||||
const {name} = this.props
|
||||
private get className(): string {
|
||||
const {name, noNameString} = this.props
|
||||
|
||||
return classnames('editable-name--preview', {
|
||||
untitled: name === '',
|
||||
return classnames('editable-name', {
|
||||
'untitled-name': name === noNameString,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,9 @@ import {
|
|||
import {downloadTextFile} from 'src/shared/utils/download'
|
||||
import {Task as TaskAPI, Organization} from '@influxdata/influx'
|
||||
|
||||
// Constants
|
||||
import {DEFAULT_TASK_NAME} from 'src/dashboards/constants'
|
||||
|
||||
interface Task extends TaskAPI {
|
||||
organization: Organization
|
||||
}
|
||||
|
@ -102,6 +105,7 @@ export class TaskRow extends PureComponent<Props & WithRouterProps> {
|
|||
onUpdate={this.handleUpdateTask}
|
||||
name={task.name}
|
||||
onEditName={this.handleClick}
|
||||
noNameString={DEFAULT_TASK_NAME}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue