Skip to content

Commit

Permalink
Merge pull request #43 from bfritscher/presets
Browse files Browse the repository at this point in the history
Presets
  • Loading branch information
bfritscher authored Jan 22, 2024
2 parents bf22050 + d6bafdb commit 3e33162
Show file tree
Hide file tree
Showing 10 changed files with 406 additions and 19 deletions.
7 changes: 7 additions & 0 deletions src/components/NavMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@
<q-item-section> Analytics Rules </q-item-section>
</q-item>

<q-item clickable v-ripple to="/searchpresets" exact>
<q-item-section avatar>
<q-icon name="sym_s_manage_search" />
</q-item-section>

<q-item-section> Search Presets </q-item-section>
</q-item>

<q-separator spaced />

Expand Down
1 change: 0 additions & 1 deletion src/components/collection/CollectionUi.vue
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,6 @@ export default defineComponent({
props: {
initialSchema: {
type: Object as () => CollectionCreateSchema | CollectionSchema | CollectionUpdateSchema,
required: true,
default: () =>
({
name: '',
Expand Down
2 changes: 1 addition & 1 deletion src/pages/ApiKeys.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
color="info"
flat
dense
href="https://typesense.org/docs/0.23.1/api/api-keys.html#create-an-api-key"
:href="`https://typesense.org/docs/${$store.state.node.data.debug.version}/api/api-keys.html#create-an-api-key`"
target="_blank"
>Documentation</q-btn
>
Expand Down
85 changes: 71 additions & 14 deletions src/pages/Collections.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,74 @@
<q-page padding>
<collection-create></collection-create>
<q-table

:filter="filter"
:columns="columns"
:rows="$store.state.node.data.collections"
row-key="name"
:pagination="{ rowsPerPage: 0, sortBy: 'name' }"
>
<template v-slot:body="props">
<template v-slot:body="props">
<q-tr :props="props">
<q-td key="name" :props="props">
<q-btn no-caps flat :to="`/collection/${props.row.name}/search`" size="1.2em" class="text-bold">{{ props.row.name }}</q-btn>
<q-btn
no-caps
flat
:to="`/collection/${props.row.name}/search`"
size="1.2em"
class="text-bold"
>{{ props.row.name }}</q-btn
>
</q-td>
<q-td key="actions" :props="props">
<q-btn flat round icon="sym_s_more_vert">
<q-menu>
<q-item dense clickable :to="`/collection/${props.row.name}/document`">
<q-item
dense
clickable
:to="`/collection/${props.row.name}/document`"
>
<q-item-section>Import</q-item-section>
<q-item-section avatar>
<q-avatar icon="sym_s_file_upload" />
</q-item-section>
</q-item>
<q-item dense clickable @click="exportCollection(props.row.name)">
<q-item
dense
clickable
@click="exportCollection(props.row.name)"
>
<q-item-section>Export</q-item-section>
<q-item-section avatar>
<q-avatar icon="sym_s_file_download" />
</q-item-section>
</q-item>
<q-item dense clickable :to="`/collection/${props.row.name}/schema`">
<q-item
dense
clickable
:to="`/collection/${props.row.name}/schema`"
>
<q-item-section>Edit</q-item-section>
<q-item-section avatar>
<q-avatar icon="sym_s_data_object" />
</q-item-section>
</q-item>
<q-item dense clickable flat style="color: #DE3B39" @click="drop(props.row.name)">
<q-item
dense
clickable
@click="cloneCollection(props.row.name)"
>
<q-item-section>Clone Schema</q-item-section>
<q-item-section avatar>
<q-avatar icon="sym_s_content_copy" />
</q-item-section>
</q-item>
<q-item
dense
clickable
flat
style="color: #de3b39"
@click="drop(props.row.name)"
>
<q-item-section>Delete</q-item-section>
<q-item-section avatar>
<q-avatar icon="sym_s_delete" />
Expand All @@ -45,15 +79,19 @@
</q-btn>
</q-td>
<q-td key="num_documents" :props="props">
<q-btn no-caps flat :to="`/collection/${props.row.name}/search`">{{ props.row.num_documents }} <q-icon name="sym_s_search" size="1em" right /></q-btn>
<q-btn no-caps flat :to="`/collection/${props.row.name}/search`"
>{{ props.row.num_documents }}
<q-icon name="sym_s_search" size="1em" right
/></q-btn>
</q-td>
<q-td key="schema_fields" :props="props">
<q-btn no-caps flat :to="`/collection/${props.row.name}/schema`" >{{ props.row.fields.length || 0 }} <q-icon name="sym_s_data_object" size="1em" right /></q-btn>
<q-btn no-caps flat :to="`/collection/${props.row.name}/schema`"
>{{ props.row.fields.length || 0 }}
<q-icon name="sym_s_data_object" size="1em" right
/></q-btn>
</q-td>
<q-td key="created_at" :props="props">
{{
new Date(props.row.created_at * 1000).toLocaleString()
}}
{{ new Date(props.row.created_at * 1000).toLocaleString() }}
</q-td>
</q-tr>
</template>
Expand All @@ -77,7 +115,7 @@

<script lang="ts">
import CollectionCreate from 'src/components/collection/CollectionCreate.vue';
import { defineComponent } from 'vue';;
import { defineComponent } from 'vue';
export default defineComponent({
components: { CollectionCreate },
name: 'Collections',
Expand Down Expand Up @@ -156,6 +194,25 @@ export default defineComponent({
void this.$store.dispatch('node/dropCollection', name);
});
},
}
cloneCollection(collectionName: string) {
this.$q
.dialog({
title: 'Clone Schema',
message: 'Provide name for new collection? (documents are not copied!, only schema, currations and synonyms)',
prompt: {
model: '',
type: 'text',
},
cancel: true,
persistent: true,
})
.onOk((destinationName) => {
void this.$store.dispatch('node/cloneCollectionSchema', {
collectionName,
destinationName,
});
});
},
},
});
</script>
191 changes: 191 additions & 0 deletions src/pages/SearchPresets.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
<template>
<q-page padding>
<q-expansion-item
expand-separator
icon="sym_s_add_circle"
expand-icon="sym_s_unfold_more"
expanded-icon="sym_s_unfold_less"
:label="`${isUpdate ? 'Update' : 'Add'} Search Preset`"
header-class="bg-primary text-white"
v-model="expanded"
>
<q-card style="height: 60vh" class="bg-surface column">
<q-card-section class="q-col-gutter-md row">
<q-input
class="col-12 col-sm-6"
v-model="preset.name"
label="Name"
filled
:rules="[(val) => !!val || 'Field is required']" />
<q-btn
type="a"
icon="sym_s_help"
no-caps
color="info"
flat
dense
:href="`https://typesense.org/docs/${$store.state.node.data.debug.version}/api/search.html#presets`"
target="_blank"
>Documentation</q-btn
>
</q-card-section>
<monaco-editor v-model="keyJson"></monaco-editor>
<q-banner inline-actions class="text-white bg-red" v-if="jsonError">
Invalid Format: {{ jsonError }}
</q-banner>

<q-card-actions align="right" class="bg-primary">
<q-btn
size="md"
padding="sm lg"
unelevated
color="primary"
:disable="!!jsonError"
@click="createSearchPreset()"
>{{ isUpdate ? 'Update' : 'Add' }} Preset</q-btn
>
</q-card-actions>
</q-card>
</q-expansion-item>

<q-table
class="q-mt-md"
title="Search Presets"
flat
bordered
:filter="filter"
:rows="$store.state.node.data.searchPresets"
:columns="columns"
row-key="id"
>
<template v-slot:top-left>
<div class="text-h6"><q-icon size="md" name="sym_s_manage_search" /> Search Presets</div>
</template>
<template v-slot:top-right>
<q-input
borderless
dense
debounce="300"
v-model="filter"
placeholder="Search"
>
<template v-slot:append>
<q-icon name="sym_s_search" />
</template>
</q-input>
</template>
<template v-slot:body-cell-actions_op="props">
<q-td class="text-right">
<q-btn
flat
color="primary"
@click="editSearchPreset(props.row)"
icon="sym_s_edit"
title="Edit"
></q-btn>
<q-btn
flat
color="negative"
@click="deleteSearchPreset(props.row.name)"
icon="sym_s_delete_forever"
title="Delete"
></q-btn>
</q-td>
</template>
</q-table>
</q-page>
</template>

<script lang="ts">
import { PresetSchema } from 'typesense/lib/Typesense/Preset';
import MonacoEditor from '../components/MonacoEditor.vue';
import { defineComponent } from 'vue';
export default defineComponent({
name: 'SearchPresets',
components: { MonacoEditor },
data() {
return {
jsonError: null as string | null,
preset: {
name: '',
value: {
'collection': 'products',
'q': '*',
'sort_by': 'popularity',
},
},
expanded: this.$store.state.node.data.searchPresets.length === 0,
filter: '',
columns: [
{
label: 'Name',
name: 'name',
field: 'name',
sortable: true,
align: 'left',
},
{
label: 'Search Parameters',
name: 'value',
field: (row: PresetSchema) => JSON.stringify(row.value),
sortable: true,
align: 'left',
},
{
label: 'Actions',
name: 'actions_op',
align: 'right',
},
],
};
},
computed: {
keyJson: {
get(): string {
return JSON.stringify(this.preset.value, null, 2);
},
set(json: string) {
try {
this.preset.value = JSON.parse(json);
this.jsonError = null;
} catch (e) {
this.jsonError = (e as Error).message;
}
},
},
isUpdate(): boolean {
return this.$store.state.node.data.searchPresets
.map((p:any) => p.name)
.includes(this.preset.name);
},
},
mounted() {
void this.$store.dispatch('node/getSearchPresets');
},
methods: {
async createSearchPreset() {
await this.$store.dispatch(
'node/upsertSearchPreset',
JSON.parse(JSON.stringify(this.preset))
);
},
editSearchPreset(preset: PresetSchema) {
this.preset = JSON.parse(JSON.stringify(preset));
this.expanded = true;
},
deleteSearchPreset(name: string) {
this.$q
.dialog({
title: 'Confirm',
message: `Delete preset ${name}?`,
cancel: true,
persistent: true,
})
.onOk(() => {
void this.$store.dispatch('node/deleteSearchPreset', name);
});
},
},
});
</script>
Loading

0 comments on commit 3e33162

Please sign in to comment.