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: Implement authz overview and revoke (backport #1093) #1108

Open
wants to merge 1 commit into
base: release/v2.x
Choose a base branch
from
Open
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
Binary file added frontend/public/desmos-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/public/no-authz-grants-illustration.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/public/revoke-image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 18 additions & 2 deletions frontend/src/app/(routes)/authz/AuthzPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@ import DialogCreateAuthzGrant from './components/DialogCreateAuthzGrant';

const AuthzPage = ({ chainIDs }: { chainIDs: string[] }) => {
const [isGrantsToMe, setIsGrantsToMe] = useState(true);

const [dialogGrantOpen, setDialogGrantOpen] = useState(false);
const hanldeDialogGrantClose = () => {
const handleDialogGrantClose = () => {
setDialogGrantOpen(false);
};
<<<<<<< HEAD
console.log(chainIDs);
// TODO: dispatch and fetch the grants from authz state
=======

>>>>>>> cc4fb21 (feat: Implement authz overview and revoke (#1093))
return (
<div className="py-6 px-10">
<div className="space-y-10">
Expand Down Expand Up @@ -47,14 +52,25 @@ const AuthzPage = ({ chainIDs }: { chainIDs: string[] }) => {
</div>
</div>
<div>
<<<<<<< HEAD
{/* TODO: Create UI to display grants and render data */}
{isGrantsToMe ? 'Grants to me' : 'Grants by me'}
=======
{isGrantsToMe ? (
<GrantsToMe chainIDs={chainIDs} />
) : (
<GrantsByMe
chainIDs={chainIDs}
handleGrantDialogOpen={() => setDialogGrantOpen(true)}
/>
)}
>>>>>>> cc4fb21 (feat: Implement authz overview and revoke (#1093))
</div>
</div>
</div>
<DialogCreateAuthzGrant
open={dialogGrantOpen}
onClose={hanldeDialogGrantClose}
onClose={handleDialogGrantClose}
/>
</div>
);
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/app/(routes)/authz/[...chainNames]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import { RootState } from '@/store/store';
import { useParams } from 'next/navigation';
import React from 'react';
import AuthzPage from '../AuthzPage';
import '../authz.css'
import '../authz.css';


const Authz = () => {
const params = useParams();

const paramChains = params.chainNames;
const chainNames =
typeof paramChains === 'string' ? [paramChains] : paramChains;
Expand All @@ -31,6 +33,7 @@ const Authz = () => {
- Chain Not found -
</div>
)}

</>
);
};
Expand Down
47 changes: 47 additions & 0 deletions frontend/src/app/(routes)/authz/authz.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,50 @@
.grants-type-btn-selected {
@apply primary-gradient;
}
<<<<<<< HEAD
=======
.authz-card {
@apply flex flex-col items-start gap-4 backdrop-blur-[2px] p-6 rounded-2xl;
background: #0e0b26;

}
.grant-address {
@apply flex items-center gap-2 opacity-80 p-2 rounded-lg;
background: rgba(255, 255, 255, 0.1);
}
.authz-card-grid {
@apply grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6;
}
.authz-permission-card {
@apply flex flex-col items-start gap-6 backdrop-blur-[2px] p-6 rounded-2xl;
background: rgba(255, 255, 255, 0.05);
}
.authz-small-text {
@apply text-[rgba(255,255,255,0.50)] text-sm font-normal leading-[normal]
}


.divider-line {
@apply h-[1px] w-full my-6 bg-[#ffffff35] opacity-50;
}

.error-box {
@apply flex justify-end mt-2 h-[26px];
}

.error-chip {
@apply text-[12px] rounded-lg bg-[#ff00005b] text-white text-center leading-normal max-w-fit py-1 px-2 truncate;
}

.msg-item {
@apply flex-center-center cursor-pointer rounded-2xl px-6 py-4 text-[14px] bg-[#FFFFFF0D];
}

.grant-authz-form {
@apply rounded-2xl bg-[#FFFFFF0D] p-6;
}

.moniker-name-chip {
@apply rounded-2xl font-light text-[14px] bg-[#FFFFFF0D] px-3 py-2 max-w-[120px] truncate;
}
>>>>>>> cc4fb21 (feat: Implement authz overview and revoke (#1093))
186 changes: 186 additions & 0 deletions frontend/src/app/(routes)/authz/components/AuthzCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
import React, { useState } from 'react';
import Image from 'next/image';
import { AuthorizationInfo } from './DialogAllPermissions';
import { useAppDispatch, useAppSelector } from '@/custom-hooks/StateHooks';
import { RootState } from '@/store/store';
import {
getMsgNameFromAuthz,
getTypeURLFromAuthorization,
} from '@/utils/authorizations';

import { copyToClipboard } from '@/utils/copyToClipboard';
import { setError } from '@/store/features/common/commonSlice';
import DialogRevoke from './DialogRevoke';
import useGetChainInfo from '@/custom-hooks/useGetChainInfo';
import { resetTxStatus } from '@/store/features/authz/authzSlice';

const AuthzCard = ({
chainID,
address,
grants,
showCloseIcon = true,
grantee,
granter,
isGrantsByMe = false,
}: {
chainID: string;
address: string;
grants: Authorization[];
showCloseIcon?: boolean;
grantee: string;
granter: string;
isGrantsByMe?: boolean;
}) => {
const networkLogo = useAppSelector(
(state: RootState) => state.wallet.networks[chainID]?.network.logos.menu
);

const nameToChainIDs = useAppSelector(
(state: RootState) => state.wallet.nameToChainIDs
);

const [dialogAllPermissionsOpen, setDialogAllPermissionsOpen] =
useState(false);
const handleDialogAllPermissionsClose = () => {
setDialogAllPermissionsOpen(false);
};

const getChainName = (chainID: string) => {
let chain: string = '';
Object.keys(nameToChainIDs).forEach((chainName) => {
if (nameToChainIDs[chainName] === chainID) chain = chainName;
});
return chain;
};
// const revoke = useAppSelector((state) => state.authz.txAuthzRes);
const dispatch = useAppDispatch();
const { getDenomInfo } = useGetChainInfo();

const { decimals } = getDenomInfo(chainID);
const { displayDenom } = getDenomInfo(chainID);

return (
<div className="authz-card">
<div className="flex space-x-2 items-center text-capitalize">
<Image
className=" rounded-full"
src={networkLogo}
width={32}
height={32}
alt="Network-Logo"
/>
<p>{getChainName(chainID)}</p>
</div>
<div className="authz-small-text">
{isGrantsByMe ? 'Grantee' : 'Granter'}
</div>
<div className="grant-address truncate">
<p>{address}</p>
<Image
onClick={(e) => {
copyToClipboard(address);
dispatch(
setError({
type: 'success',
message: 'Copied',
})
);
e.preventDefault();
e.stopPropagation();
}}
src="/copy.svg"
width={24}
height={24}
alt="copy"
draggable={false}
className="cursor-pointer"
/>
</div>
<div className="authz-small-text">Permissions</div>
<div className="flex flex-wrap gap-6">
{grants.map((permission, permissionIndex) => (
<div key={permissionIndex}>
{permissionIndex > 2 ? null : (
<MessageChip
permission={permission}
granter={granter}
grantee={grantee}
chainID={chainID}
showCloseIcon={showCloseIcon}
/>
)}
</div>
))}
</div>
<div className="">
<button
className="create-grant-btn mt-4"
onClick={() => setDialogAllPermissionsOpen(true)}
>
View Details
</button>
</div>
<AuthorizationInfo
open={dialogAllPermissionsOpen}
onClose={handleDialogAllPermissionsClose}
authorization={grants}
displayDenom={displayDenom}
decimal={decimals}
chainID={chainID}
granter={granter}
grantee={grantee}
/>
</div>
);
};

export default AuthzCard;

const MessageChip = ({
permission,
granter,
grantee,
chainID,
showCloseIcon,
}: {
permission: Authorization;
granter: string;
grantee: string;
chainID: string;
showCloseIcon: boolean;
}) => {
const [dialogRevokeOpen, setDialogRevokeOpen] = useState(false);
const dispatch = useAppDispatch();
const handleDialogRevokeClose = () => {
setDialogRevokeOpen(false);
};
return (
<div>
<p className="grant-address">
{getMsgNameFromAuthz(permission)}
{showCloseIcon && (
<Image
src="/close-icon.svg"
width={16}
height={16}
alt="close-icon"
draggable={false}
className="cursor-pointer"
onClick={() => {
setDialogRevokeOpen(true);
dispatch(resetTxStatus({ chainID: chainID }));
}}
/>
)}
</p>
<DialogRevoke
open={dialogRevokeOpen}
onClose={handleDialogRevokeClose}
chainID={chainID}
grantee={grantee}
granter={granter}
typeURL={getTypeURLFromAuthorization(permission)}
/>
</div>
);
};
Loading
Loading