mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-02 20:25:47 +00:00
Added a basic framework for activity logs
This commit is contained in:
@@ -4,6 +4,7 @@ import { useEffect, useState } from 'react';
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import {
|
import {
|
||||||
|
faBook,
|
||||||
faBookOpen,
|
faBookOpen,
|
||||||
faGear,
|
faGear,
|
||||||
faKey,
|
faKey,
|
||||||
@@ -150,6 +151,11 @@ export default function Layout({ children }: LayoutProps) {
|
|||||||
title: 'Integrations',
|
title: 'Integrations',
|
||||||
emoji: <FontAwesomeIcon icon={faPlug} />
|
emoji: <FontAwesomeIcon icon={faPlug} />
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
href: '/activity/' + workspaceMapping[workspaceSelected as any],
|
||||||
|
title: 'Activity',
|
||||||
|
emoji: <FontAwesomeIcon icon={faBook} />
|
||||||
|
},
|
||||||
{
|
{
|
||||||
href: '/settings/project/' + workspaceMapping[workspaceSelected as any],
|
href: '/settings/project/' + workspaceMapping[workspaceSelected as any],
|
||||||
title: 'Project Settings',
|
title: 'Project Settings',
|
||||||
|
|||||||
@@ -0,0 +1,144 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { useRouter } from 'next/router';
|
||||||
|
import {
|
||||||
|
faAngleDown,
|
||||||
|
faAngleRight,
|
||||||
|
faX
|
||||||
|
} from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
|
||||||
|
import guidGenerator from '../../utilities/randomId';
|
||||||
|
|
||||||
|
interface ActivityTableProps {
|
||||||
|
eventName: string;
|
||||||
|
user: string;
|
||||||
|
source: string;
|
||||||
|
time: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
function timeSince(date: Date) {
|
||||||
|
const seconds = Math.floor(
|
||||||
|
((new Date() as any) - (date as any)) / 1000
|
||||||
|
) as number;
|
||||||
|
|
||||||
|
let interval = seconds / 31536000;
|
||||||
|
|
||||||
|
if (interval > 1) {
|
||||||
|
return Math.floor(interval) + ' years ago';
|
||||||
|
}
|
||||||
|
interval = seconds / 2592000;
|
||||||
|
if (interval > 1) {
|
||||||
|
return Math.floor(interval) + ' months ago';
|
||||||
|
}
|
||||||
|
interval = seconds / 86400;
|
||||||
|
if (interval > 1) {
|
||||||
|
return Math.floor(interval) + ' days ago';
|
||||||
|
}
|
||||||
|
interval = seconds / 3600;
|
||||||
|
if (interval > 1) {
|
||||||
|
return Math.floor(interval) + ' hours ago';
|
||||||
|
}
|
||||||
|
interval = seconds / 60;
|
||||||
|
if (interval > 1) {
|
||||||
|
return Math.floor(interval) + ' minutes ago';
|
||||||
|
}
|
||||||
|
return Math.floor(seconds) + ' seconds ago';
|
||||||
|
}
|
||||||
|
|
||||||
|
const ActivityLogsRow = ({ row }: { row: ActivityTableProps }): JSX.Element => {
|
||||||
|
const [payloadOpened, setPayloadOpened] = useState(false);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<tr
|
||||||
|
key={guidGenerator()}
|
||||||
|
className="bg-bunker-800 duration-100 cursor-pointer w-full"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
onClick={() => setPayloadOpened(!payloadOpened)}
|
||||||
|
className="border-mineshaft-700 border-t text-gray-300 flex items-center"
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={payloadOpened ? faAngleDown : faAngleRight}
|
||||||
|
className={`mt-3.5 ml-6 text-bunker-100 hover:bg-primary-100/[0.15] ${
|
||||||
|
payloadOpened && 'bg-primary-100/10'
|
||||||
|
} p-1 duration-100 h-4 w-4 rounded-md`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<td className="py-3 border-mineshaft-700 border-t text-gray-300">
|
||||||
|
{row.eventName}
|
||||||
|
</td>
|
||||||
|
<td className="pl-6 py-3 border-mineshaft-700 border-t text-gray-300">
|
||||||
|
{row.user}
|
||||||
|
</td>
|
||||||
|
<td className="pl-6 py-3 border-mineshaft-700 border-t text-gray-300">
|
||||||
|
{row.source}
|
||||||
|
</td>
|
||||||
|
<td className="pl-6 py-3 border-mineshaft-700 border-t text-gray-300">
|
||||||
|
{timeSince(row.time)}
|
||||||
|
</td>
|
||||||
|
{/* <td className="py-2 border-mineshaft-700 border-t">
|
||||||
|
<div className="opacity-50 hover:opacity-100 duration-200 flex items-center">
|
||||||
|
<Button
|
||||||
|
onButtonPressed={() => {}}
|
||||||
|
color="red"
|
||||||
|
size="icon-sm"
|
||||||
|
icon={faX}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</td> */}
|
||||||
|
</tr>
|
||||||
|
{payloadOpened && (
|
||||||
|
<tr className="w-full h-10 bg-bunker-700 text-bunker-200 col-span-2">
|
||||||
|
<td colSpan={5} className="">
|
||||||
|
<div className="flex flex-row ml-12 py-2 border-mineshaft-700 border-t">
|
||||||
|
<div className="w-96">Timestamp</div>
|
||||||
|
<div className="w-96">2022-12-16T04:02:44.517Z</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-row ml-12 py-2 border-mineshaft-700 border-t">
|
||||||
|
<div className="w-96">Number of Secrets</div>
|
||||||
|
<div className="w-96">32</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-row ml-12 py-2 border-mineshaft-700 border-t">
|
||||||
|
<div className="w-96">IP Address</div>
|
||||||
|
<div className="w-96">159.223.164.24</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the table for activity logs (one of the tabs)
|
||||||
|
* @param {*} props
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
const ActivityTable = ({ data }: { data: ActivityTableProps[] }) => {
|
||||||
|
return (
|
||||||
|
<div className="w-full px-6 mt-8">
|
||||||
|
<div className="table-container w-full bg-bunker rounded-md mb-6 border border-mineshaft-700 relative">
|
||||||
|
<div className="absolute rounded-t-md w-full h-[3.15rem] bg-white/5"></div>
|
||||||
|
<table className="w-full my-1">
|
||||||
|
<thead className="text-bunker-300">
|
||||||
|
<tr>
|
||||||
|
<th className="text-left pl-6 pt-2.5 pb-3"></th>
|
||||||
|
<th className="text-left pt-2.5 pb-3">Event</th>
|
||||||
|
<th className="text-left pl-6 pt-2.5 pb-3">User</th>
|
||||||
|
<th className="text-left pl-6 pt-2.5 pb-3">Source</th>
|
||||||
|
<th className="text-left pl-6 pt-2.5 pb-3">Time</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{data.map((row, index) => {
|
||||||
|
return <ActivityLogsRow key={index} row={row} />;
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ActivityTable;
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { useRouter } from 'next/router';
|
||||||
|
|
||||||
|
import ActivityTable from '~/components/basic/table/ActivityTable';
|
||||||
|
import NavHeader from '~/components/navigation/NavHeader';
|
||||||
|
import onboardingCheck from '~/components/utilities/checks/OnboardingCheck';
|
||||||
|
|
||||||
|
const data = [
|
||||||
|
{
|
||||||
|
eventName: 'Secrets Pulled',
|
||||||
|
user: '[email protected]',
|
||||||
|
source: 'CLI',
|
||||||
|
time: new Date()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
eventName: 'Secrets Pushed',
|
||||||
|
user: '[email protected]',
|
||||||
|
source: 'Web',
|
||||||
|
time: new Date()
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tab is called Home because in the future it will include some company news,
|
||||||
|
* updates, roadmap, relavant blogs, etc. Currently it only has the setup instruction
|
||||||
|
* for the new users
|
||||||
|
*/
|
||||||
|
export default function Activity() {
|
||||||
|
const router = useRouter();
|
||||||
|
const [hasUserClickedSlack, setHasUserClickedSlack] = useState(false);
|
||||||
|
const [hasUserClickedIntro, setHasUserClickedIntro] = useState(false);
|
||||||
|
const [hasUserStarred, setHasUserStarred] = useState(false);
|
||||||
|
const [hasUserPushedSecrets, setHasUserPushedSecrets] = useState(false);
|
||||||
|
const [usersInOrg, setUsersInOrg] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
onboardingCheck({
|
||||||
|
setHasUserClickedIntro,
|
||||||
|
setHasUserClickedSlack,
|
||||||
|
setHasUserPushedSecrets,
|
||||||
|
setHasUserStarred,
|
||||||
|
setUsersInOrg
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mx-6 lg:mx-0 w-full overflow-y-scroll h-screen">
|
||||||
|
<NavHeader pageName="Project Activity" isProjectRelated={true} />
|
||||||
|
<div className="flex flex-col justify-between items-start mx-4 mt-6 mb-4 text-xl max-w-5xl px-2">
|
||||||
|
<div className="flex flex-row justify-start items-center text-3xl">
|
||||||
|
<p className="font-semibold mr-4 text-bunker-100">Activity Logs</p>
|
||||||
|
</div>
|
||||||
|
<p className="mr-4 text-base text-gray-400">
|
||||||
|
Manage your integrations of Infisical with third-party services.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<ActivityTable data={data} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Activity.requireAuth = true;
|
||||||
Reference in New Issue
Block a user