diff --git a/frontend/src/components/VMediaInfo/VMediaTags.vue b/frontend/src/components/VMediaInfo/VMediaTags.vue
index 8218862bebf..30e8b41c7b3 100644
--- a/frontend/src/components/VMediaInfo/VMediaTags.vue
+++ b/frontend/src/components/VMediaInfo/VMediaTags.vue
@@ -1,32 +1,77 @@
-
-
- {{
- tag.name
+
+
+
{{
+ $t(
+ buttonStatus === "show"
+ ? "mediaDetails.tags.showMore"
+ : "mediaDetails.tags.showLess"
+ )
+ }}
+
+
+
diff --git a/frontend/src/locales/scripts/en.json5 b/frontend/src/locales/scripts/en.json5
index bd548d490a1..dd674ad2028 100644
--- a/frontend/src/locales/scripts/en.json5
+++ b/frontend/src/locales/scripts/en.json5
@@ -498,6 +498,11 @@
},
imageInfo: "Image information",
audioInfo: "Audio information",
+ tags: {
+ title: "Tags",
+ showMore: "Show more",
+ showLess: "Show less",
+ },
contentReport: {
short: "Report",
long: "Report this content",
diff --git a/frontend/src/types/analytics.ts b/frontend/src/types/analytics.ts
index f37f81c7026..eb2ba2f3db2 100644
--- a/frontend/src/types/analytics.ts
+++ b/frontend/src/types/analytics.ts
@@ -283,7 +283,7 @@ export type Events = {
/** Pagination depth */
resultPage: number
}
- /*
+ /**
* Description: Whenever the user clicks the load more button
* Questions:
* - On what page do users typically find a result?
@@ -301,7 +301,7 @@ export type Events = {
* *before* loading more results.. */
resultPage: number
}
- /*
+ /**
* Description: Whenever the user sets a filter. Filter category and key are the values used in code, not the user-facing filter labels.
* Questions:
* - Do most users filter their searches?
@@ -412,6 +412,17 @@ export type Events = {
/** the reasons for why this result is considered sensitive */
sensitivities: string
}
+ /**
+ * Description: The user expands collapsed tags or collapses the expanded ones.
+ *
+ * Questions:
+ * - Are the extra tags useful to users?
+ * - Do users ever collapse expanded tags?
+ */
+ TOGGLE_TAG_EXPANSION: {
+ /** The state of the tags after the user interaction. */
+ toState: "expanded" | "collapsed"
+ }
}
/**
diff --git a/frontend/src/utils/focus-management.ts b/frontend/src/utils/focus-management.ts
index b9db344ea18..89c9431baf1 100644
--- a/frontend/src/utils/focus-management.ts
+++ b/frontend/src/utils/focus-management.ts
@@ -88,8 +88,10 @@ export function isFocusableElement(element: HTMLElement) {
return element.matches(focusableSelector)
}
-export function focusElement(element: HTMLElement | null) {
- element?.focus()
+export function focusElement(element: HTMLElement | Element | null) {
+ if (element instanceof HTMLElement) {
+ element.focus()
+ }
}
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/select
diff --git a/frontend/test/locales/ar.json b/frontend/test/locales/ar.json
index 0f7677be5c4..6c616d9d410 100644
--- a/frontend/test/locales/ar.json
+++ b/frontend/test/locales/ar.json
@@ -191,6 +191,11 @@
"relatedError": "خطأ في جلب الوسائط ذات الصلة",
"imageInfo": "معلومات الصورة",
"audioInfo": "معلومات صوتية",
+ "tags": {
+ "title": "العلامات",
+ "showMore": "أظهر المزيد",
+ "showLess": "تظهر أقل"
+ },
"contentReport": {
"short": "تقرير",
"long": "الإبلاغ عن هذا المحتوى",
diff --git a/frontend/test/playwright/e2e/collections.spec.ts b/frontend/test/playwright/e2e/collections.spec.ts
index 6e97c8ce3b5..65d61544abd 100644
--- a/frontend/test/playwright/e2e/collections.spec.ts
+++ b/frontend/test/playwright/e2e/collections.spec.ts
@@ -4,7 +4,7 @@
* introduced in https://github.com/WordPress/openverse/pull/3831
*/
-import { test, expect } from "@playwright/test"
+import { test, expect, Page } from "@playwright/test"
import { preparePageForTests } from "~~/test/playwright/utils/navigation"
import {
@@ -12,6 +12,11 @@ import {
getH1,
// getLoadMoreButton,
} from "~~/test/playwright/utils/components"
+import { t } from "~~/test/playwright/utils/i18n"
+import {
+ collectAnalyticsEvents,
+ expectEventPayloadToMatch,
+} from "~~/test/playwright/utils/analytics"
test.describe.configure({ mode: "parallel" })
@@ -61,3 +66,43 @@ test.describe("collections", () => {
// expect(await page.locator("figure").count()).toEqual(20)
})
})
+
+const COLLAPSE_BUTTON = (page: Page) =>
+ page.getByRole("button", { name: t("mediaDetails.tags.showLess") })
+const EXPAND_BUTTON = (page: Page) =>
+ page.getByRole("button", { name: t("mediaDetails.tags.showMore") })
+
+test("some tags are hidden if there are more than 3 rows", async ({ page }) => {
+ await preparePageForTests(page, "xl", {
+ features: { additional_search_views: "on" },
+ })
+ await page.goto("/image/2bc7dde0-5aad-4cf7-b91d-7f0e3bd06750")
+
+ const tags = page.getByRole("list", { name: t("mediaDetails.tags.title") })
+ await expect(tags).toBeVisible()
+ const tagsCount = await tags.locator("li").count()
+
+ await EXPAND_BUTTON(page).click()
+ expect(await tags.locator("li").count()).toBeGreaterThan(tagsCount)
+})
+
+test("sends analytics events when tags are toggled", async ({
+ context,
+ page,
+}) => {
+ await preparePageForTests(page, "xl", {
+ features: { additional_search_views: "on" },
+ })
+ const analyticsEvents = collectAnalyticsEvents(context)
+ await page.goto("/image/2bc7dde0-5aad-4cf7-b91d-7f0e3bd06750")
+
+ await EXPAND_BUTTON(page).click()
+ await COLLAPSE_BUTTON(page).click()
+
+ const toggleEvents = analyticsEvents.filter(
+ (event) => event.n === "TOGGLE_TAG_EXPANSION"
+ )
+ expect(toggleEvents).toHaveLength(2)
+ expectEventPayloadToMatch(toggleEvents[0], { toState: "expanded" })
+ expectEventPayloadToMatch(toggleEvents[1], { toState: "collapsed" })
+})
diff --git a/frontend/test/tapes/detail/images/2bc7dde0-5aad-4cf7-b91d-7f0e3bd06750_keep-alive.json5 b/frontend/test/tapes/detail/images/2bc7dde0-5aad-4cf7-b91d-7f0e3bd06750_keep-alive.json5
new file mode 100644
index 00000000000..bcaf7538e20
--- /dev/null
+++ b/frontend/test/tapes/detail/images/2bc7dde0-5aad-4cf7-b91d-7f0e3bd06750_keep-alive.json5
@@ -0,0 +1,257 @@
+{
+ meta: {
+ createdAt: '2024-02-19T17:03:23.360Z',
+ host: 'https://api.openverse.engineering',
+ resHumanReadable: true,
+ resUncompressed: true,
+ },
+ req: {
+ headers: {
+ connection: 'keep-alive',
+ },
+ url: '/v1/images/2bc7dde0-5aad-4cf7-b91d-7f0e3bd06750/',
+ method: 'GET',
+ body: '',
+ },
+ res: {
+ status: 200,
+ headers: {
+ date: [
+ 'Mon, 19 Feb 2024 17:03:23 GMT',
+ ],
+ 'content-type': [
+ 'application/json',
+ ],
+ 'transfer-encoding': [
+ 'chunked',
+ ],
+ connection: [
+ 'keep-alive',
+ ],
+ vary: [
+ 'Accept-Encoding, Accept, Authorization, origin',
+ ],
+ allow: [
+ 'GET, HEAD, OPTIONS',
+ ],
+ 'x-ratelimit-limit-anon_burst': [
+ '20/min',
+ ],
+ 'x-ratelimit-available-anon_burst': [
+ '19',
+ ],
+ 'x-ratelimit-limit-anon_sustained': [
+ '200/day',
+ ],
+ 'x-ratelimit-available-anon_sustained': [
+ '199',
+ ],
+ 'x-frame-options': [
+ 'DENY',
+ ],
+ 'x-content-type-options': [
+ 'nosniff',
+ ],
+ 'referrer-policy': [
+ 'same-origin',
+ ],
+ 'cross-origin-opener-policy': [
+ 'same-origin',
+ ],
+ 'x-request-id': [
+ 'f3cf70767a3e4dc3bf40b854158123ea',
+ ],
+ 'cache-control': [
+ 'max-age=14400',
+ ],
+ 'cf-cache-status': [
+ 'HIT',
+ ],
+ age: [
+ '27135',
+ ],
+ 'last-modified': [
+ 'Mon, 19 Feb 2024 09:31:08 GMT',
+ ],
+ 'strict-transport-security': [
+ 'max-age=15552000; includeSubDomains; preload',
+ ],
+ server: [
+ 'cloudflare',
+ ],
+ 'cf-ray': [
+ '8580153e2f57692b-FRA',
+ ],
+ 'content-encoding': [
+ 'br',
+ ],
+ 'alt-svc': [
+ 'h3=":443"; ma=86400',
+ ],
+ },
+ body: {
+ id: '2bc7dde0-5aad-4cf7-b91d-7f0e3bd06750',
+ title: 'August Great Horned Owl',
+ indexed_on: '2020-04-25T07:58:25.731612Z',
+ foreign_landing_url: 'https://www.flickr.com/photos/7327719@N06/3823784992',
+ url: 'https://live.staticflickr.com/3486/3823784992_a1dcf4a1d1_b.jpg',
+ creator: "Vicki's Nature",
+ creator_url: 'https://www.flickr.com/photos/7327719@N06',
+ license: 'by-nc-nd',
+ license_version: '2.0',
+ license_url: 'https://creativecommons.org/licenses/by-nc-nd/2.0/',
+ provider: 'flickr',
+ source: 'flickr',
+ category: null,
+ filesize: null,
+ filetype: null,
+ tags: [
+ {
+ name: '100commentgroup',
+ accuracy: null,
+ },
+ {
+ name: 'aas2010',
+ accuracy: null,
+ },
+ {
+ name: 'beautifulworldchallenges',
+ accuracy: null,
+ },
+ {
+ name: 'bird',
+ accuracy: null,
+ },
+ {
+ name: 'bwcgg',
+ accuracy: null,
+ },
+ {
+ name: 'canon',
+ accuracy: null,
+ },
+ {
+ name: 'cnc',
+ accuracy: null,
+ },
+ {
+ name: 'faves3539',
+ accuracy: null,
+ },
+ {
+ name: 'favescontestfavored',
+ accuracy: null,
+ },
+ {
+ name: 'favescontestwinner',
+ accuracy: null,
+ },
+ {
+ name: 'favesfavoredchallenge',
+ accuracy: null,
+ },
+ {
+ name: 'favesfavoredwinner',
+ accuracy: null,
+ },
+ {
+ name: 'favesrunnerupchallenge',
+ accuracy: null,
+ },
+ {
+ name: 'favesrunnerupwinner',
+ accuracy: null,
+ },
+ {
+ name: 'favestopseedchallenge',
+ accuracy: null,
+ },
+ {
+ name: 'favestopseedchallengex2',
+ accuracy: null,
+ },
+ {
+ name: 'faveswinner',
+ accuracy: null,
+ },
+ {
+ name: 'gameshotbefore2013bigbirdportraits',
+ accuracy: null,
+ },
+ {
+ name: 'gamesweep',
+ accuracy: null,
+ },
+ {
+ name: 'gamewinner',
+ accuracy: null,
+ },
+ {
+ name: 'georgia',
+ accuracy: null,
+ },
+ {
+ name: 'goldstaraward',
+ accuracy: null,
+ },
+ {
+ name: 'goldstarawardcontest78',
+ accuracy: null,
+ },
+ {
+ name: 'greathornedowl',
+ accuracy: null,
+ },
+ {
+ name: 'motherbirds',
+ accuracy: null,
+ },
+ {
+ name: 'natureoutpost',
+ accuracy: null,
+ },
+ {
+ name: 'natureselegantshots',
+ accuracy: null,
+ },
+ {
+ name: 'owl',
+ accuracy: null,
+ },
+ {
+ name: 'readygamex2',
+ accuracy: null,
+ },
+ {
+ name: 'return',
+ accuracy: null,
+ },
+ {
+ name: 's5',
+ accuracy: null,
+ },
+ {
+ name: 'specanimal',
+ accuracy: null,
+ },
+ {
+ name: 'sweep',
+ accuracy: null,
+ },
+ {
+ name: 'vickisnature',
+ accuracy: null,
+ },
+ ],
+ attribution: '"August Great Horned Owl" by Vicki\'s Nature is licensed under CC BY-NC-ND 2.0. To view a copy of this license, visit https://creativecommons.org/licenses/by-nc-nd/2.0/.',
+ fields_matched: [],
+ mature: false,
+ height: 1024,
+ width: 1024,
+ thumbnail: 'http://localhost:49153/v1/images/2bc7dde0-5aad-4cf7-b91d-7f0e3bd06750/thumb/',
+ detail_url: 'http://localhost:49153/v1/images/2bc7dde0-5aad-4cf7-b91d-7f0e3bd06750/',
+ related_url: 'http://localhost:49153/v1/images/2bc7dde0-5aad-4cf7-b91d-7f0e3bd06750/related/',
+ unstable__sensitivity: [],
+ },
+ },
+}
\ No newline at end of file