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.

243 lines
5.9 KiB

5 years ago
5 years ago
5 years ago
  1. import * as marked from 'marked';
  2. import VueJsonPretty from 'vue-json-pretty';
  3. import isEmpty from 'lodash.isempty';
  4. import HTTP, { defaultHttpClient } from './http';
  5. import Preview from './preview.vue';
  6. const getOffsetFromUrl = (url) => {
  7. const offsetMatch = url.match(/[?#].*offset=(\d+)/);
  8. if (offsetMatch == null) {
  9. return 0;
  10. }
  11. return parseInt(offsetMatch[1], 10);
  12. };
  13. const storeOffsetInUrl = (offset) => {
  14. let href = window.location.href;
  15. const fragmentStart = href.indexOf('#') + 1;
  16. if (fragmentStart === 0) {
  17. href += '#offset=' + offset;
  18. } else {
  19. const prefix = href.substring(0, fragmentStart);
  20. const fragment = href.substring(fragmentStart);
  21. const newFragment = fragment.split('&').map((fragmentPart) => {
  22. const keyValue = fragmentPart.split('=');
  23. return keyValue[0] === 'offset'
  24. ? 'offset=' + offset
  25. : fragmentPart;
  26. }).join('&');
  27. href = prefix + newFragment;
  28. }
  29. window.location.href = href;
  30. };
  31. export default {
  32. components: { VueJsonPretty, Preview },
  33. data() {
  34. return {
  35. pageNumber: 0,
  36. docs: [],
  37. annotations: [],
  38. labels: [],
  39. guideline: '',
  40. total: 0,
  41. remaining: 0,
  42. searchQuery: '',
  43. url: '',
  44. offset: getOffsetFromUrl(window.location.href),
  45. picked: 'all',
  46. count: 0,
  47. isSuperuser: false,
  48. isMetadataActive: false,
  49. isAnnotationGuidelineActive: false,
  50. };
  51. },
  52. methods: {
  53. async nextPage() {
  54. this.pageNumber += 1;
  55. if (this.pageNumber === this.docs.length) {
  56. if (this.next) {
  57. this.url = this.next;
  58. await this.search();
  59. this.pageNumber = 0;
  60. } else {
  61. this.pageNumber = this.docs.length - 1;
  62. }
  63. }
  64. },
  65. async prevPage() {
  66. this.pageNumber -= 1;
  67. if (this.pageNumber === -1) {
  68. if (this.prev) {
  69. this.url = this.prev;
  70. await this.search();
  71. this.pageNumber = this.docs.length - 1;
  72. } else {
  73. this.pageNumber = 0;
  74. }
  75. }
  76. },
  77. async search() {
  78. await HTTP.get(this.url).then((response) => {
  79. this.docs = response.data.results;
  80. this.next = response.data.next;
  81. this.prev = response.data.previous;
  82. this.count = response.data.count;
  83. this.annotations = this.docs.map(doc => doc.annotations);
  84. this.offset = getOffsetFromUrl(this.url);
  85. });
  86. },
  87. getState() {
  88. if (this.picked === 'all') {
  89. return '';
  90. }
  91. if (this.picked === 'active') {
  92. return 'true';
  93. }
  94. return 'false';
  95. },
  96. async submit() {
  97. const state = this.getState();
  98. this.url = `docs?q=${this.searchQuery}&is_checked=${state}&offset=${this.offset}`;
  99. await this.search();
  100. this.pageNumber = 0;
  101. },
  102. removeLabel(annotation) {
  103. const docId = this.docs[this.pageNumber].id;
  104. HTTP.delete(`docs/${docId}/annotations/${annotation.id}`).then(() => {
  105. const index = this.annotations[this.pageNumber].indexOf(annotation);
  106. this.annotations[this.pageNumber].splice(index, 1);
  107. });
  108. },
  109. replaceNull(shortcut) {
  110. if (shortcut == null) {
  111. shortcut = '';
  112. }
  113. shortcut = shortcut.split(' ');
  114. return shortcut;
  115. },
  116. shortcutKey(label) {
  117. let shortcut = label.suffix_key;
  118. if (label.prefix_key) {
  119. shortcut = `${label.prefix_key} ${shortcut}`;
  120. }
  121. return shortcut;
  122. },
  123. approveDocumentAnnotations() {
  124. const document = this.docs[this.pageNumber];
  125. const approved = !this.documentAnnotationsAreApproved;
  126. HTTP.post(`docs/${document.id}/approve-labels`, { approved }).then((response) => {
  127. const documents = this.docs.slice();
  128. documents[this.pageNumber] = response.data;
  129. this.docs = documents;
  130. });
  131. },
  132. },
  133. watch: {
  134. picked() {
  135. this.submit();
  136. },
  137. annotations() {
  138. // fetch progress info.
  139. HTTP.get('statistics').then((response) => {
  140. this.total = response.data.total;
  141. this.remaining = response.data.remaining;
  142. });
  143. },
  144. offset() {
  145. storeOffsetInUrl(this.offset);
  146. },
  147. },
  148. created() {
  149. HTTP.get('labels').then((response) => {
  150. this.labels = response.data;
  151. });
  152. HTTP.get().then((response) => {
  153. this.guideline = response.data.guideline;
  154. });
  155. defaultHttpClient.get('/v1/me').then((response) => {
  156. this.isSuperuser = response.data.is_superuser;
  157. });
  158. this.submit();
  159. },
  160. computed: {
  161. achievement() {
  162. const done = this.total - this.remaining;
  163. const percentage = Math.round(done / this.total * 100);
  164. return this.total > 0 ? percentage : 0;
  165. },
  166. compiledMarkdown() {
  167. return marked(this.guideline, {
  168. sanitize: true,
  169. });
  170. },
  171. documentAnnotationsAreApproved() {
  172. const document = this.docs[this.pageNumber];
  173. return document != null && document.annotation_approver != null;
  174. },
  175. documentAnnotationsApprovalTooltip() {
  176. const document = this.docs[this.pageNumber];
  177. return this.documentAnnotationsAreApproved
  178. ? `Annotations approved by ${document.annotation_approver}, click to reject annotations`
  179. : 'Click to approve annotations';
  180. },
  181. documentMetadata() {
  182. const document = this.docs[this.pageNumber];
  183. if (document == null || document.meta == null) {
  184. return null;
  185. }
  186. const metadata = JSON.parse(document.meta);
  187. if (isEmpty(metadata)) {
  188. return null;
  189. }
  190. return metadata;
  191. },
  192. id2label() {
  193. const id2label = {};
  194. for (let i = 0; i < this.labels.length; i++) {
  195. const label = this.labels[i];
  196. id2label[label.id] = label;
  197. }
  198. return id2label;
  199. },
  200. progressColor() {
  201. if (this.achievement < 30) {
  202. return 'is-danger';
  203. }
  204. if (this.achievement < 70) {
  205. return 'is-warning';
  206. }
  207. return 'is-primary';
  208. },
  209. },
  210. };