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