rulesPanel.tsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import styled from '@emotion/styled';
  2. import TextArea from 'sentry/components/forms/controls/textarea';
  3. import {Panel, PanelBody, PanelHeader} from 'sentry/components/panels';
  4. import TimeSince from 'sentry/components/timeSince';
  5. import {IconGithub, IconGitlab, IconSentry} from 'sentry/icons';
  6. import {t} from 'sentry/locale';
  7. import space from 'sentry/styles/space';
  8. type Props = {
  9. 'data-test-id': string;
  10. dateUpdated: string | null;
  11. raw: string;
  12. type: 'codeowners' | 'issueowners';
  13. controls?: React.ReactNode[];
  14. placeholder?: string;
  15. provider?: string;
  16. repoName?: string;
  17. };
  18. function RulesPanel({
  19. raw,
  20. dateUpdated,
  21. provider,
  22. repoName,
  23. type,
  24. placeholder,
  25. controls,
  26. ['data-test-id']: dataTestId,
  27. }: Props) {
  28. function renderIcon() {
  29. switch (provider ?? '') {
  30. case 'github':
  31. return <IconGithub size="md" />;
  32. case 'gitlab':
  33. return <IconGitlab size="md" />;
  34. default:
  35. return <IconSentry size="md" />;
  36. }
  37. }
  38. function renderTitle() {
  39. switch (type) {
  40. case 'codeowners':
  41. return 'CODEOWNERS';
  42. case 'issueowners':
  43. return 'Ownership Rules';
  44. default:
  45. return null;
  46. }
  47. }
  48. return (
  49. <Panel data-test-id={dataTestId}>
  50. <PanelHeader>
  51. <Container>
  52. {renderIcon()}
  53. <Title>{renderTitle()}</Title>
  54. {repoName && <Repository>{`- ${repoName}`}</Repository>}
  55. </Container>
  56. <Container>
  57. {dateUpdated && (
  58. <SyncDate>
  59. {t('Last %s', type === 'codeowners' ? t('synced') : t('edited'))}{' '}
  60. <TimeSince date={dateUpdated} />
  61. </SyncDate>
  62. )}
  63. <Controls>{controls}</Controls>
  64. </Container>
  65. </PanelHeader>
  66. <PanelBody>
  67. <InnerPanelBody>
  68. <StyledTextArea
  69. monospace
  70. readOnly
  71. value={raw}
  72. spellCheck="false"
  73. autoComplete="off"
  74. autoCorrect="off"
  75. autoCapitalize="off"
  76. placeholder={placeholder}
  77. />
  78. </InnerPanelBody>
  79. </PanelBody>
  80. </Panel>
  81. );
  82. }
  83. export default RulesPanel;
  84. const Container = styled('div')`
  85. display: flex;
  86. align-items: center;
  87. text-transform: none;
  88. `;
  89. const Title = styled('div')`
  90. padding: 0 ${space(0.5)} 0 ${space(1)};
  91. font-size: initial;
  92. `;
  93. const Repository = styled('div')``;
  94. const InnerPanelBody = styled(PanelBody)`
  95. height: auto;
  96. `;
  97. const StyledTextArea = styled(TextArea)`
  98. height: 350px !important;
  99. overflow: auto;
  100. outline: 0;
  101. width: 100%;
  102. resize: none;
  103. margin: 0;
  104. word-break: break-all;
  105. white-space: pre-wrap;
  106. line-height: ${space(3)};
  107. border: none;
  108. box-shadow: none;
  109. color: transparent;
  110. text-shadow: 0 0 0 #9386a0;
  111. &:hover,
  112. &:focus,
  113. &:active {
  114. border: none;
  115. box-shadow: none;
  116. }
  117. `;
  118. const SyncDate = styled('div')`
  119. padding: 0 ${space(1)};
  120. font-weight: normal;
  121. `;
  122. const Controls = styled('div')`
  123. display: flex;
  124. align-items: center;
  125. gap: ${space(1)};
  126. `;