Skip to content

Commit 5e12471

Browse files
feat: re-enable exporting/importing of dashboards using v2 templates (#3817)
1 parent f7e64a6 commit 5e12471

File tree

10 files changed

+163
-14
lines changed

10 files changed

+163
-14
lines changed

src/dashboards/actions/thunks.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {get} from 'lodash'
77
// APIs
88
import * as dashAPI from 'src/dashboards/apis'
99
import * as api from 'src/client'
10-
import * as tempAPI from 'src/templates/api'
10+
import {createDashboardFromPkgerTemplate} from 'src/templates/api'
1111
import {createCellWithView} from 'src/cells/actions/thunks'
1212

1313
// Schemas
@@ -62,7 +62,6 @@ import {
6262
GetState,
6363
View,
6464
Cell,
65-
DashboardTemplate,
6665
Label,
6766
RemoteDataState,
6867
DashboardEntities,
@@ -290,13 +289,14 @@ export const getDashboards = () => async (
290289
}
291290
}
292291

293-
export const createDashboardFromTemplate = (
294-
template: DashboardTemplate
295-
) => async (dispatch, getState: GetState) => {
292+
export const createDashboardFromTemplate = (template: api.Template) => async (
293+
dispatch,
294+
getState: GetState
295+
) => {
296296
try {
297297
const org = getOrg(getState())
298298

299-
await tempAPI.createDashboardFromTemplate(template, org.id)
299+
await createDashboardFromPkgerTemplate(template, org.id)
300300

301301
const resp = await api.getDashboards({query: {orgID: org.id}})
302302

src/dashboards/apis/index.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
// APIs
22
import * as api from 'src/client'
3+
import {postTemplatesExport} from 'src/client'
4+
5+
// Utils
6+
import {downloadTextFile} from 'src/shared/utils/download'
37

48
// Types
59
import {Cell, View, NewView, RemoteDataState} from 'src/types'
@@ -88,3 +92,23 @@ export const cloneUtilFunc = async (
8892
}
8993
})
9094
}
95+
96+
export const downloadDashboardTemplate = async (dashboard): Promise<void> => {
97+
const resp = await postTemplatesExport({
98+
data: {
99+
resources: [
100+
{
101+
kind: 'Dashboard',
102+
id: dashboard.id,
103+
},
104+
],
105+
},
106+
})
107+
108+
if (resp.status === 500) {
109+
throw new Error(resp.data.message)
110+
}
111+
112+
const data = await resp.data
113+
downloadTextFile(JSON.stringify(data), dashboard.name, '.json', 'text/json')
114+
}

src/dashboards/components/dashboard_index/DashboardCard.tsx

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import React, {createRef, PureComponent, RefObject} from 'react'
33
import {connect, ConnectedProps} from 'react-redux'
44
import {withRouter, RouteComponentProps} from 'react-router-dom'
55

6+
import {downloadDashboardTemplate} from 'src/dashboards/apis'
7+
68
// Components
79
import {
810
IconFont,
@@ -69,6 +71,9 @@ interface OwnProps {
6971
type ReduxProps = ConnectedProps<typeof connector>
7072
type Props = OwnProps & ReduxProps & RouteComponentProps<{orgID: string}>
7173

74+
const fontWeight = {fontWeight: '500px'}
75+
const minWidth = {minWidth: '165px'}
76+
7277
class DashboardCard extends PureComponent<Props> {
7378
public render() {
7479
const {
@@ -178,13 +183,21 @@ class DashboardCard extends PureComponent<Props> {
178183
<Popover
179184
appearance={Appearance.Outline}
180185
enableDefaultStyles={false}
181-
style={{minWidth: '112px'}}
186+
style={minWidth}
182187
contents={() => (
183188
<List>
189+
<List.Item
190+
onClick={this.handleExport}
191+
size={ComponentSize.Small}
192+
style={fontWeight}
193+
testID="context-export-dashboard"
194+
>
195+
Download Template
196+
</List.Item>
184197
<List.Item
185198
onClick={this.handleCloneDashboard}
186199
size={ComponentSize.Small}
187-
style={{fontWeight: 500}}
200+
style={fontWeight}
188201
testID="context-clone-dashboard"
189202
>
190203
Clone
@@ -194,7 +207,7 @@ class DashboardCard extends PureComponent<Props> {
194207
onClick={this.handlePinDashboard}
195208
disabled={this.props.isPinned}
196209
size={ComponentSize.Small}
197-
style={{fontWeight: 500}}
210+
style={fontWeight}
198211
testID="context-pin-dashboard"
199212
>
200213
Pin
@@ -261,6 +274,10 @@ class DashboardCard extends PureComponent<Props> {
261274

262275
onRemoveDashboardLabel(id, label)
263276
}
277+
278+
private handleExport = () => {
279+
downloadDashboardTemplate(this.props.dashboard)
280+
}
264281
}
265282

266283
const mdtp = {
@@ -273,13 +290,15 @@ const mdtp = {
273290
sendNotification: notify,
274291
}
275292

276-
const mstp = (state: AppState) => {
293+
const mstp = (state: AppState, props: OwnProps) => {
294+
const dashboard = state.resources.dashboards.byID[props.id]
277295
const me = getMe(state)
278296
const org = getOrg(state)
279297

280298
return {
281-
org,
299+
dashboard,
282300
me,
301+
org,
283302
}
284303
}
285304
const connector = connect(mstp, mdtp)

src/dashboards/components/dashboard_index/DashboardsIndex.tsx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Libraries
22
import React, {PureComponent} from 'react'
3-
import {RouteComponentProps} from 'react-router-dom'
3+
import {Route, RouteComponentProps, Switch} from 'react-router-dom'
44
import {connect, ConnectedProps} from 'react-redux'
55

66
// Decorators
@@ -14,6 +14,7 @@ import AddResourceDropdown from 'src/shared/components/AddResourceDropdown'
1414
import GetAssetLimits from 'src/cloud/components/GetAssetLimits'
1515
import RateLimitAlert from 'src/cloud/components/RateLimitAlert'
1616
import ResourceSortDropdown from 'src/shared/components/resource_sort_dropdown/ResourceSortDropdown'
17+
import DashboardImportOverlay from 'src/dashboards/components/DashboardImportOverlay'
1718

1819
// Utils
1920
import {pageTitleSuffixer} from 'src/shared/utils/pageTitles'
@@ -84,6 +85,7 @@ class DashboardIndex extends PureComponent<Props, State> {
8485
<Page.ControlBarRight>
8586
<AddResourceDropdown
8687
onSelectNew={createDashboard}
88+
onSelectImport={this.summonImportOverlay}
8789
onSelectTemplate={this.summonTemplatePage}
8890
resourceName="Dashboard"
8991
limitStatus={limitStatus}
@@ -111,6 +113,12 @@ class DashboardIndex extends PureComponent<Props, State> {
111113
</Page.Contents>
112114
</ErrorBoundary>
113115
</Page>
116+
<Switch>
117+
<Route
118+
path="/orgs/:orgID/dashboards-list/import"
119+
component={DashboardImportOverlay}
120+
/>
121+
</Switch>
114122
</>
115123
)
116124
}
@@ -127,6 +135,16 @@ class DashboardIndex extends PureComponent<Props, State> {
127135
this.props.setDashboardSort({sortKey, sortDirection, sortType})
128136
}
129137

138+
private summonImportOverlay = (): void => {
139+
const {
140+
history,
141+
match: {
142+
params: {orgID},
143+
},
144+
} = this.props
145+
history.push(`/orgs/${orgID}/dashboards-list/import`)
146+
}
147+
130148
private summonTemplatePage = (): void => {
131149
const {
132150
history,

src/dashboards/components/dashboard_index/DashboardsIndexContentsPaginated.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ class DashboardsIndexContents extends Component<Props> implements Pageable {
140140
searchTerm={searchTerm}
141141
onCreateDashboard={onCreateDashboard}
142142
summonImportFromTemplateOverlay={this.summonImportFromTemplateOverlay}
143+
summonImportOverlay={this.summonImportOverlay}
143144
/>
144145
)
145146
}
@@ -169,6 +170,16 @@ class DashboardsIndexContents extends Component<Props> implements Pageable {
169170
)
170171
}
171172

173+
private summonImportOverlay = (): void => {
174+
const {
175+
history,
176+
match: {
177+
params: {orgID},
178+
},
179+
} = this.props
180+
history.push(`/orgs/${orgID}/dashboards-list/import`)
181+
}
182+
172183
private summonImportFromTemplateOverlay = (): void => {
173184
const {
174185
history,

src/dashboards/components/dashboard_index/DashboardsIndexPaginated.tsx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Libraries
22
import React, {PureComponent} from 'react'
3-
import {RouteComponentProps} from 'react-router-dom'
3+
import {Route, RouteComponentProps, Switch} from 'react-router-dom'
44
import {connect, ConnectedProps} from 'react-redux'
55
import {AutoSizer} from 'react-virtualized'
66

@@ -22,6 +22,7 @@ import AddResourceDropdown from 'src/shared/components/AddResourceDropdown'
2222
import GetAssetLimits from 'src/cloud/components/GetAssetLimits'
2323
import RateLimitAlert from 'src/cloud/components/RateLimitAlert'
2424
import ResourceSortDropdown from 'src/shared/components/resource_sort_dropdown/ResourceSortDropdown'
25+
import DashboardImportOverlay from 'src/dashboards/components/DashboardImportOverlay'
2526

2627
// Utils
2728
import {pageTitleSuffixer} from 'src/shared/utils/pageTitles'
@@ -141,6 +142,7 @@ class DashboardIndex extends PureComponent<Props, State> {
141142
<AddResourceDropdown
142143
onSelectNew={createDashboard}
143144
onSelectTemplate={this.summonTemplatePage}
145+
onSelectImport={this.summonImportOverlay}
144146
resourceName="Dashboard"
145147
limitStatus={limitStatus}
146148
/>
@@ -186,10 +188,26 @@ class DashboardIndex extends PureComponent<Props, State> {
186188
</Page.Contents>
187189
</ErrorBoundary>
188190
</Page>
191+
<Switch>
192+
<Route
193+
path="/orgs/:orgID/dashboards-list/import"
194+
component={DashboardImportOverlay}
195+
/>
196+
</Switch>
189197
</SpinnerContainer>
190198
)
191199
}
192200

201+
private summonImportOverlay = (): void => {
202+
const {
203+
history,
204+
match: {
205+
params: {orgID},
206+
},
207+
} = this.props
208+
history.push(`/orgs/${orgID}/dashboards-list/import`)
209+
}
210+
193211
private handleFilterDashboards = (searchTerm: string): void => {
194212
const url = new URL(location.href)
195213
url.searchParams.set('searchTerm', searchTerm)

src/dashboards/components/dashboard_index/DashboardsTableEmpty.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@ import {ResourceType} from 'src/types'
1616
interface ComponentProps {
1717
searchTerm?: string
1818
onCreateDashboard: typeof createDashboard
19+
summonImportOverlay: () => void
1920
summonImportFromTemplateOverlay: () => void
2021
}
2122

2223
const DashboardsTableEmpty: FC<ComponentProps> = ({
2324
searchTerm,
2425
onCreateDashboard,
26+
summonImportOverlay,
2527
summonImportFromTemplateOverlay,
2628
}) => {
2729
if (searchTerm) {
@@ -42,6 +44,7 @@ const DashboardsTableEmpty: FC<ComponentProps> = ({
4244
</EmptyState.Text>
4345
<AddResourceDropdown
4446
onSelectNew={onCreateDashboard}
47+
onSelectImport={summonImportOverlay}
4548
onSelectTemplate={summonImportFromTemplateOverlay}
4649
resourceName="Dashboard"
4750
/>
@@ -60,6 +63,7 @@ const DashboardsTableEmpty: FC<ComponentProps> = ({
6063
</EmptyState.Text>
6164
<AddResourceDropdown
6265
onSelectNew={onCreateDashboard}
66+
onSelectImport={summonImportOverlay}
6367
onSelectTemplate={summonImportFromTemplateOverlay}
6468
resourceName="Dashboard"
6569
/>

src/dashboards/components/dashboard_index/Table.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class DashboardsTable extends PureComponent<Props> {
5656
searchTerm={searchTerm}
5757
onCreateDashboard={onCreateDashboard}
5858
summonImportFromTemplateOverlay={this.summonImportFromTemplateOverlay}
59+
summonImportOverlay={this.summonImportOverlay}
5960
/>
6061
)
6162
}
@@ -71,6 +72,16 @@ class DashboardsTable extends PureComponent<Props> {
7172
)
7273
}
7374

75+
private summonImportOverlay = (): void => {
76+
const {
77+
history,
78+
match: {
79+
params: {orgID},
80+
},
81+
} = this.props
82+
history.push(`/orgs/${orgID}/dashboards-list/import`)
83+
}
84+
7485
private summonImportFromTemplateOverlay = (): void => {
7586
const {
7687
history,

0 commit comments

Comments
 (0)