Browse Source

Further UI updates

master
Radu Liviu Carjan 3 years ago
parent
commit
6ae5f2a2fa
  1. 32
      app/Http/Controllers/SearchAndDisplaceController.php
  2. 31184
      package-lock.json
  3. 3
      package.json
  4. 5105
      public/css/app.css
  5. 6111
      public/js/app.js
  6. 7
      resources/js/app.ts
  7. 18
      resources/js/components/ProcessFile/ProcessFile.scss
  8. 89
      resources/js/components/ProcessFile/ProcessFile.ts
  9. 38
      resources/js/components/ProcessFile/ProcessFile.vue
  10. 34
      resources/js/components/Regex/Create.vue
  11. 52
      resources/js/components/Searchers/Index.vue
  12. 125
      resources/js/components/Searchers/Show.vue
  13. 17
      resources/sass/app.sass
  14. 10
      resources/views/pages/home.blade.php
  15. 7
      resources/views/pages/searchers/index.blade.php
  16. 973
      yarn.lock

32
app/Http/Controllers/SearchAndDisplaceController.php
File diff suppressed because it is too large
View File

31184
package-lock.json
File diff suppressed because it is too large
View File

3
package.json

@ -28,13 +28,14 @@
"webpack": "^5.9.0"
},
"dependencies": {
"@types/marked": "^2.0.3",
"marked": "^2.0.5",
"primeflex": "^2.0.0",
"primeicons": "^4.1.0",
"primevue": "^2.4.1",
"tsconfig-paths-webpack-plugin": "^3.5.1",
"vue": "^2.6.12",
"vue-class-component": "^7.2.6",
"vue-markdown-render": "^1.1.1",
"vue-property-decorator": "^8.1.0"
}
}

5105
public/css/app.css
File diff suppressed because it is too large
View File

6111
public/js/app.js
File diff suppressed because it is too large
View File

7
resources/js/app.ts

