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.
337 lines
14 KiB
337 lines
14 KiB
<template>
|
|
<div class="p-d-flex p-flex-row p-jc-between p-ai-stretch">
|
|
<Card class="p-mr-2 p-as-stretch file-card">
|
|
<template #header>
|
|
<Toolbar>
|
|
<template #right>
|
|
<Button @click="onAddNewSearcher"
|
|
type="button"
|
|
label="Add new searcher"
|
|
class="p-button p-button-outlined p-button-secondary p-button-sm">
|
|
</Button>
|
|
|
|
<Button @click="onDefineSearcher"
|
|
type="button"
|
|
label="Define searcher"
|
|
class="p-button p-button-outlined p-button-primary p-button-sm">
|
|
</Button>
|
|
|
|
<Button
|
|
label="Try another document"
|
|
icon="pi pi-upload"
|
|
class="p-button-success p-button-outlined p-button-sm"
|
|
@click="toggleUploadDialog()"/>
|
|
</template>
|
|
</Toolbar>
|
|
</template>
|
|
|
|
<template #title>
|
|
Original document content
|
|
</template>
|
|
|
|
<template #content>
|
|
<div class="md-viewer" style="text-align: start; font-size: 0.7em;">
|
|
<template v-if="fileContent === ''">
|
|
<Skeleton/>
|
|
<br/>
|
|
<Skeleton/>
|
|
<br/>
|
|
<Skeleton/>
|
|
<br/>
|
|
<Skeleton/>
|
|
<br/>
|
|
<Skeleton/>
|
|
<br/>
|
|
<Skeleton/>
|
|
<br/>
|
|
<Skeleton/>
|
|
<br/>
|
|
</template>
|
|
<template v-else>
|
|
<div v-html="compiledFileContent"></div>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
</Card>
|
|
|
|
<Card class="p-mr-2 p-as-stretch file-card">
|
|
<template #header>
|
|
<Toolbar>
|
|
<template #right>
|
|
<label for="show-diff-highlight" class="switch-label">Highlight differences:</label>
|
|
<InputSwitch
|
|
v-model="showDiffHighlight"
|
|
name="show-diff-highlight"
|
|
inputId="show-diff-highlight"
|
|
:disabled="processedFileContent == ''"/>
|
|
|
|
<Button
|
|
label="Download document"
|
|
icon="pi pi-download"
|
|
class="p-button-secondary p-button-outlined p-button-sm"
|
|
:disabled="processedFileContent == ''"
|
|
@click="downloadOdt"/>
|
|
|
|
<Button
|
|
label="Download raw"
|
|
:icon=" ! applyingOnOriginalDocument ? 'pi pi-download' : 'pi pi-loading'"
|
|
class="p-button-secondary p-button-outlined p-button-sm"
|
|
:disabled="processedFileContent == '' || applyingOnOriginalDocument"
|
|
@click="downloadOriginal"/>
|
|
|
|
<Button
|
|
label="Run search"
|
|
icon="pi pi-play"
|
|
class="p-button-success p-button-outlined p-button-sm"
|
|
:disabled="!canRunSearchers()"
|
|
@click="runSearchersWithoutDisplacing"/>
|
|
|
|
<Button
|
|
label="Run S&D"
|
|
icon="pi pi-play"
|
|
class="p-button-success p-button-outlined p-button-sm"
|
|
:disabled="!canRunSearchers()"
|
|
@click="runSearchers"/>
|
|
</template>
|
|
</Toolbar>
|
|
</template>
|
|
<template #title>
|
|
Processed document content
|
|
</template>
|
|
|
|
<template #content>
|
|
<div class="md-viewer" style="text-align: start; font-size: 0.7em;">
|
|
<template v-if="processing === true">
|
|
<Skeleton/>
|
|
<br/>
|
|
<Skeleton/>
|
|
<br/>
|
|
<Skeleton/>
|
|
<br/>
|
|
<Skeleton/>
|
|
<br/>
|
|
<Skeleton/>
|
|
<br/>
|
|
<Skeleton/>
|
|
<br/>
|
|
<Skeleton/>
|
|
<br/>
|
|
</template>
|
|
<template v-else-if="processedFileContentPreview !== ''">
|
|
<div v-html="compiledProcessedFileContentPreview" v-if="showDiffHighlight"></div>
|
|
<div v-html="compiledProcessedFileContent" v-else></div>
|
|
</template>
|
|
<template v-else>
|
|
<Message severity="info" :closable="false">
|
|
Not processed yet. Please select and run some filters to see the result.
|
|
</Message>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
</Card>
|
|
|
|
<Sidebar
|
|
:visible="true"
|
|
:showCloseIcon="false"
|
|
:class="{'p-sidebar-md': true, 'p-sidebar-leave-to': !searchersSidebarVisible}"
|
|
:dismissable="true"
|
|
:modal="false"
|
|
:autoZIndex="true"
|
|
:baseZIndex="1000"
|
|
position="right">
|
|
<div class="p-grid p-jc-start">
|
|
<Button
|
|
icon="pi pi-list"
|
|
class="p-button-info p-button-icon-only sidebar-toggle-button"
|
|
@click="toggleSearchersSidebar()"
|
|
:disabled="searchersDialogVisible === true"/>
|
|
</div>
|
|
|
|
<div class="p-grid p-jc-between sidebar-title-container">
|
|
<div class="p-col sidebar-title">
|
|
<h3>Document searchers</h3>
|
|
</div>
|
|
|
|
<div class="p-col-2">
|
|
<Button
|
|
icon="pi pi-plus"
|
|
class="p-button-success p-button-sm p-button-text add-searchers"
|
|
@click="toggleSearchersDialog(true)"
|
|
aria:haspopup="true"
|
|
aria-controls="searcers_dialog"/>
|
|
</div>
|
|
</div>
|
|
|
|
<Dialog header="Available document searchers"
|
|
:visible.sync="searchersDialogVisible"
|
|
:maximizable="true"
|
|
:style="{width: '50vw'}"
|
|
:contentStyle="{overflow: 'visible'}"
|
|
id="searchers_dialog"
|
|
ref="searchers-dialog">
|
|
|
|
<DataTable
|
|
:value.sync="searchers"
|
|
:selection.sync="newlySelectedSearchers"
|
|
dataKey="id"
|
|
selectionMode="multiple"
|
|
class="p-datatable-sm"
|
|
:metaKeySelection="false"
|
|
:paginator="true"
|
|
:rows="10"
|
|
paginatorTemplate="CurrentPageReport FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown"
|
|
currentPageReportTemplate="Showing {first} to {last} of {totalRecords}"
|
|
:rowsPerPageOptions="[10,20,50]"
|
|
:filters="searchersFilters">
|
|
<Column selectionMode="multiple" headerStyle="width: 3em"></Column>
|
|
|
|
<Column
|
|
field="name"
|
|
header="Name"
|
|
sortable>
|
|
<template #body="slotProps">
|
|
{{slotProps.data.name}}
|
|
</template>
|
|
<template #filter>
|
|
<InputText type="text" v-model="searchersFilters['global']" class="p-column-filter" placeholder="Search by name por description"/>
|
|
</template>
|
|
</Column>
|
|
<Column
|
|
field="description"
|
|
header="Description"
|
|
sortable
|
|
class="filter-description">
|
|
</Column>
|
|
</DataTable>
|
|
|
|
<template #footer>
|
|
<Button
|
|
label="Done"
|
|
icon="pi pi-check"
|
|
class="p-button-info p-button-outlined p-button-sm"
|
|
@click="toggleSearchersDialog(false)">
|
|
</Button>
|
|
</template>
|
|
|
|
</Dialog>
|
|
|
|
<DataTable
|
|
:value.sync="Object.values(selectedSearchers)"
|
|
dataKey="id"
|
|
class="p-datatable-sm"
|
|
:expandedRows.sync="expandedRows"
|
|
@row-reorder="onSelectedSearchersReorder"
|
|
:scrollable="true"
|
|
scrollHeight="80vh">
|
|
|
|
<Column :rowReorder="true" headerStyle="width: 3rem"/>
|
|
|
|
<Column field="name" header="Name"></Column>
|
|
|
|
<Column headerStyle="width: 3rem">
|
|
<template #body="slotProps">
|
|
<Button icon="pi pi-trash"
|
|
class="p-button-rounded p-button-warning"
|
|
@click="confirmDeleteProduct(slotProps.data)"/>
|
|
</template>
|
|
</Column>
|
|
|
|
<Column :expander="true" headerStyle="width: 3rem"/>
|
|
|
|
<template #expansion="slotProps">
|
|
<div class="options-subtable">
|
|
<div class="p-fluid">
|
|
<div class="p-field">
|
|
<div class="p-field-radiobutton">
|
|
<RadioButton name="action_type"
|
|
id="action_type_replace"
|
|
value="replace"
|
|
v-model="searchersOptions[slotProps.data.id].type">
|
|
</RadioButton>
|
|
|
|
<label for="action_type_replace">Replace</label>
|
|
</div>
|
|
|
|
<div class="p-field-radiobutton">
|
|
<RadioButton name="action_type"
|
|
id="action_type_displace"
|
|
value="displace"
|
|
v-model="searchersOptions[slotProps.data.id].type">
|
|
</RadioButton>
|
|
|
|
<label for="action_type_displace">Displace</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="p-field">
|
|
<label :for="`displace_with__${slotProps.data.id}`">
|
|
<span>
|
|
{{ searchersOptions[slotProps.data.id].type === 'replace' ? 'Replace' : 'Displace (tag)' }}
|
|
</span>
|
|
|
|
<span>
|
|
values with:
|
|
</span>
|
|
</label>
|
|
|
|
<InputText
|
|
:id="`displace_with__${slotProps.data.id}`"
|
|
type="text"
|
|
class="p-inputtext-sm"
|
|
v-model="searchersOptions[slotProps.data.id].value"
|
|
v-tooltip.top="
|
|
(slotProps.data.param === 'required') ?
|
|
'This field is required.' : null
|
|
"
|
|
:class="{'p-invalid': !isValidParam(slotProps.data.id, slotProps.data.param)}"/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<template #footer>
|
|
<Button
|
|
label="Run filters"
|
|
icon="pi pi-play"
|
|
class="p-button-success p-button-sm"
|
|
:disabled="!canRunSearchers()"
|
|
@click="toggleSearchersSidebar(); runSearchers()"/>
|
|
</template>
|
|
</DataTable>
|
|
</Sidebar>
|
|
|
|
<!-- File upload dialog -->
|
|
<Dialog header="Upload a new file"
|
|
:visible.sync="uploadDialogVisible"
|
|
:maximizable="true"
|
|
:style="{width: '50vw'}"
|
|
:contentStyle="{overflow: 'visible'}"
|
|
:baseZIndex="2014"
|
|
id="upload_dialog"
|
|
ref="upload-dialog">
|
|
|
|
<FileUpload
|
|
name="upload[]"
|
|
:showUploadButton="false"
|
|
:showCancelButton="false"
|
|
chooseLabel="Choose file"
|
|
:customUpload="true"
|
|
:auto="true"
|
|
@uploader="uploadFile">
|
|
<template #empty>
|
|
<p>Drag and drop files to here to upload.</p>
|
|
</template>
|
|
</FileUpload>
|
|
|
|
</Dialog>
|
|
|
|
<define-searcher v-if="showDefineSearcher"
|
|
:text="searcherToDefineText"
|
|
@done="onSearcherDefined"
|
|
@close="showDefineSearcher = false">
|
|
</define-searcher>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts" src="./ProcessFile.ts"></script>
|
|
<style lang="scss" src="./ProcessFile.scss"></style>
|