You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ContextPopup.vue 3.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. <script>
  2. import {SvgIcon} from '../svg.js';
  3. import {useLightTextOnBackground} from '../utils/color.js';
  4. import tinycolor from 'tinycolor2';
  5. import {GET} from '../modules/fetch.js';
  6. const {appSubUrl, i18n} = window.config;
  7. export default {
  8. components: {SvgIcon},
  9. data: () => ({
  10. loading: false,
  11. issue: null,
  12. i18nErrorOccurred: i18n.error_occurred,
  13. i18nErrorMessage: null,
  14. }),
  15. computed: {
  16. createdAt() {
  17. return new Date(this.issue.created_at).toLocaleDateString(undefined, {year: 'numeric', month: 'short', day: 'numeric'});
  18. },
  19. body() {
  20. const body = this.issue.body.replace(/\n+/g, ' ');
  21. if (body.length > 85) {
  22. return `${body.substring(0, 85)}…`;
  23. }
  24. return body;
  25. },
  26. icon() {
  27. if (this.issue.pull_request !== null) {
  28. if (this.issue.state === 'open') {
  29. if (this.issue.pull_request.draft === true) {
  30. return 'octicon-git-pull-request-draft'; // WIP PR
  31. }
  32. return 'octicon-git-pull-request'; // Open PR
  33. } else if (this.issue.pull_request.merged === true) {
  34. return 'octicon-git-merge'; // Merged PR
  35. }
  36. return 'octicon-git-pull-request'; // Closed PR
  37. } else if (this.issue.state === 'open') {
  38. return 'octicon-issue-opened'; // Open Issue
  39. }
  40. return 'octicon-issue-closed'; // Closed Issue
  41. },
  42. color() {
  43. if (this.issue.pull_request !== null) {
  44. if (this.issue.pull_request.draft === true) {
  45. return 'grey'; // WIP PR
  46. } else if (this.issue.pull_request.merged === true) {
  47. return 'purple'; // Merged PR
  48. }
  49. }
  50. if (this.issue.state === 'open') {
  51. return 'green'; // Open Issue
  52. }
  53. return 'red'; // Closed Issue
  54. },
  55. labels() {
  56. return this.issue.labels.map((label) => {
  57. let textColor;
  58. const {r, g, b} = tinycolor(label.color).toRgb();
  59. if (useLightTextOnBackground(r, g, b)) {
  60. textColor = '#eeeeee';
  61. } else {
  62. textColor = '#111111';
  63. }
  64. return {name: label.name, color: `#${label.color}`, textColor};
  65. });
  66. },
  67. },
  68. mounted() {
  69. this.$refs.root.addEventListener('ce-load-context-popup', (e) => {
  70. const data = e.detail;
  71. if (!this.loading && this.issue === null) {
  72. this.load(data);
  73. }
  74. });
  75. },
  76. methods: {
  77. async load(data) {
  78. this.loading = true;
  79. this.i18nErrorMessage = null;
  80. try {
  81. const response = await GET(`${appSubUrl}/${data.owner}/${data.repo}/issues/${data.index}/info`);
  82. const respJson = await response.json();
  83. if (!response.ok) {
  84. this.i18nErrorMessage = respJson.message ?? i18n.network_error;
  85. return;
  86. }
  87. this.issue = respJson;
  88. } catch {
  89. this.i18nErrorMessage = i18n.network_error;
  90. } finally {
  91. this.loading = false;
  92. }
  93. },
  94. },
  95. };
  96. </script>
  97. <template>
  98. <div ref="root">
  99. <div v-if="loading" class="ui active centered inline loader"/>
  100. <div v-if="!loading && issue !== null">
  101. <p><small>{{ issue.repository.full_name }} on {{ createdAt }}</small></p>
  102. <p><svg-icon :name="icon" :class="['text', color]"/> <strong>{{ issue.title }}</strong> #{{ issue.number }}</p>
  103. <p>{{ body }}</p>
  104. <div>
  105. <div
  106. v-for="label in labels"
  107. :key="label.name"
  108. class="ui label"
  109. :style="{ color: label.textColor, backgroundColor: label.color }"
  110. >
  111. {{ label.name }}
  112. </div>
  113. </div>
  114. </div>
  115. <div v-if="!loading && issue === null">
  116. <p><small>{{ i18nErrorOccurred }}</small></p>
  117. <p>{{ i18nErrorMessage }}</p>
  118. </div>
  119. </div>
  120. </template>