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.

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