rulesPanel.tsx 2.8 KB

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