implement fetching apps from BE
impl install modal
This commit is contained in:
parent
a3adcfc3da
commit
5b728d35d7
24 changed files with 649 additions and 163 deletions
|
|
@ -1,19 +1,104 @@
|
|||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import React, { useState, useCallback, useMemo } from 'react';
|
||||
import React, { useState, useCallback, useMemo, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router';
|
||||
import { SearchIcon } from '@heroicons/react/solid';
|
||||
import _, { debounce } from 'lodash';
|
||||
import { Table } from 'src/components';
|
||||
import { columns, data } from './consts';
|
||||
import { appAccessList } from 'src/components/UserModal/consts';
|
||||
import { App, AppStatus, useApps } from 'src/services/apps';
|
||||
import { AppInstallModal } from './components';
|
||||
import { getConstForStatus } from './consts';
|
||||
|
||||
export const Apps: React.FC = () => {
|
||||
const [search, setSearch] = useState('');
|
||||
const [installModalOpen, setInstallModalOpen] = useState(false);
|
||||
const [appSlug, setAppSlug] = useState(null);
|
||||
const { apps, appTableLoading, loadApps } = useApps();
|
||||
|
||||
const handleSearch = useCallback((event: any) => {
|
||||
setSearch(event.target.value);
|
||||
}, []);
|
||||
|
||||
const debouncedSearch = useCallback(debounce(handleSearch, 250), []);
|
||||
|
||||
useEffect(() => {
|
||||
loadApps();
|
||||
|
||||
return () => {
|
||||
debouncedSearch.cancel();
|
||||
};
|
||||
}, []);
|
||||
|
||||
const filterSearch = useMemo(() => {
|
||||
return data.filter((item: any) => item.name?.toLowerCase().includes(search.toLowerCase()));
|
||||
}, [search]);
|
||||
return _.filter(apps, (item) => item.name?.toLowerCase().includes(search.toLowerCase()));
|
||||
}, [apps, search]);
|
||||
|
||||
const columns: any = [
|
||||
{
|
||||
Header: 'Name',
|
||||
accessor: 'name',
|
||||
Cell: (e: any) => {
|
||||
const app = e.cell.row.original as App;
|
||||
const imageSrc = _.find(appAccessList, { name: app.slug })?.image;
|
||||
return (
|
||||
<div className="flex items-center">
|
||||
<div className="flex-shrink-0 h-10 w-10">
|
||||
<img className="h-10 w-10 rounded-md overflow-hidden" src={imageSrc} alt={app.name} />
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<div className="text-sm font-medium text-gray-900">{app.name}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
width: 'auto',
|
||||
},
|
||||
{
|
||||
Header: 'Status',
|
||||
accessor: 'status',
|
||||
Cell: (e: any) => {
|
||||
const status = e.cell.row.original.status as AppStatus;
|
||||
return (
|
||||
<div className="flex items-center">
|
||||
<div className={`flex-shrink-0 h-4 w-4 rounded-full bg-${getConstForStatus(status, 'colorClass')}`} />
|
||||
<div className={`ml-2 text-sm text-${getConstForStatus(status, 'colorClass')}`}>{status}</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
width: 'auto',
|
||||
},
|
||||
{
|
||||
Header: ' ',
|
||||
Cell: (e: any) => {
|
||||
const navigate = useNavigate();
|
||||
const appStatus = e.cell.row.original.status as AppStatus;
|
||||
if (appStatus === AppStatus.Installing) {
|
||||
return null;
|
||||
}
|
||||
const { slug } = e.cell.row.original;
|
||||
let buttonFuntion = () => navigate(`/apps/${slug}`);
|
||||
if (appStatus === AppStatus.NotInstalled) {
|
||||
buttonFuntion = () => {
|
||||
setAppSlug(slug);
|
||||
setInstallModalOpen(true);
|
||||
};
|
||||
}
|
||||
return (
|
||||
<div className="text-right opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<button
|
||||
onClick={buttonFuntion}
|
||||
type="button"
|
||||
className="inline-flex items-center px-4 py-2 border border-gray-200 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500"
|
||||
>
|
||||
{getConstForStatus(appStatus, 'buttonIcon')}
|
||||
{getConstForStatus(appStatus, 'buttonTitle')}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
width: 'auto',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
|
|
@ -51,12 +136,18 @@ export const Apps: React.FC = () => {
|
|||
<div className="-my-2 sm:-mx-6 lg:-mx-8">
|
||||
<div className="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8">
|
||||
<div className="shadow border-b border-gray-200 sm:rounded-lg">
|
||||
<Table data={filterSearch} columns={columns} />
|
||||
<Table
|
||||
data={_.filter(filterSearch, (app) => app.slug !== 'dashboard') as any}
|
||||
columns={columns}
|
||||
loading={appTableLoading}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<AppInstallModal appSlug={appSlug} onClose={() => setInstallModalOpen(false)} open={installModalOpen} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Reference in a new issue