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.

334 lines
14 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. <template>
  2. <div class="p-d-flex p-flex-row p-jc-between p-ai-stretch">
  3. <Card class="p-mr-2 p-as-stretch file-card">
  4. <template #header>
  5. <Toolbar>
  6. <template #right>
  7. <Button @click="onAddNewSearcher"
  8. type="button"
  9. label="Add new searcher"
  10. class="p-button p-button-outlined p-button-secondary p-button-sm">
  11. </Button>
  12. <Button @click="onDefineSearcher"
  13. type="button"
  14. label="Define searcher"
  15. class="p-button p-button-outlined p-button-primary p-button-sm">
  16. </Button>
  17. <Button
  18. label="Try another document"
  19. icon="pi pi-upload"
  20. class="p-button-success p-button-outlined p-button-sm"
  21. @click="toggleUploadDialog()"/>
  22. </template>
  23. </Toolbar>
  24. </template>
  25. <template #title>
  26. Original document content
  27. </template>
  28. <template #content>
  29. <div class="md-viewer" style="text-align: start; font-size: 0.7em;">
  30. <template v-if="fileContent === ''">
  31. <Skeleton/>
  32. <br/>
  33. <Skeleton/>
  34. <br/>
  35. <Skeleton/>
  36. <br/>
  37. <Skeleton/>
  38. <br/>
  39. <Skeleton/>
  40. <br/>
  41. <Skeleton/>
  42. <br/>
  43. <Skeleton/>
  44. <br/>
  45. </template>
  46. <template v-else>
  47. <div v-html="compiledFileContent"></div>
  48. </template>
  49. </div>
  50. </template>
  51. </Card>
  52. <Card class="p-mr-2 p-as-stretch file-card">
  53. <template #header>
  54. <Toolbar>
  55. <template #right>
  56. <label for="show-diff-highlight" class="switch-label">Highlight differences:</label>
  57. <InputSwitch
  58. v-model="showDiffHighlight"
  59. name="show-diff-highlight"
  60. inputId="show-diff-highlight"
  61. :disabled="processedFileContent == ''"/>
  62. <Button
  63. label="Download document"
  64. icon="pi pi-download"
  65. class="p-button-secondary p-button-outlined p-button-sm"
  66. :disabled="processedFileContent == ''"
  67. @click="downloadOdt"/>
  68. <Button
  69. label="Download original"
  70. :icon=" ! applyingOnOriginalDocument ? 'pi pi-download' : 'pi pi-loading'"
  71. class="p-button-secondary p-button-outlined p-button-sm"
  72. :disabled="processedFileContent == '' || applyingOnOriginalDocument"
  73. @click="downloadOriginal"/>
  74. <Button
  75. label="Run search"
  76. icon="pi pi-play"
  77. class="p-button-success p-button-outlined p-button-sm"
  78. :disabled="!canRunSearchers()"
  79. @click="runSearchersWithoutDisplacing"/>
  80. <Button
  81. label="Run S&D"
  82. icon="pi pi-play"
  83. class="p-button-success p-button-outlined p-button-sm"
  84. :disabled="!canRunSearchers()"
  85. @click="runSearchers"/>
  86. </template>
  87. </Toolbar>
  88. </template>
  89. <template #title>
  90. Processed document content
  91. </template>
  92. <template #content>
  93. <div class="md-viewer" style="text-align: start; font-size: 0.7em;">
  94. <template v-if="processing === true">
  95. <Skeleton/>
  96. <br/>
  97. <Skeleton/>
  98. <br/>
  99. <Skeleton/>
  100. <br/>
  101. <Skeleton/>
  102. <br/>
  103. <Skeleton/>
  104. <br/>
  105. <Skeleton/>
  106. <br/>
  107. <Skeleton/>
  108. <br/>
  109. </template>
  110. <template v-else-if="processedFileContentPreview !== ''">
  111. <div v-html="compiledProcessedFileContentPreview" v-if="showDiffHighlight"></div>
  112. <div v-html="compiledProcessedFileContent" v-else></div>
  113. </template>
  114. <template v-else>
  115. <Message severity="info" :closable="false">
  116. Not processed yet. Please select and run some filters to see the result.
  117. </Message>
  118. </template>
  119. </div>
  120. </template>
  121. </Card>
  122. <Sidebar
  123. :visible="true"
  124. :showCloseIcon="false"
  125. :class="{'p-sidebar-md': true, 'p-sidebar-leave-to': !searchersSidebarVisible}"
  126. :dismissable="true"
  127. :modal="false"
  128. :autoZIndex="true"
  129. :baseZIndex="1000"
  130. position="right">
  131. <div class="p-grid p-jc-start">
  132. <Button
  133. icon="pi pi-list"
  134. class="p-button-info p-button-icon-only sidebar-toggle-button"
  135. @click="toggleSearchersSidebar()"
  136. :disabled="searchersDialogVisible === true"/>
  137. </div>
  138. <div class="p-grid p-jc-between sidebar-title-container">
  139. <div class="p-col sidebar-title">
  140. <h3>Document searchers</h3>
  141. </div>
  142. <div class="p-col-2">
  143. <Button
  144. icon="pi pi-plus"
  145. class="p-button-success p-button-sm p-button-text add-searchers"
  146. @click="toggleSearchersDialog(true)"
  147. aria:haspopup="true"
  148. aria-controls="searcers_dialog"/>
  149. </div>
  150. </div>
  151. <Dialog header="Available document searchers"
  152. :visible.sync="searchersDialogVisible"
  153. :maximizable="true"
  154. :style="{width: '50vw'}"
  155. :contentStyle="{overflow: 'visible'}"
  156. id="searchers_dialog"
  157. ref="searchers-dialog">
  158. <DataTable
  159. :value.sync="searchers"
  160. :selection.sync="newlySelectedSearchers"
  161. dataKey="id"
  162. selectionMode="multiple"
  163. class="p-datatable-sm"
  164. :metaKeySelection="false"
  165. :paginator="true"
  166. :rows="10"
  167. paginatorTemplate="CurrentPageReport FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown"
  168. currentPageReportTemplate="Showing {first} to {last} of {totalRecords}"
  169. :rowsPerPageOptions="[10,20,50]"
  170. :filters="searchersFilters">
  171. <Column selectionMode="multiple" headerStyle="width: 3em"></Column>
  172. <Column
  173. field="name"
  174. header="Name"
  175. sortable>
  176. <template #body="slotProps">
  177. {{slotProps.data.name}}
  178. </template>
  179. <template #filter>
  180. <InputText type="text" v-model="searchersFilters['global']" class="p-column-filter" placeholder="Search by name"/>
  181. </template>
  182. </Column>
  183. <Column
  184. field="description"
  185. header="Description"
  186. sortable
  187. class="filter-description">
  188. </Column>
  189. </DataTable>
  190. <template #footer>
  191. <Button
  192. label="Done"
  193. icon="pi pi-check"
  194. class="p-button-info p-button-outlined p-button-sm"
  195. @click="toggleSearchersDialog(false)">
  196. </Button>
  197. </template>
  198. </Dialog>
  199. <DataTable
  200. :value.sync="Object.values(selectedSearchers)"
  201. dataKey="id"
  202. class="p-datatable-sm"
  203. :expandedRows.sync="expandedRows"
  204. @row-reorder="onSelectedSearchersReorder"
  205. :scrollable="true"
  206. scrollHeight="80vh">
  207. <Column :rowReorder="true" headerStyle="width: 3rem"/>
  208. <Column field="name" header="Name"></Column>
  209. <Column headerStyle="width: 3rem">
  210. <template #body="slotProps">
  211. <Button icon="pi pi-trash"
  212. class="p-button-rounded p-button-warning"
  213. @click="confirmDeleteProduct(slotProps.data)"/>
  214. </template>
  215. </Column>
  216. <Column :expander="true" headerStyle="width: 3rem"/>
  217. <template #expansion="slotProps">
  218. <div class="options-subtable">
  219. <div class="p-fluid">
  220. <div class="p-field">
  221. <div class="p-field-radiobutton">
  222. <RadioButton name="action_type"
  223. id="action_type_replace"
  224. value="replace"
  225. v-model="searchersOptions[slotProps.data.id].type">
  226. </RadioButton>
  227. <label for="action_type_replace">Replace</label>
  228. </div>
  229. <div class="p-field-radiobutton">
  230. <RadioButton name="action_type"
  231. id="action_type_displace"
  232. value="displace"
  233. v-model="searchersOptions[slotProps.data.id].type">
  234. </RadioButton>
  235. <label for="action_type_displace">Displace</label>
  236. </div>
  237. </div>
  238. </div>
  239. <div class="p-field">
  240. <label :for="`displace_with__${slotProps.data.id}`">
  241. <span>
  242. {{ searchersOptions[slotProps.data.id].type === 'replace' ? 'Replace' : 'Displace (tag)' }}
  243. </span>
  244. <span>
  245. values with:
  246. </span>
  247. </label>
  248. <InputText
  249. :id="`displace_with__${slotProps.data.id}`"
  250. type="text"
  251. class="p-inputtext-sm"
  252. v-model="searchersOptions[slotProps.data.id].value"
  253. v-tooltip.top="
  254. (slotProps.data.param === 'required') ?
  255. 'This field is required.' : null
  256. "
  257. :class="{'p-invalid': !isValidParam(slotProps.data.id, slotProps.data.param)}"/>
  258. </div>
  259. </div>
  260. </template>
  261. <template #footer>
  262. <Button
  263. label="Run filters"
  264. icon="pi pi-play"
  265. class="p-button-success p-button-sm"
  266. :disabled="!canRunSearchers()"
  267. @click="toggleSearchersSidebar(); runSearchers()"/>
  268. </template>
  269. </DataTable>
  270. </Sidebar>
  271. <!-- File upload dialog -->
  272. <Dialog header="Upload a new file"
  273. :visible.sync="uploadDialogVisible"
  274. :maximizable="true"
  275. :style="{width: '50vw'}"
  276. :contentStyle="{overflow: 'visible'}"
  277. :baseZIndex="2014"
  278. id="upload_dialog"
  279. ref="upload-dialog">
  280. <FileUpload
  281. name="upload[]"
  282. :customUpload="true"
  283. :auto="true"
  284. @uploader="uploadFile">
  285. <template #empty>
  286. <p>Drag and drop files to here to upload.</p>
  287. </template>
  288. </FileUpload>
  289. </Dialog>
  290. <define-searcher v-if="showDefineSearcher"
  291. :text="searcherToDefineText"
  292. @done="onSearcherDefined"
  293. @close="showDefineSearcher = false">
  294. </define-searcher>
  295. </div>
  296. </template>
  297. <script lang="ts" src="./ProcessFile.ts"></script>
  298. <style lang="scss" src="./ProcessFile.scss"></style>