feat(ui): changed back to relative time distance with tooltip of detailed time

This commit is contained in:
Akhil Mohan
2024-03-29 22:36:46 +05:30
parent 31ad6b0c86
commit 00f2d40803
6 changed files with 184 additions and 106 deletions

View File

@ -49,6 +49,7 @@ const MAX_ROLES_TO_BE_SHOWN_IN_TABLE = 2;
const formatRoleName = (role: string, customRoleName?: string) => {
if (role === ProjectMembershipRole.Custom) return customRoleName;
if (role === ProjectMembershipRole.Member) return "Developer";
if (role === ProjectMembershipRole.NoAccess) return "No access";
return role;
};
export const IdentityTab = withProjectPermission(
@ -173,7 +174,9 @@ export const IdentityTab = withProjectPermission(
return (
<Tag key={roleId}>
<div className="flex items-center space-x-2">
<div>{formatRoleName(role, customRoleName)}</div>
<div className="capitalize">
{formatRoleName(role, customRoleName)}
</div>
{isTemporary && (
<div>
<Tooltip

View File

@ -1,8 +1,9 @@
/* eslint-disable no-nested-ternary */
import { Controller, useFieldArray, useForm } from "react-hook-form";
import { faCaretDown, faClock, faPlus, faTrash } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { zodResolver } from "@hookform/resolvers/zod";
import { format } from "date-fns";
import { format, formatDistance } from "date-fns";
import ms from "ms";
import { twMerge } from "tailwind-merge";
import { z } from "zod";
@ -21,7 +22,8 @@ import {
Select,
SelectItem,
Spinner,
Tag
Tag,
Tooltip
} from "@app/components/v2";
import {
ProjectPermissionActions,
@ -182,24 +184,41 @@ export const IdentityRbacSection = ({ identityProjectMember, onOpenUpgradeModal
/>
<Popover>
<PopoverTrigger disabled={isMemberEditDisabled}>
<Button
variant="outline_bg"
leftIcon={isTemporary ? <FontAwesomeIcon icon={faClock} /> : undefined}
rightIcon={<FontAwesomeIcon icon={faCaretDown} className="ml-2" />}
isDisabled={isMemberEditDisabled}
className={twMerge(
"border-none bg-mineshaft-600 hover:bg-mineshaft-500 py-2.5 capitalize text-xs",
isTemporary && "text-primary",
isExpired && "text-red-600"
)}
>
{!temporaryAccess?.isTemporary
? "Permanent"
: `Expires at ${format(
new Date(temporaryAccess.temporaryAccessEndTime || ""),
"yyyy-MM-dd HH:mm:ss"
)}`}
</Button>
<div>
<Tooltip
content={
temporaryAccess?.isTemporary
? isExpired
? "Timed Access Expired"
: `Until ${format(
new Date(temporaryAccess.temporaryAccessEndTime || ""),
"yyyy-MM-dd HH:mm:ss"
)}`
: "Non expiry access"
}
>
<Button
variant="outline_bg"
leftIcon={isTemporary ? <FontAwesomeIcon icon={faClock} /> : undefined}
rightIcon={<FontAwesomeIcon icon={faCaretDown} className="ml-2" />}
isDisabled={isMemberEditDisabled}
className={twMerge(
"border-none bg-mineshaft-600 py-2.5 text-xs capitalize hover:bg-mineshaft-500",
isTemporary && "text-primary",
isExpired && "text-red-600"
)}
>
{temporaryAccess?.isTemporary
? isExpired
? "Access Expired"
: formatDistance(
new Date(temporaryAccess.temporaryAccessEndTime || ""),
new Date()
)
: "Permanent"}
</Button>
</Tooltip>
</div>
</PopoverTrigger>
<PopoverContent
arrowClassName="fill-gray-600"
@ -279,7 +298,7 @@ export const IdentityRbacSection = ({ identityProjectMember, onOpenUpgradeModal
</Popover>
<IconButton
variant="outline_bg"
className="border border-mineshaft-500 bg-mineshaft-600 hover:bg-red/20 hover:border-red/70 py-3"
className="border border-mineshaft-500 bg-mineshaft-600 py-3 hover:border-red/70 hover:bg-red/20"
ariaLabel="delete-role"
isDisabled={isMemberEditDisabled}
onClick={() => {
@ -324,7 +343,7 @@ export const IdentityRbacSection = ({ identityProjectMember, onOpenUpgradeModal
)}
isLoading={roleForm.formState.isSubmitting}
>
Save Roles
Save Roles
</Button>
</div>
</form>

View File

@ -1,8 +1,15 @@
import { Controller, useForm } from "react-hook-form";
import { faArrowRotateLeft, faCaretDown, faCheck, faClock, faPlus, faTrash } from "@fortawesome/free-solid-svg-icons";
import {
faArrowRotateLeft,
faCaretDown,
faCheck,
faClock,
faPlus,
faTrash
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { zodResolver } from "@hookform/resolvers/zod";
import { format } from "date-fns";
import { format, formatDistance } from "date-fns";
import ms from "ms";
import { twMerge } from "tailwind-merge";
import { z } from "zod";
@ -173,10 +180,15 @@ const SpecificPrivilegeSecretForm = ({
}
};
const getAccessLabel = () => {
const getAccessLabel = (exactTime = false) => {
if (isExpired) return "Access expired";
if (!temporaryAccessField?.isTemporary) return "Permanent";
return `Until ${format(new Date(temporaryAccessField.temporaryAccessEndTime || ""), "yyyy-MM-dd HH:mm:ss")}`;
if (exactTime)
return `Until ${format(
new Date(temporaryAccessField.temporaryAccessEndTime || ""),
"yyyy-MM-dd HH:mm:ss"
)}`;
return formatDistance(new Date(temporaryAccessField.temporaryAccessEndTime || ""), new Date());
};
return (
@ -281,24 +293,23 @@ const SpecificPrivilegeSecretForm = ({
<div className="mt-7 flex items-center space-x-2">
<Popover>
<PopoverTrigger disabled={isMemberEditDisabled}>
<Tooltip
asChild
content={isExpired ? "Timed access expired" : "Grant timed access"}
>
<Button
variant="outline_bg"
isDisabled={isMemberEditDisabled}
leftIcon={isTemporary ? <FontAwesomeIcon icon={faClock} /> : undefined}
rightIcon={<FontAwesomeIcon icon={faCaretDown} className="ml-2" />}
className={twMerge(
"border-none py-2.5 capitalize text-xs hover:bg-mineshaft-500",
isTemporary && "text-primary",
isExpired && "text-red-600"
)}
>
{getAccessLabel()}
</Button>
</Tooltip>
<div>
<Tooltip content={getAccessLabel(true)}>
<Button
variant="outline_bg"
leftIcon={isTemporary ? <FontAwesomeIcon icon={faClock} /> : undefined}
rightIcon={<FontAwesomeIcon icon={faCaretDown} className="ml-2" />}
isDisabled={isMemberEditDisabled}
className={twMerge(
"border-none bg-mineshaft-600 py-2.5 text-xs capitalize hover:bg-mineshaft-500",
isTemporary && "text-primary",
isExpired && "text-red-600"
)}
>
{getAccessLabel()}
</Button>
</Tooltip>
</div>
</PopoverTrigger>
<PopoverContent
arrowClassName="fill-gray-600"
@ -381,7 +392,7 @@ const SpecificPrivilegeSecretForm = ({
<Tooltip content="Cancel" className="mr-4">
<IconButton
variant="outline_bg"
className="border border-mineshaft-500 bg-mineshaft-600 hover:bg-red/20 hover:border-red/70 py-2.5"
className="border border-mineshaft-500 bg-mineshaft-600 py-2.5 hover:border-red/70 hover:bg-red/20"
ariaLabel="delete-privilege"
isDisabled={privilegeForm.formState.isSubmitting}
onClick={() => privilegeForm.reset()}
@ -389,7 +400,10 @@ const SpecificPrivilegeSecretForm = ({
<FontAwesomeIcon icon={faArrowRotateLeft} className="py-0.5" />
</IconButton>
</Tooltip>
<Tooltip content={isMemberEditDisabled ? "Access restricted" : "Save"} className="mr-4">
<Tooltip
content={isMemberEditDisabled ? "Access restricted" : "Save"}
className="mr-4"
>
<IconButton
isDisabled={isMemberEditDisabled}
className="border-none py-3"
@ -397,19 +411,22 @@ const SpecificPrivilegeSecretForm = ({
type="submit"
>
{privilegeForm.formState.isSubmitting ? (
<Spinner size="xs" className="m-0 text-slate-500 w-3 h-3" />
<Spinner size="xs" className="m-0 h-3 w-3 text-slate-500" />
) : (
<FontAwesomeIcon icon={faCheck} className="px-0.5"/>
<FontAwesomeIcon icon={faCheck} className="px-0.5" />
)}
</IconButton>
</Tooltip>
</>
) : (
<Tooltip content={isMemberEditDisabled ? "Access restricted" : "Delete"} className="mr-4">
<Tooltip
content={isMemberEditDisabled ? "Access restricted" : "Delete"}
className="mr-4"
>
<IconButton
isDisabled={isMemberEditDisabled}
variant="outline_bg"
className="border border-mineshaft-500 bg-mineshaft-600 hover:bg-red/20 hover:border-red/70 py-3"
className="border border-mineshaft-500 bg-mineshaft-600 py-3 hover:border-red/70 hover:bg-red/20"
ariaLabel="delete-privilege"
onClick={() => handlePopUpOpen("deletePrivilege")}
>
@ -480,7 +497,7 @@ export const SpecificPrivilegeSection = ({ identityId }: Props) => {
Additional Privileges
{isLoading && <Spinner size="xs" />}
</div>
<p className="text-sm text-mineshaft-400 mt-0.5">
<p className="mt-0.5 text-sm text-mineshaft-400">
Select individual privileges to associate with the identity.
</p>
<div>

View File

@ -76,6 +76,7 @@ const MAX_ROLES_TO_BE_SHOWN_IN_TABLE = 2;
const formatRoleName = (role: string, customRoleName?: string) => {
if (role === ProjectMembershipRole.Custom) return customRoleName;
if (role === ProjectMembershipRole.Member) return "Developer";
if (role === ProjectMembershipRole.NoAccess) return "No access";
return role;
};
@ -279,7 +280,9 @@ export const MemberListTab = () => {
return (
<Tag key={id}>
<div className="flex items-center space-x-2">
<div>{formatRoleName(role, customRoleName)}</div>
<div className="capitalize">
{formatRoleName(role, customRoleName)}
</div>
{isTemporary && (
<div>
<Tooltip

View File

@ -1,8 +1,9 @@
/* eslint-disable no-nested-ternary */
import { Controller, useFieldArray, useForm } from "react-hook-form";
import { faCaretDown, faClock, faPlus, faTrash } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { zodResolver } from "@hookform/resolvers/zod";
import { format } from "date-fns";
import { format, formatDistance } from "date-fns";
import ms from "ms";
import { twMerge } from "tailwind-merge";
import { z } from "zod";
@ -21,7 +22,8 @@ import {
Select,
SelectItem,
Spinner,
Tag
Tag,
Tooltip
} from "@app/components/v2";
import {
ProjectPermissionActions,
@ -170,7 +172,7 @@ export const MemberRbacSection = ({ projectMember, onOpenUpgradeModal }: Props)
{...field}
isDisabled={isMemberEditDisabled}
onValueChange={(e) => onChange(e)}
className="w-full bg-mineshaft-600 hover:bg-mineshaft-500 duration-200"
className="w-full bg-mineshaft-600 duration-200 hover:bg-mineshaft-500"
>
{projectRoles?.map(({ name, slug, id: projectRoleId }) => (
<SelectItem value={slug} key={projectRoleId}>
@ -181,25 +183,42 @@ export const MemberRbacSection = ({ projectMember, onOpenUpgradeModal }: Props)
)}
/>
<Popover>
<PopoverTrigger disabled={isMemberEditDisabled}>
<Button
variant="outline_bg"
leftIcon={isTemporary ? <FontAwesomeIcon icon={faClock} /> : undefined}
rightIcon={<FontAwesomeIcon icon={faCaretDown} className="ml-2" />}
isDisabled={isMemberEditDisabled}
className={twMerge(
"border-none bg-mineshaft-600 hover:bg-mineshaft-500 py-2.5 capitalize text-xs",
isTemporary && "text-primary",
isExpired && "text-red-600"
)}
>
{!temporaryAccess?.isTemporary
? "Permanent"
: `Until ${format(
new Date(temporaryAccess.temporaryAccessEndTime || ""),
"yyyy-MM-dd HH:mm:ss"
)}`}
</Button>
<PopoverTrigger disabled={isMemberEditDisabled} asChild>
<div>
<Tooltip
content={
temporaryAccess?.isTemporary
? isExpired
? "Timed Access Expired"
: `Until ${format(
new Date(temporaryAccess.temporaryAccessEndTime || ""),
"yyyy-MM-dd HH:mm:ss"
)}`
: "Non expiry access"
}
>
<Button
variant="outline_bg"
leftIcon={isTemporary ? <FontAwesomeIcon icon={faClock} /> : undefined}
rightIcon={<FontAwesomeIcon icon={faCaretDown} className="ml-2" />}
isDisabled={isMemberEditDisabled}
className={twMerge(
"border-none bg-mineshaft-600 py-2.5 text-xs capitalize hover:bg-mineshaft-500",
isTemporary && "text-primary",
isExpired && "text-red-600"
)}
>
{temporaryAccess?.isTemporary
? isExpired
? "Access Expired"
: formatDistance(
new Date(temporaryAccess.temporaryAccessEndTime || ""),
new Date()
)
: "Permanent"}
</Button>
</Tooltip>
</div>
</PopoverTrigger>
<PopoverContent
arrowClassName="fill-gray-600"
@ -279,7 +298,7 @@ export const MemberRbacSection = ({ projectMember, onOpenUpgradeModal }: Props)
</Popover>
<IconButton
variant="outline_bg"
className="border border-mineshaft-500 bg-mineshaft-600 hover:bg-red/20 hover:border-red/70 py-3"
className="border border-mineshaft-500 bg-mineshaft-600 py-3 hover:border-red/70 hover:bg-red/20"
ariaLabel="delete-role"
isDisabled={isMemberEditDisabled}
onClick={() => {
@ -321,7 +340,7 @@ export const MemberRbacSection = ({ projectMember, onOpenUpgradeModal }: Props)
)}
isLoading={roleForm.formState.isSubmitting}
>
Save Roles
Save Roles
</Button>
</div>
</form>

View File

@ -1,8 +1,15 @@
import { Controller, useForm } from "react-hook-form";
import { faArrowRotateLeft, faCaretDown, faCheck, faClock, faPlus, faTrash } from "@fortawesome/free-solid-svg-icons";
import {
faArrowRotateLeft,
faCaretDown,
faCheck,
faClock,
faPlus,
faTrash
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { zodResolver } from "@hookform/resolvers/zod";
import { format } from "date-fns";
import { format, formatDistance } from "date-fns";
import ms from "ms";
import { twMerge } from "tailwind-merge";
import { z } from "zod";
@ -161,10 +168,15 @@ const SpecificPrivilegeSecretForm = ({ privilege }: { privilege: TProjectUserPri
}
};
const getAccessLabel = () => {
const getAccessLabel = (exactTime = false) => {
if (isExpired) return "Access expired";
if (!temporaryAccessField?.isTemporary) return "Permanent";
return `Until ${format(new Date(temporaryAccessField.temporaryAccessEndTime || ""), "yyyy-MM-dd HH:mm:ss")}`;
if (exactTime)
return `Until ${format(
new Date(temporaryAccessField.temporaryAccessEndTime || ""),
"yyyy-MM-dd HH:mm:ss"
)}`;
return formatDistance(new Date(temporaryAccessField.temporaryAccessEndTime || ""), new Date());
};
return (
@ -269,24 +281,23 @@ const SpecificPrivilegeSecretForm = ({ privilege }: { privilege: TProjectUserPri
<div className="mt-7 flex items-center space-x-2">
<Popover>
<PopoverTrigger disabled={isMemberEditDisabled}>
<Tooltip
asChild
content={isExpired ? "Timed access expired" : "Grant timed access"}
>
<Button
variant="outline_bg"
isDisabled={isMemberEditDisabled}
leftIcon={isTemporary ? <FontAwesomeIcon icon={faClock} /> : undefined}
rightIcon={<FontAwesomeIcon icon={faCaretDown} className="ml-2" />}
className={twMerge(
"border-none py-2.5 capitalize text-xs hover:bg-mineshaft-500",
isTemporary && "text-primary",
isExpired && "text-red-600"
)}
>
{getAccessLabel()}
</Button>
</Tooltip>
<div>
<Tooltip content={getAccessLabel(true)}>
<Button
variant="outline_bg"
leftIcon={isTemporary ? <FontAwesomeIcon icon={faClock} /> : undefined}
rightIcon={<FontAwesomeIcon icon={faCaretDown} className="ml-2" />}
isDisabled={isMemberEditDisabled}
className={twMerge(
"border-none bg-mineshaft-600 py-2.5 text-xs capitalize hover:bg-mineshaft-500",
isTemporary && "text-primary",
isExpired && "text-red-600"
)}
>
{getAccessLabel()}
</Button>
</Tooltip>
</div>
</PopoverTrigger>
<PopoverContent
arrowClassName="fill-gray-600"
@ -369,7 +380,7 @@ const SpecificPrivilegeSecretForm = ({ privilege }: { privilege: TProjectUserPri
<Tooltip content="Cancel" className="mr-4">
<IconButton
variant="outline_bg"
className="border border-mineshaft-500 bg-mineshaft-600 hover:bg-red/20 hover:border-red/70 py-2.5"
className="border border-mineshaft-500 bg-mineshaft-600 py-2.5 hover:border-red/70 hover:bg-red/20"
ariaLabel="delete-privilege"
isDisabled={privilegeForm.formState.isSubmitting}
onClick={() => privilegeForm.reset()}
@ -377,7 +388,10 @@ const SpecificPrivilegeSecretForm = ({ privilege }: { privilege: TProjectUserPri
<FontAwesomeIcon icon={faArrowRotateLeft} className="py-0.5" />
</IconButton>
</Tooltip>
<Tooltip content={isMemberEditDisabled ? "Access restricted" : "Save"} className="mr-4">
<Tooltip
content={isMemberEditDisabled ? "Access restricted" : "Save"}
className="mr-4"
>
<IconButton
isDisabled={isMemberEditDisabled}
className="border-none py-3"
@ -385,19 +399,22 @@ const SpecificPrivilegeSecretForm = ({ privilege }: { privilege: TProjectUserPri
type="submit"
>
{privilegeForm.formState.isSubmitting ? (
<Spinner size="xs" className="m-0 text-slate-500 w-3 h-3" />
<Spinner size="xs" className="m-0 h-3 w-3 text-slate-500" />
) : (
<FontAwesomeIcon icon={faCheck} className="px-0.5"/>
<FontAwesomeIcon icon={faCheck} className="px-0.5" />
)}
</IconButton>
</Tooltip>
</>
) : (
<Tooltip content={isMemberEditDisabled ? "Access restricted" : "Delete"} className="mr-4">
<Tooltip
content={isMemberEditDisabled ? "Access restricted" : "Delete"}
className="mr-4"
>
<IconButton
isDisabled={isMemberEditDisabled}
variant="outline_bg"
className="border border-mineshaft-500 bg-mineshaft-600 hover:bg-red/20 hover:border-red/70 py-3"
className="border border-mineshaft-500 bg-mineshaft-600 py-3 hover:border-red/70 hover:bg-red/20"
ariaLabel="delete-privilege"
onClick={() => handlePopUpOpen("deletePrivilege")}
>
@ -463,7 +480,7 @@ export const SpecificPrivilegeSection = ({ membershipId }: Props) => {
Additional Privileges
{isLoading && <Spinner size="xs" />}
</div>
<p className="text-sm text-mineshaft-400 mt-0.5">
<p className="mt-0.5 text-sm text-mineshaft-400">
Select individual privileges to associate with the user.
</p>
<div>