Skip to content

Commit

Permalink
Surface template and collection in search results and on asset page a…
Browse files Browse the repository at this point in the history
…ccording to settings (#273)
  • Loading branch information
jxjj authored Jun 17, 2024
1 parent bb36f08 commit 49c988e
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 8 deletions.
55 changes: 52 additions & 3 deletions src/components/AssetDetailsPanel/AssetDetailsPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,43 @@
'text-2xl': isOpen,
}" />
</template>
<WidgetList v-if="assetId" :assetId="assetId" class="py-4 md:py-0" />
<MoreLikeThis v-if="assetId" :items="moreLikeThisItems" />
<template v-if="assetId && asset && template">
<CollectionTuple
v-if="showCollectionTop"
:collectionId="asset.collectionId"
label="Collection" />

<Tuple v-if="showTemplateTop" label="Template">
{{ template.templateName }}
</Tuple>
<WidgetList :assetId="assetId" class="py-4 md:py-0" />
<CollectionTuple
v-if="showCollectionBottom"
:collectionId="asset.collectionId"
label="Collection" />

<Tuple v-if="showTemplateBottom" label="Template">
{{ template.templateName }}
</Tuple>

<MoreLikeThis :items="moreLikeThisItems" />
</template>
</Panel>
</div>
</template>
<script setup lang="ts">
import { computed, ref, watch } from "vue";
import Panel from "@/components/Panel/Panel.vue";
import WidgetList from "@/components/WidgetList/WidgetList.vue";
import Tuple from "@/components/Tuple/Tuple.vue";
import CollectionTuple from "./CollectionTuple.vue";
import { getAssetTitle } from "@/helpers/displayUtils";
import { useAsset } from "@/helpers/useAsset";
import MoreLikeThis from "../MoreLikeThis/MoreLikeThis.vue";
import PanelLabel from "../Panel/PanelLabel.vue";
import api from "@/api";
import { SearchResultMatch } from "@/types";
import { TEMPLATE_SHOW_PROPERTY_POSITIONS } from "@/constants/constants";
const props = withDefaults(
defineProps<{
Expand All @@ -46,8 +68,35 @@ defineEmits<{
}>();
const assetIdRef = computed(() => props.assetId);
const { asset } = useAsset(assetIdRef);
const { asset, template } = useAsset(assetIdRef);
const moreLikeThisItems = ref<SearchResultMatch[]>([]);
const showCollectionBottom = computed(
() =>
template.value?.showCollection &&
template.value?.showCollectionPosition ===
TEMPLATE_SHOW_PROPERTY_POSITIONS.BOTTOM
);
const showCollectionTop = computed(
() =>
template.value?.showCollection &&
template.value?.showCollectionPosition ===
TEMPLATE_SHOW_PROPERTY_POSITIONS.TOP
);
const showTemplateBottom = computed(
() =>
template.value?.showTemplate &&
template.value?.showTemplatePosition ===
TEMPLATE_SHOW_PROPERTY_POSITIONS.BOTTOM
);
const showTemplateTop = computed(
() =>
template.value?.showTemplate &&
template.value?.showTemplatePosition ===
TEMPLATE_SHOW_PROPERTY_POSITIONS.TOP
);
watch(
assetIdRef,
Expand Down
53 changes: 53 additions & 0 deletions src/components/AssetDetailsPanel/CollectionTuple.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<template>
<Tuple v-if="collectionPath?.length" label="Collection">
<template
v-for="(collection, index) in collectionPath"
:key="collection.id">
<Link
:to="`/collections/${collection.id}`"
:class="{ 'mr-1': index < collectionPath.length - 1 }">
{{ collection.title }}
</Link>
<span v-if="index < collectionPath.length - 1" class="mr-1">/</span>
</template>
</Tuple>
</template>
<script setup lang="ts">
import Tuple from "@/components/Tuple/Tuple.vue";
import Link from "@/components/Link/Link.vue";
import { computed } from "vue";
import { useInstanceStore } from "@/stores/instanceStore";
import { AssetCollection } from "@/types";
const props = defineProps<{
collectionId: AssetCollection["id"];
}>();
const instanceStore = useInstanceStore();
// create a path to the collection
// so we can display it as a breadcrumb
// like "Collection A / Collection B / Collection C"
const collectionPath = computed(() => {
if (!props.collectionId) return null;
const collection = instanceStore.collectionIndex[props.collectionId];
if (!collection) {
throw new Error(
`Collection ${props.collectionId} not found in instanceStore`
);
}
// construct a path to this collection
const path = [collection];
let child = collection;
while (child.parentId) {
child = instanceStore.collectionIndex[child.parentId];
path.unshift(child);
}
return path;
});
</script>
<style scoped></style>
21 changes: 21 additions & 0 deletions src/components/SearchResultCard/CollectionHeirarchy.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<template>
<div v-if="collectionHierarchy?.length">
<dt class="font-bold text-xs uppercase">Collection</dt>
<dd>
<span
v-for="collection in collectionHierarchy"
:key="collection.id"
class="after:content-['/'] after:mr-1 after:ml-1 after:text-neutral-400 after:last:content-none">
{{ collection.title }}
</span>
</dd>
</div>
</template>
<script setup lang="ts">
import * as T from "@/types";
defineProps<{
collectionHierarchy: T.SearchResultMatch["collectionHierarchy"];
}>();
</script>
<style scoped></style>
14 changes: 10 additions & 4 deletions src/components/SearchResultCard/SearchResultCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,23 @@
{{ excerptLabel ?? title }}
</h1>
<div
v-if="props.searchMatch?.entries"
class="search-result-card__contents max-h-[15rem] overflow-y-auto overflow-x-hidden">
<dl class="text-sm">
<dl class="text-sm flex flex-col gap-2">
<div
v-for="(entry, index) in props.searchMatch.entries"
:key="index"
class="mb-2">
:key="index">
<dt class="font-bold text-xs uppercase">
{{ entry?.label ?? "Item" }}
</dt>
<dd>{{ entry.entries?.join(", ") }}</dd>
</div>
<CollectionHeirarchy
v-if="instanceStore.instance.showCollectionInSearchResults"
:collectionHierarchy="props.searchMatch.collectionHierarchy" />
<div v-if="instanceStore.instance.showTemplateInSearchResults">
<dt class="font-bold text-xs uppercase">Template</dt>
<dd>{{ searchMatch.template.name }}</dd>
</div>
</dl>
</div>
</MediaCard>
Expand All @@ -65,6 +70,7 @@ import Link from "@/components/Link/Link.vue";
import Chip from "@/components/Chip/Chip.vue";
import { useInstanceStore } from "@/stores/instanceStore";
import RemoveFromDrawerButton from "@/components/RemoveFromDrawerButton/RemoveFromDrawerButton.vue";
import CollectionHeirarchy from "./CollectionHeirarchy.vue";
const props = defineProps<{
searchMatch: SearchResultMatch;
Expand Down
5 changes: 5 additions & 0 deletions src/constants/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,8 @@ export const GLOBAL_FIELD_IDS = {
LOCATION: "GLOBAL_LOCATION",
FILE_TYPE: "GLOBAL_FILE_TYPE",
} as const;

export const TEMPLATE_SHOW_PROPERTY_POSITIONS = {
BOTTOM: 0,
TOP: 1,
} as const;
4 changes: 4 additions & 0 deletions src/helpers/selectInstanceFromResponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export function selectInstanceFromResponse(
instanceName,
instanceId,
instanceHasLogo,
instanceShowCollectionInSearchResults,
instanceShowTemplateInSearchResults,
contact,
useCentralAuth,
centralAuthLabel,
Expand Down Expand Up @@ -48,5 +50,7 @@ export function selectInstanceFromResponse(
featuredAssetText,
userCanSearchAndBrowse,
templates: templatesArray,
showCollectionInSearchResults: instanceShowCollectionInSearchResults,
showTemplateInSearchResults: instanceShowTemplateInSearchResults,
};
}
2 changes: 2 additions & 0 deletions src/stores/instanceStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ const createState = () => ({
featuredAssetText: null,
userCanSearchAndBrowse: false,
templates: [],
showCollectionInSearchResults: true,
showTemplateInSearchResults: true,
}),
customHeaderMode: ref<number>(0),
customHeader: ref<string | null>(null),
Expand Down
18 changes: 17 additions & 1 deletion src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import type { Ref } from "vue";
import { SEARCH_RESULTS_VIEWS, SORT_KEYS } from "@/constants/constants";
import {
SEARCH_RESULTS_VIEWS,
SORT_KEYS,
TEMPLATE_SHOW_PROPERTY_POSITIONS,
} from "@/constants/constants";
import { AxiosRequestConfig } from "axios";

export * from "./TimelineJSTypes";
Expand Down Expand Up @@ -464,9 +468,17 @@ export interface Asset {
title?: string[];
[key: string]: unknown;
}

type TemplateShowPropertyPosition =
(typeof TEMPLATE_SHOW_PROPERTY_POSITIONS)[keyof typeof TEMPLATE_SHOW_PROPERTY_POSITIONS];

export interface Template {
templateId: string;
templateName: string;
showCollection: boolean;
showCollectionPosition: TemplateShowPropertyPosition;
showTemplate: boolean;
showTemplatePosition: TemplateShowPropertyPosition;
widgetArray: WidgetProps[];
collections?: Record<string | number, string | undefined | unknown>;
allowedCollections?:
Expand Down Expand Up @@ -517,6 +529,8 @@ export interface ApiInstanceNavResponse {
instanceId: number;
instanceHasLogo: boolean;
instanceLogo: number;
instanceShowCollectionInSearchResults: true;
instanceShowTemplateInSearchResults: true;
contact: string;
useCentralAuth: boolean;
centralAuthLabel: string;
Expand Down Expand Up @@ -559,6 +573,8 @@ export interface ElevatorInstance {
// may be true even if user is not logged in
userCanSearchAndBrowse: boolean;
templates: { id: number; name: string }[];
showCollectionInSearchResults;
showTemplateInSearchResults;
}

export interface RawAssetCollection {
Expand Down

0 comments on commit 49c988e

Please sign in to comment.