Changelog
O que há de novo.
Cada melhoria para a plataforma, como ele envia.
· kamo-shared-library
Página e filtro de citações de uma conta no banco de dados
Uma visão de conta precisa de cada citação em todos os seus leads. Carregando- as para renderizar uma página degrada todos os meses a conta está em uso, e qualquer total exibido só cobriria o que foi obtido — então, paginar, filtrar e ordenar tudo acontece no SQL. A consulta é nativa porque Quote detém apenas um leadId suave sem associação para participar através; junta leads.uid = commerce quotes.lead id e escopos em leads.account uid. Puxar os leads da conta para uma lista IN não sobreviveria a um grande livro de negócios. Cada filtro é um predicado nulo-guardado, então uma consulta serve a grade não filtrada e qualquer combinação de filtros em vez de um método por permutação. Chaves de ordenação são permitidas: o valor atinge um ORDER BY nativo, então aceitando um O nome de campo arbitrário do cliente seria um ponto de injeção. A projeção da lista também ganha sentAt, acceptedAt, version and the option/line contages — uma visão geral é lida para "quanto tempo isso foi fora, ele pousou", que o anterior os campos não puderam responder.
· kamo-signer-monorepo
Mostrar o agente atribuído na cópia do cliente
Corresponde à antevisão da equipa: o cabeçalho nomeia a org, isto nomeia a pessoa a perguntar.
· kamo-internal
Mostrar o agente atribuído na antevisão
Um painel "Seu contato" acima do rodapé — nome, título, telefone e e-mail — assim o cliente sabe a quem perguntar sobre o preço. Ausente inteiramente quando o chumbo não é atribuído.
· SecurityService
Resolver o agente ao lado do cliente, a partir de uma busca de liderança
Ambos os blocos saem da mesma pista, então os controladores obtê-lo uma vez e derivar cada em vez de bater no serviço duas vezes por renderização. Ainda org-scoped em ambos lugares; na página pública o escopo vem da própria organização do link de compartilhamento.
· kamo-shared-library
Nomeie o agente atribuído ao líder no documento
O cabeçalho identifica o org, mas um cliente com uma pergunta sobre as necessidades de preço a pessoa que possui a relação. A citação agora carrega o agente designado do líder — nome, cargo, e-mail de trabalho e telefone de trabalho. Apenas dados de contacto de trabalho: uma citação contém a identidade comercial do agente, nunca número pessoal que acontece de se sentar em seu registro de membros. O título da tarefa prefere jobTitleOfficial, que é o que a org escolheu imprimir, antes do JobTitle vinculado. Um chumbo não atribuído, ou um agente sem nada gravado, não produz nenhum bloco em vez de um "O teu contacto" vai para o espaço em branco. A resolução do nome reutiliza o mesmo caminho. já usa para o agente de empréstimo atribuído, por isso a citação nomes o agente exatamente como o O resto da vista de chumbo faz.
· kamo-internal
Reatribuir ao agente uma oportunidade
O diálogo do aprovador ganha um selecionador de agentes, desenhado do mesmo pool da infraestrutura valida contra. A coluna do Agente mostra quem detém a oportunidade. com uma legenda âmbar "Reatribuída de ..." quando essa já não é o agente que perguntou — o solicitante permanece no registro e na história de qualquer maneira. O controle de cabeça de chumbo segue o suporte também. Estava a desligar o solicitante. que após uma reatribuição teria oferecido a janela de extensão ao agente que já não a possui e a oculta daquele que a possui — e aos portões da infra-estrutura Esse ponto final no titular, pelo que a oferta teria terminado num 403.
· SecurityService
Reatribua o agente de detenção e envie um e-mail para todos os efeitos
Um aprovador pode agora dar uma oportunidade a um agente diferente. O solicitante é nunca reescrito — applyPrimaryAgent registra o movimento como sua própria linha de histórico com ambos os nomes, então seis meses depois o registro mostra que se moveu em vez de como se o novo agente o pedisse. Propriedade da extensão, o cabeçalho controle e a máscara de detalhe todos seguem o suporte agora; o filtro "Agente" corresponde OU seja o fim de uma reatribuição, porque escondê-la do agente que a encontrou e do agente que o detém são ambas respostas erradas. Nove notificações abrangem o ciclo de vida. Pedidos e pedidos de extensão todos os que os podem decidir — ambos os direitos de decisão, uma vez que um membro que só pode negar seria de outra forma nunca aprender um pedido existe para negar. Decisões e edições ir para o titular, o solicitante original quando isso difere, e cada colega em um comissão dividida; uma edição adicionalmente envia quem quer que tenha deslocado, porque perder uma comissão compartilhar silenciosamente é exatamente para o que esses e-mails são. Duas coisas estão carregando em como o envio é sequenciado: - Resolução e renderização acontecem EAGERLY, dentro da transação do chamador, enquanto a entidade ainda detém os valores sobre os quais o email se trata. AprovarExtension () clears os campos de extensão imediatamente após, então uma leitura posterior descreveria "não tempo adicional" em um email cujo assunto é quanto tempo foi concedido. - O SENDING espera por... Anunciando uma decisão que uma falha posterior volta iria deixar agentes segurando um e-mail para um aprovação que nunca aconteceu, e depoisCompleção em vez de depoisCommit significa a conexão do banco de dados é liberada antes do início do HTTP de saída. Os valores da tabela de detalhes escapam no ponto em que entram no mapa: os nomes dos membros são texto livre, a tabela é injetada como HTML bruto, e o renderizador escapa Nada. Uma edição que não muda nada não envia e-mail e uma reserva PENDING Não envia nenhum "atualizado" - ninguém foi informado que ainda existe. 60 testes.
· EmailService
Amostras de antevisão para as nove notificações de oportunidade
Sem um braço aqui, o editor de Modelos de Email do administrador renderiza cada placeholder em branco, então qualquer um que personalize estes nove seria editar um esqueleto vazio. Um braço para todos os nove: eles compartilham uma variável definida por design, então um único mapa de amostra torna cada um deles fielmente. Map. ofEntradas porque Map.of caps em dez Os pares e o conjunto são maiores do que isso.
· InitializerService
Agente primário reatribuível numa oportunidade reservada
PRIMARY AGENT MEMBER ID é quem detém a oportunidade agora; PEDIDO BY MEMBER ID fica intocada para sempre. Nulable with no backfill in proposite — nullable means "nunca reatribuiu", e copiar o solicitante em linhas existentes destruiria Essa distinção em todas as reservas anteriores à coluna. Aplicado contra a produção em 2026-08-04; coluna e índice verificados presentes.
· kamo-shared-library
Agente primário reatribuível e nove modelos de notificação
Um aprovador pode dar uma oportunidade — e a comissão com ele — a um Agente. PRIMARY AGENT MEMBER ID é quem o detém agora; PEDIDO BY MEMBER ID é nunca mais escreveu, porque quem encontrou o acordo é um fato sobre o passado e Sobrescrevê-lo apagaria o único registro que o agente original trouxe. Null significa "nunca redesignado", que é uma declaração diferente de "redesignado de volta ao solicitante" — assim as linhas existentes são deixadas sozinhas em vez de recheadas. effectiveAgentMemberId() é o detentor, e é o que agora decide quem pode pedir uma extensão e quem o cabeçalho principal trata como o proprietário. Uma vez uma oportunidade move, o solicitante original é um nome na história, não uma reivindicação sobre ele. Nove modelos canônicos cobrem o ciclo de vida: um pedido ou extensão vai a todos os que o podem decidir; a cada aprovação, negação, edição, extensão expirar e fechar vai para o agente segurando-o, o agente que perguntou se isso é agora outra pessoa, e todos os colegas numa comissão dividida. Eles compartilham uma shell gerada para que o layout não possa derivar entre eles, e um conjunto de variáveis para que um modelo possa referenciar qualquer coisa sem uma alteração Java correspondente — o que importa porque uma variável em falta transforma-se numa string vazia com apenas um AVISO, e envia um e-mail lendo "reservado até".
· kamo-internal
Comissão global, incumprimentos de mercado e nenhuma unidade pré-escolhida
Três mudanças na forma como a comissão é capturada. Já nada é pré-selecionado. Percentagem/montante e uma vez/recorrente ambos começar a desactivar cada divisão da comissão, então cada um declara o seu tipo porque Alguém o disse. Um "Percento" pré-selecionado é indistinguível de um considerado escolha, e a diferença entre 15% de uma venda e $15 é o pagamento inteiro. O envio permanece desativado até que uma linha inicial esteja terminada. O aprovador concorda agora com uma comissão GLOBAL — o que a organização paga sobre o venda ao agente requerente e ao grupo com quem partilham, do qual As divisões por colega são esculpidas. Aparece nas janelas de aprovação e edição e como uma coluna na lista reservada, e um mercado pode carregar um padrão que a pre-preencha. Predefinições do mercado Pre-preencha apenas a HOPROVAL. Semeando uma edição do mercado seria deixar uma poupança que era sobre datas selo em uma comissão que ninguém concordou, e fazer "nenhuma comissão" impossível de manter. Limpar uma figura pré-cheia agora envia um Comissão explícita clara, rastreou o que o formulário ABERTO com o que é armazenado — caso contrário, excluir um padrão pré- preenchido não envia nada e o O servidor coloca-o de volta. Além disso: um padrão de mercado meio cheio agora bloqueia o salvamento em vez de ser deixado cair e relatado como sucesso; a coluna da comissão não inventa mais "uma vez" quando nenhuma cadência foi definida; quantidades divididas na dica usar a mesma formatação de dinheiro como a coluna; e Add Market limpa os campos de citação que herdava da última mercado editado.
· SecurityService
Concordar com uma comissão global na aprovação, semeada do mercado
O aprovador agora registra o que a organização paga na venda para o requerente Agente e seu grupo. Omitir a aprovação e aplicar o incumprimento do mercado do chumbo — isso é o que torna o mercado definindo um padrão em vez de uma sugestão apenas o Honras da UI. applyComission define os três campos e nunca os mescla no campo com o que é armazenado. A fusão parece inofensiva e não é: uma edição carregando apenas um o tipo de ação viraria um 15 armazenado de quinze por cento para quinze dólares, Redenminando um pagamento que ninguém queria tocar. Um padrão de mercado inválido ou semi- configurado é registrado e ignorado ao invés de Atirado. Um padrão é conveniência, não lei, e um salvo através de algum outro caminho Com um número absurdo não deve transformar-se em uma falta de mercado inaprovável — o Aprovador ainda pode digitar uma comissão em, e aprovar sem um é legítimo. A Comissão clara é honrada antes de tudo, incluindo o incumprimento do mercado: um aprovador que suprime uma figura pré-cheia tomou uma decisão, e silenciosamente Pô-lo de volta iria invertê-lo. 49 testes, incluindo os caminhos claros, o guarda da fusão, e ambos casos de mau padrão.
· InitializerService
Colunas da Comissão para as oportunidades reservadas e os incumprimentos do mercado
Seis colunas nulas: a comissão geral acordou numa oportunidade reservada, e o incumprimento do mercado que o pre-preencha na aprovação. NUMERIC( 19,4) para corresponder ao tabela dividida — dinheiro é exatamente decimal ou comissões disputas seguir. Aplicado contra a produção em 2026-08-04; todos os seis verificados presentes.
· kamo-shared-library
A comissão global sobre uma venda e os incumprimentos do mercado
Uma oportunidade reservada registra agora o que a organização paga fora da venda a o agente requerente e o grupo com o qual partilham — a panela o por colega As divisões são esculpidas. Um mercado líder carrega um padrão que pré-preenchi-lo quando É concedida uma homologação. Cada coluna é nulável sem padrão. Uma reserva que ninguém aprovou não comissão acordada e um mercado que não tenha configurado um não tem padrão; escrever um zero em qualquer um dos dois colocaria uma figura que ninguém escolheu num registo de pagamento. Três campos de pedidos não teriam sido suficientes. Um JSON nulo e um campo ausente são a mesma coisa após a desserialização, e ausência já significa dois outros coisas aqui — "use o padrão de mercado" em aprovar, "deixe-o sozinho" em uma edição. Assim, a Comissão clara diz remoção em voz alta; sem ele, um aprovador que suprime um A comissão fica em silêncio, e depois de aprovar o padrão que eles acabaram de limpar volta. LeadIdentity ganha os padrões de mercado e findIdentities agora soletra sua Alinhamentos à esquerda. Escrito como o caminho implícito l.market.x, Hibernate emite um INNER a adesão e todas as pistas sem mercado saem inteiramente da projecção — que teria aparecido como "leader sem nome" nas linhas que ninguém olha duas vezes.
· kamo-internal
Renderize os detalhes do cliente sobre a antevisão, a partir da liderança
Removendo os campos do próprio destinatário da citação deixados "Preparados para" em branco, porque o nome do cliente só veio de uma conta ligada e as cotações geradas pelo lead não têm nenhuma. A pré-visualização imprime agora o bloco que o servidor monta a partir da liderança. A empresa lidera-o. quando existe uma — uma citação a uma empresa é dirigida à empresa, com o contato nomeado abaixo — então endereço, telefone e e-mail, cada omitido quando o lead não Leva-o.
· kamo-signer-monorepo
Mostrar os detalhes do cliente na cópia do cliente
A empresa dirige o bloco quando há um — uma citação para um negócio é dirigida ao negócio, com o contacto por baixo dele. Corresponde exactamente à antevisão da equipa.
· SecurityService
Resolva o lead do destinatário para as vistas da equipe e do cliente
Org-escoberto em ambos os lugares. Na página pública, o escopo vem do próprio link organização, de modo que um símbolo nunca pode emergir uma pista pertencente a outro inquilino.
· kamo-shared-library
Põe os detalhes do cliente no documento, lê o papel principal
Deixar cair os campos do próprio destinatário da citação deixou o documento sem nada a dizer o cliente: o nome do cliente só veio de uma conta vinculada, que aspas criadas pelo lead não tem, então "Preparado para" em branco impresso. O destinatário está agora reunido a partir da liderança — nome, empresa, endereço, telefone, e-mail. É uma pesquisa em vez de uma associação porque a citação deliberadamente mantém apenas um suave leadId assim o módulo de lead permanece independentemente implantável, para que os controladores resolvam e passar o bloco dentro Um chumbo meio cheio é o caso normal, não a exceção: os leads chegam de fornecedores com Seja qual for a fonte capturada. O endereço colapsa para uma linha e salta o que é desaparecido, então uma pista segurando apenas uma cidade imprime "Londres" em vez de ", Londres, ". Um chumbo que não pode ser lido não produz nenhum bloco em vez de lançar — uma citação cuja liderança foi excluído ainda deve renderizar.
· kamo-internal
Mover aspas para fora do comércio e para a liderança
Citações se sentaram no oleoduto de comércio, ao lado de ordens e carrinhos em vez de ao lado do São para o cliente. Eles agora vivem na liderança: uma guia de Citações diretamente após o Líder do Cliente Dados, mostrados apenas onde o mercado os permite. A página de citação standalone se foi em vez de ser mantida atrás de uma bandeira — a liderança já fornece o cabeçalho, a identidade do cliente, suas comunicações e seus documentos, segundo layout de registro em cima do que duplicou o cromo e dividiu o histórico do cliente Em dois. Selecionar uma citação desliza a lista para fora e o editor para dentro, e o cabeçalho principal Nunca sai do ecrã. As abas Comunicações e Documentos são retiradas pela mesma razão. Os mercados ganham um switch Habilitar Citações e os termos padrão com os quais suas citações começam. Sem EDIT QUOTE TERMS o campo de termos é desativado E omitido da carga útil; o servidor tira-lo também, uma vez que uma entrada desabilitada é apresentação, não execução. IDs de subtab perdem "quotas"; seu teste de regressão agora afirma a propriedade geral — cada tab após o primeiro mantém o seu próprio índice — por isso ainda guarda o bug de rejeição sem nomeando uma aba que já não existe.
· SecurityService
Expor as configurações das cotações por mercado; aplicar os termos de concessão
market-config agora diz à view principal se deve oferecer uma aba de Citações e que redação a nova cotação começa com, e os objetivos do mercado de ida e volta ambos os campos. As edições de termos são despojadas do servidor para chamadas sem EDIT QUOTE TERMS. Desactivar a campo na UI é apresentação; um PATCH feito à mão não deve ser capaz de reescrever o org's O texto legal também.
· kamo-shared-library
As citações pertencem a leads, configurados por mercado
As citações eram um artefato de trade-pipeline, que os coloca ao lado de ordens e carrinhos em vez do que ao lado do cliente que são para. Eles agora penduram a liderança: o mercado decide se seus leads podem carregar aspas em tudo, e os termos padrão cada citação em que O mercado começa com. Por mercado, em vez de por org, porque um balcão de hipotecas emite estimativas de empréstimos sob TRID e não tem utilidade para uma citação genérica, enquanto um mercado de serviços vive sobre eles. Os termos assumem o compromisso jurídico da organização, afastando-se assim da formulação do mercado numa única A cotação é a sua própria subvenção — EDIT QUOTE TERMS. Um campo de termos nulos já significava "deixar imutável" na atualização, que é o que permite que o controller despi-lo para chamadas sem o Certo. Também deixa cair o nome/endereço/telefone do próprio destinatário da citação: o lead já detém o os detalhes do cliente, e fotografando-os duplicaram um registro editado em outro lugar que A derivar dele. Esquema aplicado por KamoInitializer antes deste commit; colunas verificadas.
· SecurityService
Pedidos de reserva, aprovação e auditoria
Superfície REST atrás /leades/oportunidades/reservado e Oportunidade de Reserva controle no cabeçalho principal, além do serviço que possui os invariantes. Direitos, aplicados explicitamente porque este serviço é executado permitidoTodos sem @EnableMethodSecurity — uma verificação em falta é um controle em falta, não uma negação padrão: VER OPPORTUNIDADES cada leitura CREATE OPPORTUNIDADES levantando um pedido, e pedindo mais tempo por conta própria EDIT OPPORTUNIDADES que aprovam, editam, encerram, decidem sobre uma extensão DELETE OPPORTUNIDADES "Deny Opportunity", que a UI coloca atrás de uma confirmação Negar é terminal, mas não destrutivo: a reserva, suas divisões e seu todo histórico permanecer legível na aba Negado. Este é o ponto de negar que a supressão. Detalhes que valem a pena manter: - O ponto final do cabeçalho é legível apenas com CREATE, uma vez que o botão tem de saber que estado prestar — mas um chamador sem VER quem não é a exploração O agente tem uma projecção reduzida. A comissão divide e justifica que VER existe para proteger não são divulgados pelo portão ampliado. Reconstruído como um allow-list, então um campo adicionado mais tarde não pode vazar por omissão. - A lista mascara contato e empresa em leads não atribuídos para os membros sem VER UNASSIGNED LEADs, correspondente ao LeadController. Quem alegou o que não é o secreto; a perspectiva é. - Extendendo é fechado em ser o agente que detém a reserva, sem deus bypass: manter uma reserva é um fato de identidade, não um direito, e um A extensão é arquivada sob o nome do requerente. - Uma reserva caducada que é reiniciada em vez de retomar, então reservadoAté == reservadoDe + aprovado Os dias continuam a ser mantidos — update() re-derives o fim desde o início, e um começo velho iria apagar silenciosamente o subsídio. - O conjunto de comissões repartidas são os titulares do VIEW LEADS mais bolsista-todos os proprietários / administradores, idêntico ao que o endpoint do coletor oferece. Computando-o da tabela de direitos sozinho fez a oferta dropdown um proprietário o backend então rejeitado. - Expirar é uma varredura agendada para que as abas possam paginar em uma coluna real, mas cada DTO relata diasContinuando com o relógio do banco de dados, então as leituras estão corretas entre varreduras, independentemente. 36 testes cobrem o ciclo de vida, a aritmética da data e as regras de divisão.
· InitializerService
Tabelas para reservas de oportunidades de liderança
Espelhos ChumboOportunidadeReserva, ChumboOportunidadeComissão Em Kamo-compartilhado-biblioteca. ddl- auto: atualização seria criá-los a partir das entidades de qualquer maneira; a DDL explícita é a convenção da casa e torna a forma revisionável aqui em vez de apenas inferível a partir de anotações. Aplicado contra a produção em 2026-08-04 — todos os três quadros e cada índice existem, propriedade do usuário do aplicativo.
· kamo-shared-library
Entidades para reservas de oportunidade de lead com caixa de tempo
Um agente tem direito exclusivo ao encerramento de uma pista para uma janela delimitada; Aprovar subsídios, editá-lo ou negá-lo, e colegas podem ser oferecidos uma parte de a comissão. Três tabelas: a reserva, sua comissão divide, e um Trilha de auditoria só para apêndices. Pontos de projeto que são de carga: - Lead, organização e referências de membros são colunas de ID simples sem estrangeiros chaves, combinando LEAD HISTORY e LEAD TASK. O rasto tem de sobreviver ao chumbo. eliminação e churn membro sem ser capaz de bloquear ou cascata-lo. - dbNow () usa CAST( now() AS timestamp). O BarataDB está nu agora () é TIMESTAMPTZ, que Hibernate 6 materializa-se como um Instant que não pode ser lançado ao declarado LocalDateTime — e a abreviatura ::timestamp é mutilada pela consulta nativa leitura ':' como prefixo de parâmetro. Nenhum dos dois aparece no momento da compilação. - A lista de páginas usa JpaSpecificationExecutor em vez de JPQL com (:Param IS NULL OR ...) guardas, porque o BarataDB rejeita uma ligação não tipificada parâmetro num teste IS NULL nu. - LeadIdentity é uma projeção, não a entidade Lead: Lead maps four @ManyToOne associações que default ao EAGER, listando assim 100 reservas por entidade Disparar centenas de selects para dados que a grelha nunca mostra. - As ordens da linha do tempo do histórico por (dateCreated DESC, id DESC). BarataDB's now() é a hora da transação, então linhas escritas por uma edição compartilham-na exatamente; sem o tiebreak uma trilha de auditoria se reembaralha entre cargas de página. Nenhum estereótipo aqui — o serviço próprio declara o feijão, então nenhum outro serviço paga pela verificação do repositório.
· kamo-internal
Endereçar a citação a uma pessoa; resumo pára de custar a altura do cabeçalho
Mover o resumo para fora da coluna direita fixou a largura, mas comprou-o de volta como um banda sob o título. Agora está na lacuna que já existia entre o título e As ações rápidas, por isso não custa nenhum espaço. Essa lacuna é finita, então menos mostrar em linha e o resto ficar a um clique de distância — uma ordem carrega doze e iria excluir o acções. Permanece visível em cada largura em vez de desaparecer em telas estreitas. A citação também ganha seu destinatário: para quem é, opcionalmente seu endereço e telefone. Estes levam a primeira seção porque é a primeira coisa que você decide, e quando um a conta está ligada o campo de nome mostra o que de outra forma ela cairia. A O bloco "Preparado para" renderiza todos os três e reflete o que está sendo digitado do que foi salvo pela última vez.
· kamo-shared-library
Endereçar uma citação a alguém que ainda não é uma conta
O destinatário foi derivado exclusivamente de uma conta ligada, pelo que qualquer cotação suscitada para um Prospect — que é a maioria deles — imprimiu uma linha em branco "Preparada para" e a finalizada O documento não disse para quem era. A citação agora carrega o nome do destinatário, endereço e telefone em seu próprio direito. O quê? staff digitado ganha sobre a conta vinculada: eles disseram o que deve ser impresso, e um a conta renomeada mais tarde não deve reescrever silenciosamente uma citação que já foi enviada. Endereço é forma livre porque os formatos postais não são uniformes o suficiente para dividir em campos que trabalhar internacionalmente, e imprime como escrito. Uma revisão leva o destinatário Avançar — mesma oferta, mesma pessoa. Esquema aplicado por KamoInitializer antes deste commit; colunas verificadas presentes.
· kamo-internal
Abre o perfil de um membro da sua linha
Adiciona uma quarta ação à doca de hover da linha, ligando- se a **************************** É um verdadeiro NextLink em vez de um manipulador de cliques, então clique no meio e "abrir em uma nova aba" comporta-se e o guarda de repo-hard-navigation permanece satisfeito; o painel fecha na navegação para que o seu bloqueio de rolagem do corpo não sobreviver à mudança de rota. A ação é fechada da forma como os portões de destino em si: as configurações do membro página redireciona você para o seu próprio perfil a menos que você mantenha MANAGEM MEMBERS, GESTÃO MEMBER SECURIDADE, CONFIGURO SISTEMA, EDIT MEMBER ACCESS LEVEL, Allow PROMOTING MEMBERS ou ********************** (ou deus / plataforma admin). Sem um desses o ícone é escondido em vez de oferecido como um morto Fim. A tua própria fila mostra-o sempre.
· kamo-internal
Fail the build when a component calls a key messages/ does not define
next-intl renders the key path verbatim for a missing key, and messages/ is gitignored here — populated at image-build time from kamo-translation-dictionary — so a rename that lands in only one of the two repos ships as visible gibberish with nothing to catch it. That is how the department contact fields came to render **************** on the settings screen, and how the entire HMDA demographics form (39 labels) shipped against a namespace that only contained `lar`. scripts/check-i18n-keys.mjs resolves each translator binding's namespace, then checks every literal key, the static prefix of every template-literal key, and the values passed against the {placeholders} in the message — in both directions, since an unsupplied ICU argument throws MissingValueError and an unused one silently drops data. It understands ICU brace escaping and plural sub-messages, and treats <tag> as a placeholder only for t.rich/t.markup. 1737 files in ~1.4s. Wired into `npm test` and into the Dockerfile ahead of the build, with --require-messages there so a skipped dictionary sync fails loudly instead of turning the guard into a no-op. Typing t() against `typeof en` was tried first and rejected: a JSON import widens values to `string`, so next-intl cannot infer placeholders and rejects correct calls like t('...range', {start, end, total}); it also tripled typecheck time (81s -> 249s) and would have needed ~150 edits to non-buggy code. Call-site fixes for what it found: - dropped a `default:` option passed to t() in the chat components and LanguageButton; next-intl has no such fallback option, so it was dead weight. - commerce lowStock passed {count} for {available}, MultiFileUploader {types} for {list}, and audioVideo master volume {pct} for {percent} — all three threw at format time. - DnsSetupStudio passed a {domain} its subtitle does not use.
· kamo-internal
Opções de navegação Pin/unpin dos navegadores e da plataforma de lançamento
Os membros poderiam mover uma opção entre a barra lateral e a barra superior, mas nunca Tira uma das naves completamente. Acrescenta uma terceira colocação — NENHUMA, "não e duas maneiras de alcançá-lo, ambos dirigindo o mesmo menu compartilhado: - clique com o botão direito numa opção móvel no NavPri/NavTop: o menu de colocação abre em - o controle de canto em cada painel home-launchpad: um chip tranquilo que lê onde a opção atualmente se senta e se expande no hover, abrindo o mesmo menu Unpinned nunca é um beco sem saída. A plataforma de lançamento agora é renderizada de cada portão opção em vez da união dos dois navs, então uma opção não a paleta de comandos faz o mesmo, e cada mudança levanta um nome de brinde de desfazer onde a opção foi. A Disposição de Navegação página de configurações cresce uma coluna correspondente. O solucionador mantém sua invariante — cada opção fechada em exatamente um balde — e uma NENHUMA explícita agora bate uma ordem de zona velha, então um unpin sobrevive a uma bolha escrito antes. Os layouts armazenados no legado não têm entradas NENHUMA e não resolvem Exatamente como antes; O Reset to Standard nunca pode deixar nada desprevenido. Cobertos por novos testes para resolverNavLayout, que não tinha nenhum.
· kamo-internal
Ocultar departamentos vazios, mover o filtro de status para a pasta
- Departamentos sem membros já não prestam. O ponto final do serviço retorna todos os departamentos na org incluindo os vazios, então a lista foi mostrando seções que nunca poderiam conter ninguém. O "não" por departamento O placeholder dos membros vai com eles, sendo inacessível agora. - O filtro Tudo/Online/Offline move-se do cabeçalho do painel para baixo a tira de tabulação, então ela fica na área do diretório com a lista filtros em vez de aparecer para filtrar o painel inteiro (nunca foi aplicado Chats ou Acesso Móvel). - O estado vazio só sugere ajustar a pesquisa/filtro quando um é realmente aplicado; uma org sem membros não tem nada para ajustar.

Seu universo está esperando.
Comece gratuitamente em minutos.Adicione produtos sempre que estiver pronto — sem migração, sem novos logins.
Gratuito para sempre — não é necessário cartão de crédito