importDashboardFromFileModal.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. import {Fragment, useState} from 'react';
  2. import {browserHistory} from 'react-router';
  3. import {css} from '@emotion/react';
  4. import {createDashboard} from 'sentry/actionCreators/dashboards';
  5. import {addErrorMessage, addSuccessMessage} from 'sentry/actionCreators/indicator';
  6. import {Button} from 'sentry/components/button';
  7. import {CodeSnippet} from 'sentry/components/codeSnippet';
  8. import {IconUpload} from 'sentry/icons';
  9. import {t} from 'sentry/locale';
  10. import {normalizeUrl} from 'sentry/utils/withDomainRequired';
  11. import {
  12. assignDefaultLayout,
  13. getInitialColumnDepths,
  14. } from 'sentry/views/dashboards/layoutUtils';
  15. import {Wrapper} from 'sentry/views/discover/table/quickContext/styles';
  16. // Internal feature - no specs written.
  17. function ImportDashboardFromFileModal({
  18. Header,
  19. Body,
  20. Footer,
  21. organization,
  22. api,
  23. location,
  24. }) {
  25. const [dashboardData, setDashboardData] = useState('');
  26. const [validated, setValidated] = useState(false);
  27. function validateFile(fileToUpload) {
  28. if (!fileToUpload || !(fileToUpload.type === 'application/json')) {
  29. addErrorMessage('You must upload a JSON file');
  30. setValidated(false);
  31. setDashboardData('');
  32. return false;
  33. }
  34. setValidated(true);
  35. return true;
  36. }
  37. const handleFileChange = e => {
  38. const fileToUpload = e.target.files[0];
  39. if (validateFile(fileToUpload)) {
  40. const fileReader = new FileReader();
  41. fileReader.readAsText(fileToUpload, 'UTF-8');
  42. fileReader.onload = event => {
  43. const target = event.target;
  44. if (target && typeof target.result === 'string') {
  45. const parsed = JSON.parse(target.result);
  46. const formatted = JSON.stringify(parsed, null, '\t');
  47. setDashboardData(formatted);
  48. }
  49. };
  50. }
  51. };
  52. const handleUploadClick = async () => {
  53. const dashboard = JSON.parse(dashboardData);
  54. try {
  55. const newDashboard = await createDashboard(
  56. api,
  57. organization.slug,
  58. {
  59. ...dashboard,
  60. widgets: assignDefaultLayout(dashboard.widgets, getInitialColumnDepths()),
  61. },
  62. true
  63. );
  64. addSuccessMessage(`${dashboard.title} dashboard template successfully added`);
  65. loadDashboard(newDashboard.id);
  66. } catch (error) {
  67. addErrorMessage('Could not upload dashboard, JSON may be invalid');
  68. }
  69. };
  70. const loadDashboard = (dashboardId: string) => {
  71. browserHistory.push(
  72. normalizeUrl({
  73. pathname: `/organizations/${organization.slug}/dashboards/${dashboardId}/`,
  74. query: location.query,
  75. })
  76. );
  77. };
  78. return (
  79. <Fragment>
  80. <Header closeButton>
  81. <h4>{t('Import Dashboard from JSON File')}</h4>
  82. </Header>
  83. <Body>
  84. <Wrapper>
  85. <input type="file" onChange={handleFileChange} />
  86. </Wrapper>
  87. <Wrapper>
  88. <Button
  89. onClick={handleUploadClick}
  90. size="md"
  91. disabled={!validated}
  92. priority="primary"
  93. icon={<IconUpload />}
  94. >
  95. {t('Import')}
  96. </Button>
  97. </Wrapper>
  98. </Body>
  99. {validated && (
  100. <Fragment>
  101. <Footer />
  102. <Wrapper>
  103. <h4>{t('Preview')}</h4>
  104. </Wrapper>
  105. <CodeSnippet language="json">{dashboardData}</CodeSnippet>
  106. </Fragment>
  107. )}
  108. </Fragment>
  109. );
  110. }
  111. export default ImportDashboardFromFileModal;
  112. export const modalCss = css`
  113. max-width: 700px;
  114. margin: 70px auto;
  115. `;