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

feat/discover-checkbox-latest-only #1102

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
5 changes: 5 additions & 0 deletions .changeset/lovely-bags-exercise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@eventcatalog/core": patch
---

feat(core): users can now filter by latest version of resources on the discover page
38 changes: 38 additions & 0 deletions eventcatalog/src/components/Checkbox.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
import type { HTMLAttributes } from 'astro/types';

export type Props = HTMLAttributes<'input'> & {
id: string;
name: string;
label: string;
};

const { id, name, label, class: className, ...attrs } = Astro.props;
---

<label for={id} class="relative block cursor-pointer select-none pl-5">
<input id={id} name={name} type="checkbox" class="h-0 w-0 cursor-pointer appearance-none group" {...attrs} />
<span class="text-md text-gray-700">{label}</span>
</label>

<style>
input::before {
@apply absolute left-0 top-1/2 block h-4 w-4 -translate-y-1/2 rounded-[4px] border border-gray-300;
content: '';
}

input:checked::before {
@apply bg-purple-600;
}

input:focus::before {
@apply outline outline-purple-300;
}

input:checked::after {
@apply absolute left-0 top-1/2 block h-4 w-4 -translate-y-1/2 bg-center bg-no-repeat;
content: '';
/** inline unicons checkmark SVG */
background-image: url("data:image/svg+xml;utf-8,<svg width='10' height='8' viewBox='0 0 10 8' fill='none' xmlns='http://www.w3.org/2000/svg'><path fill-rule='evenodd' clip-rule='evenodd' d='M9.04731 1.01279C9.34958 1.296 9.36503 1.77062 9.08182 2.07289L4.19342 7.29032C3.77774 7.73398 3.07363 7.73398 2.65795 7.29032L1.01279 5.53443C0.729585 5.23216 0.745038 4.75754 1.04731 4.47433C1.34958 4.19112 1.8242 4.20658 2.1074 4.50884L3.42568 5.91586L7.98721 1.04731C8.27042 0.745037 8.74504 0.729585 9.04731 1.01279Z' fill='white'/></svg>");
}
</style>
30 changes: 28 additions & 2 deletions eventcatalog/src/components/Tables/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ import type { CollectionEntry } from 'astro:content';
import DebouncedInput from './DebouncedInput';

import { getColumnsByCollection } from './columns';
import { useEffect, useMemo, useState } from 'react';
import { useEffect, useMemo, useState, type EventHandler } from 'react';
import type { CollectionTypes } from '@types';
import { isSameVersion } from '@utils/collections/util';

