Skip to content
Merged
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ node_modules
build
.vite
bun.lockb
package-lock.json
.DS_Store
coverage
data/
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"@google-cloud/storage": "^8.0.1",
"@lucide/svelte": "^1.34.0",
"chart.js": "^4.5.1",
"nodemailer": "^9.0.6"
"nodemailer": "^9.0.6",
"svelte-i18n": "^4.0.1"
}
}
21 changes: 11 additions & 10 deletions src/lib/components/AppNavbar.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script lang="ts">
import { onMount } from 'svelte';
import { Building2, ChevronDown, FolderKanban, LogOut, UserRound } from '@lucide/svelte';
import { _ } from 'svelte-i18n';

type NavbarUser = { username: string; role: { name: string } | string | null };

Expand Down Expand Up @@ -81,7 +82,7 @@
class="btn-secondary flex max-w-55 items-center gap-2 rounded-2xl px-3 py-1.5 text-sm font-medium text-slate-700"
>
<FolderKanban class="h-4 w-4 shrink-0 text-slate-500" />
<span class="truncate">{currentProject ? currentProject.name : 'Select project'}</span>
<span class="truncate">{currentProject ? currentProject.name : $_('nav.selectProject')}</span>
<ChevronDown class="h-3.5 w-3.5 shrink-0 text-slate-500" />
</button>

