Skip to content

Commit

Permalink
add owners count and prepare for disabling
Browse files Browse the repository at this point in the history
  • Loading branch information
bklimov-web committed Dec 5, 2024
1 parent 7f3a073 commit 7876bf5
Show file tree
Hide file tree
Showing 9 changed files with 102 additions and 53 deletions.
9 changes: 8 additions & 1 deletion portals-ui/packages/core/src/model/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ export type Configuration = {
entries: Record<string, any>[];
};

type ProjectData = {
type?: string;
value: string;
};

type ProjectTags = Record<string, ProjectData>;

export type Project = AclEntry<AclClass.folder> & {
id: number;
name: string;
Expand All @@ -47,6 +54,6 @@ export type Project = AclEntry<AclClass.folder> & {
hasMetadata: boolean;
}>;
metadata?: Record<string, any>;
data?: Record<string, any>;
data?: ProjectTags;
storages?: Record<string, any>[];
};
7 changes: 3 additions & 4 deletions portals-ui/packages/core/src/model/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ export type User = AclEntry<AclClass.user> & {
roles: Role[];
};

export type UserInfo = AclEntry<AclClass.user> &
Omit<User, 'userName' | 'admin' | 'blocked'> & {
name: string;
};
export type UserInfo = Omit<User, 'userName' | 'admin' | 'blocked'> & {
name: string;
};
Original file line number Diff line number Diff line change
@@ -1,35 +1,34 @@
import type { Project } from '@cloud-pipeline/core';
import { SelectFilter } from './select-filter';
import { ProjectFilter, projectTagsToDisplay } from '../constants';
import { useOwnersFilter, useProjectTags } from '../hooks';

type Tags = {
[key: string]: string[];
};
import { useOwnersFilter } from '../hooks';
import type { Tag, TagFilters } from '../types';

type Props = {
projects: Project[];
filteredProjects: Project[];
onFilterValueChange: (tagName: string, selectedTags?: string[]) => void;
tagsToFilter: Tags;
tagsToFilter: TagFilters;
projectTags: Record<string, Tag[]>;
};

