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

All updates for 1.6 #43

Merged
merged 5 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading