Feat: Auto-check all assets by default, show unified asset count in table, display read-only inherited assets in modal
This commit is contained in:
parent
d30d8d6b1e
commit
fa781d08f5
@ -59,7 +59,7 @@ export class AuthController {
|
|||||||
}).parse(req.body);
|
}).parse(req.body);
|
||||||
|
|
||||||
const result = await this.authService.updatePartner(partnerId, {
|
const result = await this.authService.updatePartner(partnerId, {
|
||||||
partnerGroup: partnerGroup === null ? undefined : partnerGroup,
|
partnerGroup: (partnerGroup === null || partnerGroup === '') ? null : partnerGroup,
|
||||||
assignedNdaId: assignedNdaId === null ? undefined : assignedNdaId,
|
assignedNdaId: assignedNdaId === null ? undefined : assignedNdaId,
|
||||||
assignedMsaId: assignedMsaId === null ? undefined : assignedMsaId,
|
assignedMsaId: assignedMsaId === null ? undefined : assignedMsaId,
|
||||||
sharedAssetIds,
|
sharedAssetIds,
|
||||||
|
|||||||
@ -137,7 +137,7 @@ export class AuthService {
|
|||||||
return { inviteToken, emailSent, emailError };
|
return { inviteToken, emailSent, emailError };
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updatePartner(partnerId: string, options: { partnerGroup?: string, assignedNdaId?: string, assignedMsaId?: string, sharedAssetIds?: string[], mfaEnabled?: boolean }) {
|
public async updatePartner(partnerId: string, options: { partnerGroup?: string | null, assignedNdaId?: string | null, assignedMsaId?: string | null, sharedAssetIds?: string[], mfaEnabled?: boolean }) {
|
||||||
const user = await prisma.user.findUnique({
|
const user = await prisma.user.findUnique({
|
||||||
where: { id: partnerId }
|
where: { id: partnerId }
|
||||||
});
|
});
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import {
|
|||||||
Copy,
|
Copy,
|
||||||
Trash2,
|
Trash2,
|
||||||
Plus,
|
Plus,
|
||||||
|
Lock,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
@ -154,7 +155,10 @@ export const DirectoryPage: React.FC = () => {
|
|||||||
const [partnerAssetToRemove, setPartnerAssetToRemove] = useState<{ id: string, title: string } | null>(null);
|
const [partnerAssetToRemove, setPartnerAssetToRemove] = useState<{ id: string, title: string } | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getAssets().then(setAllAssets).catch(console.error);
|
getAssets().then((assets) => {
|
||||||
|
setAllAssets(assets);
|
||||||
|
setSelectedAssetIds(assets.map(a => a.id));
|
||||||
|
}).catch(console.error);
|
||||||
getLegalDocuments().then(setAllDocs).catch(console.error);
|
getLegalDocuments().then(setAllDocs).catch(console.error);
|
||||||
getAssetGroups().then(setAssetGroups).catch(console.error);
|
getAssetGroups().then(setAssetGroups).catch(console.error);
|
||||||
}, []);
|
}, []);
|
||||||
@ -560,6 +564,12 @@ export const DirectoryPage: React.FC = () => {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
setInviteResult(null);
|
setInviteResult(null);
|
||||||
setEmail("");
|
setEmail("");
|
||||||
|
setPartnerGroup("");
|
||||||
|
setAssignedNdaId("");
|
||||||
|
setAssignedMsaId("");
|
||||||
|
setMfaRequired(true);
|
||||||
|
setSelectedAssetIds(allAssets.map(a => a.id));
|
||||||
|
setInviteAssetSearch("");
|
||||||
setIsInviteOpen(true);
|
setIsInviteOpen(true);
|
||||||
}}
|
}}
|
||||||
variant="primary"
|
variant="primary"
|
||||||
@ -740,6 +750,7 @@ export const DirectoryPage: React.FC = () => {
|
|||||||
) : (
|
) : (
|
||||||
paginatedPartners.map((partner) => {
|
paginatedPartners.map((partner) => {
|
||||||
const sc = getStatusConfig(partner.onboardingStatus);
|
const sc = getStatusConfig(partner.onboardingStatus);
|
||||||
|
const pGroup = partner.partnerGroup;
|
||||||
return (
|
return (
|
||||||
<tr
|
<tr
|
||||||
key={partner.id}
|
key={partner.id}
|
||||||
@ -772,9 +783,16 @@ export const DirectoryPage: React.FC = () => {
|
|||||||
setSelectedPartnerForAssets(partner);
|
setSelectedPartnerForAssets(partner);
|
||||||
setIsPartnerAssetsOpen(true);
|
setIsPartnerAssetsOpen(true);
|
||||||
}}
|
}}
|
||||||
className="text-xs font-bold text-ink-700 hover:text-ink-950 hover:underline cursor-pointer focus:outline-none"
|
className="text-xs font-bold text-ink-700 hover:text-ink-950 hover:underline cursor-pointer focus:outline-none flex flex-col items-start gap-0.5"
|
||||||
>
|
>
|
||||||
{partner.sharedAssets?.length || 0} assets
|
<span>
|
||||||
|
{((partner.sharedAssets?.length || 0) + (pGroup ? (assetGroups.find(g => g.name.trim().toLowerCase() === pGroup.trim().toLowerCase())?.assets?.length || 0) : 0))} assets
|
||||||
|
</span>
|
||||||
|
{pGroup && assetGroups.some(g => g.name.trim().toLowerCase() === pGroup.trim().toLowerCase()) && (
|
||||||
|
<span className="text-[9px] text-amber-600 font-extrabold uppercase tracking-wide">
|
||||||
|
Includes {pGroup} Group
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-5 py-4">
|
<td className="px-5 py-4">
|
||||||
@ -971,15 +989,52 @@ export const DirectoryPage: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
/* Current Shared Assets List */
|
/* Current Shared Assets List */
|
||||||
(!selectedPartnerForAssets?.sharedAssets || selectedPartnerForAssets.sharedAssets.length === 0) ? (
|
/* Current Shared Assets List */
|
||||||
|
(() => {
|
||||||
|
const matchedGroup = selectedPartnerForAssets?.partnerGroup
|
||||||
|
? assetGroups.find(g => g.name.trim().toLowerCase() === selectedPartnerForAssets.partnerGroup.trim().toLowerCase())
|
||||||
|
: null;
|
||||||
|
const inheritedAssets = matchedGroup ? matchedGroup.assets : [];
|
||||||
|
const directAssets = selectedPartnerForAssets?.sharedAssets || [];
|
||||||
|
const totalCount = directAssets.length + inheritedAssets.length;
|
||||||
|
|
||||||
|
if (totalCount === 0) {
|
||||||
|
return (
|
||||||
<div className="text-center py-10 bg-ink-50/50 border border-dashed border-ink-200 rounded-xl">
|
<div className="text-center py-10 bg-ink-50/50 border border-dashed border-ink-200 rounded-xl">
|
||||||
<Folder className="w-10 h-10 text-ink-300 mx-auto mb-2" />
|
<Folder className="w-10 h-10 text-ink-300 mx-auto mb-2" />
|
||||||
<p className="text-xs font-bold text-ink-900 font-sans">No assets shared</p>
|
<p className="text-xs font-bold text-ink-900 font-sans">No assets shared</p>
|
||||||
<p className="text-[10px] text-ink-450 mt-1 font-sans">There are no assets currently assigned to this partner.</p>
|
<p className="text-[10px] text-ink-450 mt-1 font-sans">There are no assets currently assigned to this partner.</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
<div className="border border-ink-200 rounded-xl overflow-hidden divide-y divide-ink-200 bg-ink-0 max-h-[350px] overflow-y-auto">
|
<div className="border border-ink-200 rounded-xl overflow-hidden divide-y divide-ink-200 bg-ink-0 max-h-[350px] overflow-y-auto">
|
||||||
{selectedPartnerForAssets.sharedAssets.map((item: any) => {
|
{/* Group Inherited Assets */}
|
||||||
|
{inheritedAssets.map((asset: any) => (
|
||||||
|
<div key={`group-asset-${asset.id}`} className="flex items-center justify-between p-3 hover:bg-ink-100 transition-colors font-sans">
|
||||||
|
<div className="flex items-center gap-3 min-w-0">
|
||||||
|
{getFileIcon(asset.type || '', asset.title)}
|
||||||
|
<div className="min-w-0 font-sans">
|
||||||
|
<p className="text-xs font-bold text-ink-900 truncate">{asset.title}</p>
|
||||||
|
<div className="flex items-center gap-2 mt-1">
|
||||||
|
<span className="text-[8px] px-1.5 py-0.2 rounded bg-ink-100 border border-ink-200 text-ink-600 font-bold uppercase tracking-wider">
|
||||||
|
{asset.categoryId || 'General'}
|
||||||
|
</span>
|
||||||
|
<span className="text-[8px] px-1.5 py-0.2 rounded bg-amber-500/10 border border-amber-500/20 text-amber-700 font-extrabold uppercase tracking-wider">
|
||||||
|
Inherited ({selectedPartnerForAssets?.partnerGroup})
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="p-1.5 text-ink-400 cursor-not-allowed shrink-0 ml-4" title="Inherited via group permissions (Read-only)">
|
||||||
|
<Lock className="w-4 h-4 text-ink-400" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{/* Direct Shared Assets */}
|
||||||
|
{directAssets.map((item: any) => {
|
||||||
const asset = item.asset;
|
const asset = item.asset;
|
||||||
if (!asset) return null;
|
if (!asset) return null;
|
||||||
return (
|
return (
|
||||||
@ -1011,7 +1066,8 @@ export const DirectoryPage: React.FC = () => {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
|
})()
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user