Expand All @@ -91,12 +92,12 @@
>
{#if !organizationSlug}
<p class="px-4 py-3 text-sm text-slate-500">
No organization selected. <a href="/cluster-settings/orgs" class="underline"
>Choose one</a
{$_('nav.noOrganizationSelected')} <a href="/cluster-settings/orgs" class="underline"
>{$_('nav.chooseOne')}</a
>.
</p>
{:else if projects.length === 0}
<p class="px-4 py-3 text-sm text-slate-500">No hay proyectos activos.</p>
<p class="px-4 py-3 text-sm text-slate-500">{$_('nav.noActiveProjects')}</p>
{:else}
<div class="max-h-72 overflow-y-auto py-1">
{#each projects as project (project.id)}
Expand All @@ -121,7 +122,7 @@
on:click={closeProjectDropdown}
class="block border-t border-slate-100 bg-slate-50 px-4 py-2.5 text-sm font-medium text-slate-700 hover:bg-slate-100"
>
View all projects
{$_('nav.viewAllProjects')}
</a>
{/if}
</div>
Expand All @@ -134,7 +135,7 @@
href="/how-to"
class="hidden rounded-full border border-slate-200 px-3 py-1.5 text-sm font-medium text-slate-600 transition-colors hover:border-slate-300 hover:text-slate-900 md:inline-flex"
>
How To
{$_('nav.howTo')}
</a>

{#if user}
Expand All @@ -157,31 +158,31 @@
>
<div class="border-b border-slate-100 bg-slate-50 px-4 py-3">
<p class="truncate text-sm font-semibold text-slate-900">{user.username}</p>
<p class="truncate text-xs text-slate-500 capitalize">{roleName} Account</p>
<p class="truncate text-xs text-slate-500 capitalize">{roleName} {$_('nav.account')}</p>
</div>
<a
href="/profile"
on:click={closeUserDropdown}
class="flex items-center gap-2 px-4 py-3 text-sm font-medium text-slate-700 transition-colors hover:bg-slate-50"
>
<UserRound class="h-4 w-4" />
Profile
{$_('nav.profile')}
</a>
<a
href="/org"
on:click={closeUserDropdown}
class="flex items-center gap-2 px-4 py-3 text-sm font-medium text-slate-700 transition-colors hover:bg-slate-50"
>
<Building2 class="h-4 w-4" />
Change Organization
{$_('nav.changeOrganization')}
</a>
<a
href="/auth/logout"
on:click={closeUserDropdown}
class="flex w-full items-center gap-2 px-4 py-3 text-left text-sm font-medium text-red-600 transition-colors hover:bg-red-50"
>
<LogOut class="h-4 w-4" />
Sign out
{$_('nav.signOut')}
</a>
</div>
{/if}
Expand Down
97 changes: 49 additions & 48 deletions src/lib/components/AppSidebar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
Layers,
ShieldAlert,
} from '@lucide/svelte';
import { _ } from 'svelte-i18n';

type NavItem = { label: string; href: string; icon: ComponentType };
type NavModule = { name: string; icon: ComponentType; items: NavItem[] };
Expand Down Expand Up @@ -55,27 +56,27 @@
// one JSON-like tree drives the whole sidebar: category > module > items
$: categories = [
{
name: 'Inicio',
name: $_('sidebar.categories.inicio'),
modules: [
{
name: 'Overview',
name: $_('sidebar.modules.overview'),
icon: LayoutDashboard,
items: organizationSlug
? [
{
label: 'Overview',
label: $_('sidebar.items.overview'),
href: `/org/${organizationSlug}/overview`,
icon: LayoutDashboard,
},
{
label: 'CVEs',
label: $_('sidebar.items.cves'),
href: `/org/${organizationSlug}/cves`,
icon: ShieldAlert,
},
]
: [
{
label: 'Seleccionar organización',
label: $_('sidebar.items.selectOrganization'),
href: '/cluster-settings/orgs',
icon: Building2,
},
Expand All @@ -86,12 +87,12 @@
...(currentProject?.modules?.vault
? [
{
name: 'Seguridad',
name: $_('sidebar.categories.seguridad'),
modules: [
{
name: 'Vault',
name: $_('sidebar.modules.vault'),
icon: Shield,
items: [{ label: 'Vault', href: `${projectBase}/vault`, icon: Shield }],
items: [{ label: $_('sidebar.modules.vault'), href: `${projectBase}/vault`, icon: Shield }],
},
],
},
Expand All @@ -100,30 +101,30 @@
...(currentProject?.modules?.codereport
? [
{
name: 'Analisis',
name: $_('sidebar.categories.analisis'),
modules: [
{
name: 'Code Report',
name: $_('sidebar.modules.codeReport'),
icon: BarChart3,
items: [
{
label: 'Dashboard',
label: $_('sidebar.items.dashboard'),
href: `${projectBase}/code-report/dashboard`,
icon: LayoutDashboard,
},
{ label: 'Services', href: `${projectBase}/code-report/services`, icon: Layers },
{ label: $_('sidebar.items.services'), href: `${projectBase}/code-report/services`, icon: Layers },
{
label: 'CVEs',
label: $_('sidebar.items.cves'),
href: `/org/${currentProjectOrgSlug}/cves?project=${currentProjectSlug}`,
icon: ShieldAlert,
},
{
label: 'Security Policies',
label: $_('sidebar.items.securityPolicies'),
href: `${projectBase}/code-report/security-policy`,
icon: Shield,
},
{ label: 'History', href: `${projectBase}/code-report/history`, icon: GitBranch },
{ label: 'Settings', href: `${projectBase}/code-report/settings`, icon: Settings },
{ label: $_('sidebar.items.history'), href: `${projectBase}/code-report/history`, icon: GitBranch },
{ label: $_('sidebar.items.settings'), href: `${projectBase}/code-report/settings`, icon: Settings },
],
},
],
Expand All @@ -133,13 +134,13 @@
...(currentProject?.modules?.stateiac
? [
{
name: 'GitOps',
name: $_('sidebar.categories.gitops'),
modules: [
{
name: 'State IaC',
name: $_('sidebar.modules.stateIac'),
icon: GitBranch,
items: [
{ label: 'State IaC', href: `${projectBase}/state-iac`, icon: GitBranch },
{ label: $_('sidebar.modules.stateIac'), href: `${projectBase}/state-iac`, icon: GitBranch },
],
},
],
Expand All @@ -149,26 +150,26 @@
...(currentProjectSlug && canManageProject
? [
{
name: 'Proyecto',
name: $_('sidebar.categories.proyecto'),
modules: [
{
name: 'Project Settings',
name: $_('sidebar.modules.projectSettings'),
icon: FolderKanban,
items: [
{ label: 'Información', href: `${projectBase}/settings/overview`, icon: Info },
{ label: $_('sidebar.items.information'), href: `${projectBase}/settings/overview`, icon: Info },
{
label: 'Users and Groups',
label: $_('sidebar.items.usersAndGroups'),
href: `${projectBase}/settings/users-groups`,
icon: Users,
},
{
label: 'Roles and Permissions',
label: $_('sidebar.items.rolesAndPermissions'),
href: `${projectBase}/settings/roles-permissions`,
icon: Shield,
},
{ label: 'Audit', href: `${projectBase}/settings/audit`, icon: ScrollText },
{ label: $_('sidebar.items.audit'), href: `${projectBase}/settings/audit`, icon: ScrollText },
{
label: 'Server Keys',
label: $_('sidebar.items.serverKeys'),
href: `${projectBase}/settings/server-keys`,
icon: Shield,
},
Expand All @@ -179,46 +180,46 @@
]
: []),
{
name: 'Sistema',
name: $_('sidebar.categories.sistema'),
modules: [
...(organizationSlug && canManageOrganization
? [
{
name: 'Organization Settings',
name: $_('sidebar.modules.organizationSettings'),
icon: Settings,
items: [
{
label: 'Projects',
label: $_('sidebar.items.projects'),
href: `/org/${organizationSlug}/settings/projects`,
icon: FolderKanban,
},
{
label: 'Global',
label: $_('sidebar.items.global'),
href: `/org/${organizationSlug}/settings/global`,
icon: Shield,
},
{
label: 'Users',
label: $_('sidebar.items.users'),
href: `/org/${organizationSlug}/settings/users`,
icon: Users,
},
{
label: 'Roles & Permissions',
label: $_('sidebar.items.rolesAndPermissions'),
href: `/org/${organizationSlug}/settings/roles-permissions`,
icon: Users,
},
{
label: 'System & Backup',
label: $_('sidebar.items.systemAndBackup'),
href: `/org/${organizationSlug}/settings/system-backup`,
icon: Database,
},
{
label: 'Server Access Keys',
label: $_('sidebar.items.serverAccessKeys'),
href: `/org/${organizationSlug}/settings/server-access-keys`,
icon: KeyRound,
},
{
label: 'Audit',
label: $_('sidebar.items.audit'),
href: `/org/${organizationSlug}/settings/audit`,
icon: ScrollText,
},
Expand All @@ -229,18 +230,18 @@
...(canAccessClusterSettings
? [
{
name: 'Cluster Settings',
name: $_('sidebar.modules.clusterSettings'),
icon: Building2,
items: [
{ label: 'Organizations', href: '/cluster-settings/orgs', icon: Building2 },
{ label: $_('sidebar.items.organizations'), href: '/cluster-settings/orgs', icon: Building2 },
{
label: 'Roles & Permissions',
label: $_('sidebar.items.rolesAndPermissions'),
href: '/cluster-settings/roles-permissions',
icon: Shield,
},
{ label: 'Users', href: '/cluster-settings/users', icon: Users },
{ label: 'Database', href: '/cluster-settings/database', icon: Database },
{ label: 'Audit Log', href: '/cluster-settings/audit', icon: ScrollText },
{ label: $_('sidebar.items.users'), href: '/cluster-settings/users', icon: Users },
{ label: $_('sidebar.items.database'), href: '/cluster-settings/database', icon: Database },
{ label: $_('sidebar.items.auditLog'), href: '/cluster-settings/audit', icon: ScrollText },
],
},
]
Expand Down Expand Up @@ -273,7 +274,7 @@
{#if !collapsed && organizationName}
<div class="min-w-0">
<p class="text-[10px] font-semibold uppercase tracking-[0.22em] text-slate-500">
Organization
{$_('sidebar.organization')}
</p>
<h2 class="mt-1 truncate text-sm font-semibold text-slate-900">{organizationName}</h2>
</div>
Expand All @@ -283,8 +284,8 @@
type="button"
class="btn-secondary inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-md text-slate-600"
on:click={toggleCollapsed}
aria-label={collapsed ? 'Expand sidebar' : 'Collapse sidebar'}
title={collapsed ? 'Expand sidebar' : 'Collapse sidebar'}
aria-label={collapsed ? $_('sidebar.expandSidebar') : $_('sidebar.collapseSidebar')}
title={collapsed ? $_('sidebar.expandSidebar') : $_('sidebar.collapseSidebar')}
>
{#if collapsed}
<PanelLeftOpen class="h-4 w-4" />
Expand All @@ -310,17 +311,17 @@
</div>
{#if !collapsed}
<div class="min-w-0">
<p class="text-sm font-medium">Setup pending</p>
<p class="text-sm font-medium">{$_('sidebar.setupPending')}</p>
</div>
{/if}
</a>
{/if}

<div class="space-y-4">
{#each categories as category (category.name)}
{#each categories as category, categoryIndex (category.name)}
<section
class:border-t={category.name === 'Sistema'}
class:pt-4={category.name === 'Sistema'}
class:border-t={categoryIndex === categories.length - 1}
class:pt-4={categoryIndex === categories.length - 1}
class="border-slate-200"
>
{#if !collapsed}
Expand Down
Loading