links info
This commit is contained in:
@@ -30,7 +30,7 @@ export async function GET(request: NextRequest) {
|
||||
}
|
||||
|
||||
if (team) {
|
||||
whereConditions.push(`hasToken(teams, 'team_id', '${team}')`);
|
||||
whereConditions.push(`arrayExists(x -> JSONExtractString(x, 'team_id') = '${team}', JSONExtractArrayRaw(teams))`);
|
||||
}
|
||||
|
||||
const whereClause = whereConditions.join(' AND ');
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useEffect, useState } from 'react';
|
||||
import { getSupabaseClient } from '../utils/supabase';
|
||||
import { AuthChangeEvent } from '@supabase/supabase-js';
|
||||
import { Loader2, ExternalLink, Search } from 'lucide-react';
|
||||
import { TeamSelector } from '@/app/components/ui/TeamSelector';
|
||||
|
||||
// Define attribute type to avoid using 'any'
|
||||
interface LinkAttributes {
|
||||
@@ -136,28 +137,75 @@ export default function LinksPage() {
|
||||
console.error('Error parsing attributes:', e);
|
||||
}
|
||||
|
||||
// Get team name
|
||||
let teamName = '';
|
||||
// Get team names
|
||||
const teamNames: string[] = [];
|
||||
try {
|
||||
if (link.teams) {
|
||||
const teams = typeof link.teams === 'string'
|
||||
? JSON.parse(link.teams)
|
||||
: link.teams || [];
|
||||
|
||||
if (Array.isArray(teams) && teams.length > 0 && teams[0].team_name) {
|
||||
teamName = teams[0].team_name;
|
||||
if (Array.isArray(teams)) {
|
||||
teams.forEach(team => {
|
||||
if (team.team_name) {
|
||||
teamNames.push(team.team_name);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error parsing teams:', e);
|
||||
}
|
||||
|
||||
// Get project names
|
||||
const projectNames: string[] = [];
|
||||
try {
|
||||
if (link.projects) {
|
||||
const projects = typeof link.projects === 'string'
|
||||
? JSON.parse(link.projects)
|
||||
: link.projects || [];
|
||||
|
||||
if (Array.isArray(projects)) {
|
||||
projects.forEach(project => {
|
||||
if (project.project_name) {
|
||||
projectNames.push(project.project_name);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error parsing projects:', e);
|
||||
}
|
||||
|
||||
// Get tag names
|
||||
const tagNames: string[] = [];
|
||||
try {
|
||||
if (link.tags) {
|
||||
const tags = typeof link.tags === 'string'
|
||||
? JSON.parse(link.tags)
|
||||
: link.tags || [];
|
||||
|
||||
if (Array.isArray(tags)) {
|
||||
tags.forEach(tag => {
|
||||
if (tag.tag_name) {
|
||||
tagNames.push(tag.tag_name);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error parsing tags:', e);
|
||||
}
|
||||
|
||||
return {
|
||||
title: link.title || attributes.title || 'Untitled',
|
||||
slug: link.slug || attributes.slug || '',
|
||||
domain: domain,
|
||||
originalUrl: link.original_url || attributes.originalUrl || attributes.original_url || '',
|
||||
teamName: teamName,
|
||||
teamNames: teamNames,
|
||||
projectNames: projectNames,
|
||||
tagNames: tagNames,
|
||||
teamName: teamNames[0] || '', // Keep for backward compatibility
|
||||
createdAt: new Date(link.created_at).toLocaleDateString(),
|
||||
visits: link.click_count || 0
|
||||
};
|
||||
@@ -168,6 +216,9 @@ export default function LinksPage() {
|
||||
slug: '',
|
||||
domain: 'shorturl.example.com',
|
||||
originalUrl: '',
|
||||
teamNames: [],
|
||||
projectNames: [],
|
||||
tagNames: [],
|
||||
teamName: '',
|
||||
createdAt: '',
|
||||
visits: 0
|
||||
@@ -305,19 +356,22 @@ export default function LinksPage() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<select
|
||||
value={teamFilter || ''}
|
||||
onChange={(e) => {
|
||||
setTeamFilter(e.target.value || null);
|
||||
setCurrentPage(1); // Reset to page 1 when filtering
|
||||
}}
|
||||
className="rounded-md border border-gray-300 py-2 pl-3 pr-10 text-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500"
|
||||
>
|
||||
<option value="">All Teams</option>
|
||||
{teams.map(team => (
|
||||
<option key={team.id} value={team.id}>{team.name}</option>
|
||||
))}
|
||||
</select>
|
||||
<div className="flex items-center gap-2">
|
||||
<TeamSelector
|
||||
value={teamFilter || ''}
|
||||
onChange={(value) => {
|
||||
// 如果是多选模式,值将是数组。对于空数组,设置为 null
|
||||
if (Array.isArray(value)) {
|
||||
setTeamFilter(value.length > 0 ? value[0] : null);
|
||||
} else {
|
||||
setTeamFilter(value || null);
|
||||
}
|
||||
setCurrentPage(1); // Reset to page 1 when filtering
|
||||
}}
|
||||
className="w-64"
|
||||
multiple={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Links table */}
|
||||
@@ -339,9 +393,20 @@ export default function LinksPage() {
|
||||
return (
|
||||
<tr key={link.id} className="hover:bg-gray-50">
|
||||
<td className="px-6 py-4">
|
||||
<div className="flex flex-col">
|
||||
<div className="flex flex-col space-y-1">
|
||||
<span className="font-medium text-gray-900">{metadata.title}</span>
|
||||
<span className="text-xs text-blue-500">{shortUrl}</span>
|
||||
|
||||
{/* Tags */}
|
||||
{metadata.tagNames.length > 0 && (
|
||||
<div className="flex flex-wrap gap-1.5 mt-1">
|
||||
{metadata.tagNames.map((tag, index) => (
|
||||
<span key={index} className="inline-flex items-center rounded-full bg-gray-100 px-2 py-0.5 text-xs font-medium text-gray-800">
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-6 py-4 text-sm text-gray-500">
|
||||
@@ -356,7 +421,31 @@ export default function LinksPage() {
|
||||
</a>
|
||||
</td>
|
||||
<td className="px-6 py-4 text-sm text-gray-500">
|
||||
{metadata.teamName}
|
||||
<div className="flex flex-col space-y-1">
|
||||
{/* Teams */}
|
||||
{metadata.teamNames.length > 0 ? (
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
{metadata.teamNames.map((team, index) => (
|
||||
<span key={index} className="inline-flex items-center rounded-full bg-blue-100 px-2 py-0.5 text-xs font-medium text-blue-800">
|
||||
{team}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<span>-</span>
|
||||
)}
|
||||
|
||||
{/* Projects */}
|
||||
{metadata.projectNames.length > 0 && (
|
||||
<div className="flex flex-wrap gap-1.5 mt-1">
|
||||
{metadata.projectNames.map((project, index) => (
|
||||
<span key={index} className="inline-flex items-center rounded-full bg-green-100 px-2 py-0.5 text-xs font-medium text-green-800">
|
||||
{project}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-6 py-4 text-sm text-gray-500">
|
||||
{metadata.createdAt}
|
||||
|
||||
Reference in New Issue
Block a user