feat(web): English paths, and a portfolio that updates itself
/cartera, /explorar and /p/:key/proponer are /portfolio, /explore and /p/:key/propose now, like every other path; the Spanish ones redirect, so links already shared keep working. Settings sections go by ?section= with English names. The portfolio reads itself again, quietly, when a ticket, sprint or release of the projects shown changes, when my projects change, or when the live connection comes back; «En directo» replaces the refresh button. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -61,7 +61,7 @@ const SECTIONS: SettingsSection[] = [
|
||||
hint: 'Quién ve el proyecto y si el público puede proponer cosas.',
|
||||
},
|
||||
{
|
||||
id: 'flujo',
|
||||
id: 'workflow',
|
||||
draft: true,
|
||||
label: 'Flujo de trabajo',
|
||||
hint: 'Las columnas del tablero, a cuáles se puede pasar desde cada una y cuándo algo está hecho.',
|
||||
@@ -73,31 +73,31 @@ const SECTIONS: SettingsSection[] = [
|
||||
hint: 'Tipos, áreas y campos propios. Lo que ya se usa no se borra: se archiva y deja de ofrecerse.',
|
||||
},
|
||||
{
|
||||
id: 'equipos',
|
||||
id: 'teams',
|
||||
draft: true,
|
||||
label: 'Equipos',
|
||||
hint: 'Grupos de miembros, para asignarles tickets y avisarles con «@equipo».',
|
||||
},
|
||||
{
|
||||
id: 'automatizaciones',
|
||||
id: 'automations',
|
||||
label: 'Automatizaciones',
|
||||
hint: 'Reglas «cuando… si… entonces…» que hacen solas el trabajo repetido.',
|
||||
needs: 'manage',
|
||||
},
|
||||
{
|
||||
id: 'integraciones',
|
||||
id: 'integrations',
|
||||
label: 'Integraciones',
|
||||
hint: 'Commits y pull requests de Git en cada ticket, y avisos a otros sistemas.',
|
||||
needs: 'manage',
|
||||
},
|
||||
{
|
||||
id: 'datos',
|
||||
id: 'data',
|
||||
label: 'Importar y exportar',
|
||||
hint: 'Los tickets en CSV: sacarlos, o traerlos de TaskStream o de Jira.',
|
||||
needs: 'manage',
|
||||
},
|
||||
{
|
||||
id: 'peligro',
|
||||
id: 'danger',
|
||||
label: 'Zona peligrosa',
|
||||
hint: 'Archivar el proyecto o eliminarlo del todo.',
|
||||
needs: 'owner',
|
||||
@@ -106,13 +106,13 @@ const SECTIONS: SettingsSection[] = [
|
||||
|
||||
/** Which section holds each part of the draft. */
|
||||
const DRAFT_SECTION: Partial<Record<keyof ProjectSettings, string>> = {
|
||||
statuses: 'flujo',
|
||||
transitions: 'flujo',
|
||||
checklistBeforeDone: 'flujo',
|
||||
statuses: 'workflow',
|
||||
transitions: 'workflow',
|
||||
checklistBeforeDone: 'workflow',
|
||||
issueTypes: 'tickets',
|
||||
areas: 'tickets',
|
||||
customFields: 'tickets',
|
||||
teams: 'equipos',
|
||||
teams: 'teams',
|
||||
};
|
||||
|
||||
/** "Datos y análisis" → "DATOS_Y_ANALISIS": ids of new values (they never change after saving). */
|
||||
@@ -157,9 +157,9 @@ function idFrom(name: string): string {
|
||||
@for (item of sections(); track item.id) {
|
||||
<a
|
||||
[routerLink]="[]"
|
||||
[queryParams]="{ seccion: item.id }"
|
||||
[queryParams]="{ section: item.id }"
|
||||
[class.is-active]="item.id === current().id"
|
||||
[class.is-danger]="item.id === 'peligro'"
|
||||
[class.is-danger]="item.id === 'danger'"
|
||||
[attr.aria-current]="item.id === current().id ? 'page' : null"
|
||||
>
|
||||
<span>{{ item.label }}</span>
|
||||
@@ -233,7 +233,7 @@ function idFrom(name: string): string {
|
||||
proponga una idea.
|
||||
} @else if (project.acceptsProposals) {
|
||||
Abierto: cualquiera puede enviar un error o una idea desde
|
||||
<a class="ts-plain-link" routerLink="../proponer">el formulario</a
|
||||
<a class="ts-plain-link" routerLink="../propose">el formulario</a
|
||||
>. Llegan como tickets con la etiqueta «propuesta», y se pueden
|
||||
votar.
|
||||
} @else {
|
||||
@@ -268,7 +268,7 @@ function idFrom(name: string): string {
|
||||
>
|
||||
<fieldset [disabled]="!facade.canManage()">
|
||||
@switch (current().id) {
|
||||
@case ('flujo') {
|
||||
@case ('workflow') {
|
||||
<!-- Statuses -->
|
||||
<section class="ts-panel ts-block" aria-labelledby="st-title">
|
||||
<header class="ts-block__head">
|
||||
@@ -735,7 +735,7 @@ function idFrom(name: string): string {
|
||||
</ol>
|
||||
</section>
|
||||
}
|
||||
@case ('equipos') {
|
||||
@case ('teams') {
|
||||
<!-- Teams -->
|
||||
<section class="ts-panel ts-block" aria-labelledby="teams-title">
|
||||
<header class="ts-block__head">
|
||||
@@ -802,24 +802,24 @@ function idFrom(name: string): string {
|
||||
|
||||
@if (facade.canManage() && facade.project(); as project) {
|
||||
@switch (current().id) {
|
||||
@case ('automatizaciones') {
|
||||
@case ('automations') {
|
||||
<ts-automations [projectId]="project.id" />
|
||||
}
|
||||
@case ('integraciones') {
|
||||
@case ('integrations') {
|
||||
<ts-git-integration
|
||||
[projectId]="project.id"
|
||||
[projectKey]="project.key"
|
||||
/>
|
||||
<ts-webhooks [projectId]="project.id" />
|
||||
}
|
||||
@case ('datos') {
|
||||
@case ('data') {
|
||||
<ts-transfer [projectId]="project.id" [projectKey]="project.key" />
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@if (
|
||||
current().id === 'peligro' && facade.isOwner() && facade.project();
|
||||
current().id === 'danger' && facade.isOwner() && facade.project();
|
||||
as project
|
||||
) {
|
||||
<section
|
||||
@@ -1610,8 +1610,8 @@ export class SettingsPage {
|
||||
protected readonly icons = TYPE_ICONS;
|
||||
protected readonly fieldTypes = FIELD_TYPES;
|
||||
|
||||
/** `?seccion=` (`withComponentInputBinding`). */
|
||||
readonly seccion = input<string | undefined>();
|
||||
/** `?section=` (`withComponentInputBinding`). */
|
||||
readonly section = input<string | undefined>();
|
||||
|
||||
protected readonly sections = computed(() =>
|
||||
SECTIONS.filter(
|
||||
@@ -1623,7 +1623,7 @@ export class SettingsPage {
|
||||
);
|
||||
protected readonly current = computed(
|
||||
() =>
|
||||
this.sections().find((s) => s.id === this.seccion()) ??
|
||||
this.sections().find((s) => s.id === this.section()) ??
|
||||
this.sections()[0],
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user