Repo for the search and displace core module including the interface to select files and search and displace operations to run on them.
https://searchanddisplace.com
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.
283 lines
8.3 KiB
283 lines
8.3 KiB
import marked from 'marked';
|
|
import {Vue, Component, Prop, Watch} from 'vue-property-decorator';
|
|
import {FileData} from '@/interfaces/FileData';
|
|
|
|
@Component
|
|
export default class ProcessFile extends Vue {
|
|
|
|
/**
|
|
* Props
|
|
*/
|
|
// The data for the file we are processing
|
|
@Prop({default: {id: -1, file: '', path: ''}})
|
|
public readonly file!: FileData;
|
|
|
|
// The list of available searchers
|
|
@Prop({default: []})
|
|
public readonly searchers!: [];
|
|
|
|
|
|
/**
|
|
* Class members
|
|
*/
|
|
// The id of the interval used to query the file status
|
|
private intervalId!: any;
|
|
|
|
// The content of the file we are processing
|
|
private fileContent: string = '';
|
|
|
|
// The processed document content
|
|
private processedFileContent: string = '';
|
|
|
|
private processedFileContentPreview: string = '';
|
|
|
|
private documentDiffIndexes: { [key: string]: Array<{ start: number; end: number; }>; } = {};
|
|
|
|
// Flag to determine whether the text is processing or not
|
|
private processing: boolean = false;
|
|
|
|
// Toggles the visibility of the selected searchers sidebar
|
|
private searchersSidebarVisible: boolean = false;
|
|
|
|
// Toggles the visibility of the available searchers dialog
|
|
private searchersDialogVisible: boolean = false;
|
|
|
|
// Toggles the visibility of the document upload dialog
|
|
private uploadDialogVisible: boolean = false;
|
|
|
|
// The list of filters/searchers in a format usable by the datatable
|
|
// private searchersData: Array<{ id: string; name: string; type: string; }> = [];
|
|
|
|
// The list of filters applied to the selected searchers
|
|
private searchersFilters: any = [];
|
|
|
|
// The list of selected filters/searchers
|
|
private selectedSearchers: any = {};
|
|
|
|
//The list of expanded rows in the selected filters/searchers table
|
|
private expandedRows: Array<any> = [];
|
|
|
|
// The list of options applied to the searchers (for the moment, only replace_with)
|
|
private searchersOptions: { [key: string]: string } = {};
|
|
|
|
// Flag to determine whether or not we will show the diff highlights
|
|
private showDiffHighlight: boolean = false;
|
|
|
|
private newlySelectedSearchers: Array<{ id: string; name: string; }> = [];
|
|
|
|
/**
|
|
*
|
|
*/
|
|
created() {
|
|
this.intervalId = setInterval(this.waitForFile, 3000);
|
|
}
|
|
|
|
/**
|
|
* MD-to-HTML compiled file content
|
|
*/
|
|
get compiledFileContent(): string {
|
|
return marked(this.fileContent);
|
|
}
|
|
|
|
/**
|
|
* MD-to-HTML compiled processed file content
|
|
*/
|
|
get compiledProcessedFileContent(): string {
|
|
return marked(this.processedFileContent);
|
|
}
|
|
|
|
/**
|
|
* MD-to-HTML compiled processed file content with diff highlight
|
|
*/
|
|
get compiledProcessedFileContentPreview(): string {
|
|
return marked(this.processedFileContentPreview);
|
|
}
|
|
|
|
/**
|
|
* Toggle the sidebar containing the searchers
|
|
*/
|
|
private toggleSearchersSidebar() {
|
|
this.searchersSidebarVisible = !this.searchersSidebarVisible;
|
|
}
|
|
|
|
/**
|
|
* Toggle the menu containing the list of available searchers
|
|
*
|
|
* @param {string} newValue The new value for the dialog visibility
|
|
*/
|
|
private toggleSearchersDialog(newValue?: boolean) {
|
|
if (typeof newValue !== 'undefined') {
|
|
this.searchersDialogVisible = newValue;
|
|
} else {
|
|
this.searchersDialogVisible = !this.searchersDialogVisible;
|
|
}
|
|
|
|
if ( ! this.searchersDialogVisible) {
|
|
for (let selectedSearcher of this.newlySelectedSearchers) {
|
|
// this.selectedSearchers[selectedSearcher.id] = selectedSearcher;
|
|
this.$set(this.selectedSearchers, selectedSearcher.id, selectedSearcher);
|
|
|
|
this.expandedRows = Object.values(this.selectedSearchers).filter((p: any) => p.id);
|
|
}
|
|
|
|
this.newlySelectedSearchers = [];
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Toggle the dialog which lets the user upload a new document
|
|
*
|
|
* @param {boolean} newValue
|
|
*/
|
|
toggleUploadDialog(newValue?: boolean) {
|
|
|
|
if (typeof newValue !== 'undefined') {
|
|
this.uploadDialogVisible = newValue;
|
|
} else {
|
|
this.uploadDialogVisible = !this.searchersDialogVisible;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A method which uploads the files to the server for processing
|
|
*
|
|
* @param event The event containing the uploaded files information
|
|
*/
|
|
public async uploadFile(event: any): Promise<void> {
|
|
|
|
this.$confirm.require({
|
|
message: 'You will lose any progress on the current uploaded document. Are you sure you want to proceed?',
|
|
header: 'Confirmation',
|
|
icon: 'pi pi-exclamation-triangle',
|
|
accept: () => {
|
|
this.fileContent = this.processedFileContent = '';
|
|
let file = event.files[0];
|
|
this.toggleUploadDialog(false);
|
|
this.$emit('newFile', file);
|
|
},
|
|
reject: () => {
|
|
// TODO: Show a message to the user that the action was cancelled.
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Wait for the file to be processed in ingest
|
|
*/
|
|
private async waitForFile() {
|
|
|
|
const response = await this.$api.getFileData(this.file.id);
|
|
|
|
if (response.content !== null) {
|
|
|
|
if (response.ingest_status === 'fail') {
|
|
this.$toast.add({
|
|
severity: 'error',
|
|
summary: 'File error',
|
|
detail: 'THere was an error processing the file in ingest',
|
|
life: 3000
|
|
});
|
|
} else {
|
|
this.fileContent = response.content;
|
|
|
|
this.$toast.add({
|
|
severity: 'success',
|
|
summary: 'File loaded',
|
|
detail: 'The file has been processed by ingest.',
|
|
life: 3000
|
|
});
|
|
|
|
clearInterval(this.intervalId);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param $event
|
|
*/
|
|
private onSelectedSearchersReorder($event: any) {
|
|
Object.assign({}, this.selectedSearchers, $event.value);
|
|
}
|
|
|
|
private confirmDeleteProduct(searcher: any) {
|
|
this.$delete(this.selectedSearchers, searcher.id);
|
|
}
|
|
|
|
/**
|
|
* Run the searchers
|
|
*/
|
|
private async runSearchers() {
|
|
this.processing = true;
|
|
this.processedFileContent = '';
|
|
|
|
let searchers: Array<{ key: string; replace_with: string; }> = [];
|
|
|
|
Object.values(this.selectedSearchers).forEach((searcher: any) => {
|
|
searchers.push({
|
|
'key': searcher.id,
|
|
'replace_with': this.searchersOptions[searcher.id] || ''
|
|
});
|
|
});
|
|
|
|
const response = await this.$api.filterDocument(this.fileContent, searchers);
|
|
|
|
this.processedFileContent = response.content;
|
|
this.documentDiffIndexes = response.indexes;
|
|
this.createDiffPreview();
|
|
|
|
this.processing = false;
|
|
}
|
|
|
|
/**
|
|
* Create the diff preview for the document
|
|
*/
|
|
private createDiffPreview() {
|
|
console.log('CREATING DIFF PREVIEW: ', this.processedFileContent);
|
|
this.processedFileContentPreview = this.processedFileContent;
|
|
|
|
let indexes: Array<{ start: number; end: number }> = [];
|
|
|
|
for (let searcher in this.documentDiffIndexes) {
|
|
const searcherIndexes = this.documentDiffIndexes[searcher];
|
|
|
|
searcherIndexes.forEach(index => {
|
|
indexes.push(index);
|
|
});
|
|
}
|
|
|
|
indexes.sort((a, b) => {
|
|
return b.start - a.start;
|
|
});
|
|
|
|
this.processedFileContentPreview = indexes.reduce(
|
|
(r, a) => {
|
|
r[a.start] = '<mark>' + r[a.start];
|
|
r[a.end] += '</mark>';
|
|
return r;
|
|
},
|
|
this.processedFileContent.split('')
|
|
).join('');
|
|
}
|
|
|
|
/**
|
|
* Download the document in ODT format
|
|
*/
|
|
private async downloadOdt() {
|
|
let response = await this.$api.convertFile(this.processedFileContent);
|
|
|
|
window.open(`${window.location.origin}/file/download/` + response.path);
|
|
}
|
|
|
|
/**
|
|
* Watch the `showDiffHighlight` property for changes
|
|
*
|
|
* @param {boolean} newValue
|
|
* @param {boolean} oldValue
|
|
*/
|
|
@Watch('showDiffHighlight')
|
|
private onDiffHighlightChanged(newValue: boolean, oldValue: boolean): void {
|
|
//
|
|
}
|
|
}
|