export const ProjectFilters = ({
projects,
filteredProjects,
tagsToFilter,
onFilterValueChange,
projectTags,
}: Props) => {
const projectTags = useProjectTags(projects);
const { handleFocus, users = [] } = useOwnersFilter();
const { handleFocus, users = [] } = useOwnersFilter(filteredProjects);

return (
<div className="flex flex-wrap gap-2">
{projectTagsToDisplay.map(({ id, label }) => (
<div>
<SelectFilter
key={id}
options={projectTags[id]?.map((type) => ({
id: type,
name: type,
options={projectTags[id]?.map((tag) => ({
id: tag.id,
name: tag.count ? `${tag.id} (${tag.count})` : tag.id,
disabled: false,
}))}
selectedValues={tagsToFilter[id] ?? []}
onChange={(selectedItems) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { memo, useCallback } from 'react';
type Option = {
id: string;
name: string;
disabled?: boolean;
};

type Props = {
Expand Down Expand Up @@ -36,17 +37,27 @@ export const SelectFilter = memo(
);

return (
<PickerInput
dataSource={dataSource}
value={selectedValues}
onValueChange={handleValueChange}
selectionMode="multi"
placeholder={label}
valueType="id"
maxItems={1}
onFocus={onFocus}
isSingleLine
/>
<div className="flex items-center space-x-1">
<p>{label}:</p>
<PickerInput
dataSource={dataSource}
value={selectedValues}
onValueChange={handleValueChange}
selectionMode="multi"
getRowOptions={(item) => ({
isDisabled: item?.disabled,
checkbox: {
isDisabled: item?.disabled,
isVisible: true,
},
})}
placeholder={`Select ${label}`}
valueType="id"
maxItems={1}
onFocus={onFocus}
isSingleLine
/>
</div>
);
},
);
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type { Project } from '@cloud-pipeline/core';
import { noop } from '@cloud-pipeline/core';
import { useCallback, useMemo } from 'react';
import { useUsersInfoState } from '../../../state/users-info/hooks';
import { loadUsersInfo } from '../../../state/users-info/load-users-info';

export const useOwnersFilter = () => {
export const useOwnersFilter = (filteredProjects: Project[]) => {
const { usersInfo, pending, loaded } = useUsersInfoState();

const handleFocus = useCallback(() => {
Expand All @@ -12,15 +13,25 @@ export const useOwnersFilter = () => {
}
}, [loaded, pending, usersInfo]);

const usersWithStringId = useMemo(() => {
return usersInfo?.map((user) => ({ ...user, id: user.name }));
}, [usersInfo]);
const preparedUsers = useMemo(() => {
return usersInfo?.map((user) => {
const projectsCount = filteredProjects.filter(
(project) => project.owner === user.name,
).length;

return {
name: `${user.name} (${projectsCount})`,
id: user.name,
count: projectsCount,
};
});
}, [filteredProjects, usersInfo]);

return useMemo(
() => ({
handleFocus,
users: usersWithStringId,
users: preparedUsers,
}),
[handleFocus, usersWithStringId],
[handleFocus, preparedUsers],
);
};
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { useCallback, useMemo, useState } from 'react';
import { ProjectFilter } from '../constants';
import type { Project } from '@cloud-pipeline/core';
import type { TagFilters } from '../types';

export const useProjectFilters = () => {
const [tagsToFilter, setTagsToFilter] = useState<Record<string, string[]>>(
{},
);
const [tagsToFilter, setTagsToFilter] = useState<TagFilters>({});

const doesProjectMatchFilters = useCallback(
(project: Project) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,43 @@
import type { Project } from '@cloud-pipeline/core';
import { useMemo } from 'react';
import type { Tag } from '../types';

export const useProjectTags = (projects: Project[]) => {
export const useProjectTags = (projects?: Project[]) => {
return useMemo(() => {
if (!projects) {
if (!projects?.length) {
return {};
}

const tags: Record<string, Set<string>> = {};
// Map for faster lookup
const tagsMap: Record<string, Map<string, Tag>> = {};

for (const project of projects) {
if (project.data) {
for (const [key, { value }] of Object.entries(project.data)) {
if (!tags[key]) {
tags[key] = new Set();
}
for (const { data } of projects) {
if (!data) {
continue;
}

for (const [key, { value }] of Object.entries(data)) {
if (!tagsMap[key]) {
tagsMap[key] = new Map();
}

tags[key].add(value);
const currentTagMap = tagsMap[key];
const tag = currentTagMap.get(value);

if (tag) {
tag.count++;
} else {
currentTagMap.set(value, { id: value, count: 1 });
}
}
}

return Object.fromEntries(
Object.entries(tags).map(([key, values]) => [key, Array.from(values)]),
);
// Convert maps to arrays
const tags: Record<string, Tag[]> = {};
for (const [key, tagMap] of Object.entries(tagsMap)) {
tags[key] = Array.from(tagMap.values());
}

return tags;
}, [projects]);
};
6 changes: 4 additions & 2 deletions portals-ui/sites/ngs-portal/src/pages/projects/projects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { List, ListHeader } from '@cloud-pipeline/components';
import { useSearch } from '../../shared/hooks/use-search.ts';
import HighlightedText from '../../shared/highlight-text';
import { ProjectFilters } from './components/project-filters.tsx';
import { useProjectFilters } from './hooks';
import { useProjectFilters, useProjectTags } from './hooks';

export function ProjectsPage() {
useEffect(() => {
Expand All @@ -23,6 +23,7 @@ export function ProjectsPage() {
items: projects ?? [],
matchesFilter: doesProjectMatchFilters,
});
const projectTags = useProjectTags(projects);

if (error) {
return <div>{error}</div>;
Expand All @@ -39,7 +40,8 @@ export function ProjectsPage() {
return (
<div className="flex flex-col overflow-auto">
<ProjectFilters
projects={projects}
filteredProjects={filtered}
projectTags={projectTags}
onFilterValueChange={handleFilterValueChange}
tagsToFilter={tagsToFilter}
/>
Expand Down
6 changes: 6 additions & 0 deletions portals-ui/sites/ngs-portal/src/pages/projects/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export type Tag = {
id: string;
count: number;
};

export type TagFilters = Record<string, string[]>;

0 comments on commit 7876bf5

Please sign in to comment.