declare module '@tanstack/react-table' {
// @ts-ignore
Expand All @@ -32,10 +33,12 @@ export const Table = ({
data: initialData,
collection,
mode = 'simple',
checkboxLatestId,
}: {
data: CollectionEntry<'events'>[];
collection: string;
mode: 'simple' | 'full';
checkboxLatestId: string;
mode?: 'simple' | 'full';
}) => {
const [data, _setData] = useState(initialData);
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
Expand All @@ -48,6 +51,20 @@ export const Table = ({
}
}, []);

const [showOnlyLatest, setShowOnlyLatest] = useState(true);

useEffect(() => {
const checkbox = document.getElementById(checkboxLatestId);

function handleChange(evt: Event) {
setShowOnlyLatest((evt.target as HTMLInputElement).checked);
}

checkbox?.addEventListener('change', handleChange);

return () => checkbox?.removeEventListener('change', handleChange);
}, [checkboxLatestId]);

const columns = useMemo(() => getColumnsByCollection(collection), [collection]);

const table = useReactTable({
Expand All @@ -63,6 +80,15 @@ export const Table = ({
getPaginationRowModel: getPaginationRowModel(),
state: {
columnFilters,
globalFilter: showOnlyLatest,
},
onGlobalFilterChange: setShowOnlyLatest,
globalFilterFn: (row, _columnId, showOnlyLatest: boolean) => {
if (showOnlyLatest) {
return isSameVersion(row.original.data.version, row.original.data.latestVersion);
}

return true;
},
});

Expand Down
11 changes: 8 additions & 3 deletions eventcatalog/src/layouts/DiscoverLayout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { buildUrl } from '@utils/url-builder';
import { getQueries } from '@utils/queries';
import { MagnifyingGlassIcon } from '@heroicons/react/20/solid';
import VerticalSideBarLayout from './VerticalSideBarLayout.astro';
import Checkbox from '@components/Checkbox.astro';

const events = await getEvents();
const queries = await getQueries();
Expand All @@ -22,6 +23,8 @@ const flows = await getFlows();
const { title, subtitle, data, type } = Astro.props;
const currentPath = Astro.url.pathname;

const checkboxLatestId = 'latest-only';

const tabs = [
{
label: `Events (${events.length})`,
Expand Down Expand Up @@ -102,17 +105,19 @@ const tabs = [
<!-- Table -->
<div class="pb-20 ml-6 md:pr-10">
<div>
<div class="sm:flex sm:items-center py-4 pb-4" id="discover-title">
<div class="sm:flex sm:items-end py-4 pb-4" id="discover-title">
<div class="sm:flex-auto space-y-2">
<h1 class="text-4xl font-semibold text-gray-900 capitalize">{title}</h1>
<p class="text-md text-gray-700">{subtitle}</p>
</div>
<div class="p-4 border border-gray-200 rounded-md">
<Checkbox id={checkboxLatestId} name={checkboxLatestId} label="Show latest version only" checked />
</div>
</div>
<div class="mt-4 flow-root">
<div class="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
<div class="inline-block min-w-full align-middle sm:px-6 lg:px-8">
<!-- @ts-ignore -->
<Table data={data} collection={type} client:load />
<Table checkboxLatestId={checkboxLatestId} data={data} collection={type} client:load />
</div>
</div>
</div>
Expand Down
16 changes: 15 additions & 1 deletion eventcatalog/src/utils/__tests__/collections/util.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { satisfies, sortStringVersions } from '@utils/collections/util';
import { isSameVersion, satisfies, sortStringVersions } from '@utils/collections/util';
import { describe, it, expect } from 'vitest';

describe('Collections - utils', () => {
Expand Down Expand Up @@ -37,4 +37,18 @@ describe('Collections - utils', () => {
expect(sortStringVersions(versions)).toEqual({ versions: result, latestVersion: latest });
});
});

describe('isSameVersion', () => {
it.each([
[{ versions: ['1', '2'], result: false }],
[{ versions: ['1', '1'], result: true }],
[{ versions: ['2.0.0', '1.1.0'], result: false }],
[{ versions: ['2.0.0', '2.0.0'], result: true }],
[{ versions: ['a', 'b'], result: false }],
[{ versions: ['a', 'a'], result: true }],
[{ versions: ['1.0.0', undefined], result: false }],
])('should returns $result when versions is $versions', ({ versions, result }) => {
expect(isSameVersion(versions[0], versions[1])).toBe(result);
});
});
});
13 changes: 12 additions & 1 deletion eventcatalog/src/utils/collections/util.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { CollectionTypes } from '@types';
import type { CollectionEntry } from 'astro:content';
import { coerce, compare, satisfies as satisfiesRange } from 'semver';
import { coerce, compare, eq, satisfies as satisfiesRange } from 'semver';

export const getPreviousVersion = (version: string, versions: string[]) => {
const index = versions.indexOf(version);
Expand All @@ -13,6 +13,17 @@ export const getVersions = (data: CollectionEntry<CollectionTypes>[]) => {
return sortStringVersions(versions);
};

export function isSameVersion(v1: string | undefined, v2: string | undefined) {
const semverV1 = coerce(v1);
const semverV2 = coerce(v2);

if (semverV1 != null && semverV2 != null) {
return eq(semverV1, semverV2);
}

return v1 === v2;
}

/**
* Sorts versioned items. Latest version first.
*/
Expand Down
Loading