Updated drawer filters
bug fixes pagination constrained to 2000 records
This commit is contained in:
37
package-lock.json
generated
37
package-lock.json
generated
@@ -9,7 +9,7 @@
|
||||
"version": "0.0.21",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@armco/analytics": "^0.2.2",
|
||||
"@armco/analytics": "^0.2.5",
|
||||
"@armco/armory-react-components": "^0.0.20",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@reduxjs/toolkit": "^1.8.1",
|
||||
@@ -17,6 +17,7 @@
|
||||
"bootstrap": "^5.3.0",
|
||||
"classnames": "^2.3.2",
|
||||
"d3": "^7.8.5",
|
||||
"highcharts": "^11.2.0",
|
||||
"highlight.js": "^11.8.0",
|
||||
"js-cookie": "^3.0.5",
|
||||
"moment": "^2.29.4",
|
||||
@@ -101,9 +102,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@armco/analytics": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@armco/analytics/-/analytics-0.2.2.tgz",
|
||||
"integrity": "sha512-dnzL1TQVx35RoCJGf5LKH1Rf/VqGmQTsoZY0niicdzXhPQk/qA2V8X/q0iIJMZgwQ3CO35437zxKx/QWV3xaVQ==",
|
||||
"version": "0.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@armco/analytics/-/analytics-0.2.5.tgz",
|
||||
"integrity": "sha512-esgKYvXGCTM2TWeFd6a9lkQRZur5Y9ATVElxgWKjMRak0DSFbBE1CGJbsKaSf398gv622ZkVmLgIq9DbIbbesw==",
|
||||
"dependencies": {
|
||||
"jet-logger": "^1.3.1",
|
||||
"jquery": "^3.7.0",
|
||||
@@ -15549,6 +15550,11 @@
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/highcharts": {
|
||||
"version": "11.2.0",
|
||||
"resolved": "https://registry.npmjs.org/highcharts/-/highcharts-11.2.0.tgz",
|
||||
"integrity": "sha512-9i650YK7ZBA1Mgtr3avMkLVCAI45RQvYnwi+eHsdFSaBGuQN6BHoa4j4lMkSJLv0V4LISTK1z7J7G82Lzd7zwg=="
|
||||
},
|
||||
"node_modules/highlight.js": {
|
||||
"version": "11.8.0",
|
||||
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.8.0.tgz",
|
||||
@@ -17175,9 +17181,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/jquery": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.0.tgz",
|
||||
"integrity": "sha512-umpJ0/k8X0MvD1ds0P9SfowREz2LenHsQaxSohMZ5OMNEU2r0tf8pdeEFTHMFxWVxKNyU9rTtK3CWzUCTKJUeQ=="
|
||||
"version": "3.7.1",
|
||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
|
||||
"integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg=="
|
||||
},
|
||||
"node_modules/js-cookie": {
|
||||
"version": "3.0.5",
|
||||
@@ -22545,9 +22551,9 @@
|
||||
}
|
||||
},
|
||||
"@armco/analytics": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@armco/analytics/-/analytics-0.2.2.tgz",
|
||||
"integrity": "sha512-dnzL1TQVx35RoCJGf5LKH1Rf/VqGmQTsoZY0niicdzXhPQk/qA2V8X/q0iIJMZgwQ3CO35437zxKx/QWV3xaVQ==",
|
||||
"version": "0.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@armco/analytics/-/analytics-0.2.5.tgz",
|
||||
"integrity": "sha512-esgKYvXGCTM2TWeFd6a9lkQRZur5Y9ATVElxgWKjMRak0DSFbBE1CGJbsKaSf398gv622ZkVmLgIq9DbIbbesw==",
|
||||
"requires": {
|
||||
"jet-logger": "^1.3.1",
|
||||
"jquery": "^3.7.0",
|
||||
@@ -33746,6 +33752,11 @@
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"highcharts": {
|
||||
"version": "11.2.0",
|
||||
"resolved": "https://registry.npmjs.org/highcharts/-/highcharts-11.2.0.tgz",
|
||||
"integrity": "sha512-9i650YK7ZBA1Mgtr3avMkLVCAI45RQvYnwi+eHsdFSaBGuQN6BHoa4j4lMkSJLv0V4LISTK1z7J7G82Lzd7zwg=="
|
||||
},
|
||||
"highlight.js": {
|
||||
"version": "11.8.0",
|
||||
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.8.0.tgz",
|
||||
@@ -34904,9 +34915,9 @@
|
||||
}
|
||||
},
|
||||
"jquery": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.0.tgz",
|
||||
"integrity": "sha512-umpJ0/k8X0MvD1ds0P9SfowREz2LenHsQaxSohMZ5OMNEU2r0tf8pdeEFTHMFxWVxKNyU9rTtK3CWzUCTKJUeQ=="
|
||||
"version": "3.7.1",
|
||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
|
||||
"integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg=="
|
||||
},
|
||||
"js-cookie": {
|
||||
"version": "3.0.5",
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
"build-storybook": "storybook build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@armco/analytics": "^0.2.2",
|
||||
"@armco/analytics": "^0.2.5",
|
||||
"@armco/armory-react-components": "^0.0.20",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@reduxjs/toolkit": "^1.8.1",
|
||||
@@ -36,6 +36,7 @@
|
||||
"bootstrap": "^5.3.0",
|
||||
"classnames": "^2.3.2",
|
||||
"d3": "^7.8.5",
|
||||
"highcharts": "^11.2.0",
|
||||
"highlight.js": "^11.8.0",
|
||||
"js-cookie": "^3.0.5",
|
||||
"moment": "^2.29.4",
|
||||
|
||||
@@ -74,6 +74,14 @@ const ConfigRowItem = (props: ConfigRowItemProps): JSX.Element => {
|
||||
onClick={() => (edited ? setEdited(false) : setEdited(true))}
|
||||
/>
|
||||
</span>
|
||||
<span className={`me-3 ${edited ? "pe-none" : "cursor-pointer"}`}>
|
||||
<LoadableIcon
|
||||
icon="md/MdAdd"
|
||||
width="1.3rem"
|
||||
color={!configIsSubmittable ? "green" : "rgba(0, 128, 0, 0.3)"}
|
||||
onClick={() => onDelete && onDelete(config?._id)}
|
||||
/>
|
||||
</span>
|
||||
<span className={edited ? "pe-none" : "cursor-pointer"}>
|
||||
<LoadableIcon
|
||||
icon="ri/RiDeleteBin6Line"
|
||||
|
||||
@@ -33,7 +33,7 @@ const ConfigurationViewer = (props: ConfigurationViewerProps): JSX.Element => {
|
||||
const addConfig = (key: string, value: string, _id?: string) => {
|
||||
const payload: ObjectType = {
|
||||
key,
|
||||
value: JSON.parse(value),
|
||||
value,
|
||||
namespace: namespace._id,
|
||||
version: "v1",
|
||||
}
|
||||
|
||||
@@ -1,17 +1,31 @@
|
||||
import { ReactNode } from "react"
|
||||
import { useState } from "react"
|
||||
import { DrawerProps } from "../../types/components.interface"
|
||||
import "./Drawer.component.scss"
|
||||
|
||||
interface DrawerProps {
|
||||
children?: ReactNode
|
||||
classes?: string
|
||||
}
|
||||
import LoadableIcon from "../atoms/LoadableIcon"
|
||||
|
||||
const Drawer = (props: DrawerProps): JSX.Element => {
|
||||
const { children, classes } = props
|
||||
const { children, classes, isCollapsible } = props
|
||||
const [collapsed, setCollapsed] = useState<boolean>()
|
||||
|
||||
return (
|
||||
<aside className={`ar-Drawer${classes ? " " + classes : ""}`}>
|
||||
{children}
|
||||
<aside
|
||||
className={`ar-Drawer${classes ? " " + classes : ""}${
|
||||
isCollapsible ? " position-relative" : ""
|
||||
}${collapsed ? " collapsed" : ""}`}
|
||||
>
|
||||
{isCollapsible && (
|
||||
<LoadableIcon
|
||||
classes="position-absolute top-1 end-1 cursor-pointer"
|
||||
icon={
|
||||
collapsed
|
||||
? "tb/TbLayoutSidebarLeftExpand"
|
||||
: "tb/TbLayoutSidebarLeftCollapse"
|
||||
}
|
||||
size="1.5rem"
|
||||
onClick={() => setCollapsed(!collapsed)}
|
||||
/>
|
||||
)}
|
||||
{!collapsed && children}
|
||||
</aside>
|
||||
)
|
||||
}
|
||||
|
||||
3
src/app/components/FontsList/FontsList.component.scss
Executable file
3
src/app/components/FontsList/FontsList.component.scss
Executable file
@@ -0,0 +1,3 @@
|
||||
.ar-FontsList {
|
||||
|
||||
}
|
||||
8
src/app/components/FontsList/FontsList.test.ts
Executable file
8
src/app/components/FontsList/FontsList.test.ts
Executable file
@@ -0,0 +1,8 @@
|
||||
import React from "react"
|
||||
import FontsList from "./FontsList"
|
||||
|
||||
describe("FontsList", () => {
|
||||
it("renders without error", () => {
|
||||
|
||||
})
|
||||
})
|
||||
93
src/app/components/FontsList/FontsList.tsx
Executable file
93
src/app/components/FontsList/FontsList.tsx
Executable file
@@ -0,0 +1,93 @@
|
||||
import { ChangeEvent, useEffect, useState } from "react"
|
||||
import { FontsListProps } from "../../types/components.interface"
|
||||
import { ArrayType } from "../../types/types"
|
||||
import { ArButtonVariants, ArLoaderTypes, ArSizes } from "../../types/enums"
|
||||
import { Button, Loader, Search } from ".."
|
||||
import { Helper } from "../../utils"
|
||||
import "./FontsList.component.scss"
|
||||
|
||||
const FontsList = (props: FontsListProps): JSX.Element => {
|
||||
const [fonts, setFonts] = useState<ArrayType>()
|
||||
const [page, setPage] = useState<ArrayType>()
|
||||
const [loading, setLoading] = useState<boolean>()
|
||||
|
||||
// TODO: Fetch Fonts
|
||||
useEffect(() => {}, [])
|
||||
|
||||
return (
|
||||
<div className="ar-FontsList h-100 w-100">
|
||||
{!fonts && (
|
||||
<Loader label="Loading Fonts..." type={ArLoaderTypes.SHAPES} />
|
||||
)}
|
||||
<div className="ar-FontsList__header-pagination-search-upload py-2 px-3 mb-2 border">
|
||||
<div className="row">
|
||||
<div className="col-4 d-flex align-items-center">
|
||||
<h6 className="mb-0 h-100 flex-center px-3 border-right">
|
||||
<Button
|
||||
variant={ArButtonVariants.LINK}
|
||||
content="Categories"
|
||||
size={ArSizes.SMALL}
|
||||
splitOptions={[
|
||||
{
|
||||
label: "All",
|
||||
},
|
||||
{
|
||||
label: "Business",
|
||||
},
|
||||
{
|
||||
label: "Medical",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</h6>
|
||||
</div>
|
||||
<span className="col-4 d-none d-md-flex flex-v-center justify-content-end">
|
||||
<Button
|
||||
classes="h-100 float-end me-3"
|
||||
content="Create"
|
||||
size={ArSizes.SMALL}
|
||||
variant={ArButtonVariants.LINK}
|
||||
preIcon="io5/IoCreateOutline"
|
||||
/>
|
||||
<Button
|
||||
classes="h-100 float-end me-3"
|
||||
content="Upload"
|
||||
size={ArSizes.SMALL}
|
||||
variant={ArButtonVariants.SUCCESS}
|
||||
/>
|
||||
</span>
|
||||
<div className="col-4 offset-4 offset-md-0 flex-v-center">
|
||||
<Search
|
||||
classes="bg-white"
|
||||
placeholder="Search by name, tags, description"
|
||||
onChange={Helper.debounce(
|
||||
(event: ChangeEvent<HTMLInputElement>) => null,
|
||||
// onSearchChanged(event.target.value),
|
||||
1000,
|
||||
)}
|
||||
data={
|
||||
fonts
|
||||
? fonts.map(
|
||||
(font): SearchItem => ({
|
||||
label: font.name,
|
||||
data: font,
|
||||
}),
|
||||
)
|
||||
: []
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{page && (
|
||||
<div className="ar-FontsList__icon-tile-container py-2 px-3 border d-flex justify-content-between flex-wrap flex-grow-1">
|
||||
{loading && (
|
||||
<Loader label="Applying filters..." type={ArLoaderTypes.CIRCLE} />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default FontsList
|
||||
3
src/app/components/FontsList/index.ts
Executable file
3
src/app/components/FontsList/index.ts
Executable file
@@ -0,0 +1,3 @@
|
||||
import FontsList from "./FontsList"
|
||||
|
||||
export default FontsList
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
Tags,
|
||||
TextInput,
|
||||
} from ".."
|
||||
import { ObjectType } from "../../types/types"
|
||||
import "./IconController.component.scss"
|
||||
|
||||
const complement = (hex?: string) => {
|
||||
@@ -151,15 +150,18 @@ const IconController = (props: IconControllerProps): JSX.Element => {
|
||||
setUnit(e.value)
|
||||
}
|
||||
options={[
|
||||
// @ts-ignore
|
||||
{ label: "rem", value: "rem" },
|
||||
// @ts-ignore
|
||||
{ label: "px", value: "px" },
|
||||
// @ts-ignore
|
||||
{ label: "vh", value: "vh" },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Tags classes="col-12 h-75" label={name} />
|
||||
<Tags classes="col-12 h-100 px-0" label={name} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useAppDispatch, useAppSelector } from "../../hooks"
|
||||
import { notify, setRightPanelContent } from "../../store"
|
||||
import {
|
||||
getFavorites,
|
||||
getSelectedTag,
|
||||
removeFavorite,
|
||||
setFavorites,
|
||||
} from "../../pages/IconsPage/IconsPage.slice"
|
||||
@@ -20,20 +21,68 @@ import {
|
||||
ArButtonVariants,
|
||||
ArIconTileTypes,
|
||||
ArLoaderTypes,
|
||||
ArPageTriggers,
|
||||
ArPopoverSlots,
|
||||
ArPopoverTriggers,
|
||||
ArSizes,
|
||||
} from "../../types/enums"
|
||||
import { IconTileProps, IconsListProps } from "../../types/components.interface"
|
||||
import Helper from "../../utils/helper"
|
||||
import { FunctionType, ObjectType, SegmentType } from "../../types/types"
|
||||
|
||||
import { Helper, Network } from "../../utils"
|
||||
import API_CONFIG from "../../config/api-config"
|
||||
import { ENDPOINTS } from "../../config/constants"
|
||||
import "./IconsList.component.scss"
|
||||
import { SegmentType } from "../../types/types"
|
||||
|
||||
const fetchIconsPage = (
|
||||
limit: number,
|
||||
from: number,
|
||||
filters: ObjectType,
|
||||
dataSetter: FunctionType,
|
||||
pageSetter: FunctionType,
|
||||
setLoading: FunctionType,
|
||||
) => {
|
||||
const pageApi =
|
||||
API_CONFIG.STATIC_HOST[process.env.NODE_ENV] +
|
||||
ENDPOINTS.STATIC.ICON.ROOT +
|
||||
ENDPOINTS.STATIC.ICON.PAGE
|
||||
const queryParams: ObjectType = { pageSize: limit, from, ...filters }
|
||||
// if (
|
||||
// filters &&
|
||||
// typeof filters === "object" &&
|
||||
// Object.keys(filters).length > 0
|
||||
// ) {
|
||||
// queryParams.filters = filters
|
||||
// }
|
||||
Network.get(pageApi, queryParams)
|
||||
.then((response) => {
|
||||
if (response && response.status === 200) {
|
||||
if (response.body && dataSetter) {
|
||||
dataSetter(response.body)
|
||||
pageSetter(response.body.slice(0, 100))
|
||||
}
|
||||
}
|
||||
setLoading(false)
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error)
|
||||
setLoading(false)
|
||||
})
|
||||
}
|
||||
|
||||
const IconsList = (props: IconsListProps): JSX.Element => {
|
||||
const { icons, onSearchChanged } = props
|
||||
const { onSearchChanged, searchString } = props
|
||||
const [icons, setIcons] = useState<Array<IconResponse>>()
|
||||
const [page, setPage] = useState<Array<IconResponse>>()
|
||||
const [view, setView] = useState<SegmentType>()
|
||||
const [loading, setLoading] = useState<boolean>()
|
||||
const dispatch = useAppDispatch()
|
||||
const favorites = useAppSelector(getFavorites)
|
||||
const selectedTag = useAppSelector<string | undefined>(getSelectedTag)
|
||||
|
||||
useEffect(() => {
|
||||
setView({ name: ArIconTileTypes.COMFY })
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (favorites) {
|
||||
@@ -43,10 +92,17 @@ const IconsList = (props: IconsListProps): JSX.Element => {
|
||||
}
|
||||
}, [favorites, dispatch])
|
||||
|
||||
const slices =
|
||||
icons &&
|
||||
icons.length > 0 &&
|
||||
Helper.generateSlices(icons.length, 100, "index")
|
||||
useEffect(() => {
|
||||
const filters: ObjectType = {}
|
||||
if (selectedTag) {
|
||||
filters.tags = selectedTag
|
||||
}
|
||||
if (searchString) {
|
||||
filters.search = searchString
|
||||
}
|
||||
setLoading(true)
|
||||
fetchIconsPage(2000, 0, filters, setIcons, setPage, setLoading)
|
||||
}, [selectedTag, searchString])
|
||||
|
||||
const onIconTileClick = (iconProps: IconResponse) => {
|
||||
dispatch(
|
||||
@@ -59,7 +115,7 @@ const IconsList = (props: IconsListProps): JSX.Element => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="ar-IconsList h-100 w-100 overflow-auto position-relative">
|
||||
<div className="ar-IconsList h-100 w-100 overflow-auto position-relative d-flex flex-column">
|
||||
{!icons && (
|
||||
<Loader label="Loading Icons..." type={ArLoaderTypes.SHAPES} />
|
||||
)}
|
||||
@@ -127,9 +183,11 @@ const IconsList = (props: IconsListProps): JSX.Element => {
|
||||
<Search
|
||||
classes="bg-white"
|
||||
placeholder="Search by name, tags, description"
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) =>
|
||||
onSearchChanged(event.target.value)
|
||||
}
|
||||
onChange={Helper.debounce(
|
||||
(event: ChangeEvent<HTMLInputElement>) =>
|
||||
onSearchChanged(event.target.value),
|
||||
1000,
|
||||
)}
|
||||
data={
|
||||
icons
|
||||
? icons.map(
|
||||
@@ -144,11 +202,14 @@ const IconsList = (props: IconsListProps): JSX.Element => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{icons && (
|
||||
<div className="ar-IconsList__icon-tile-container py-2 px-3 border d-flex justify-content-between flex-wrap">
|
||||
{icons.slice(0, 100).map((icon, index) => (
|
||||
{page && (
|
||||
<div className="ar-IconsList__icon-tile-container py-2 px-3 border d-flex justify-content-between flex-wrap flex-grow-1">
|
||||
{loading && (
|
||||
<Loader label="Applying filters..." type={ArLoaderTypes.CIRCLE} />
|
||||
)}
|
||||
{page.map((icon, index) => (
|
||||
<Popover trigger={ArPopoverTriggers.HOVER}>
|
||||
{view && view.name !== ArIconTileTypes.LIST ? (
|
||||
{!view || view.name !== ArIconTileTypes.LIST ? (
|
||||
<span slot={ArPopoverSlots.POPOVER}>{icon.name}</span>
|
||||
) : null}
|
||||
<IconTile
|
||||
@@ -157,10 +218,12 @@ const IconsList = (props: IconsListProps): JSX.Element => {
|
||||
? (view.name as ArIconTileTypes)
|
||||
: ArIconTileTypes.COMFY
|
||||
}
|
||||
hideBorder={view?.name !== ArIconTileTypes.LIST}
|
||||
classes={view?.name}
|
||||
slot={ArPopoverSlots.ANCHOR}
|
||||
key={index}
|
||||
icon={icon}
|
||||
iconSize={view?.name === ArIconTileTypes.LIST ? "1rem" : "2rem"}
|
||||
onClick={onIconTileClick}
|
||||
tools={[
|
||||
{
|
||||
@@ -226,13 +289,20 @@ const IconsList = (props: IconsListProps): JSX.Element => {
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{slices && (
|
||||
<Pagination
|
||||
classes="my-3 flex-center"
|
||||
data={slices}
|
||||
maxPillsToShow={5}
|
||||
/>
|
||||
)}
|
||||
{/* {slices && ( */}
|
||||
<Pagination
|
||||
classes="my-3 flex-center"
|
||||
data={icons}
|
||||
maxPillsToShow={5}
|
||||
pageSetter={setPage}
|
||||
// trigger={ArPageTriggers.SCROLL}
|
||||
count={1}
|
||||
load={100}
|
||||
dataFetcher={(load, count) =>
|
||||
fetchIconsPage(load, count, {}, setIcons, setPage, setLoading)
|
||||
}
|
||||
/>
|
||||
{/* )} */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ import "./LoginProvider.component.scss"
|
||||
const LoginProvider = (props: LoginProviderProps): JSX.Element => {
|
||||
return (
|
||||
<iframe
|
||||
src="https://iam.notabuck.com"
|
||||
// src="http://localhost:3001"
|
||||
// src="https://iam.notabuck.com"
|
||||
src="http://localhost:3001"
|
||||
title="IAM"
|
||||
className="ar-LoginProvider h-100"
|
||||
/>
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
.ar-Main {
|
||||
.ar-Drawer {
|
||||
transition: width 0.3s;
|
||||
width: 15%;
|
||||
&.collapsed {
|
||||
width: 3.5rem;
|
||||
}
|
||||
& + .ar-Content {
|
||||
width: 85%;
|
||||
// width: 85%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,11 @@ const Main = (props: MainProps): JSX.Element => {
|
||||
} = props
|
||||
return (
|
||||
<main className="ar-Main d-flex flex-grow-1 w-100">
|
||||
{drawerContent && <Drawer classes="d-flex h-100">{drawerContent}</Drawer>}
|
||||
{drawerContent && (
|
||||
<Drawer classes="d-flex h-100" isCollapsible>
|
||||
{drawerContent}
|
||||
</Drawer>
|
||||
)}
|
||||
<SidePanel
|
||||
header={leftPanelHeader || "Header Name"}
|
||||
placement={ArPlacement.LEFT}
|
||||
|
||||
@@ -4,17 +4,19 @@ import { ArVizProps } from "../../../types/components.interface"
|
||||
import { ArVisualizationTypes } from "../../../types/enums"
|
||||
import { generateBubbleChart } from "../../../utils/chartGenerators"
|
||||
import "./ArViz.component.scss"
|
||||
import BubbleChart from "../BubbleChart"
|
||||
import { ObjectType } from "../../../types/types"
|
||||
|
||||
const dataDummy = [
|
||||
{ source: "Item 1", x: 100, y: 60, val: 1350, color: "#C9D6DF" },
|
||||
{ source: "Item 2", x: 30, y: 80, val: 2500, color: "#F7EECF" },
|
||||
{ source: "Item 3", x: 50, y: 40, val: 5700, color: "#E3E1B2" },
|
||||
{ source: "Item 4", x: 190, y: 100, val: 30000, color: "#F9CAC8" },
|
||||
{ source: "Item 5", x: 80, y: 170, val: 47500, color: "#D1C2E0" },
|
||||
{ source: "Item 1", val: 1350, color: "#C9D6DF" },
|
||||
{ source: "Item 2", val: 2500, color: "#F7EECF" },
|
||||
{ source: "Item 3", val: 5700, color: "#E3E1B2" },
|
||||
{ source: "Item 4", val: 30000, color: "#F9CAC8" },
|
||||
{ source: "Item 5", val: 47500, color: "#D1C2E0" },
|
||||
]
|
||||
|
||||
const ArViz = (props: ArVizProps): JSX.Element => {
|
||||
const { type, data, demo } = props
|
||||
const { clickHandler, type, data, demo } = props
|
||||
const svgContainerRef = useRef(null)
|
||||
|
||||
useEffect(() => {
|
||||
@@ -34,7 +36,9 @@ const ArViz = (props: ArVizProps): JSX.Element => {
|
||||
}
|
||||
}, [svgContainerRef, data])
|
||||
|
||||
return (
|
||||
return type === ArVisualizationTypes.BUBBLE ? (
|
||||
<BubbleChart data={data as Array<ObjectType>} clickHandler={clickHandler} />
|
||||
) : (
|
||||
<div className="ar-ArViz h-100 w-100 overflow-auto p-3">
|
||||
<svg
|
||||
id="ar-ArViz__chart-container"
|
||||
|
||||
3
src/app/components/atoms/BubbleChart/BubbleChart.component.scss
Executable file
3
src/app/components/atoms/BubbleChart/BubbleChart.component.scss
Executable file
@@ -0,0 +1,3 @@
|
||||
.ar-BubbleChart {
|
||||
|
||||
}
|
||||
8
src/app/components/atoms/BubbleChart/BubbleChart.test.ts
Executable file
8
src/app/components/atoms/BubbleChart/BubbleChart.test.ts
Executable file
@@ -0,0 +1,8 @@
|
||||
import React from "react"
|
||||
import BubbleChart from "./BubbleChart"
|
||||
|
||||
describe("BubbleChart", () => {
|
||||
it("renders without error", () => {
|
||||
|
||||
})
|
||||
})
|
||||
100
src/app/components/atoms/BubbleChart/BubbleChart.tsx
Executable file
100
src/app/components/atoms/BubbleChart/BubbleChart.tsx
Executable file
@@ -0,0 +1,100 @@
|
||||
import { useEffect, useRef } from "react"
|
||||
import Highcharts from "highcharts"
|
||||
import HighchartsMore from "highcharts/highcharts-more"
|
||||
import { BubbleChartProps } from "../../../types/components.interface"
|
||||
import "./BubbleChart.component.scss"
|
||||
import { ObjectType } from "../../../types/types"
|
||||
|
||||
HighchartsMore(Highcharts)
|
||||
|
||||
const BubbleChart = (props: BubbleChartProps): JSX.Element => {
|
||||
const { clickHandler, data } = props
|
||||
const chartRef = useRef(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (chartRef.current && data) {
|
||||
const labels = Object.keys(data)
|
||||
const values = Object.values(data)
|
||||
|
||||
const options = {
|
||||
chart: {
|
||||
type: "packedbubble",
|
||||
},
|
||||
title: {
|
||||
text: null,
|
||||
},
|
||||
tooltip: {
|
||||
formatter: function (): string {
|
||||
return (
|
||||
"Tag: <b>" +
|
||||
("point" in this && (this.point as ObjectType).name) +
|
||||
"</b><br>Count: <b>" +
|
||||
("y" in this && this.y) +
|
||||
"</b>"
|
||||
)
|
||||
},
|
||||
},
|
||||
credits: {
|
||||
enabled: false,
|
||||
},
|
||||
plotOptions: {
|
||||
packedbubble: {
|
||||
minSize: "30%",
|
||||
maxSize: "120%",
|
||||
zMin: 0,
|
||||
zMax: 1000,
|
||||
layoutAlgorithm: {
|
||||
splitSeries: false,
|
||||
gravitationalConstant: 0.02,
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
format: "{point.name}",
|
||||
filter: {
|
||||
property: "y",
|
||||
operator: ">",
|
||||
value: 250,
|
||||
},
|
||||
style: {
|
||||
color: "black",
|
||||
textOutline: "none",
|
||||
fontWeight: "normal",
|
||||
},
|
||||
},
|
||||
events: {
|
||||
click: function (e: any) {
|
||||
clickHandler && clickHandler(e)
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
cursor: "pointer",
|
||||
showInLegend: false,
|
||||
data: labels.map((label, index) => ({
|
||||
// x: index, // X-axis position
|
||||
// y: values[index], // Y-axis value
|
||||
// z: values[index], // Bubble size value
|
||||
value: values[index],
|
||||
name: label, // Label for the bubble
|
||||
})),
|
||||
},
|
||||
],
|
||||
xAxis: {
|
||||
visible: false,
|
||||
},
|
||||
yAxis: {
|
||||
visible: false,
|
||||
},
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
Highcharts.chart(chartRef.current, options)
|
||||
}
|
||||
}, [data]) // Re-render chart when data prop changes
|
||||
|
||||
return <div ref={chartRef} style={{ width: "100%" }}></div>
|
||||
}
|
||||
|
||||
export default BubbleChart
|
||||
3
src/app/components/atoms/BubbleChart/index.ts
Executable file
3
src/app/components/atoms/BubbleChart/index.ts
Executable file
@@ -0,0 +1,3 @@
|
||||
import BubbleChart from "./BubbleChart"
|
||||
|
||||
export default BubbleChart
|
||||
@@ -19,7 +19,7 @@ const Dropdown = (props: DropdownProps): JSX.Element => {
|
||||
onSelectionChanged(
|
||||
{
|
||||
value: e.target.value,
|
||||
data: options.find((o) => (o.name || o.label) === e.target.value),
|
||||
data: options?.find((o) => (o.name || o.label) === e.target.value),
|
||||
},
|
||||
context,
|
||||
)
|
||||
@@ -37,10 +37,10 @@ const Dropdown = (props: DropdownProps): JSX.Element => {
|
||||
onChange={onLocalChange}
|
||||
aria-label={ariaLabel}
|
||||
>
|
||||
{options.map((option, index) => (
|
||||
{options?.map((option, index) => (
|
||||
<option
|
||||
key={(id || label) + "dropdown-" + index}
|
||||
value={option.name || option.label}
|
||||
value={(option.name || option.label) as string}
|
||||
>
|
||||
{option.label}
|
||||
</option>
|
||||
|
||||
@@ -13,6 +13,7 @@ const IconTile = (props: IconTileProps): JSX.Element => {
|
||||
hideBorder,
|
||||
hideFooter,
|
||||
icon,
|
||||
iconSize,
|
||||
onClick,
|
||||
tools,
|
||||
toolsPlacement,
|
||||
@@ -65,8 +66,8 @@ const IconTile = (props: IconTileProps): JSX.Element => {
|
||||
>
|
||||
<LoadableIcon
|
||||
// key={icon.name}
|
||||
size="2rem"
|
||||
svgB64String={btoa(icon.svg)}
|
||||
size={iconSize}
|
||||
svgB64String={btoa(icon.icon)}
|
||||
color={hovered ? "blue" : "grey"}
|
||||
/>
|
||||
{type !== ArIconTileTypes.LIST && iconTools}
|
||||
|
||||
@@ -1,19 +1,49 @@
|
||||
import { ReactNode, useEffect, useState } from "react"
|
||||
import { Icon, SelectionPill } from "../.."
|
||||
import { PaginationProps } from "../../../types/components.interface"
|
||||
import { ArPageTriggers } from "../../../types/enums"
|
||||
import { Helper } from "../../../utils"
|
||||
import { ObjectType } from "../../../types/types"
|
||||
import { PageInfoType } from "../../../types/entity.interface"
|
||||
import "./Pagination.component.scss"
|
||||
|
||||
const Pagination = (props: PaginationProps): JSX.Element => {
|
||||
const { classes, data, maxPillsToShow } = props
|
||||
const Pagination = (props: PaginationProps): ReactNode => {
|
||||
const {
|
||||
classes,
|
||||
count,
|
||||
data,
|
||||
dataFetcher,
|
||||
load,
|
||||
maxPillsToShow,
|
||||
pageSetter,
|
||||
pageSize,
|
||||
trigger,
|
||||
} = props
|
||||
const [currentPage, setCurrentPage] = useState<number>()
|
||||
const [pages, setPages] = useState<Array<PageInfoType>>()
|
||||
const [pageWindow, setPageWindow] = useState<number>()
|
||||
let selectorBlockRenders
|
||||
const navItemSize = "1.2rem"
|
||||
|
||||
if (data) {
|
||||
if (maxPillsToShow && data.length > maxPillsToShow) {
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
const slices =
|
||||
data &&
|
||||
data.length > 0 &&
|
||||
Helper.generateSlices(data.length, pageSize || 100, "index")
|
||||
slices && setPages(slices)
|
||||
setPageWindow(0)
|
||||
}
|
||||
}, [data])
|
||||
|
||||
if (pages && data && pageWindow !== undefined) {
|
||||
if (maxPillsToShow && pages.length > maxPillsToShow) {
|
||||
selectorBlockRenders = []
|
||||
// TODO: onclick
|
||||
selectorBlockRenders.push(
|
||||
<SelectionPill
|
||||
classes="me-2 border-radius"
|
||||
disabled={pageWindow === 0}
|
||||
data={{
|
||||
label: (
|
||||
<Icon
|
||||
@@ -24,12 +54,12 @@ const Pagination = (props: PaginationProps): JSX.Element => {
|
||||
/>
|
||||
),
|
||||
}}
|
||||
onClick={() => {}}
|
||||
onClick={() => setPageWindow(pageWindow - maxPillsToShow)}
|
||||
/>,
|
||||
)
|
||||
selectorBlockRenders = selectorBlockRenders.concat(
|
||||
data
|
||||
.slice(0, maxPillsToShow)
|
||||
pages
|
||||
.slice(pageWindow, pageWindow + maxPillsToShow)
|
||||
.map((obj, index, arr) => (
|
||||
<SelectionPill
|
||||
classes={
|
||||
@@ -40,13 +70,25 @@ const Pagination = (props: PaginationProps): JSX.Element => {
|
||||
: ""
|
||||
}
|
||||
data={obj}
|
||||
onClick={() => {}}
|
||||
selected={currentPage === obj.sliceIndex}
|
||||
// onClick={() => dataFetcher && dataFetcher(load, count)}
|
||||
onClick={(pageInfo: ObjectType) => {
|
||||
const pageData = data.slice(
|
||||
(pageInfo.data as ObjectType).startIndex as number,
|
||||
(pageInfo.data as ObjectType).endIndex as number,
|
||||
)
|
||||
pageSetter && pageSetter(pageData)
|
||||
setCurrentPage(
|
||||
(pageInfo.data as ObjectType).sliceIndex as number,
|
||||
)
|
||||
}}
|
||||
/>
|
||||
)),
|
||||
)
|
||||
selectorBlockRenders.push(
|
||||
<SelectionPill
|
||||
classes="ms-2 border-radius"
|
||||
disabled={pages?.length <= pageWindow}
|
||||
data={{
|
||||
label: (
|
||||
<Icon
|
||||
@@ -57,18 +99,18 @@ const Pagination = (props: PaginationProps): JSX.Element => {
|
||||
/>
|
||||
),
|
||||
}}
|
||||
onClick={() => {}}
|
||||
onClick={() => setPageWindow(pageWindow + maxPillsToShow)}
|
||||
/>,
|
||||
)
|
||||
} else {
|
||||
// TODO: Add onClickhandler
|
||||
selectorBlockRenders = data.map((obj) => (
|
||||
selectorBlockRenders = pages.map((obj) => (
|
||||
<SelectionPill data={obj} onClick={() => {}} />
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
return trigger === ArPageTriggers.SCROLL ? null : (
|
||||
<div className={`ar-Pagination${classes ? " " + classes : ""}`}>
|
||||
{selectorBlockRenders}
|
||||
</div>
|
||||
|
||||
@@ -24,4 +24,9 @@
|
||||
&.selected {
|
||||
background-color: var(--ar-bg-selected);
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
pointer-events: none;
|
||||
cursor: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,24 @@
|
||||
import { useState } from "react"
|
||||
import { useEffect, useState } from "react"
|
||||
import { SelectionPillProps } from "../../../types/components.interface"
|
||||
import "./SelectionPill.component.scss"
|
||||
|
||||
type PILLSIZES = "large" | "medium" | "small"
|
||||
interface SelectionPillProps {
|
||||
classes?: string
|
||||
context?: string
|
||||
data: { [key: string]: string | number | JSX.Element }
|
||||
onClick: Function
|
||||
size?: PILLSIZES
|
||||
}
|
||||
|
||||
const SelectionPill = (props: SelectionPillProps): JSX.Element => {
|
||||
const { classes, context, data, onClick, size } = props
|
||||
const [selected, setSelected] = useState<boolean>()
|
||||
const { classes, context, data, disabled, onClick, selected, size } = props
|
||||
const [localSelected, setLocalSelected] = useState<boolean>()
|
||||
|
||||
useEffect(() => {
|
||||
setLocalSelected(selected)
|
||||
}, [selected])
|
||||
|
||||
return (
|
||||
<span
|
||||
className={`ar-SelectionPill inline-flex-center border${
|
||||
classes ? " " + classes : ""
|
||||
}${size ? " " + size : ""}
|
||||
${selected ? " selected" : ""}`}
|
||||
${selected ? " selected" : ""}
|
||||
${disabled ? " disabled" : ""}`}
|
||||
onClick={() => {
|
||||
setSelected(!selected)
|
||||
setLocalSelected(!localSelected)
|
||||
onClick && onClick({ value: data.label || "", data })
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -4,39 +4,47 @@ import {
|
||||
ArPopoverTriggers,
|
||||
ArVisualizationTypes,
|
||||
} from "../../../types/enums"
|
||||
import { ObjectType } from "../../../types/types"
|
||||
import ArViz from "../ArViz"
|
||||
import LoadableIcon from "../LoadableIcon"
|
||||
import Popover from "../Popover"
|
||||
import "./Tags.component.scss"
|
||||
|
||||
const Tags = (props: TagsProps): JSX.Element => {
|
||||
const { classes, label } = props
|
||||
const { clickHandler, classes, hideHeader, label, tags } = props
|
||||
return (
|
||||
<div className={`ar-Tags w-100${classes ? " " + classes : ""}`}>
|
||||
<div className="border h-100">
|
||||
<div className="ar-Tags__header fw-bold border-bottom py-1 px-2">
|
||||
<div className="d-inline-block me-2">
|
||||
{(label ? label : "") + " Tags"}
|
||||
</div>
|
||||
<Popover classes="d-inline-block" trigger={ArPopoverTriggers.HOVER}>
|
||||
<div
|
||||
slot={ArPopoverSlots.POPOVER}
|
||||
style={{
|
||||
width: "6rem",
|
||||
whiteSpace: "normal",
|
||||
lineHeight: "1.2rem",
|
||||
}}
|
||||
>
|
||||
Please use up/down errors to indicate if a tag matches the icon.
|
||||
<div className="h-100">
|
||||
{!hideHeader && (
|
||||
<div className="ar-Tags__header fw-bold border-bottom py-1 px-2">
|
||||
<div className="d-inline-block me-2">
|
||||
{(label ? label : "") + " Tags"}
|
||||
</div>
|
||||
<LoadableIcon
|
||||
icon="md.MdInfoOutline"
|
||||
slot={ArPopoverSlots.ANCHOR}
|
||||
/>
|
||||
</Popover>
|
||||
</div>
|
||||
|
||||
<Popover classes="d-inline-block" trigger={ArPopoverTriggers.HOVER}>
|
||||
<div
|
||||
slot={ArPopoverSlots.POPOVER}
|
||||
style={{
|
||||
width: "6rem",
|
||||
whiteSpace: "normal",
|
||||
lineHeight: "1.2rem",
|
||||
}}
|
||||
>
|
||||
Please use up/down arrows to indicate if a tag matches the icon.
|
||||
</div>
|
||||
<LoadableIcon
|
||||
icon="md.MdInfoOutline"
|
||||
slot={ArPopoverSlots.ANCHOR}
|
||||
/>
|
||||
</Popover>
|
||||
</div>
|
||||
)}
|
||||
<div className="ar-Tags__container flex-h-center">
|
||||
<ArViz type={ArVisualizationTypes.BUBBLE} data={[]} />
|
||||
<ArViz
|
||||
clickHandler={clickHandler}
|
||||
type={ArVisualizationTypes.BUBBLE}
|
||||
data={tags as ObjectType}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* PLOP_INJECT_IMPORT */
|
||||
import BubbleChart from "./atoms/BubbleChart"
|
||||
import CronTab from "./atoms/CronTab"
|
||||
import Carousel from "./molecules/Carousel"
|
||||
import Swiper from "./molecules/Swiper"
|
||||
@@ -140,9 +141,10 @@ import Alert from "./atoms/Alert"
|
||||
|
||||
export {
|
||||
/* PLOP_INJECT_EXPORT */
|
||||
CronTab,
|
||||
Carousel,
|
||||
Swiper,
|
||||
BubbleChart,
|
||||
CronTab,
|
||||
Carousel,
|
||||
Swiper,
|
||||
TaskList,
|
||||
TaskLoginPrompt,
|
||||
TaskViewer,
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
import { useState } from "react"
|
||||
import { AlphabetFilter, CategoryFilter, Dropdown, Pillbox } from "../.."
|
||||
import { selectTag } from "../../../pages/IconsPage/IconsPage.slice"
|
||||
import { useAppDispatch } from "../../../hooks"
|
||||
import { AlphabetFilter, CategoryFilter, Dropdown, Pillbox, Tags } from "../.."
|
||||
import { PillProps } from "../../atoms/Pill/Pill"
|
||||
import {
|
||||
BasicFilterConfig,
|
||||
BasicFilterType,
|
||||
FilterState,
|
||||
FiltersProps,
|
||||
} from "../../../types/filterconfig"
|
||||
import Helper from "../../../utils/helper"
|
||||
import "./Filters.component.scss"
|
||||
|
||||
@@ -9,14 +17,13 @@ const Filters = (props: FiltersProps): JSX.Element => {
|
||||
const [filters, setFilters] = useState<FilterState | undefined>(
|
||||
initialFilters,
|
||||
)
|
||||
const dispatch = useAppDispatch()
|
||||
const useData = filteredData || data
|
||||
const total = useData && useData.length
|
||||
|
||||
const countOptions = Helper.generateSlices(
|
||||
total || 0,
|
||||
config.count || 0,
|
||||
"range",
|
||||
)
|
||||
const countOptions =
|
||||
config.count !== undefined &&
|
||||
Helper.generateSlices(total || 0, config.count || 0, "range")
|
||||
|
||||
const onLocalFilterChange = (
|
||||
data: BasicFilterType | undefined,
|
||||
@@ -120,26 +127,33 @@ const Filters = (props: FiltersProps): JSX.Element => {
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const clickHandler = (e: any) => {
|
||||
dispatch(selectTag(e.point.name))
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="ar-Filters p-3 h-100 overflow-auto">
|
||||
<div className="ar-Filters p-3 h-100 overflow-auto w-100">
|
||||
<h5>Filters</h5>
|
||||
{"count" in config && (
|
||||
<Dropdown
|
||||
classes="mb-3"
|
||||
context="count"
|
||||
id="icon-range-selector"
|
||||
label="Select a range"
|
||||
options={countOptions}
|
||||
onSelectionChanged={(data: BasicFilterConfig) => {
|
||||
onLocalFilterChange(data, "count")
|
||||
}}
|
||||
/>
|
||||
<>
|
||||
<Dropdown
|
||||
classes="mb-3"
|
||||
context="count"
|
||||
id="icon-range-selector"
|
||||
label="Select a range"
|
||||
options={countOptions || []}
|
||||
onSelectionChanged={(data: BasicFilterConfig) => {
|
||||
onLocalFilterChange(data, "count")
|
||||
}}
|
||||
/>
|
||||
<Pillbox
|
||||
classes="mb-3"
|
||||
data={flatFilters}
|
||||
onChange={onLocalFilterChange}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<Pillbox
|
||||
classes="mb-3"
|
||||
data={flatFilters}
|
||||
onChange={onLocalFilterChange}
|
||||
/>
|
||||
{config.alphabet && (
|
||||
<AlphabetFilter onSelectionChanged={onLocalFilterChange} />
|
||||
)}
|
||||
@@ -156,6 +170,13 @@ const Filters = (props: FiltersProps): JSX.Element => {
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<Tags
|
||||
clickHandler={clickHandler}
|
||||
classes="col-12 h-75"
|
||||
label={"test"}
|
||||
tags={config.tags}
|
||||
hideHeader
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,20 +7,26 @@ export const ICON_ROOT = `${
|
||||
|
||||
export const SESSION_COOKIE_NAME = "x-access-token"
|
||||
|
||||
export const DEFAULT_LOCALE = {
|
||||
direction: "ltr",
|
||||
format: moment.localeData().longDateFormat("L"),
|
||||
separator: " - ",
|
||||
applyLabel: "Apply",
|
||||
cancelLabel: "Cancel",
|
||||
weekLabel: "W",
|
||||
customRangeLabel: "Custom Range",
|
||||
daysOfWeek: moment.weekdaysMin(),
|
||||
monthNames: moment.monthsShort(),
|
||||
firstDay: moment.localeData().firstDayOfWeek(),
|
||||
}
|
||||
// export const DEFAULT_LOCALE = {
|
||||
// direction: "ltr",
|
||||
// format: moment.localeData().longDateFormat("L"),
|
||||
// separator: " - ",
|
||||
// applyLabel: "Apply",
|
||||
// cancelLabel: "Cancel",
|
||||
// weekLabel: "W",
|
||||
// customRangeLabel: "Custom Range",
|
||||
// daysOfWeek: moment.weekdaysMin(),
|
||||
// monthNames: moment.monthsShort(),
|
||||
// firstDay: moment.localeData().firstDayOfWeek(),
|
||||
// }
|
||||
|
||||
export const ENDPOINTS = {
|
||||
STATIC: {
|
||||
ICON: {
|
||||
ROOT: "/icon",
|
||||
PAGE: "/page",
|
||||
},
|
||||
},
|
||||
USERS: {
|
||||
ROOT: "/secure/users",
|
||||
ADD: "/add",
|
||||
|
||||
@@ -1,9 +1,28 @@
|
||||
import FontsList from "../../components/FontsList"
|
||||
import Main from "../../components/Main"
|
||||
import Footer from "../../components/Footer"
|
||||
import "./FontsPage.page.scss"
|
||||
|
||||
interface FontsPageProps {}
|
||||
|
||||
const FontsPage = (props: FontsPageProps): JSX.Element => {
|
||||
return <div className="ar-FontsPage">Be Here Soon</div>
|
||||
return (
|
||||
<div className="ar-FontsPage">
|
||||
<Main
|
||||
contentClasses="p-2"
|
||||
mainContent={
|
||||
<FontsList
|
||||
icons={[]}
|
||||
onSearchChanged={() => {}}
|
||||
// searchString={searchText}
|
||||
/>
|
||||
}
|
||||
// rightPanelContent={rightPanelContent}
|
||||
// rightPanelHeader="Favorites"
|
||||
/>
|
||||
<Footer />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default FontsPage
|
||||
|
||||
@@ -4,6 +4,7 @@ import { IconTileProps } from "../../types/components.interface"
|
||||
|
||||
export interface IconsPageState {
|
||||
favorites: Array<IconTileProps>
|
||||
selectedTag?: string
|
||||
}
|
||||
|
||||
const initialState: IconsPageState = {
|
||||
@@ -20,11 +21,16 @@ export const iconsPageSlice = createSlice({
|
||||
removeFavorite: (state, action: PayloadAction<IconTileProps>) => {
|
||||
state.favorites.splice(state.favorites.indexOf(action.payload))
|
||||
},
|
||||
selectTag: (state, action: PayloadAction<string>) => {
|
||||
state.selectedTag = action.payload
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export const { setFavorites, removeFavorite } = iconsPageSlice.actions
|
||||
export const { selectTag, setFavorites, removeFavorite } =
|
||||
iconsPageSlice.actions
|
||||
|
||||
export const getFavorites = (state: RootState) => state.iconsPage.favorites
|
||||
export const getSelectedTag = (state: RootState) => state.iconsPage.selectedTag
|
||||
|
||||
export default iconsPageSlice.reducer
|
||||
|
||||
@@ -6,21 +6,22 @@ import Footer from "../../components/Footer"
|
||||
import Main from "../../components/Main"
|
||||
import IconsList from "../../components/IconsList"
|
||||
import { ObjectType } from "../../types/types"
|
||||
import { FilterState } from "../../types/filterconfig"
|
||||
import Network from "../../utils/network"
|
||||
import Helper from "../../utils/helper"
|
||||
import "./IconsPage.page.scss"
|
||||
|
||||
interface IconsPageProps {}
|
||||
|
||||
const fetchData = async (setIcons: Function) => {
|
||||
const fetchData = async (api: string, cb: Function) => {
|
||||
const response: { status: number; body: Array<IconResponse> } =
|
||||
await Network.getStatic("/icon/all", null, null)
|
||||
setIcons(response.body)
|
||||
await Network.getStatic(api, null, null)
|
||||
cb && cb(response.body)
|
||||
}
|
||||
|
||||
const IconsPage = (props: IconsPageProps): JSX.Element => {
|
||||
const [icons, setIcons] = useState<Array<IconResponse> | undefined>()
|
||||
// const [icons, setIcons] = useState<Array<IconResponse> | undefined>()
|
||||
const [searchText, setSearchText] = useState<string | undefined>()
|
||||
const [tags, setTags] = useState<ObjectType>()
|
||||
const [filteredIcons, setFilteredIcons] = useState<
|
||||
Array<IconResponse> | undefined
|
||||
>()
|
||||
@@ -34,62 +35,70 @@ const IconsPage = (props: IconsPageProps): JSX.Element => {
|
||||
getRightPanelContent,
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
!icons && fetchData(setIcons)
|
||||
}, [icons])
|
||||
// useEffect(() => {
|
||||
// !icons && fetchData("/icon/all", setIcons)
|
||||
// }, [icons])
|
||||
|
||||
useEffect(() => {
|
||||
if (icons) {
|
||||
let finalFilteredIconList: Array<IconResponse> | undefined = icons
|
||||
if (searchText) {
|
||||
finalFilteredIconList = Helper.recrusiveFilter(
|
||||
finalFilteredIconList,
|
||||
searchText,
|
||||
false,
|
||||
["name"],
|
||||
)
|
||||
}
|
||||
if (filters && finalFilteredIconList) {
|
||||
const alphabet =
|
||||
filters.alphabet &&
|
||||
(filters.alphabet as Array<BasicFilterConfig>).length > 0 &&
|
||||
(filters.alphabet as Array<BasicFilterConfig>).map(
|
||||
(al: BasicFilterConfig) => al.value,
|
||||
)
|
||||
finalFilteredIconList = Helper.matchArrayFilters(
|
||||
finalFilteredIconList,
|
||||
alphabet,
|
||||
"name",
|
||||
"starts",
|
||||
)
|
||||
|
||||
const categories = filters.categories && filters.categories
|
||||
|
||||
if (categories) {
|
||||
Object.keys(categories).forEach((category) => {
|
||||
const categoryValue = categories[category as keyof BasicFilterType]
|
||||
if ((categoryValue as Array<ObjectType>).length > 0) {
|
||||
finalFilteredIconList = Helper.matchArrayFilters(
|
||||
finalFilteredIconList,
|
||||
categoryValue,
|
||||
"group",
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const countFilter =
|
||||
filters.count && "data" in filters.count && filters.count.data
|
||||
if (countFilter) {
|
||||
finalFilteredIconList = finalFilteredIconList?.slice(
|
||||
"startIndex" in countFilter ? +countFilter.startIndex : 0,
|
||||
"endIndex" in countFilter ? +countFilter.endIndex : 0,
|
||||
)
|
||||
}
|
||||
}
|
||||
setFilteredIcons(finalFilteredIconList)
|
||||
const variant = "gt100"
|
||||
const parseTags = (tagReponse: ObjectType) => {
|
||||
setTags(tagReponse[variant] as ObjectType)
|
||||
}
|
||||
}, [filters, icons, searchText])
|
||||
!tags && fetchData(`/icon/tag/all?variants=${variant}`, parseTags)
|
||||
}, [tags])
|
||||
|
||||
// useEffect(() => {
|
||||
// if (icons) {
|
||||
// let finalFilteredIconList: Array<IconResponse> | undefined = icons
|
||||
// if (searchText) {
|
||||
// finalFilteredIconList = Helper.recrusiveFilter(
|
||||
// finalFilteredIconList,
|
||||
// searchText,
|
||||
// false,
|
||||
// ["name"],
|
||||
// )
|
||||
// }
|
||||
// if (filters && finalFilteredIconList) {
|
||||
// const alphabet =
|
||||
// filters.alphabet &&
|
||||
// (filters.alphabet as Array<BasicFilterConfig>).length > 0 &&
|
||||
// (filters.alphabet as Array<BasicFilterConfig>).map(
|
||||
// (al: BasicFilterConfig) => al.value,
|
||||
// )
|
||||
// finalFilteredIconList = Helper.matchArrayFilters(
|
||||
// finalFilteredIconList,
|
||||
// alphabet,
|
||||
// "name",
|
||||
// "starts",
|
||||
// )
|
||||
|
||||
// const categories = filters.categories && filters.categories
|
||||
|
||||
// if (categories) {
|
||||
// Object.keys(categories).forEach((category) => {
|
||||
// const categoryValue = categories[category as keyof BasicFilterType]
|
||||
// if ((categoryValue as Array<ObjectType>).length > 0) {
|
||||
// finalFilteredIconList = Helper.matchArrayFilters(
|
||||
// finalFilteredIconList,
|
||||
// categoryValue,
|
||||
// "group",
|
||||
// )
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
// const countFilter =
|
||||
// filters.count && "data" in filters.count && filters.count.data
|
||||
// if (countFilter) {
|
||||
// finalFilteredIconList = finalFilteredIconList?.slice(
|
||||
// "startIndex" in countFilter ? +countFilter.startIndex : 0,
|
||||
// "endIndex" in countFilter ? +countFilter.endIndex : 0,
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// setFilteredIcons(finalFilteredIconList)
|
||||
// }
|
||||
// }, [filters, icons, searchText])
|
||||
|
||||
return (
|
||||
<div className="ar-IconsPage d-flex flex-column">
|
||||
@@ -97,15 +106,25 @@ const IconsPage = (props: IconsPageProps): JSX.Element => {
|
||||
contentClasses="p-2"
|
||||
drawerContent={
|
||||
<Filters
|
||||
config={{ count: 1000, alphabet: true, categories: ["group"] }}
|
||||
data={icons}
|
||||
config={{
|
||||
// count: 1000,
|
||||
// alphabet: true,
|
||||
// categories: ["group"],
|
||||
tags,
|
||||
}}
|
||||
// config={{ tags }}
|
||||
// data={icons}
|
||||
filteredData={filteredIcons}
|
||||
initialFilters={filters}
|
||||
onFilterChange={setFilters}
|
||||
/>
|
||||
}
|
||||
mainContent={
|
||||
<IconsList icons={filteredIcons} onSearchChanged={setSearchText} />
|
||||
<IconsList
|
||||
icons={filteredIcons}
|
||||
onSearchChanged={setSearchText}
|
||||
searchString={searchText}
|
||||
/>
|
||||
}
|
||||
rightPanelContent={rightPanelContent}
|
||||
// rightPanelHeader="Favorites"
|
||||
|
||||
@@ -169,4 +169,12 @@ label.required:after {
|
||||
|
||||
.bg {
|
||||
background-color: var(--ar-bg);
|
||||
}
|
||||
|
||||
.top-1 {
|
||||
top: 1rem;
|
||||
}
|
||||
|
||||
.end-1 {
|
||||
right: 1rem;
|
||||
}
|
||||
@@ -15,6 +15,8 @@ import {
|
||||
ArButtonVariants,
|
||||
ArIconTileTypes,
|
||||
ArLoaderTypes,
|
||||
ArPageTriggers,
|
||||
ArPillSizes,
|
||||
ArPlacement,
|
||||
ArPopoverPositions,
|
||||
ArPopoverTriggers,
|
||||
@@ -26,6 +28,7 @@ import {
|
||||
FrameContentDefinition,
|
||||
Locale,
|
||||
Namespace,
|
||||
PageInfoType,
|
||||
Task,
|
||||
ToolItemConfig,
|
||||
TreeListData,
|
||||
@@ -72,6 +75,14 @@ export interface FormInputProps extends BaseProps {
|
||||
}
|
||||
|
||||
/* PLOP_INJECT_INTERFACE */
|
||||
export interface FontsListProps extends BaseProps {
|
||||
}
|
||||
|
||||
export interface BubbleChartProps extends BaseProps {
|
||||
clickHandler?: FunctionType
|
||||
data: Array<ObjectType>
|
||||
}
|
||||
|
||||
export interface CronTabProps extends BaseProps {
|
||||
onChange: FunctionType
|
||||
value?: ObjectType | string
|
||||
@@ -224,6 +235,7 @@ export interface BubbleVizProps extends BaseProps {
|
||||
}
|
||||
|
||||
export interface ArVizProps extends BaseProps {
|
||||
clickHandler?: FunctionType
|
||||
type: ArVisualizationTypes
|
||||
data: ArrayType | ObjectType
|
||||
}
|
||||
@@ -242,7 +254,10 @@ export interface IconControllerProps extends BaseProps {
|
||||
}
|
||||
|
||||
export interface TagsProps extends BaseProps {
|
||||
clickHandler?: FunctionType
|
||||
hideHeader?: boolean
|
||||
label?: string
|
||||
tags?: ObjectType
|
||||
}
|
||||
|
||||
export interface ColorSelectorProps extends BaseProps {
|
||||
@@ -423,12 +438,14 @@ export type SliderProps = { focussed?: boolean } & TextInputProps
|
||||
export interface IconsListProps extends BaseProps {
|
||||
icons?: Array<IconResponse>
|
||||
onSearchChanged: Function
|
||||
searchString?: string
|
||||
}
|
||||
|
||||
export interface IconTileProps extends BaseProps {
|
||||
hideBorder?: boolean
|
||||
hideFooter?: boolean
|
||||
icon: IconResponse
|
||||
iconSize?: string
|
||||
onClick?: Function
|
||||
tools?: Array<ToolItemConfig>
|
||||
toolsPlacement?: string
|
||||
@@ -448,9 +465,23 @@ export interface ButtonProps extends BaseProps {
|
||||
splitTrigger?: ArPopoverTriggers
|
||||
}
|
||||
|
||||
export interface DrawerProps {
|
||||
children?: ReactNode
|
||||
classes?: string
|
||||
isCollapsible?: boolean
|
||||
}
|
||||
|
||||
export interface PaginationProps extends BaseProps {
|
||||
data: Array<{ [key: string]: string | number }>
|
||||
count: number
|
||||
isHeadless?: boolean
|
||||
load: number
|
||||
trigger?: ArPageTriggers
|
||||
maxPillsToShow?: number
|
||||
pageSetter?: FunctionType
|
||||
pageSize?: number
|
||||
// data?: Array<{ [key: string]: string | number }>
|
||||
data?: Array<PageItem>
|
||||
dataFetcher?: FunctionType
|
||||
}
|
||||
|
||||
export interface HeaderProps {
|
||||
@@ -529,7 +560,7 @@ export interface DropdownProps extends FormInputProps {
|
||||
id?: string
|
||||
label?: string
|
||||
onSelectionChanged: Function
|
||||
options: Array<{ [key: string]: string | number }>
|
||||
options?: Array<PageInfoType>
|
||||
}
|
||||
|
||||
export interface ModalProps {
|
||||
@@ -639,3 +670,12 @@ export interface DateProps extends FormInputProps {
|
||||
}
|
||||
|
||||
export interface CardProps extends BaseProps {}
|
||||
|
||||
export interface SelectionPillProps extends BaseProps {
|
||||
context?: string
|
||||
data: PageInfoType
|
||||
disabled?: boolean
|
||||
onClick: Function
|
||||
selected?: boolean
|
||||
size?: ArPillSizes
|
||||
}
|
||||
|
||||
@@ -121,3 +121,11 @@ export interface CronType {
|
||||
week: string
|
||||
month: string
|
||||
}
|
||||
|
||||
export interface PageInfoType {
|
||||
label: string | JSX.Element
|
||||
name?: string
|
||||
sliceIndex?: number
|
||||
startIndex?: number
|
||||
endIndex?: number
|
||||
}
|
||||
|
||||
@@ -115,3 +115,14 @@ export enum JobStatus {
|
||||
SUSPENDED = "suspended",
|
||||
ARCHIVED = "archived",
|
||||
}
|
||||
|
||||
export enum ArPageTriggers {
|
||||
SELECTOR = "selector",
|
||||
SCROLL = "scroll",
|
||||
}
|
||||
|
||||
export enum ArPillSizes {
|
||||
LARGE = "large",
|
||||
MEDIUM = "medium",
|
||||
SMALL = "small",
|
||||
}
|
||||
|
||||
13
src/app/types/filterconfig.d.ts
vendored
13
src/app/types/filterconfig.d.ts
vendored
@@ -1,15 +1,18 @@
|
||||
interface BasicFilterConfig {
|
||||
import { ObjectType } from "./types"
|
||||
|
||||
export interface BasicFilterConfig {
|
||||
value: string
|
||||
data?: { [key: string]: string | number }
|
||||
}
|
||||
|
||||
interface FilterConfig {
|
||||
export interface FilterConfig {
|
||||
count?: number
|
||||
alphabet?: boolean
|
||||
categories?: Array<string>
|
||||
tags?: ObjectType
|
||||
}
|
||||
|
||||
interface FiltersProps {
|
||||
export interface FiltersProps {
|
||||
data?: Array<any>
|
||||
filteredData?: Array<any>
|
||||
config: FilterConfig
|
||||
@@ -17,13 +20,13 @@ interface FiltersProps {
|
||||
onFilterChange: Function
|
||||
}
|
||||
|
||||
interface FilterState {
|
||||
export interface FilterState {
|
||||
count?: BasicFilterType
|
||||
alphabet?: BasicFilterType
|
||||
categories?: BasicFilterType
|
||||
}
|
||||
|
||||
type BasicFilterType =
|
||||
export type BasicFilterType =
|
||||
| { [key: string]: Array<BasicFilterConfig> }
|
||||
| BasicFilterConfig
|
||||
| Array<BasicFilterConfig>
|
||||
|
||||
5
src/app/types/iconresponse.d.ts
vendored
5
src/app/types/iconresponse.d.ts
vendored
@@ -1,7 +1,10 @@
|
||||
interface IconResponse {
|
||||
interface PageItem {}
|
||||
|
||||
interface IconResponse extends PageItem {
|
||||
name: string
|
||||
group: string
|
||||
svg: string
|
||||
icon: string
|
||||
tags?: Array<string>
|
||||
description?: string
|
||||
message?: string
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { lazy } from "react"
|
||||
import { FunctionType } from "../types/types"
|
||||
import { PageInfoType } from "../types/entity.interface"
|
||||
|
||||
class Helper {
|
||||
static populatePagesInRoutes(routes: RouteConfig[]) {
|
||||
@@ -87,7 +88,7 @@ class Helper {
|
||||
) {
|
||||
let i = 0,
|
||||
j = 0
|
||||
const slices = []
|
||||
const slices: Array<PageInfoType> = []
|
||||
while (i < count) {
|
||||
let addUp = sliceLength
|
||||
if (i + sliceLength > count) {
|
||||
|
||||
@@ -137,13 +137,17 @@ export default class Network {
|
||||
}
|
||||
|
||||
static stringifyUrl(url: string, queryParams?: any) {
|
||||
if (!queryParams) {
|
||||
return url || ""
|
||||
}
|
||||
const arrLength = Object.keys(queryParams).length
|
||||
return url
|
||||
? queryParams
|
||||
? Object.keys(queryParams).reduce(
|
||||
(acc, key) => acc.concat(`${key}=${queryParams[key]}`),
|
||||
url + "?",
|
||||
)
|
||||
: url
|
||||
? Object.keys(queryParams).reduce(
|
||||
(acc, key, index) =>
|
||||
acc.concat(`${key}=${queryParams[key]}`) +
|
||||
(index < arrLength - 1 ? "&" : ""),
|
||||
url + "?",
|
||||
)
|
||||
: ""
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user