Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KZL 299 - Autocomplete on attribute name in basic filters #434

Merged
merged 50 commits into from Aug 23, 2018
Merged
Show file tree
Hide file tree
Changes from 43 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
e1ac9fa
gitignore: add vscode files to .gitignore
etrousset Jul 18, 2018
73185c8
gitignore: add vscode files to .gitignore
etrousset Jul 18, 2018
705ac95
filters: refactoring
etrousset Jul 20, 2018
9062ba7
filters: refactor
etrousset Jul 20, 2018
7dfe79d
refactoring: avoid huge logic expression...
etrousset Jul 20, 2018
a3e1110
basic-filter: fixed operand drop list size
etrousset Jul 20, 2018
c4c5e40
Merge branch 'KZL-30-restore-last-search-query-after-doc-edit' of git…
etrousset Jul 20, 2018
b04d4ee
filter restoration: search filter are now stored and restored
etrousset Jul 27, 2018
c4dc0ea
wip
etrousset Aug 3, 2018
95e56d2
add query params in router
Njuelle Aug 6, 2018
5695aaf
Merge remote-tracking branch 'origin/2.x' into KZL-30-restore-last-se…
xbill82 Aug 6, 2018
2d24043
1st stage of filters big refactor
xbill82 Aug 7, 2018
a4afe37
WIP refactoring filters
xbill82 Aug 7, 2018
65e9c6f
Basic search refactored and working
xbill82 Aug 8, 2018
e453291
Raw search refactored and working
xbill82 Aug 8, 2018
6657c9e
Pagination refactored and working
xbill82 Aug 8, 2018
44aaaf6
Tiny cleanups
xbill82 Aug 8, 2018
1c25c91
Watch refactored and working
xbill82 Aug 9, 2018
00dc00c
Fixed security
xbill82 Aug 9, 2018
cd168ff
Fixed reset button in Watch
xbill82 Aug 9, 2018
3382e05
Minor cleanups
xbill82 Aug 9, 2018
5860e90
Unit tested filter manager + minor fixes
xbill82 Aug 9, 2018
2f27b1f
Cleanup of ESLint errors on test files
xbill82 Aug 9, 2018
66efa1c
Removed FilterManager class
xbill82 Aug 9, 2018
1f7d308
Wooooops...
xbill82 Aug 9, 2018
550701e
Applied remarks from @Aschen
xbill82 Aug 13, 2018
831f2dd
Distributed collection-item styles in components
xbill82 Aug 13, 2018
83554f1
Quickfilters styles dispatched to components
xbill82 Aug 13, 2018
dd8363c
Dispatched advanced filter styles to components
xbill82 Aug 13, 2018
d397985
Dispatched principal layout styles to components
xbill82 Aug 13, 2018
0723398
Side nav styles dispatched to components
xbill82 Aug 13, 2018
613743b
Treeview fixes and style dispatch
xbill82 Aug 13, 2018
5c9e00b
Harmonized classes with BEM convention
xbill82 Aug 14, 2018
fb31ba4
Make BasicFilter great again
xbill82 Aug 14, 2018
9227671
Merge remote-tracking branch 'origin/2.x' into filters-css-refactor
xbill82 Aug 14, 2018
15999c4
Fixed Treeview disappearing on medium screens
xbill82 Aug 21, 2018
2fe5865
Add autocomplete field on attribute input, build item list from colle…
Aschen Aug 21, 2018
a1c6f49
Add custom autocomplete component + integrate it for BasicFilter attr…
Aschen Aug 22, 2018
ee8af53
Merge branch 'filters-css-refactor' into KZL-299/autocomplete-on-attr…
Aschen Aug 22, 2018
5c64ba1
merge ok
Aschen Aug 22, 2018
73a8f31
Use the autocomplete in watch view
Aschen Aug 22, 2018
ae24c29
Change selected item color
Aschen Aug 23, 2018
dbc0217
Use coding standard style for event
Aschen Aug 23, 2018
353c205
Scope style + use color variable
Aschen Aug 23, 2018
f6f05a4
Dont open list if no results
Aschen Aug 23, 2018
946ad6c
Merge branch '2.x' into KZL-299/autocomplete-on-attribute-name
Aschen Aug 23, 2018
0d2f91d
Update for PR
Aschen Aug 23, 2018
a082285
Update for PR
Aschen Aug 23, 2018
a215a9d
Nitpicking
Aschen Aug 23, 2018
8929e23
Nitpicking
Aschen Aug 23, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5,264 changes: 2,634 additions & 2,630 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Expand Up @@ -38,6 +38,7 @@
"http-server": "^0.11.1",
"lodash": "^4.17.10",
"serve-static": "^1.13.2",
"vue-autosuggest": "^1.5.0",
"vue-quill-editor": "^1.1.1"
},
"devDependencies": {
Expand Down
130 changes: 130 additions & 0 deletions src/components/Common/Autocomplete.vue
@@ -0,0 +1,130 @@
<template>
<div>
<input
type="text"
v-model="search"
:class="inputClass"
:placeholder="placeholder"
@input="onInput"
@keydown.down="onArrowDown"
@keydown.up="onArrowUp"
@keydown.enter.prevent="onEnter"
/>

<ul class="autocomplete-results" v-show="isOpen">
<li
v-for="(result, i) in results"
:key="i"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:key="result"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:key="result"

@click="setResult(result)"
class="autocomplete-result"
:class="{ 'is-active': i === arrowCounter }"
>
{{ result }}
</li>
</ul>

</div>
</template>

<script>
export default {
name: 'autocomplete',
props: {
item: {
type: String,
required: false,
default: () => ''
},
items: {
type: Array,
required: false,
default: () => []
},
inputClass: {
type: String,
required: false,
default: () => ''
},
placeholder: {
type: String,
required: false,
default: () => ''
}
},
data() {
return {
search: '',
results: [],
isOpen: false,
arrowCounter: -1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd call this selectionCursor or something similar

}
},
methods: {
onInput() {
this.isOpen = true
this.filterResults()
},
filterResults() {
this.results = this.items.filter(item => item.toLowerCase().indexOf(this.search.toLowerCase()) > -1)
},
setResult(result) {
this.search = result
this.isOpen = false
this.$emit('autocomplete::change', result)
},
onArrowDown() {
if (this.arrowCounter + 1 < this.results.length) {
this.arrowCounter = this.arrowCounter + 1
}
},
onArrowUp() {
if (this.arrowCounter > 0) {
this.arrowCounter = this.arrowCounter - 1
}
},
onEnter() {
this.setResult(this.results[this.arrowCounter])
this.arrowCounter = -1
},
handleClickOutside(evt) {
if (!this.$el.contains(evt.target)) {
this.isOpen = false
this.arrowCounter = -1
}
}
},
mounted() {
document.addEventListener('click', this.handleClickOutside)
},
destroyed() {
document.removeEventListener('click', this.handleClickOutside)
}
}
</script>

<style>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be scoped?

.autocomplete-results {
padding: 0;
margin: 0;
border: 1px solid #eeeeee;
height: 120px;
overflow: auto;
}

.autocomplete-result.is-active {
background-color: #0397ef;
color: white;
}

.autocomplete-result {
list-style: none;
text-align: left;
padding: 4px 2px;
cursor: pointer;
}

.autocomplete-result:hover {
background-color: #0397ef;
color: white;
}
</style>
7 changes: 6 additions & 1 deletion src/components/Common/CommonList.vue
Expand Up @@ -17,6 +17,7 @@
:length-document="selectedDocuments.length"
:document-to-delete="documentToDelete"
:perform-delete="performDelete"
:collection-mapping="collectionMapping"
@filters-updated="onFiltersUpdated"
@create-clicked="create"
@toggle-all="toggleAll"
Expand Down Expand Up @@ -70,7 +71,11 @@ export default {
performSearch: Function,
performDelete: Function,
routeCreate: String,
routeUpdate: String
routeUpdate: String,
collectionMapping: {
type: Object,
required: true
}
},

data() {
Expand Down
7 changes: 6 additions & 1 deletion src/components/Common/CrudlDocument.vue
Expand Up @@ -5,6 +5,7 @@
@reset="onFiltersUpdated"
:available-operands="searchFilterOperands"
:current-filter="currentFilter"
:collection-mapping="collectionMapping"
>
</filters>

Expand Down Expand Up @@ -146,7 +147,11 @@ export default {
sorting: Object,
searchFilterOperands: Object,
documentToDelete: String,
performDelete: Function
performDelete: Function,
collectionMapping: {
type: Object,
required: true
}
},
data() {
return {
Expand Down
38 changes: 36 additions & 2 deletions src/components/Common/Filters/BasicFilter.vue
Expand Up @@ -9,7 +9,12 @@
<div v-for="(orBlock, groupIndex) in filters.basic" v-bind:key="`orBlock-${groupIndex}`" class="BasicFilter-orBlock row">
<div v-for="(andBlock, filterIndex) in orBlock" v-bind:key="`andBlock-${filterIndex}`" class="BasicFilter-andBlock row dots">
<div class="col s4">
<input placeholder="Attribute" type="text" class="validate" v-model="andBlock.attribute">
<autocomplete
:items="attributeItems"
input-class="validate"
placeholder="Attribute"
@autocomplete::change="(attribute) => selectAttribute(attribute, groupIndex, filterIndex)"
/>
</div>
<div class="col s3">
<m-select v-model="andBlock.operator">
Expand Down Expand Up @@ -66,6 +71,7 @@

<script>
import MSelect from '../../Common/MSelect'
import Autocomplete from '../Autocomplete'

const emptyBasicFilter = { attribute: null, operator: 'match', value: null }
const emptySorting = { attribute: null, order: 'asc' }
Expand Down Expand Up @@ -94,10 +100,15 @@ export default {
type: Boolean,
required: false,
default: true
},
collectionMapping: {
type: Object,
required: true
}
},
components: {
MSelect
MSelect,
Autocomplete
},
data() {
return {
Expand All @@ -107,7 +118,15 @@ export default {
}
}
},
computed: {
attributeItems () {
return this.buildAttributeList(this.collectionMapping)
}
},
methods: {
selectAttribute(attribute, groupIndex, filterIndex) {
this.filters.basic[groupIndex][filterIndex].attribute = attribute
},
submitSearch() {
let filters = this.filters.basic

Expand Down Expand Up @@ -171,6 +190,19 @@ export default {
}

this.filters.basic[groupIndex].splice(filterIndex, 1)
},
buildAttributeList(mapping, path = []) {
let attributes = []

for (const [attributeName, attributeValue] of Object.entries(mapping)) {
if (attributeValue.hasOwnProperty('properties')) {
attributes = attributes.concat(this.buildAttributeList(attributeValue.properties, path.concat(attributeName)))
} else if (attributeValue.hasOwnProperty('type')) {
attributes = attributes.concat(path.concat(attributeName).join('.'))
}
}

return attributes
}
},
watch: {
Expand All @@ -194,6 +226,8 @@ export default {
}
}
}
},
mounted() {
}
}
</script>
Expand Down
7 changes: 6 additions & 1 deletion src/components/Common/Filters/Filters.vue
Expand Up @@ -35,6 +35,7 @@
:submit-button-label="submitButtonLabel"
:action-buttons-visible="actionButtonsVisible"
:sorting="sorting"
:collection-mapping="collectionMapping"
@update-filter="onBasicFilterUpdated"
@reset="onReset">
</basic-filter>
Expand Down Expand Up @@ -152,7 +153,11 @@ export default {
default: true
},
currentFilter: Object,
formatFromBasicSearch: Function
formatFromBasicSearch: Function,
collectionMapping: {
type: Object,
required: true
}
},
data() {
return {
Expand Down
9 changes: 1 addition & 8 deletions src/components/Data/Collections/Steps/Mapping.vue
Expand Up @@ -54,22 +54,15 @@
<div class="col s4" v-show="!collectionIsRealtimeOnly">
<div class="row">
<p class="help">
<<<<<<< HEAD
A mapping defines how a document and its properties
are stored and indexed.
<a href="http://docs.kuzzle.io/api-documentation/controller-collection/update-mapping/" target="_blank">Read more about mapping</a>.
</br> </br>
=======
Mapping is the process of defining how a document,
and the fields it contains, are stored and indexed.
<a href="http://docs.kuzzle.io/api-documentation/controller-collection/update-mapping/" target="_blank">Read more about mapping</a>
</br>
>>>>>>> origin/master
You should omit the root "properties" field in this form.
<pre>
{
"age": { "type": "integer" },
"name": { "type": "string" }
"name": { "type": "text" }
}
</pre>
</p>
Expand Down
11 changes: 8 additions & 3 deletions src/components/Data/Collections/Watch.vue
Expand Up @@ -37,6 +37,7 @@
:available-operands="realtimeFilterOperands"
:quick-filter-enabled="false"
:sorting-enabled="false"
:collection-mapping="collectionMapping"
@filters-updated="onFiltersUpdated"
@reset="onReset"
>
Expand Down Expand Up @@ -117,18 +118,17 @@
<script>
import CollectionTabs from './Tabs'
import Headline from '../../Materialize/Headline'

import collapsible from '../../../directives/Materialize/collapsible.directive'
import Notification from '../Realtime/Notification'
import LastNotification from '../Realtime/LastNotification'
import SubscriptionControls from '../Realtime/SubscriptionControls'
import CollectionDropdown from '../Collections/Dropdown'
import Filters from '../../Common/Filters/Filters'
import kuzzle from '../../../services/kuzzle'
// import { SET_BASIC_FILTER } from '../../../vuex/modules/common/crudlDocument/mutation-types'
import * as filterManager from '../../../services/filterManager'
import { canSubscribe } from '../../../services/userAuthorization'
import { SET_TOAST } from '../../../vuex/modules/common/toaster/mutation-types'
import { getMappingDocument } from '../../../services/kuzzleWrapper'

import Vue from 'vue'

Expand All @@ -151,14 +151,19 @@ export default {
warning: { message: '', count: 0, lastTime: null, info: false },
notifStyle: {},
scrollDown: true,
lastNotification: {}
lastNotification: {},
collectionMapping: {}
}
},
created() {
window.addEventListener('scroll', this.handleScroll)
},
mounted() {
this.notifications = []
getMappingDocument(this.collection, this.index)
.then(response => {
this.collectionMapping = response.mapping
})
},
destroyed() {
this.reset()
Expand Down
15 changes: 14 additions & 1 deletion src/components/Data/Documents/List.vue
Expand Up @@ -18,6 +18,7 @@
:display-create="canCreateDocument(index, collection)"
:perform-search="performSearchDocuments"
:perform-delete="performDeleteDocuments"
:collection-mapping="collectionMapping"
route-create="DataCreateDocument"
route-update="DataUpdateDocument">

Expand Down Expand Up @@ -82,11 +83,17 @@ import {
} from '../../../services/userAuthorization'
import {
performSearchDocuments,
performDeleteDocuments
performDeleteDocuments,
getMappingDocument
} from '../../../services/kuzzleWrapper'

export default {
name: 'DocumentsList',
data () {
return {
collectionMapping: {}
}
},
props: {
index: String,
collection: String
Expand Down Expand Up @@ -128,6 +135,12 @@ export default {
canEditCollection,
performSearchDocuments,
performDeleteDocuments
},
mounted() {
getMappingDocument(this.collection, this.index)
.then(response => {
this.collectionMapping = response.mapping
})
}
}
</script>