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.
 
 
 
 
 
 

352 lines
8.5 KiB

import * as marked from 'marked';
import VueJsonPretty from 'vue-json-pretty';
import isEmpty from 'lodash.isempty';
import HTTP from './http';
import Preview from './preview.vue';
const getOffsetFromUrl = (url) => {
const offsetMatch = url.match(/[?#].*offset=(\d+)/);
if (offsetMatch == null) {
return 0;
}
return parseInt(offsetMatch[1], 10);
};
const removeHost = (url) => {
if (!url) {
return url;
}
const hostMatch = url.match(/^https?:\/\/[^/]*\/(.*)$/);
if (hostMatch == null) {
return url;
}
return `${window.location.origin}/${hostMatch[1]}`;
};
const storeOffsetInUrl = (offset) => {
let href = window.location.href;
const fragmentStart = href.indexOf('#') + 1;
if (fragmentStart === 0) {
href += '#offset=' + offset;
} else {
const prefix = href.substring(0, fragmentStart);
const fragment = href.substring(fragmentStart);
const newFragment = fragment.split('&').map((fragmentPart) => {
const keyValue = fragmentPart.split('=');
return keyValue[0] === 'offset'
? 'offset=' + offset
: fragmentPart;
}).join('&');
href = prefix + newFragment;
}
window.location.href = href;
};
const getLimitFromUrl = (url, prevLimit) => {
try {
const limitMatch = url.match(/[?#].*limit=(\d+)/);
return parseInt(limitMatch[1], 10);
} catch (err) {
return prevLimit;
}
};
const getSidebarTotal = (count, limit) => (
count !== 0 && limit !== 0
? Math.ceil(count / limit)
: 0
);
const getSidebarPage = (offset, limit) => (
limit !== 0
? Math.ceil(offset / limit) + 1
: 0
);
export default {
components: { VueJsonPretty, Preview },
data() {
return {
pageNumber: 0,
docs: [],
annotations: [],
labels: [],
guideline: '',
total: 0,
remaining: 0,
searchQuery: '',
url: '',
offset: getOffsetFromUrl(window.location.href),
picked: 'all',
ordering: '',
count: 0,
prevLimit: 0,
paginationPages: 0,
paginationPage: 0,
singleClassClassification: false,
isAnnotationApprover: false,
isMetadataActive: false,
isAnnotationGuidelineActive: false,
};
},
methods: {
resetScrollbar() {
const textbox = this.$refs.textbox;
if (textbox) {
textbox.scrollTop = 0;
}
},
async nextPage() {
this.pageNumber += 1;
if (this.pageNumber === this.docs.length) {
if (this.next) {
this.url = this.next;
await this.search();
this.pageNumber = 0;
} else {
this.pageNumber = this.docs.length - 1;
}
} else {
this.resetScrollbar();
}
},
async prevPage() {
this.pageNumber -= 1;
if (this.pageNumber === -1) {
if (this.prev) {
this.url = this.prev;
await this.search();
this.pageNumber = this.docs.length - 1;
} else {
this.pageNumber = 0;
}
} else {
this.resetScrollbar();
}
},
async nextPagination() {
if (this.next) {
this.url = this.next;
await this.search();
this.pageNumber = 0;
} else {
this.pageNumber = this.docs.length - 1;
}
this.resetScrollbar();
},
async prevPagination() {
if (this.prev) {
this.url = this.prev;
await this.search();
this.pageNumber = this.docs.length - this.limit;
} else {
this.pageNumber = 0;
}
this.resetScrollbar();
},
async search() {
await HTTP.get(this.url).then((response) => {
this.docs = response.data.results;
this.next = removeHost(response.data.next);
this.prev = removeHost(response.data.previous);
this.count = response.data.count;
this.annotations = this.docs.map(doc => doc.annotations);
this.offset = getOffsetFromUrl(this.url);
this.prevLimit = this.limit;
if (this.next || this.prevLimit) {
this.limit = getLimitFromUrl(this.next, this.prevLimit);
} else {
this.limit = this.count;
}
this.paginationPages = getSidebarTotal(this.count, this.limit);
this.paginationPage = getSidebarPage(this.offset, this.limit);
});
},
documentMetadataFor(i) {
const document = this.docs[i];
if (document == null || document.meta == null) {
return null;
}
const metadata = JSON.parse(document.meta);
if (isEmpty(metadata)) {
return null;
}
return metadata;
},
getState() {
if (this.picked === 'all') {
return '';
}
if (this.picked === 'active') {
return 'true';
}
return 'false';
},
async submit() {
const state = this.getState();
this.url = `docs?q=${this.searchQuery}&is_checked=${state}&offset=${this.offset}&ordering=${this.ordering}`;
await this.search();
this.pageNumber = 0;
},
removeLabel(annotation) {
const docId = this.docs[this.pageNumber].id;
return HTTP.delete(`docs/${docId}/annotations/${annotation.id}`).then(() => {
const index = this.annotations[this.pageNumber].indexOf(annotation);
this.annotations[this.pageNumber].splice(index, 1);
});
},
replaceNull(shortcut) {
if (shortcut == null) {
shortcut = '';
}
shortcut = shortcut.split(' ');
return shortcut;
},
shortcutKey(label) {
let shortcut = label.suffix_key;
if (label.prefix_key) {
shortcut = `${label.prefix_key} ${shortcut}`;
}
return shortcut;
},
approveDocumentAnnotations() {
const document = this.docs[this.pageNumber];
const approved = !this.documentAnnotationsAreApproved;
HTTP.post(`docs/${document.id}/approve-labels`, { approved }).then((response) => {
Object.assign(this.docs[this.pageNumber], response.data);
});
},
},
watch: {
picked() {
this.submit();
},
ordering() {
this.offset = 0;
this.submit();
},
annotations() {
// fetch progress info.
HTTP.get('statistics?include=total&include=remaining').then((response) => {
this.total = response.data.total;
this.remaining = response.data.remaining;
});
},
offset() {
storeOffsetInUrl(this.offset);
},
},
created() {
HTTP.get('labels').then((response) => {
this.labels = response.data;
});
HTTP.get().then((response) => {
this.singleClassClassification = response.data.single_class_classification;
this.guideline = response.data.guideline;
const roles = response.data.current_users_role;
this.isAnnotationApprover = roles.is_annotation_approver || roles.is_project_admin;
});
this.submit();
},
computed: {
achievement() {
const done = this.total - this.remaining;
const percentage = Math.round(done / this.total * 100);
return this.total > 0 ? percentage : 0;
},
compiledMarkdown() {
const documentMetadata = this.documentMetadata;
const guideline = documentMetadata && documentMetadata.guideline
? documentMetadata.guideline
: this.guideline;
return marked(guideline, {
sanitize: true,
});
},
documentAnnotationsAreApproved() {
const document = this.docs[this.pageNumber];
return document != null && document.annotation_approver != null;
},
documentAnnotationsApprovalTooltip() {
const document = this.docs[this.pageNumber];
return this.documentAnnotationsAreApproved
? `Annotations approved by ${document.annotation_approver}, click to reject annotations`
: 'Click to approve annotations';
},
displayDocumentMetadata() {
let documentMetadata = this.documentMetadata;
if (documentMetadata == null) {
return null;
}
documentMetadata = { ...documentMetadata };
delete documentMetadata.guideline;
delete documentMetadata.documentSourceUrl;
return documentMetadata;
},
documentMetadata() {
return this.documentMetadataFor(this.pageNumber);
},
id2label() {
const id2label = {};
for (let i = 0; i < this.labels.length; i++) {
const label = this.labels[i];
id2label[label.id] = label;
}
return id2label;
},
progressColor() {
if (this.achievement < 30) {
return 'is-danger';
}
if (this.achievement < 70) {
return 'is-warning';
}
return 'is-primary';
},
},
};