@ -31,6 +31,8 @@ import ProgressSpinner from 'primevue/progressspinner';
import InputText from 'primevue/inputtext';
import Dialog from 'primevue/dialog';
import Message from 'primevue/message';
import Timeline from 'primevue/timeline';
import ScrollPanel from 'primevue/scrollpanel';
// Own components
import AppHeader from './components/layout/Header.vue';
@ -38,6 +40,7 @@ import AppFooter from './components/layout/Footer.vue';
import RegexCreate from './components/Regex/Create.vue';
import SearchersCreate from './components/Searchers/Create.vue';
import SearchersShow from './components/Searchers/Show.vue';
import SearchersIndex from './components/Searchers/Index.vue';
import ApiPlugin from './plugins/ApiPlugin';
import Home from './components/Home/Home.vue';
import ProcessFile from './components/ProcessFile/ProcessFile.vue';
@ -49,7 +52,6 @@ Vue.use(PrimeVue, {
Vue.use(ToastService);
Vue.use(ApiPlugin);
// Vue.component('vue-markdown', VueMarkdown);
Vue.component('Button', Button);
Vue.component('Panel', Panel);
Vue.component('Card', Card);
@ -74,6 +76,8 @@ Vue.component('ProgressSpinner', ProgressSpinner);
Vue.component('InputText', InputText);
Vue.component('Dialog', Dialog);
Vue.component('Message', Message);
Vue.component('Timeline', Timeline);
Vue.component('ScrollPanel', ScrollPanel);
// Layout
Vue.component('app-header', AppHeader);
@ -86,6 +90,7 @@ Vue.component('regex-create', RegexCreate);
Vue.component('searchers-create', SearchersCreate);
Vue.component('searchers-show', SearchersShow);
Vue.component('searchers-index', SearchersIndex);
// Includes
Vue.component('process-file', ProcessFile);

18
resources/js/components/ProcessFile/ProcessFile.scss

@ -2,9 +2,6 @@
flex: 0 1 49%;
}
// .filters-card {
// flex: 0 1 24%
// }
.p-overlaypanel {
// width: 450px;
min-width: 450px;
@ -35,16 +32,27 @@ button.add-searchers {
height: 100%;
}
.p-button.sidebar-toggle-button {
position: absolute;
left: calc(-16px - 2.357rem);
top: 50px;
border-radius: 3px 0 0 3px;
}
.p-col.sidebar-title {
display: flex;
align-content: flex-start;
justify-content: flex-start;
}
.p-grid.sidebar-title-container {
padding-top: 50px;
label.switch-label {
padding-right: 10px;
}
// .p-grid.sidebar-title-container {
// padding-top: 50px;
// }
.md-viewer {
text-align: start;

89
resources/js/components/ProcessFile/ProcessFile.ts

@ -1,7 +1,7 @@
import axios from 'axios';
// import OverlayPanel from 'primevue/overlaypanel/OverlayPanel';
import marked from 'marked';
import { Vue, Component, Prop, Watch } from 'vue-property-decorator';
import { FileData } from '@/interfaces/FileData';
import { FileData } from '@interfaces/FileData';
@Component
export default class ProcessFile extends Vue {
@ -30,6 +30,10 @@ export default class ProcessFile extends Vue {
// 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;
@ -54,6 +58,9 @@ export default class ProcessFile extends Vue {
// 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;
/**
*
*/
@ -71,6 +78,27 @@ export default class ProcessFile extends Vue {
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
*/
@ -124,6 +152,10 @@ export default class ProcessFile extends Vue {
}
/**
*
* @param $event
*/
private onSelectedSearchersReorder($event: any)
{
this.selectedSearchers = $event.value;
@ -149,12 +181,61 @@ export default class ProcessFile extends Vue {
console.log(response);
this.processedFileContent = response.content;
this.documentDiffIndexes = response.diff;
this.createDiffPreview();
this.processing = false;
}
private async downloadOdt()
{
/**
* Create the diff preview for the document
*/
private createDiffPreview() {
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('http://core.sandd/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
{
console.log('OLD: ', oldValue);
console.log('NEW: ', newValue);
}
}

38
resources/js/components/ProcessFile/ProcessFile.vue

@ -25,7 +25,7 @@
<Skeleton /><br />
</template>
<template v-else>
<vue-markdown :source="fileContent" />
<div v-html="compiledFileContent"></div>
</template>
</div>
</template>
@ -43,10 +43,18 @@
</template>
<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
@ -55,12 +63,6 @@
class="p-button-success p-button-outlined p-button-sm"
:disabled="fileContent == ''"
@click="runSearchers()"/>
<Button
label="Toggle filters list"
icon="pi pi-list"
class="p-button-info p-button-outlined p-button-sm"
@click="toggleSearchersSidebar()"/>
</template>
</Toolbar>
</template>
@ -76,8 +78,9 @@
<Skeleton /><br />
<Skeleton /><br />
</template>
<template v-else-if="processedFileContent !== ''">
<vue-markdown :source="processedFileContent" />
<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">
@ -91,11 +94,22 @@
<Sidebar
:visible.sync="searchersSidebarVisible"
:showCloseIcon="true"
class="p-sidebar-md"
: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()"/>
</div>
<div class="p-grid p-jc-between sidebar-title-container">
<div class="p-col sidebar-title">
<h3>Document searchers</h3>

34
resources/js/components/Regex/Create.vue

@ -1,16 +1,22 @@
<template>
<div id="regex-create">
<div>
<div>
<input v-model="name"
type="text"
placeholder="Enter searcher name"
class="input">
<div class="p-d-flex p-flex-column p-ai-center" id="regex-create">
<div class="p-formgroup-inline">
<div class="p-field">
<span class="p-float-label">
<InputText
v-model="name"
type="text"
class="p-inputtext-sm"
name="name"
id="name"/>
<label for="name">Enter searcher name</label>
</span>
</div>
<button @click="onSave" :disabled=" ! name || ! pattern">
Save
</button>
<Button
label="Save"
class="p-button-sm p-button-raised"
@click="onSave"
:disabled="!name || !pattern" />
</div>
<div class="regex-box">
@ -67,3 +73,9 @@ export default class Create extends Vue {
}
};
</script>
<style lang="scss" scoped>
#regex-create {
margin-top: 25px;
}
</style>

52
resources/js/components/Searchers/Index.vue

@ -1,19 +1,33 @@
<template>
<div style="display: flex; flex-direction: row;">
<div v-for="(searcher, id) in searchers"
:key="id"
@click="onSelect(id)"
class="box flex-column"
:class="{selected: id === selectedSearcherId}"
style="margin-left: 1rem;">
<div>
<span> {{ searcher.name }} </span>
</div>
<div style="margin-top: 5px; color: dodgerblue;">
<a @click.stop="onOpen(id)"> View </a>
</div>
</div>
<div class="p-d-flex p-flex-wrap">
<Card
v-for="(searcher, id) in searchers"
:key="id"
:class="{'p-mr-4': true, 'selected': (id === selectedSearcherId), 'p-shadow-10': (id === selectedSearcherId)}">
<template #title>
{{ searcher.name }}
</template>
<template #content>
{{ searcher.description }}
</template>
<template #footer>
<Button
icon="pi pi-check-square"
label="Select"
class="p-button-sm"
@click="onSelect(id)" />
<Button
icon="pi pi-eye"
label="View"
class="p-button-secondary p-button-sm"
style="margin-left: .5em"
@click.stop="onOpen(id)"/>
</template>
</Card>
</div>
</template>
@ -22,7 +36,7 @@ import {Component, Vue} from "vue-property-decorator";
@Component({
})
export default class Create extends Vue {
export default class Index extends Vue {
private searchers: any = {};
private selectedSearcherId: string = '';
@ -63,3 +77,9 @@ export default class Create extends Vue {
}
};
</script>
<style lang="scss" scoped>
.p-card {
transition: box-shadow 0.2s ease-in-out;
}
</style>

125
resources/js/components/Searchers/Show.vue

@ -1,50 +1,97 @@
<template>
<div id="searchers-show">
<div>
<h3>{{ searcher.name }}</h3>
<h5>{{ searcher.description }}</h5>
<a v-if="editable"
:href="`/searchers/${searcher.id}/edit`">
Edit
</a>
</div>
<div v-for="(row, rowIndex) in searcher.rows" :key="`row-${rowIndex}`" class="flex-row">
<div v-for="(searcherItem, columnIndex) in row" :key="`column-${columnIndex}`">
<div class="box is-plain">
<template v-if="searcherItem.hasOwnProperty('name')">
<searcher-show :editable="false"
:searcher="searcherItem">
</searcher-show>
</template>
<Panel :header="searcher.name">
<template #icons>
<a
class="p-panel-header-icon p-link"
v-if="editable"
:href="`/searchers/${searcher.id}/edit`"
>
<span class="pi pi-cog"></span>
</a>
</template>
<div class="p-d-flex p-jc-start">
<h5>{{ searcher.description }}</h5>
<template v-else>
<b>{{ searcherItem.expression }}</b>
<Timeline :value="searcher.rows">
<template #opposite="slotProps">
<small class="p-text-secondary">
{{ slotProps.index + 1 }}
</small>
</template>
<template #content="slotProps">
<ScrollPanel
style="max-width: 90vw; height: 125px"
class="searcher-list"
>
<div
v-for="(
searcherItem, columnIndex
) in slotProps.item"
:key="`column-${columnIndex}`"
>
<div class="box is-plain p-shadow-5">
<template
v-if="
searcherItem.hasOwnProperty('name')
"
>
<searcher-show
:editable="false"
:searcher="searcherItem"
></searcher-show>
</template>
<p>
<!-- // Show example here, so for example the user has to input the example in order to save-->
<!-- // the regex, show highlight, so apply regex on example text-->
</p>
<template v-else>
<b>{{ searcherItem.expression }}</b>
</template>
</div>
</div>
</ScrollPanel>
<Divider />
</template>
</div>
</Timeline>
</div>
</div>
</Panel>
</div>
</template>
<script lang="ts">
import {Component, Vue, Prop} from "vue-property-decorator";
@Component({
name: 'SearcherShow',
})
export default class Create extends Vue {
@Prop({default: {}})
public readonly searcher!: Object;
@Prop({default: true})
public readonly editable!: boolean;
};
import { Component, Vue, Prop } from "vue-property-decorator";
@Component({
name: "SearcherShow",
})
export default class Create extends Vue {
@Prop({ default: {} })
public readonly searcher!: Object;
@Prop({ default: true })
public readonly editable!: boolean;
}
</script>
<style lang="scss" scoped>
::v-deep .p-timeline-event-opposite {
flex: 0 !important;
}
::v-deep .p-timeline-event-content {
margin-bottom: 25px;
}
::v-deep .searcher-list {
.p-scrollpanel-content {
display: flex;
flex-direction: row;
padding-top: 25px
}
.p-scrollpanel-bar {
background-color: #1976d2;
opacity: 1;
transition: background-color 0.3s;
}
}
</style>

17
resources/sass/app.sass

@ -7,9 +7,9 @@
@import '~primeflex/src/_spacing'
@import '~primeflex/src/_elevation'
// @import '~primevue/resources/themes/fluent-light/theme.css'
// @import '~primevue/resources/themes/vela-green/theme.css'
@import '~primevue/resources/themes/mdc-light-indigo/theme.css'
@import '~primevue/resources/themes/fluent-light/theme.css'
//@import '~primevue/resources/themes/mdc-light-indigo/theme.css'
// @import '~primevue/resources/themes/saga-blue/theme.css'
@import '~primevue/resources/primevue.min.css'
@import '~primeicons/primeicons.css'
@ -44,16 +44,13 @@ body
// Temp location
.box
border: 1px solid black
min-width: 100px
min-height: 100px
padding: 10px
display: flex
justify-content: center
align-items: center
cursor: pointer
margin-left: 1rem
margin-bottom: 1rem
background-color: var(--surface-e)
text-align: center
padding: 1rem
border-radius: 4px
&.selected
border-color: dodgerblue

10
resources/views/pages/home.blade.php

@ -1,13 +1,5 @@
@extends('app')
@section('content')
<div class="page-wrapper">
<app-header></app-header>
<div class="content">
<home :searchers="{{ json_encode($searchers) }}"></home>
</div>
</div>
<app-footer></app-footer>
<home :searchers="{{ json_encode($searchers) }}"></home>
@endsection

7
resources/views/pages/searchers/index.blade.php

@ -0,0 +1,7 @@
@extends('app')
@section('content')
<searchers-index :searchers="{{ json_encode($searchers) }}"></searchers-index>
@endsection

973
yarn.lock
File diff suppressed because it is too large
View File

Loading…
Cancel
Save