Skip to content

Commit

Permalink
fix: persist search by example on page refresh (#1606)
Browse files Browse the repository at this point in the history
Co-authored-by: Thanh Pham <[email protected]>
Co-authored-by: Yohann Paris <[email protected]>
Co-authored-by: blanchco <[email protected]>
Co-authored-by: Cole Blanchard <[email protected]>
Co-authored-by: Edwin Lai <[email protected]>
Co-authored-by: Daniel Chang <[email protected]>
Co-authored-by: Jamie Waese <[email protected]>
Co-authored-by: Shawn Yama <[email protected]>
Co-authored-by: Tom Szendrey <[email protected]>
  • Loading branch information
10 people authored Jul 29, 2023
1 parent 3ae4fad commit 4f91b67
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ import {
useSearchByExampleOptions,
extractResourceName
} from '@/page/data-explorer/search-by-example';
import { getResourceID } from '@/utils/data-util';
const props = defineProps<{
showSuggestions: boolean;
Expand All @@ -157,8 +158,7 @@ const selectedSearchByExampleOptions = ref<SearchByExampleOptions>({
backwardCitation: false,
relatedContent: false
});
const { searchByExampleOptions, searchByExampleItem, searchByExampleAssetCardProp } =
useSearchByExampleOptions();
const { searchByExampleOptions, searchByExampleItem } = useSearchByExampleOptions();
function clearQuery() {
query.value = '';
Expand All @@ -167,20 +167,21 @@ function clearQuery() {
const initiateSearch = () => {
emit('query-changed', query.value);
router.push({ name: RouteName.DataExplorerRoute, query: { q: query.value, byExample: 'false' } });
router.push({ name: RouteName.DataExplorerRoute, query: { q: query.value } });
EventService.create(EventType.Search, resources.activeProject?.id, query.value);
};
function initiateSearchByExample() {
searchByExampleItem.value = searchByExampleSelectedAsset.value;
searchByExampleOptions.value = { ...selectedSearchByExampleOptions.value };
searchByExampleToggle.value = false;
// used in order to update the "showing x of y results with ... to <Asset Card>"
// section after a search by example is initiated
searchByExampleAssetCardProp.value = { ...searchByExampleItem.value };
// used to update the search bar text with the name of the search by example asset
query.value = extractResourceName(searchByExampleItem.value);
router.push({ name: RouteName.DataExplorerRoute, query: { q: query.value, byExample: 'true' } });
router.push({
name: RouteName.DataExplorerRoute,
query: { resourceId: getResourceID(searchByExampleItem.value!) }
});
}
function addToQuery(term: string) {
Expand Down Expand Up @@ -230,7 +231,6 @@ function onDrop() {
searchByExampleToggle.value = true; // Maintains open search by example popup once an asset is successfully dropped
searchByExampleSelectedAsset.value = getDragData('asset');
searchByExampleSelectedResourceType.value = getDragData('resourceType');
searchByExampleItem.value = searchByExampleSelectedAsset.value;
isDraggedOver.value = false;
}
Expand Down
67 changes: 36 additions & 31 deletions packages/client/hmi-client/src/page/data-explorer/DataExplorer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@
<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
import TeraSliderPanel from '@/components/widgets/tera-slider-panel.vue';
import { fetchData, getXDDSets } from '@/services/data';
import { fetchData, getDocumentById, getXDDSets } from '@/services/data';
import {
ResourceType,
ResultType,
Expand Down Expand Up @@ -148,8 +148,7 @@ const route = useRoute();
const queryStore = useQueryStore();
const resources = useResourcesStore();
const { searchByExampleOptions, searchByExampleItem, searchByExampleAssetCardProp } =
useSearchByExampleOptions();
const { searchByExampleOptions, searchByExampleItem } = useSearchByExampleOptions();
const dataItems = ref<SearchResults[]>([]);
const dataItemsUnfiltered = ref<SearchResults[]>([]);
const selectedSearchItems = ref<ResultType[]>([]);
Expand Down Expand Up @@ -276,20 +275,12 @@ const executeSearch = async () => {
};
// handle the search-by-example for finding related documents, models, and/or datasets
if (
executeSearchByExample.value &&
(searchByExampleItem.value || searchByExampleAssetCardProp.value)
) {
const id = getResourceID(
searchByExampleItem.value ?? searchByExampleAssetCardProp.value
) as string;
if (executeSearchByExample.value && searchByExampleItem.value) {
const id = getResourceID(searchByExampleItem.value) as string;
//
// find related documents (which utilizes the xDD doc2vec API through the HMI server)
//
if (
isDocument(searchByExampleItem.value ?? searchByExampleAssetCardProp.value) &&
searchParams.xdd
) {
if (isDocument(searchByExampleItem.value) && searchParams.xdd) {
searchParams.xdd.dataset = xddDataset.value;
if (searchByExampleOptions.value.similarContent) {
searchParams.xdd.similar_search_enabled = executeSearchByExample.value;
Expand All @@ -303,21 +294,15 @@ const executeSearch = async () => {
//
// find related models (which utilizes the TDS provenance API through the HMI server)
//
if (
isModel(searchByExampleItem.value ?? searchByExampleAssetCardProp.value) &&
searchParams.model
) {
if (isModel(searchByExampleItem.value) && searchParams.model) {
searchParams.model.related_search_enabled = executeSearchByExample.value;
searchParams.model.related_search_id = id;
searchType = ResourceType.MODEL;
}
//
// find related datasets (which utilizes the TDS provenance API through the HMI server)
//
if (
isDataset(searchByExampleItem.value ?? searchByExampleAssetCardProp.value) &&
searchParams.dataset
) {
if (isDataset(searchByExampleItem.value) && searchParams.dataset) {
searchParams.dataset.related_search_enabled = executeSearchByExample.value;
searchParams.dataset.related_search_id = id;
searchType = ResourceType.DATASET;
Expand Down Expand Up @@ -406,7 +391,7 @@ const executeSearch = async () => {
};
const clearSearchByExampleSelections = () => {
// clear out the serch by example option selections
// clear out the search by example option selections
searchByExampleOptions.value = {
similarContent: false,
forwardCitation: false,
Expand Down Expand Up @@ -440,7 +425,6 @@ const onSearchByExample = async (searchOptions: SearchByExampleOptions) => {
await executeSearch();
searchByExampleItem.value = null;
dirtyResults.value[resourceType.value] = false;
}
};
Expand Down Expand Up @@ -556,6 +540,16 @@ async function executeNewQuery() {
dirtyResults.value[resourceType.value] = false;
}
async function searchByExampleOnPageRefresh(resourceId: string) {
if (!searchByExampleItem.value) {
searchByExampleItem.value = await getDocumentById(resourceId);
}
if (!Object.values(searchByExampleOptions.value).some((v) => v)) {
searchByExampleOptions.value.similarContent = true;
}
onSearchByExample(searchByExampleOptions.value);
}
// this is called whenever the user apply some facet filter(s)
watch(clientFilters, async (n, o) => {
if (filtersUtil.isEqual(n, o)) return;
Expand All @@ -579,15 +573,19 @@ watch(clientFilters, async (n, o) => {
watch(
() => route.query,
() => {
// Adding another query param 'byExample' for what should be a better way to determine whether we are searching by example or not.
// For now this is just a boolean string but this can be looked into further to maybe add additional parameters when searching by example.
// i.e. refreshing will land the user on the page with the example resource type already populated and used to search
if (route.query.byExample !== 'true') executeNewQuery();
// The query changes in the following cases:
// - when a user does a normal search - there is no `resourceId`
// - when a user does a search by example - there is a `resourceId`
// - when a user navigates back and forth on a page
if (route.query.resourceId) {
searchByExampleOnPageRefresh(route.query.resourceId.toString());
} else {
executeNewQuery();
}
}
);
watch(searchByExampleOptions, () => onSearchByExample(searchByExampleOptions.value));
// Default query on reload
onMounted(async () => {
xddDatasets.value = await getXDDSets();
Expand All @@ -597,7 +595,14 @@ onMounted(async () => {
} else {
resources.setXDDDataset('xdd-covid-19'); // give xdd dataset a default value
}
executeNewQuery();
// On reload, if the url has a resourceId, we know that a user just did a search by example
// so we want to preserve the search by example so we perform a search by example instead of a normal search
if (route.query.resourceId) {
searchByExampleOnPageRefresh(route.query.resourceId.toString());
} else {
executeNewQuery();
}
});
onUnmounted(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
{{ resourceType.toUpperCase() }}
<div
class="asset-filters"
v-if="resourceType === ResourceType.XDD && asset.knownEntities?.askemObjects"
v-if="resourceType === ResourceType.XDD && (asset as Document).knownEntities?.askemObjects"
>
<template
v-for="icon in [
Expand All @@ -28,20 +28,25 @@
/>
</template>
</div>
<div v-else-if="resourceType === ResourceType.MODEL">{{ asset.schema_name }}</div>
<div v-else-if="resourceType === ResourceType.MODEL">
{{ (asset as Model).schema_name }}
</div>
</div>
<header class="title" v-html="title" />
<div class="details" v-html="formatDetails" />
<ul class="snippets" v-if="snippets">
<li v-for="(snippet, index) in snippets" :key="index" v-html="snippet" />
</ul>
<div class="description" v-html="highlightSearchTerms(asset.description)" />
<div
class="description"
v-html="highlightSearchTerms((asset as Model | Dataset).description)"
/>
<div
class="parameters"
v-if="resourceType === ResourceType.MODEL && asset?.semantics?.ode?.parameters"
v-if="resourceType === ResourceType.MODEL && (asset as Model).semantics?.ode?.parameters"
>
PARAMETERS:
{{ asset.semantics.ode.parameters }}
{{ (asset as Model).semantics?.ode.parameters }}
<!--may need a formatting function this attribute is always undefined at the moment-->
</div>
<div class="features" v-else-if="resourceType === ResourceType.DATASET">
Expand All @@ -51,7 +56,9 @@
<footer><!--pill tags if already in another project--></footer>
</main>
<aside class="preview-and-options">
<figure v-if="resourceType === ResourceType.XDD && asset.knownEntities?.askemObjects">
<figure
v-if="resourceType === ResourceType.XDD && (asset as Document).knownEntities?.askemObjects"
>
<template v-if="relatedAsset">
<img
v-if="relatedAsset.properties.image"
Expand Down Expand Up @@ -105,7 +112,7 @@ import { watch, ref, computed, ComputedRef } from 'vue';
import { isEmpty } from 'lodash';
import { XDDExtractionType } from '@/types/XDD';
import { Document, Extraction, XDDUrlExtraction, Dataset, Model } from '@/types/Types';
import { ResourceType } from '@/types/common';
import { ResourceType, ResultType } from '@/types/common';
import * as textUtil from '@/utils/text';
import { useDragEvent } from '@/services/drag-drop';
Expand All @@ -116,7 +123,7 @@ type UrlExtraction = {
};
const props = defineProps<{
asset: Document & Model & Dataset;
asset: ResultType;
resourceType: ResourceType;
highlight?: string;
}>();
Expand All @@ -137,8 +144,8 @@ const chosenExtractionFilter = ref<XDDExtractionType | 'Asset'>('Asset');
const urlExtractions = computed(() => {
const urls: UrlExtraction[] = [];
if (props.asset.knownEntities.askemObjects) {
const documentsWithUrls = props.asset.knownEntities.askemObjects.filter(
if ((props.asset as Document).knownEntities.askemObjects) {
const documentsWithUrls = (props.asset as Document).knownEntities.askemObjects.filter(
(ex) =>
ex.askemClass === XDDExtractionType.Doc &&
ex.properties.documentBibjson?.knownEntities &&
Expand All @@ -162,9 +169,9 @@ const urlExtractions = computed(() => {
});
const extractions: ComputedRef<UrlExtraction[] & Extraction[]> = computed(() => {
if (props.asset.knownEntities.askemObjects) {
if ((props.asset as Document).knownEntities.askemObjects) {
const allExtractions = [
...(props.asset.knownEntities.askemObjects as UrlExtraction[] & Extraction[]),
...((props.asset as Document).knownEntities.askemObjects as UrlExtraction[] & Extraction[]),
...(urlExtractions.value as UrlExtraction[] & Extraction[])
];
Expand All @@ -177,10 +184,15 @@ const extractions: ComputedRef<UrlExtraction[] & Extraction[]> = computed(() =>
const relatedAsset = computed(() => extractions.value[relatedAssetPage.value]);
const snippets = computed(() =>
props.asset.highlight ? Array.from(props.asset.highlight).splice(0, 3) : null
(props.asset as Document).highlight
? Array.from((props.asset as Document).highlight).splice(0, 3)
: null
);
const title = computed(() => {
const value = props.resourceType === ResourceType.XDD ? props.asset.title : props.asset.name;
const value =
props.resourceType === ResourceType.XDD
? (props.asset as Document).title
: (props.asset as Model | Dataset).name;
return highlightSearchTerms(value);
});
Expand Down Expand Up @@ -224,14 +236,14 @@ function updateExtractionFilter(extractionType: XDDExtractionType) {
// Return formatted author, year, journal
const formatDetails = computed(() => {
if (props.resourceType === ResourceType.XDD) {
const details = `${props.asset.author.map((a) => a.name).join(', ')} (${props.asset.year}) ${
props.asset.journal
}`;
const details = `${(props.asset as Document).author.map((a) => a.name).join(', ')} (${
(props.asset as Document).year
}) ${(props.asset as Document).journal}`;
return highlightSearchTerms(details);
}
if (props.resourceType === ResourceType.DATASET) {
return props.asset?.url;
return (props.asset as Dataset).url;
}
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { ResultType, ResourceType } from '@/types/common';
import TeraAssetCard from '@/page/data-explorer/components/tera-asset-card.vue';
const props = defineProps<{
asset: Document & Model & Dataset;
asset: ResultType;
isPreviewed: boolean;
resourceType: ResourceType;
selectedSearchItems: ResultType[];
Expand All @@ -36,15 +36,15 @@ const isSelected = () =>
props.selectedSearchItems.find((item) => {
if (isDocument(item)) {
const itemAsDocument = item as Document;
return itemAsDocument.title === props.asset.title;
return itemAsDocument.title === (props.asset as Document).title;
}
if (isDataset(item)) {
const itemAsDataset = item as Dataset;
return itemAsDataset.id === props.asset.id;
return itemAsDataset.id === (props.asset as Dataset).id;
}
if (isModel(item)) {
const itemAsModel = item as Model;
return itemAsModel.id === props.asset.id;
return itemAsModel.id === (props.asset as Model).id;
}
return false;
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
<div class="result-details">
<span class="result-count">
<template v-if="isLoading">Loading...</template>
<template v-else-if="props.searchTerm">
<template v-else-if="props.searchTerm || searchByExampleOptionsStr">
{{ resultsText }}
<span v-if="searchByExampleOptionsStr.length === 0"> "{{ props.searchTerm }}" </span>
<div v-else-if="searchByExampleOptionsStr.length > 0" class="search-by-example-card">
<tera-asset-card
:asset="searchByExampleAssetCardProp"
:asset="searchByExampleItem!"
:resource-type="(resultType as ResourceType)"
/>
</div>
Expand Down Expand Up @@ -53,7 +53,7 @@
</template>

<script setup lang="ts">
import { ref, computed, PropType, onUnmounted } from 'vue';
import { ref, computed, PropType } from 'vue';
import { Document, XDDFacetsItemResponse, Dataset, Model } from '@/types/Types';
import useQueryStore from '@/stores/query';
import { SearchResults, ResourceType, ResultType } from '@/types/common';
Expand All @@ -66,7 +66,7 @@ import {
} from '@/page/data-explorer/search-by-example';
import TeraSearchItem from './tera-search-item.vue';
const { searchByExampleAssetCardProp } = useSearchByExampleOptions();
const { searchByExampleItem } = useSearchByExampleOptions();
const props = defineProps({
dataItems: {
Expand Down Expand Up @@ -182,10 +182,6 @@ const itemsText = computed(() => {
const s = resultsCount.value === 1 ? '' : 's';
return `Showing ${resultsCount.value} ${truncated}item${s}.`;
});
onUnmounted(() => {
searchByExampleAssetCardProp.value = null;
});
</script>

<style scoped>
Expand Down
Loading

0 comments on commit 4f91b67

Please sign in to comment.