Changelog
O que há de novo.
Cada melhoria para a plataforma, como ele envia.
· kamo-internal
Escreva uma descrição do suporte agendado como texto rico
A descrição de... Três linhas de texto. É a superfície de escrita /kb/nova agora, menos imagens e a biblioteca de mídia — aqueles que enviam para a mídia KB, que é a casa certa para artigo e o errado para um campo de configurações. A coluna contém duas formas a partir daqui: um documento lexical em qualquer coisa salva desde, e prosa nua em cada fileira mais velha do que isso, uma vez que nada reescrever Eles. app/lib/richTextField.ts é a ponte. Detecta um documento por análise em vez de por um aparelho principal — prosa como "somente clientes beta" é legal, e farejar iria enviá-lo através parseEditorState, que lança, abre o editor vazio e perde o texto do autor na próxima gravação. Prosa de legado é envolto em um documento para que ele abra como texto editável. Um editor vazio ainda serializa para um parágrafo em branco, então o que é armazenado é decidido pelo texto simples que o editor devolve, não pelo JSON — um descrição como ausente em todos os lugares rio abaixo. Cada leitor é alimentado com as palavras em vez do documento: o assistente de reserva o cartão de picador mantém seu teaser de duas linhas, e o passo confirmado ganha o renderizado descrição, que é o único lugar onde a formatação de um autor escrito é na verdade Lê. RichTextView o transforma através do lexicalToHtml sanitising, e mostra um valor legado como texto escapado — seja qual for a pasta que uma vez foi transportada para um texto simples campo é exatamente o que de outra forma funcionaria. O KbArticleEditor ganha espaço e permiteMedia; a tipografia de antevisão de notas em globals.css é agora compartilhada com uma superfície de leitura .kamo-richtext, que difere apenas em que seus links funcionam. Requer o MediaService que conhece a descriçãoPlain — implantado e verificado antes de pousar, uma vez que seu ObjectMapper rejeita propriedades desconhecidas.
· kamo-login
Adicionar o selecionador de espaço de trabalho
Um sinal que nomeia nenhuma organização agora retorna com uma lista em vez de uma sessão. Esta é a metade do cliente: /api/login passa essa carga útil através (antes do controlo sem OTK, que, de outro modo, iria reportar um sign-in as a failure), /api/session/select relés a escolha e plantas o sessão exatamente como /api/login faz, e um terceiro passo no cartão pergunta qual espaço de trabalho. Construído em torno do que os membros realmente fazem, que é aberto o mesmo espaço de trabalho que última vez: o lembrado é pré-selecionado e nomeado no botão, então isto é uma confirmação em vez de uma pesquisa, enquanto todas as alternativas fica a uma tecla de distância. Setas mover, Enter abre e busca aparece Passados oito espaços de trabalho. O apelido sob cada nome não é decoração. Organizações aqui verdadeiramente share names -- existem quatro chamadas "Acme Corp" -- então é a única coisa que distingue duas fileiras. Um florescer: um único trilho que salta entre linhas através de layout compartilhado, então a seleção do teclado é legível sem um anel de foco em cada elemento. Honrado contra prefere-reduzido-moção, e o passo só monta após o senha, então a opacidade serializada:0 que faz Framer estados iniciais A primeira pintura do bloco nunca se aplica aqui. Ainda inalcançável na produção: SecurityService porta o catador por trás ******************* que está desligado. Isto aterra a UI Primeiro para que a bandeira tenha algo para ligar.
· MediaService
Carregar a descrição do tipo em ambas as suas formas
A descrição é um documento lexical agora, então o serviço armazena o texto simples espelhar o cliente envia ao lado dele e dá aos leitores a forma que puderem usar realmente. WebinarTypeDTO ganha descriçãoPlain para uma superfície que quer as palavras em vez do que o documento. A reserva pública DTO eo agendado-webinar DTO obter texto simples apenas — nem uma página anónima nem um lembrete tem um Lexical runtime, e imprimir o estado de editor bruto em um leitor é pior do que nada. O espelho é escrito incondicionalmente ao lado do documento: um pedido que carrega Nenhum espelho está carregando prosa, assim, clareando ele coloca a fileira de volta no legado os leitores de forma já caem para trás, onde um espelho velho ao lado de um fresco descrição seriam palavras que já não correspondem. Requer a coluna webinar type.description plain, aplicada por KamoInitializer e verificado presente em Yugabyte antes deste pouso.
· InitializerService
Colunas de descrição de texto rico no tipo Webinar
Espelha a alteração da entidade de compartilhamento. Duas coisas que a mesa precisa antes MediaService mapeia-os. A coluna descrição tem de ser ilimitada: possui um estado de editor Lexical Agora, e um tecto varchar não iria truncar, iria rejeitar todo o excepto com um erro de valor muito longo dentro de uma atualização @Transactional que então volta e não deixa nada para explicar. Verificação-então-alter em vez de um ALTER nu, porque a entidade declarou TEXT desde que a tabela foi criada — assim em cada banco de dados esta plataforma executa os curto-circuitos sonda e nenhuma DDL é emitida em tudo, o que importa em YugabyteDB onde uma COLUNA ALTER incondicional ... TIPO registraria uma falha em cada inicialização. description plain é novo: o espelho de texto simples, nullable sem padrão, porque null é o valor honesto para cada linha que precede o editor e é o que diz a um leitor para voltar à descrição. Verificado contra o cluster ao vivo: descrição já era texto, e ambos colunas estão presentes após a execução.
· kamo-shared-library
Armazenar a descrição do tipo como texto rico
A descrição sobre o que é, é um O editor lexical está agora em vez de uma linha de prosa, então a coluna tem que ser um TEXTO ilimitado encadernado como um varchar longo — um @Lob nu em um mapa String para um PostgreSQL objeto grande (oid) em Hibernate 6, que esta coluna não é. DESCRIÇÃO PLAIN é o espelho de texto simples que o editor escreve ao lado do documento, pela mesma razão TrainingSlide mantém o corpoTexto ao lado do corpoJson: apenas um tempo de execução Lexical pode ler um documento Lexical, de modo que cada consumidor quer as palavras teriam que enviar um analisador para um editor interno formato. RichTextValues lê qualquer forma, porque linhas escritas antes do O editor chegou ainda mantém prosa nua e nada os reescreve. PublicWebinarTypeDTO continua servindo texto simples: uma página de reserva anônima não tem E um campo público muda silenciosamente de prosa para JSON imprimir o estado bruto do editor num visitante. CreateWebinarTypeRequest Ganhos ignoradosDesconhecidos — MediaService constrói seu próprio ObjectMapper de um ObjectMapper(), então FAIL ON UNKNOWN PROPERTIES é Na falha de Jackson de verdade e cada campo futuro aqui é uma armadilha de ordem de implantação.
· SecurityService
Deixe um membro entrar sem uma máquina nomear sua org
Adiciona a segunda metade da divisão: um sinal que nomeia nenhuma organização autentica o usuário, então pergunta qual espaço de trabalho. POSTO /api/security/session/select transforma uma escolha numa sessão, e SignInCompletionService detém cada portão entre uma senha correta e um sessão utilizável para que o login e a seleção não possam se separar. Atingido em dois casos. Uma máquina que nomeia nenhuma organização sempre adia... Antes disso, era um sinal que não podia ser bem sucedido. Tirado. O host da plataforma é o caso de a mudança existir para: login.kamocrm.com resolve para KamoCRM Inc., então sem isso ele continua Copiando cada sinal para essa org e um membro de uma org sem domínio Ainda não consigo entrar. O segundo caso está por trás de tudo. FALSE padrão. Ligar faz um membro de várias orgs receber um lista de espaços de trabalho em vez de uma sessão, que um cliente não pode renderizar lê-se como um login falhado -- 17 de 53 usuários têm mais de uma associação. Ele continua com o lançamento que ensina kamo-login o catador. Até em seguida, este lançamento não muda nada para ninguém assinar hoje, e um domínio personalizado mantém o caminho original de qualquer forma. As regras de divulgação são preservadas deliberadamente. Uma senha correta que pode entrar nada é recusado nas mesmas palavras que um errado, ou a forma torna-se um oráculo para credenciais válidas. A lista de espaços de trabalho nunca é uma autoridade: seleção re-prova adesão, então um editado, velho ou inventado A lista recebe uma recusa. O selectToken não é uma sessão -- uso único, cinco minutos, um ID de usuário e Nada mais. **************************** sinalizou corretamente o novo endpoint como pré-sessão; é linha de base com o raciocínio, uma vez que endpoint cujo objetivo é cunhar uma sessão não tem nenhuma solução. Org ids cruza todos os novos fios como cordas digitais. 1200096283020229788 é um id real aqui e não tem representação dupla exata. 923 testes passam.
· InitializerService
Lembre- se da última área de trabalho em que um membro entrou
users.last org id suporta o coletor de espaço de trabalho. Uma organização é não mais tempo nomeado pelo nome da máquina, então um membro que pertence a várias opções uma após a assinatura; esta coluna deixa de ser uma nova decisão cada Bom dia. Uma declaração, ao contrário do UserIsFakeMigration é quatro. Essa coluna acaba NÃO NULL com um DEFAULT e Yugabyte rejeita ADD COLUNN ... NÃO NULL em um Mesa povoada. Este é deliberadamente nulável sem predefinição e não chave estrangeira: NULL é o valor significativo para "ainda não foi escolhido", que é cada conta predating o catador, e uma chave estrangeira deixaria um Org apagado bloqueia uma entrada. Uma identidade velha é inofensiva -- o escolhidor apenas usa- o para pré- seleccionar uma linha que já está a listar. Já aplicado na base de dados live, uma vez que este serviço não tem IC e empurrá-lo navio nada; isto é o que dá um ambiente fresco o coluna.
· kamo-internal
Um arquivo pode ser deixado em qualquer lugar em uma janela de bate-papo, não só na faixa de entrada
O alvo da gota era a superfície do compositor sozinho — algumas dezenas de pixels no fundo de uma janela que de outra forma são todas as mensagens. Uma captura de tela não fez nada. e pior: o padrão do navegador para uma queda de arquivo não reclamada é NAVIGAR a aba para o arquivo, que leva cada janela aberta e cada rascunho não enviado com ele. `useComposerIngest` ganhos `bindDropTarget', que liga os gestos de arrasto a um elemento compositor não possui, e `ComposerSurface` resolve esse elemento do DOM — o shell's próprio `data-tool-janela', ou `data-chatbox-root` para um chat que desenha seu próprio frame. Nativo ouvintes na fase CAPTURE, para que nada dentro da janela possa levar o gesto primeiro ou parar é curto antes que a janela tenha visto; apenas arrastar arquivos são reivindicados, então o chat de IA árvore de pastas mantém o seu próprio arrastar e soltar intocado. Um arrastar de arquivo é reivindicado mesmo ao anexar está bloqueado — recusar o arquivo não deve custar ao membro a página. Um ingere ainda por compositor, para que a janela e a superfície nunca possam encenar a mesma gota Duas vezes. Bate-papo de membros, tickets de suporte, conversas sociais, chat de IA e SMS a única superfície que eles compartilham; um compositor sem janela em torno dele mantém o comportamento antigo.
· kamo-internal
Largue o bloco de saudação e coloque o masthead em uma linha
O masthead da plataforma de lançamento carregava um kicker, um rumo "boa tarde" e um linha de status de aplicativos/título/period/data ao lado do logotipo, e do próprio membro controles flutuaram sobre ele absolutamente — então o cabeçalho reservou um 150px calha e ~130px de altura para dizer a hora do dia. O logotipo e os controles agora compartilhar uma linha flex, que é a altura do logotipo sozinho, e da grade começa muito mais alto.
· kamo-internal
Mover Ligantes e Envios para a direita da tira
A tira agora separa o que um gerenciador de documentos é de onde ele leva você. Esquerda: Originals, Modified, Common — três visualizações dos mesmos documentos. Direita: os quatro atalhos de ícones, em seguida, Binders e Uploads como destinos, mantendo seus rótulos e suas tintas. Lá fora eles não são mais filhos de <Tabs>, então eles estabelecem ativoTab Se eles próprios e marcar o seu próprio estado selecionado — não há indicador fora O grupo para o fazer. Uma página pintada mostra a selecção com um sublinhado branco: on marrom e azul que é a única dica que lê em um olhar sem perturbar o preenchimento, e reserva o 3px se selecionado ou não o rótulo faz não mudar quando está clicado. PintadoTab também carrega sua própria tipografia e dimensionamento agora. Dentro de <Tabs> aqueles veio do `& .MuiTab-root` do pai; uma Tab autônoma não herda nada disso e teria renderizado nos padrões de maiúsculas da MUI.
· kamo-marketing
Definir o título entre aspas
Citações em torno da linha do banner, como solicitado — mas renderizadas a partir de CSS («open-quote`/`close-quote` contra «quotes: auto`) em vez de dactilografados no corda, por duas razões. O gasoduto já traduziu `previewBanner.headline` em 19 locais Desde que a E67f59b aterrou. «traduzir.ts » re-queue uma chave apenas quando falta ou ainda igual ao inglês, então adicionar aspas ao valor inglês deixaria todos os 19 traduções exatamente como são — inglês citado, tudo o mais não citado — e não falta '-força' nunca iria notar. Essa é a armadilha em que a mudança de nome e67f59b foi escrito para evitar, e fazê-lo novamente para terceiro nome da chave e uma segunda retradução completa de uma linha que não mudou Palavra. E o glifo não é partilhado. Conjuntos alemães „...“, francês “...”, japonês ... Uma par digitado em en.json é uma convenção que os outros 21 locais carregam erroneamente ou soltar; `quotes: auto` resolve contra o `lang` em <html>, que [locale]/layout.tsx já define por locale, então cada um tem o seu próprio. Inglês resolve para o “...” encaracolado que a cópia da exibição quer em vez da máquina de escrever par. `quotes: auto` é o valor inicial e é escrito de qualquer forma - `quotes` é herdado, então uma regra de antepassado adicionada mais tarde poderia mudar o que esta renderiza sem tocar neste bloco. Nada mais no globals.css o define hoje. Nenhuma mudança de dicionário neste, por isso, nenhum empurrão cross-repo ordenando para errar.
· kamo-internal
Expressão — cor, espírito animal e logotipo como uma decisão
Dois controles de canto se tornam um. Essa separação foi um acidente da ordem características enviadas em vez de uma distinção que qualquer um detém: uma cor, um padrão e a marca da organização são três LAYERs de uma questão — o que faz isso Os painéis parecem — e combinam-se. Escolhendo-os de dois popups significava que você nunca poderia ver a combinação que você estava fazendo enquanto o fazia, então a folha abre em uma visualização ao vivo empilhando todos os três exatamente como o painel os empilha. TERCEIRO-QUATRO ANIMAIS ESPÍRITO, como SVG < padrão> defs em vez de gradientes CSS. Gradientes fazem listras e pontos e muito pouco mais, e metade desta lista é rosetas, remendos poligonais, escamas sobrepostas e penas de um pavão. SVG desenha formas reais, permanece nítida em qualquer tamanho do painel, leva a tinta do membro diretamente, e é markup em vez de um ativo — nenhum pedido para que o CSP tenha uma opinião sobre e nenhum bytes para transmitir. Formas são dados declarados girados em elementos, então nada atinge o DOM como uma cadeia interpolada, e cada tinta é hex-checked no caminho para dentro pela mesma razão que o designer de quadros As cores são. Cor e padrão são armazenados separadamente e combinar, porque eles são escolhas separadas: mudar de ideias sobre a cor não deve perder animal. A tinta padrão do padrão é a cor da borda do próprio papel — sua profundidade companheiro – assim "Sage + Leopard" significa leopardo em sábio em vez de leopardo em alguma tonalidade não relacionada, que é o que um membro escolhendo esses dois claramente significava. Uma tinta explícita da rampa de org ou a sua própria paleta sobrepõe-a. O padrão pinta sob o conteúdo do painel e seu vidro, ao contrário da marca org que teve que se mover na frente para sobreviver ao borrão. Uma textura pertence sob o mesma superfície fosco a cor está sob; na frente imprimiria zebra riscas na mensagem de alguém. Aplica-se em qualquer lugar que os controles antigos fizeram — widgets, cartões de aplicativo, notas presas, a banda pined-widget — já que todos os quatro já compartilharam o cromo do painel. PaneColorButton e PaneBrandControl são excluídos ao invés de deixados ao lado de seus substituição: duas maneiras de definir uma coisa é como eles derivam.
· kamo-internal
Conte com a guia Binders e pouse em Selected Docs
A aba lê "Binders (n)" de modo que a contagem do arquivo Docs Selected é visível da faixa — incluindo (0), o que é o caso vale a pena ver, uma vez que Diz que a pasta está vazia antes que o membro vá procurá-la. A inserção da aba agora abre Docs Selecionados. O membro chega aqui de escolher documentos, para que o fichário é o que eles vieram para; fazendo-os encontrá-lo no A lista foi um passo sem decisão. Abrir outra pasta durante uma visita não é desfeito pela próxima sincronização — o "já desembarcado" bandeira é um ref reset por desmontagem, por isso re-lands por visita em vez de lutar contra o membro no meio da sessão. Uma nova chave i18n em vez de uma legenda de tabs. pastas: a janela do pacote legal usa esse como um rótulo simples e não tem conta para colocar nele.
· kamo-internal
O quadro é o painel, não algo dentro de um
Cada outro widget é conteúdo no cartão de vidro fosco da plataforma de lançamento, com cabeçalho, um título e um controle de canto. Uma moldura não é: renderizada que forma é uma moldura sentado dentro de um segundo, quadro invisível, e a moldagem O membro desenhado torna-se um detalhe dentro do retângulo de outra pessoa. Assim, o registro ganha `próprioSurface', e declarando que tira exatamente o três coisas que combatem tal widget em vez de servi - lo — o vidro superfície, o fundo cor swatch (um quadro já tem uma cor mat e um moldando o membro escolhido) e o fundo LOGO (uma marca d'água impressa através da fotografia de alguém). Ambos os lugares que pintar a decoração do painel honra é: a grade ordenável e a banda presa. O que o cabeçalho carrega ainda está lá como controles que desvanecem sobre o moldagem — o nome do quadro numa placa legível inferior-esquerda, o caminho para a sua editor e o controle de remoção superior-direita. Escuro e translúcido em vez do o cromo claro habitual do launchpad, porque estes se sentam em uma fotografia e um pálido O botão desaparece no momento em que um céu brilhante pousa naquele canto. Eles param. eventos de ponteiro de alcançar o painel por baixo, ou alcançar o editor começaria um arrasto. Uma bandeira no registro em vez de uma verificação para o ID deste widget, então o segundo widget que pinta sua própria superfície não precisa de mudanças aqui.
· kamo-internal
Mostrar em que camadas de um documento modificado foi trabalhado
Um documento tem um registro modificado, então a aba Modificada tem uma linha por Documento. A coluna nomeia as camadas tocadas em vez de qual de dois tipos a linha foi: Documento uma vez que seus bytes diferem do original, Form Fields uma vez campos foram colocados sobre ele, e "Não editado ainda" para um registro que foi derivado da abertura de um editor e depois nada foi feito. Esse último estado é real e vale a pena dizer: abrir um editor deriva o registro, então reivindicando uma camada lá diria ao membro que eles editaram algo que eles apenas Olha.
· kamo-marketing
Troque o crachá NOW LIVE pela manchete que estava escondendo
A faixa superior levou com uma pílula de seis caracteres — bordado, maiúscula, pulsante — e colocar a mensagem real depois dela. A pílula agora carrega a mensagem: "Executar o seu negócio sem o Kamo é um erro." Nenhum dos cromos do distintivo sobrevive a isso. Uma caixa de 1px em torno de uma frase completa lê como botão, `text-transform: maiúsculo` gritaria uma linha escrita em frase caso, e 1.2px rastreamento é uma medida emblemática em vez de uma leitura. A `:: depois 'lavagem branca e seu `badge-pulse' keyframe ir com eles, juntamente com a entrada '.preview-banner-live' morta na lista de movimento reduzido — o animação estava no pseudo-elemento, por isso fixar o elemento nunca fez nada. O que resta é ousado e branco. #fff sobre #cc1111, a parada mais leve do gradiente atrás dele, medidas 5.25:1; o resto do banner fica a 0.92 alfa, assim o peso e que últimos 8% de branco separam o título do linha changelog ao lado dele. O ponto de interrupção do wrap move 640px -> 768px. Esse número foi escolhido quando este slot manteve seis caracteres; a linha nowrap única agora mede ~625px com o copy changelog depois dele, então em 640px o banner gastaria o último ~15px de a sua gama de linhas únicas transbordando a sua própria caixa fixa de 38px. 768 terminar com o ponto de paragem de movimento reduzido abaixo, para que o banner pare de brilhar e começa a embrulhar em uma largura em vez de dois 128px separados. A chave de cópia é RENAMED, não reavaliada (lado dicionário, mesmo conjunto de alterações). `traduzir.ts` filas de uma chave apenas quando está faltando ou quando seu valor ainda igual à fonte inglesa — não tem noção de uma string inglesa que mudou. Edição `nowLive` no local teria deixado todos os 21 locais traduzindo "Agora Viva!" até que alguém pensou em correr "--força". Falta uma nova chave em todo o lado. assim a próxima sincronização capta-o, e `writeLocaleFile` itera as chaves do en, que Poda o velho de cada localidade. Até que isso corra, o retorno inglês merge em i18n/request.ts renderiza a frase em inglês em vez de uma chave bruta.
· InitializerService
Mesclar os dois registros modificados em um com duas camadas
Quando um documento tem ambos os tipos, a linha CLASSIC sobrevive — é aquela que pode conter bytes editados — o design é remarcado para ele, e o FORM FILLABLE A linha é suprimida. Perder cada lado seria perder o trabalho de membro: os bytes são edições feitas em LibreOffice, o design é a colocação de campo feita à mão. O índice único torna-se uma linha por original em vez de uma por (original, kind), e só é construído após a mesclagem não deixa nenhum documento segurando dois. modified kind é deliberadamente deixado na tabela. Derrubaria qualquer coisa. O pod DocsService ainda executa a imagem anterior no meio do rollout, que nomeia o coluna em cada Img SELECT; ele pode ir uma vez que a frota virou. O corredor anterior não cria mais o antigo índice único per-kind, então os dois migrações não gastam cada corrida lutando por ele. Aplicado a prod à frente deste empurrão: 8 linhas modificadas, 4 projetos de transporte, 2 com bytes diferentes, nenhum dobrou, nada perdeu.
· kamo-internal
Quadro de imagens – fotos e vídeos de um membro, em uma moldura que ele constrói
O primeiro widget INSTANCED. Um membro pendura quantas armações quiserem, cada um. com seu próprio conteúdo, sua própria moldagem e seu próprio lugar na grade, de uma entrada de registo. O Mitre. Um quadro é um perfil de moldagem repetido em quatro lados e cortado em 45° onde eles se encontram, que é como um quadro real é feito ea razão esta modelo não tem "borda superior" ou "borda esquerda" — não há nada para manter em passo Porque só há uma coisa. Um membro projeta a seção transversal, os quatro lados caem fora dele, e cada canto é uma linha de 45° POR CONSTRUÇÃO em vez do que por um estilo que qualquer um pode errar. Cada lado é um trapezóide cortado fora de uma caixa de tamanho completo e pintada com um gradiente a correr da borda exterior para dentro; as extremidades inclinadas são a mitra, e quatro delas telham a borda com sem sobreposição e sem costura. As cores «fronteira-*» teriam sido livres e ferramenta errada: eles não podem carregar um perfil multi-banda ou uma textura, e um membro que editou um lado teria mais três para consertar. A foto. Razão de aspecto sempre mantida, quadro sempre preenchido, transbordamento recortado. Letterboxing dentro de uma moldagem parece uma falha no quadro em vez de um propriedade da foto. As instâncias viajam como `widget:picture-frame#<uuid>` através do layout, o loja de painéis e a preferência de exibição/esconde, por isso uma moldura mantém o seu próprio tamanho, cor, logotipo e posição e escondendo um deixa seus irmãos sozinhos. O ID vocabulário movido para widgetIds — puro e coberto, porque essas strings são persistente no arranjo armazenado de cada membro e sua forma é carga de carga. Uma instância defaults to SHOWN: the member made it, and making É a decisão de tê-la. O editor da... coloca o quadro no tamanho pendurado à esquerda e tudo o que o muda em A direita. A antevisão é o componente SAME que o launchpad renderiza, não um fac-símile — uma moldagem que olha refinado a 90px é uma laje a 400, e dois os renderers iriam derivar com a pré-visualização sendo aquele que drifted. Gravações são debochado e otimista: projetar um quadro é uma centena de pequenas mudanças em um minuto, então um botão de salvamento significaria perder o lote para um erro de clique. Todas as cores num desenho armazenado são verificadas antes de atingir um gradiente. Estas bolhas são dados de autoria de membros que estão a ser interpolados num atributo de estilo, e a verificação é o que mantém um frame salvo de ser uma forma para escrever CSS arbitrária. A mídia reordena com setas em vez de arrastar: esta grade fica dentro de uma página acessível a partir de uma plataforma de lançamento o membro já arrasta painéis em torno, e Uma segunda superfície de arrasto diferente é como as pessoas movem a coisa errada. Setas também funcionam em um telefone e com um teclado. Os envios vão um de cada vez — disparando vinte pedidos simultâneos de várias partes em uma pod é como um membro com uma pasta de férias derruba o serviço para todos Mais uma vez.
· SecurityService
Endpoints de quadros e mídia, e semeia os novos direitos
Só a si mesmo, e aplicada no QUERY. Cada leitura e escrita resolve o membro da sessão e cada chamada de repositório toma esse id, incluindo a pesquisa em um único frame — um frame id é um UUID que viaja para o navegador e para trás, para que uma descobertaById iria entregar a parede de outra pessoa para quem quer que adivinhasse Uma. Não há deliberadamente "gerir os quadros de outro membro" ponto final: e o controle do administrador sobre este recurso é o direito, não o conteúdo. A mídia passa pelo ImageService em vez de ser armazenada aqui, que compra conteúdo-endereçado dedup (a mesma foto em três quadros é um arquivo armazenado), contabilidade de armazenamento de org, e reprodução através do proxy de imagem existente – que já fala HTTP Range, então um vídeo já procura. Hashes são calculado no controlador porque o gasoduto valida o contra o seu próprio e o chamador aqui É o servidor; isso é o que todos os outros O carregador do lado do servidor na plataforma faz. O ORDER de uma apresentação de slides vive na blob de configurações do frame, não como uma coluna sobre cada imagem: uma linha de imagem é compartilhada por cada associação que se refere ao seu bytes, então uma coluna de ordenação nela pertenceria a qualquer quadro escrito por último. A eliminação de uma moldura destrói a mídia. Deixando as fileiras para trás iria manter faturando a organização para um muro que ninguém pode abrir, que é o órfão classe esta plataforma já foi mordida por antes. Tectos: 12 quadros por membro, 120 itens por quadro, 100 MB por arquivo. O último é bem abaixo dos outros limites de upload da plataforma de propósito — isto é parede decoração que autojoga atrás de uma plataforma de lançamento, e um vídeo de 2 GB seria obtido por cada página que o membro abre. A semente de direitos de MANAGEM OWN BACKGROUND IMAGES, que já diz isso membro pode decorar sua própria tela com seus próprios uploads — a semente mais segura do lote, uma vez que nada em um quadro são os dados de outra pessoa. ADDED deliberadamente NÃO semeia, ao contrário de todos os outros widgets: os outros abrem sobre algo que o membro já tem e são úteis no momento em que aparecem, enquanto Uma moldura vazia que ninguém pediu é bagunça. Os manipuladores nomeiam o helper de sessão atualMembro para que o não autenticado endpoint catchet pode ver a guarda — sua varredura lê um corpo de método e faz Não siga chamadas.
· InitializerService
Criar a tabela de imagens quadros
Uma linha por widget de quadro de imagem um membro tem organizado em seu launchpad. Uma tabela em vez de uma blob preferência porque as fotos e vídeos em um frame são linhas de imagem carregando seu id em assoc object id, e uma associação precisa de algo durável para apontar. Um ID de quadro que vive apenas dentro de um membro Preferências JSON seria uma chave estrangeira para nada: nada poderia impor que o frame ainda existe, e limpar as preferências de um membro Orfãos silenciosamente todos os byte que eles tinham carregado. configurações é TEXTO segurando JSON de propósito. É a aparência do quadro — leia inteiro para desenhar um painel, escrito inteiro em salvar, nunca colunas cada novo bisel ou grão que o designer cresce seria outra DDL mudar a aterragem aqui antes do serviço que a mapeia, para um valor sem consulta nunca filtrará. @Order(0) pela convenção de esquema: uma vez que a entidade de compartilhamento de lib exista, qualquer corredor que carrega um PictureFrame através do JPA emite estas colunas em sua SELECT, então uma migração tardia nunca seria alcançada — um anterior runner iria morrer em "relation picture frames não existe" e fazer a execução Para baixo primeiro. NOTA PARA DEPLOY: SecurityService executa hibernate ddl-auto: nenhum, então esta tabela não aparece por si só. Este serviço deve ser executado antes da moldura da imagem O recurso funciona.
· kamo-shared-library
O esquema, os direitos e o domínio de armazenamento por trás dos widgets de quadros
Um Picture Frame é fotos e vídeos de um membro em seu próprio lanchepad, e um membro pode enforcar vários. Isto é tudo o que a plataforma precisa para segurar Uma. PictureFrame é uma linha em vez de uma chave na blob de preferência do membro porque os meios são linhas de imagem associadas BY frame id, e uma associação precisa de algo durável para apontar. Escopo dos membros, em vez de o utilizador: os bytes são armazenados sob uma organização e contados contra ela, então um frame que seguiu uma pessoa entre orgs colocaria um org's armazenamento em outro A conta do org. Sua aparência é uma coluna JSON — lido inteiro para desenhar um painel, escrito inteiro em salvar, nunca queried em — assim que um designer que cresce um bisel no próximo mês não precisa de uma mudança DDL antes dele. ImageAssocType.PICTURE FRAME escopos para o Quadro, não o membro: vários frames são vários slideshows, e scoping para o membro faria cada um Eles mostram tudo. Ele compra conteúdo-endereçado dedup de graça, então um membro que coloca a mesma foto em três quadros é cobrado por um. StorageDomain.PICTURE FRAMES recebe sua própria linha em vez de ser dobrada em Um balde geral. Este é o único domínio que as pessoas de uma organização preenchem alguns megabytes de cada vez com ninguém administrando-o, e uma org observando sua A lei precisa de ver isso separadamente dos documentos em que o seu negócio é executado. O teste de cobertura teria falhado a compilação de outra forma, que é o ponto Dela. Direitos seguem a forma que qualquer outro widget usa — PICTURE FRAME WIDGET mais as quatro crianças políticas — penduradas fora MANAGEM OWN BACKGROUND IMAGES, a direita que já governa a mídia pessoal que um membro coloca em sua própria tela. Não é uma raiz: um elemento cuja concessão é inacessível do grupo que possui a sua dados é um direito que ninguém encontra. Ids 229-233; 228 foi tomada. Taxonomia 219/156/32/31 -> 224/161/32/31.
· kamo-internal
Colocar os quatro atalhos de membros numa linha
são uma classe de controle, então eles agora compartilham uma linha: canto superior direito lê como uma única tira em vez de uma pilha de duas linhas. styling; ele usa a pílula compartilhadaLinkSx como seus vizinhos, e colapsa o seu rótulo em xs como eles fazem, então quatro atalhos ainda cabem em um telefone. A linha envolve em vez de transbordar quando um membro detém cada um deles.
· kamo-internal
Posição e cor para o logotipo de um painel, e sempre deixar um membro abrir o editor
O editor era impraticável para qualquer um que o rolo não tivesse decidido. «brandOf» respondido null até que uma marca existisse e o controle fosse fechado na resposta, assim um membro cujo a semeadura não tinha corrido — ou não tinha persistido — não tinha nenhum botão e nenhuma maneira de dar pane um logótipo. Um painel indeciso é um sem marca, não um que falta: Sempre responde, e o editor está sempre lá. A banda de pined-widget tinha o mesmo sintoma por uma razão diferente. Ele renderiza fora ClassificableCard, que é o que revela o cromo de um painel sobre pairar, então seus controles se sentaram em opacidade 0 permanentemente. Ele carrega a própria regra agora. POSIÇÃO. Nove âncoras no popup, desenhadas como uma grade cujas células cada um tem um ponto em seu próprio canto, para que o picador lê como o painel que ele representa. A rotação teve de passar para o logotipo em si: girando a caixa de dimensionamento balançou uma marca borda-anchored em torno do painel centro e fora do canto o membro tinha acabado de colocá-lo. Cor. A marca pode ser pintada uma silhueta sólida, através do ThemeLogo existente sobreposiçãoColor — uma máscara CSS, por isso atinge uma cor arbitrária em vez de empurrar o as cores próprias da arte ao redor. Duas fontes: a rampa da marca da organização Dedurou-se porque uma orgia que estabeleceu apenas uma primária tiver a sua luz e o seu valor mais leve predefinido; e a paleta do próprio membro, usando o companheiro profundo de cada cor em vez de seu papel pastel, uma vez que uma silhueta pálida num painel pálido é uma marca que ninguém consegue ver. DIMENSÃO ENTRE O ROLO, entre 0,55 e 1,1 do painel. Cada marca em exatamente 0,85 foi o dizer que uma página tinha sido gerada em vez de composta.
· kamo-internal
Pinte as notas mestre nas cores da organização
"Nosso Master Note" é o PRIMÁRIO da organização e "Meu Master Note" seu SEGUNDO, cada um como um pastel — um 18% tint no branco. O par lê como um conjunto em um olhar, e nenhum pode ser confundido com uma das doze cores pós-it membro escolhe para suas próprias notas. Derivado de -- cor- primário / --color-secundário em vez de um feitiço, então uma org-branco-marca tem sua própria marca. A borda é pisou contra ardósia e o papel deliberadamente não é: uma org pode definir um primário quase branco, e um 18% de que é apenas uma folha mais clara, mas um A borda misturada a partir dele sozinho seria uma regra invisível, pin e caret. Mesmo raciocinando como os tokens da barra de rolagem da página. Uma consequência, e é o ponto: uma nota mestre não tem mais paleta. A cor é o que diz de quem é a nota, que não é a escolha de um membro — por isso o o swatch desapareceu do painel, do cartão, do adesivo e do editor e do KBService Para de semear um. "33" teve que ir com ele. Adicionando dígitos hexadecimais a um mix de cores () a expressão produz uma declaração que o navegador cai silenciosamente, deixando bordas com nenhuma cor em tudo; comStickyAlpha () toma ambas as formas e cada superfície de notas vai através dela agora. useMasterNotes também se une com o cache da sobreposição flutuante, o caminho selectPinned Panes faz — caso contrário, uma nota principal editada em seu pegajoso mostrou a sua tempo de montagem do texto na plataforma de lançamento até uma recarga.
· kamo-internal
Coloque as duas notas mestre em cada plataforma de lançamento
"My Master Note" e "Our Master Note" são painéis na mesma grade de classificação que tudo mais — arrastado, redimensionado e ordenado como qualquer outro painel — e nenhum pode ser removido. A organização tem um anel cónico-gradiente pintado do --color-primary, a única borda móvel na página, então o único painel que fez não vem do membro lê como tal do outro lado da sala. Parado a uma estática Anel sob o movimento preferido. Ambos estão presos, então eles chegam na lista também; selecionePinnedPanes gotas eles lá, ou cada um seria pintado duas vezes e o duplicado seria a cópia sem o distintivo e a borda. Fetched from /api/notes/master, que não está fechado no aplicativo Notas: o pintado painéis de notas são o aplicativo Notas derramando na página inicial, e estes são móveis da própria página inicial. Cada controle que o servidor recusaria é retirado em vez de desativado: não unpin, sem apagar e sem renomear em qualquer nota mestre, e sem cor, sem barra de ferramentas e nenhuma superfície de digitação na organização é para um membro sem direito. A membro somente leitura recebe um leitor — a mesma renderização do painel usa — em vez de um editor cujos salvamentos seriam rejeitados depois de terem feito o trabalho. notasApi.saveNote rotas por escopo, assim o pegajoso, o editor, a parede e o O coletor de cores do launchpad pára de precisar de saber que a nota da organização tem nenhum membro e por isso não pode ser atingido pelo endpoint per-id.
· KBService
Servir, fornecer e proteger as duas notas mestre
GET /api/notes/master responde tanto e provisões o que estiver faltando. PUT /api/notes/master/org escreve "Our Master Note", endereçada pela organização em vez de pela nota id, então não há nada para adivinhar e nenhuma outra organização nota para alcançar. Editá-lo requer MANAGEM ORG MASTER NOTE ou propriedade do organização — o andar do proprietário é a garantia anti-bloqueio, uma vez que o direito é deliberadamente não semeado em papéis existentes. GET /master deliberadamente não toma notas direito. VEJA NOTAS as notas *app*; estes são acessórios da plataforma de lançamento home, e "cada membro sempre tem um" tem quer dizer todos os membros. As listas ordinárias mantêm o seu portão VER NOTAS e agora também devolver a nota da organização, para que seja legível e pesquisável na parede. As regras são aplicadas aqui em vez de no cliente: uma nota mestre não pode ser suprimido (409 — um fato sobre a nota, não sobre quem está perguntando), não pode ser sem pin, e não pode ser renomeado. Título e pin são ignorados em vez de rejeitados, porque o editor envia todos os campos em cada gravação e recusa da requisição falhar uma edição para o CORPO sobre um título que o membro nunca tocou. As chaves de conteúdo seguem o escopo: chaveForOrg(orgId) para a nota da organização, então cada O membro da organização pode lê-lo. Derivando-o de quem quer que o tenha escrito Fazer uma nota compartilhada legível por uma pessoa. Provisão é seu próprio feijão e sua própria transação, e faz todas as leituras anteriores sua primeira escrita: desde a mudança para Yugabyte um SELECT após uma escrita em um A transação pode voltar 4001 e abortar. Um método privado em NotesService teria sido inerte como @Transactional e executado na transação do chamador.
· InitializerService
Adicionar as colunas do master- scope às notas
MASTER SCOPE ('MEMBER' / 'ORG' / NULL) e ORGANIZAÇÃO ID, mais os dois índices a entidade declara e um índice único parcial por escopo para que uma nota mestre viva por membro e por organização é executada pela base de dados em vez de apenas o achado-então-criar em NotesService. Sem backfill: cada nota existente é uma nota comum e NULL lê exatamente como Isso. O mestre nota que eles mesmos são providos lazily na primeira leitura que quer-los, que abrange os membros e organizações criadas após esta execução sem uma segunda migração. @Order(0), como cada corredor de adição de colunas: o momento em que a biblioteca compartilhada mapeia estas colunas, qualquer corredor que carrega uma nota através de JPA emite-los em seu SELECT, Então uma migração ordenada tardia nunca é alcançada. Aplicado a Yugabyte 2026-08-22: todas as sete declarações aplicadas, ambas as colunas e todos os quatro índices verificados estão presentes.
· kamo-shared-library
Modele as notas de mestre e a direita que guarda os org's
Uma nota principal é a única nota que um membro — ou uma organização — sempre fez. "Minha Nota Mestra" é provida por associação; "Nossa Nota Mestra" é uma por organização e aparece na plataforma de lançamento de cada membro. Ambas são linhas comuns `notas' carregando um SCOPE MASTER, não uma tabela nova, então o Editor lexical, salvamento automático, versões, cores, o pegajoso flutuante e o RAG publicar todos continuam trabalhando com nada para manter em passo. Uma linha ORG carrega um NULL MEMBRO ID de propósito: cada localizador de membros corresponde `n.member.id = :memberId', para que a nota da organização nunca possa ser retornado pela listagem privada de um membro, atualização ou exclusão. Lê que deve vê-lo passar pelo novo `...VisibleToMember` localizadores, que se alargam a ele explicitamente; escreve manter o par de membros e assim não pode alcançá-lo em tudo. MANAGEM ORG MASTER NOTE (228) é uma raiz autônoma com um tipo de serviço nulo, MANAGEM ORG BRANDING: o papel, o título de trabalho e apenas editores de departamento renderizar a seção de um serviço quando a org tem aquele aplicativo ativado, e o mestre de org a nota está em todas as plataformas de lançamento se as Notas estão ou não ligadas. Não parentado a VER NOTAS pela mesma razão — KBService serve a nota sem notas certas.
· kamo-internal
Marcar um terço dos painéis de um membro com o logotipo org, e deixá-los afinar
Um terço dos painéis de um membro usam a mesma marca de org / leads e /calendar transporte, em Escala de painel. Que painéis, e como, é enrolado uma vez e mantido. O que o rolo decide. A marca de um painel depende da forma do painel. indo para, porque um wordmark e um ícone se encaixam retângulos diferentes. Um painel quadrado é o o jogo de moeda declarado entre os dois. Um largo inclina - se para o sinal de palavra em três em quatro — um wordmark IS wide, e um ícone quadrado em uma faixa de quatro colunas é um ponto em um campo. Um alto Pega sempre no marcador de palavras e gira-o no sentido dos ponteiros do relógio, que se encaixa num painel alto melhor do que qualquer um dos dois. E cada painel de marca tem alguns graus de inclinação o que quer que mais foi rolado: uma marca colocada perfeitamente quadrado em um painel retangular lê como um erro de layout, e alguns graus fora verdadeiro lê como um selo, que é o que é. A tilt vai de qualquer forma, porque uma página de marcas todas inclinadas esquerda lê como um bug de renderização. PER PANE, NUNCA VEZ — a diferença em relação à semeadura de cores, e a razão de um painel que não é marcado tem que gravado em vez de deixado em branco. Ausência significa "este painel é novo, roll it", que é o que permite que um widget ligado no próximo mês, uma nota semana ou um aplicativo recentemente concedido tomar o mesmo passe em sua primeira aparência, enquanto nada já na página se move. É também o backfill: uma plataforma de lançamento disposta antes de qualquer um dos essa existência não traz decisões, então cada um de seus painéis é novo por essa definição e é rolado na próxima carga. Nenhuma migração, e nenhum membro o recurso não consegue alcançar. O OPT-ONG vem primeiro. Uma organização cujo bgWatermark é NENHUMA se transformou logotipos de fundo desligados; uma nova superfície não é uma isenção de uma preferência já expresso, de modo que esses painéis não render nenhuma marca seja lá o que foi rolado. O editor. Um controle ao lado da cor abre um popover para a marca em si: cheio, simples ou nenhum, mais rotação, tamanho, matiz e contraste. Tudo nele é vivo — o valor vai diretamente para a preferência que o painel renderiza de, então um membro arrastando o o slider de matiz observa o painel atrás da mudança popover enquanto eles se arrastam. Armazenados contra seus registro de membro como qualquer outra preferência de painel. O filtro é matiz-rotado e contraste em vez da escala de cinza da marca d'água da página, porque a escala de cinza tira a tonalidade e deixou ao membro um controle deslizante que não moveu nada. Reset-to-defaults na página widgets deliberadamente NÃO limpa marcas: re-rolling a logo iria entregar alguém uma plataforma de lançamento diferente cada vez que eles pressionaram-no, o que não é Uma reinicialização.
· kamo-internal
Editar no Modo Clássico e redesenhar quando salvar
O editor preenchedor de formulários pode agora se ramificar para LibreOffice. O servidor deriva a versão clássica no caminho se o documento não tem um, que é o ponto de ofereci-lo a partir daqui — um membro que só acrescentou formulário campos ainda não tem uma cópia clássica para abrir. Quando essa outra aba salva, o editor recarrega. As páginas onde os seus campos estão assentados ter acabado de mudar por baixo dele, e de outra forma iria continuar a desenhar os Eles foram colocados sobre. É o que diz em vez de redesenhar em silêncio: diferença entre "o documento atualizado" e "meus campos saltou para no razão", e depois de um fluxo eles podem realmente precisar de movimento. O editor que fez o salvamento não é carregado deliberadamente — ele já detém os bytes que escreveu, e recarregando-o iria descartar qualquer coisa digitada desde então. Os IDs são comparados como cadeias de fim a fim. Dois IDs de membros int64 diferentes comparar EQUAL como números, o que significaria o salvamento de um colega recarregando seu editor; o teste afirma que a igualdade diretamente para que a razão não seja apenas um comentário.

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