Pre production2 - #831
Open
charles-ramos wants to merge 37 commits into
Open
Conversation
Fase A do porte production1 -> production2:
- src/dashboard/Data/Agent/ (Agent.react.js, Agent.scss, AgentConfigDialog.react.js)
e src/lib/AgentService.js
- Empty state com B4aEmptyState + botao Configure; dialog com B4aFormModal (padrao
visual do production2)
- Form "Configure" (localStorage, provider OpenAI) para o usuario informar a apiKey
pela UI, sem editar o config.json
- Rota /agent no Dashboard.js + secao Agent na sidebar (DashboardView)
- Parse-Dashboard/app.js: porta a rota POST /apps/:appId/agent + makeOpenAIRequest +
database tools + conversas; adiciona require('parse/node'); usa fetch global (Node 18,
sem node-fetch); express.json() escopado so na rota (production2 nao tem body-parser global)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
O package.json declarava core-js em 3.28.0 (dependencies) e 3.6.5 (devDependencies). Sem lockfile, o npm install deixava o 3.6.5 no topo, que nao tem modulos como es.error.cause.js/es.array.at.js/etc. O babel usa corejs '3.28' (useBuiltIns 'entry'), entao o `npm run dashboard` (webpack build.config.js) quebrava com ~40 erros "Can't resolve 'core-js/modules/...'". Alinhado ambos para 3.28.0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sem lockfile, o npm resolvia um tslib antigo (sem __spreadArray) no topo. O @amplitude/analytics-core chama tslib.__spreadArray em runtime -> TypeError -> tela branca no dashboard. tslib e transitivo (nao esta no package.json), entao forcei via "overrides" para 2.6.2 (tem __spreadArray, retrocompativel). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…uction2 - Agent.scss convertido do tema claro (production1) para o dark do production2: fundo #0f1c32, superficies/bolhas/input escuros, texto claro, acento azul. Layout/estrutura mantidos. - Toolbar: section "Core" -> "Agent" (breadcrumb correto). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Porta da production1 os constraints que faltavam no production2: - matches (regex, String) -> query.matches(field, str, modifiers) - onOrBefore (Date) -> query.lessThanOrEqualTo - onOrAfter (Date) -> query.greaterThanOrEqualTo Definicoes em Constraints + FieldConstraints (String/Date) em src/lib/Filters.js, e os cases correspondentes em src/lib/queryFromFilters.js. O production2 ja tinha neq/keyNeq/stringContainsString. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…que) O BrowserCell do production2 importa B4aBrowserCell.scss, que NAO tinha as classes .selected/.leftBorder/.rightBorder/.topBorder/.bottomBorder. A logica de selecao (handleCellClick + selectedCells) ja funcionava, mas classes.push(styles.selected) empurrava undefined -> celula selecionava internamente mas nao pintava (nenhum erro no console). Copiadas as 5 regras do BrowserCell.scss normal. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…curo - Cmd/Ctrl+C agora copia o INTERVALO de celulas selecionadas (tab/newline), nao so a celula focada. No production2 o range faz setCurrent(null) -> copyableValue undefined -> o case 67 existente nao copiava nada. Adicionado o copy multi-celula no topo do handleKey (guard >= 0 pra nao quebrar no estado inicial). - .selected: de #e3effd (claro) para rgba(22,105,252,.3) e bordas #1669fc — legivel no Data Browser escuro do production2 (antes o texto claro sumia no fundo azul-claro). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Portado da production1: no handleKey, case 32 (Space) faz toggle do selectRow da linha "current" (quando nao esta editando). production2 nao tinha esse case. Guards para this.props.selectRow/selection/data existirem. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…lique pegar
O checkbox usava checked={selection['*'] || selection[obj.id]} sem coercao — quando
selection[id] era undefined, o input virava NAO-controlado, e a transicao
nao-controlado->controlado no clique fazia o React nao registrar a marcacao. Coercao
com !! (igual production1) mantem o input sempre controlado. O espaco ja funcionava
porque ia direto no selectRow.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…(upstream) Porta a feature drag-to-select da production1: mousedown num checkbox inicia o arrasto, cada checkbox que o mouse passa por cima marca/desmarca, mouseup encerra. - Browser.react: estado rowCheckboxDragging/draggedRowSelection, metodos onMouseDownRowCheckBox/onMouseUpRowCheckBox/onMouseOverRowCheckBox, listener global de mouseup, e passa os handlers pro DataBrowser (fluem via ...other ao BrowserTable). - BrowserTable: repassa onMouseDown/OverRowCheckBox aos 3 <BrowserRow>. - BrowserRow: checkbox com onMouseDown, checkCell com onMouseOver. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…orage Agora que o pre-production2 tem getEnvVars/updateEnvVars (feature do production2): - Configure -> Save: grava a apiKey na env var OPENAI_API_KEY do app (merge com as existentes via getEnvVars); dispara rebuild do app (comportamento da feature). - Agent carrega: le a apiKey via getEnvVars; partes nao-secretas (name/provider/model) ficam em localStorage. A chave nunca persiste no disco do browser. - Dialog: onSubmit retorna a promise -> modal mostra "Saving..." durante o rebuild e surface erros. Descricao do campo API Key atualizada. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- icon 'collaborate-solid' (nao existia no sprite -> item sem icone) trocado por 'b4a-agent' (icone dedicado que ja existe em src/icons). - Remove subsections: [] -> o Sidebar renderizava um submenu VAZIO (bloco grande em branco abaixo de "Agent"). Sem a chave subsections, o item fica compacto como o "Overview". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rtilhada
- AgentConfigDialog vira gerenciador de lista: 1 API Key compartilhada + N modelos
(Display name + model), com "+ Add model" e "Remove" por modelo.
- saveAgentConfig({apiKey, models}): grava a chave no env var OPENAI_API_KEY (uma so)
e a lista de modelos (nao-secreta) no localStorage; monta em memoria cada modelo
com a chave compartilhada.
- loadAgentConfig: le a lista do localStorage + a chave do env var.
- O seletor "Model" no toolbar do Agent ja itera models -> troca entre eles.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Troca os icones dos menus do toolbar do Agent (que vieram do upstream) pelos B4a: - Model: gear-solid -> b4a-app-settings-icon - Permissions: locked-solid -> b4a-lock-icon - Chat: collaborate-solid -> b4a-agent Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- B4aSidebarSection.getIconContent nao tinha case pro 'b4a-agent' -> no estado ATIVO caia no default (null) e o icone sumia. Add case que renderiza o sprite b4a-agent. - AgentConfigDialog: "+ Add model" (link no rodape) vira um botao "+" (b4a-add-outline-circle) no topo da secao Models, seguindo o padrao de "adicionar row". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Layout (offsets eram da production1): - left 300px -> 280px ($b4aSidebarWidth) no emptyStateOverlay e chatForm - top/padding-top 116px -> 127px (header 63 + toolbar 64 do production2) - sidebar colapsada: $sidebarCollapsedWidth -> 88px ($b4aSidebarCollapsedWidth) - agentContainer: removido o background navy de 100vh que vazava ACIMA do toolbar cinza (a region do header). O navy agora vem do chatWindow/emptyStateOverlay, abaixo do toolbar. Tooltips (title do BrowserMenu = tooltip nativo) mais descritivos: - Model -> "Select AI model" - Permissions -> "Permissions — what the agent can do in your database" - Chat -> "Chat options (clear conversation)" Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…at" vago Remove o menu "Chat" (que juntava Configure + Clear num icone so, pouco intuitivo) e coloca dois botoes diretos no toolbar: - "+" (b4a-add-outline-circle) -> abre o Configure (add/editar/remover modelos). tooltip "Add / configure models". - Clear (b4a-trash-icon) -> limpa a conversa. tooltip "Clear conversation". Estilo .toolbarAction (icone com padding + hover). clearChat ja guardava o browserMenuRef. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ixeira) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
lixeira parecia deletar dados, refresh parecia recarregar. O padrao de chat moderno para recomecar e o icone de compor/lapis = nova conversa. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Lixeira parecia deletar dados, refresh parecia recarregar, lapis parecia editar/voltar. Texto "Clear" e inequivoco. Tooltip "Clear conversation". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
O upgradePrompt (newFeaturesInLatestVersion) aparecia na pagina /apps sugerindo atualizar o dashboard. Removido o bloco; upgradePrompt fica sempre null. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Rotulo no toolbar com o nome do modelo selecionado (title mostra o model id, ex. gpt-4o) — dá pra ver qual está ativo sem abrir o menu. - selectedAgentModel deixa de ser global e passa a ser por-app (selectedAgentModel_<slug>); setDefaultModel respeita a escolha salva do app ou cai no primeiro modelo. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tre apps) O componente Agent é reaproveitado ao navegar entre apps (só o contexto/slug muda, não há remount), então selectedModel/userAgentConfig/messages ficavam com os valores do app anterior. Agora detecta a troca de slug em componentDidUpdate e recarrega a partir do storage do app novo. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…alStorage Antes só a API key era env var; a lista de modelos ficava em localStorage (agentUserConfig_<slug>), o que fazia o display name vazar entre apps. Agora a config inteira (key em OPENAI_API_KEY + lista em AGENT_MODELS) é env var, então o backend é a única fonte por-app. Também guarda o render do modelo ativo no toolbar para só mostrar quando o modelo existe na lista do app atual. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…letar o agent - Remove o default "My model": o campo de display name começa vazio e, se ficar vazio, cai no id do modelo (ex. gpt-4). Assim nada aparece no toolbar antes de o usuário salvar um modelo de verdade. - Adiciona "Delete agent" (danger zone) no dialog: remove os env vars OPENAI_API_KEY e AGENT_MODELS, limpa a seleção por-app e volta ao empty state. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Em vez de POST /apps/:id/agent no servidor do dashboard (mandando a apiKey no corpo), o frontend agora chama POST /parse-app/:slug/agent na API back4app via ParseApp.sendAgentMessage(). A chave OpenAI é lida da env var do app no backend; o browser não envia mais segredo. O agent server-side é stateless, então o histórico recente é enviado a cada request. validateModelConfig não exige mais apiKey no cliente. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Em vez de campo livre pro id do modelo, um dropdown com modelos OpenAI comuns (gpt-4o, o3, gpt-5, ...) + opção "Custom…" que revela um campo de texto pra digitar qualquer id (ex. release nova). Evita typo e modelo inexistente sem travar quem quer um modelo fora da lista. O flag `custom` é só de UI (não é persistido); Save continua exigindo um model id. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
O agent deixa de rodar na API compartilhada e passa a rodar dentro do container do app do cliente, como uma Cloud Function (dashboardAgent). Assim escala com os recursos do próprio app e a chave nunca sai do container. - Novo cloud/dashboard-agent/index.js (dashboard-agent.cloud.js): loop OpenAI + tools via Parse SDK (useMasterKey local), lê OPENAI_API_KEY/AGENT_MODELS do env, exige master key. Importado como texto cru (webpack ?raw / asset/source). - agentCloudProvisioning.js: injeta/atualiza o arquivo gerenciado (marcador @back4app-dashboard-agent) e o require no main.js sem sobrescrever código do cliente; aborta com erro claro em colisão de nome; remove no delete. - ParseApp.getCloudCode/saveCloudCode; saveAgentConfig instala o cloud code ao salvar (colisão aborta antes de qualquer write), deleteAgentConfig remove. - Dialog mostra aviso explícito de que salvar instala Cloud Code e redeploya. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…le fallback Parse.Cloud.httpRequest was removed in Parse Server 6+. HTTP now uses global fetch (Node 18+) with a fallback to Node's built-in https module, so the Cloud Function also runs on Node 14 (fetch/AbortController are guarded and unused there). Clearer network/timeout error message. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…confusion The agent was inventing app IDs / server URLs and telling users it lacked the master key. Now the proxy passes the real app context (appId, appName, dashboardAPI serverURL) into the function, which injects it into the system prompt as authoritative values. Added instructions: DB access is already granted via tools (master key handled server-side) — never ask for it, never fabricate IDs/URLs/schema, and call getSchema/queryClass to answer instead of guessing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The deploy endpoint (POST /parse-app/:id/cloud → CLI /deploy) and the dashboard's
own Cloud Code editor store data.code as a base64 data URI (data:...;base64,<b64>);
writeJsTreeData treats a non-data-URI string AS base64, so writing raw text would
corrupt the file. Now encode our writes and decode when reading (UTF-8 safe, so a
customer's accented main.js round-trips intact). Confirmed the endpoint/body
({tree:[cloud,public]}) matches the dashboard's existing deploy exactly.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ainer) The container's env-var injection mangles JSON (quotes/braces), so process.env.AGENT_MODELS reached the Cloud Function unparseable → "No models configured" even though it was set (OPENAI_API_KEY, a plain string, worked fine — that's the tell). Store the model list base64-encoded (charset [A-Za-z0-9+/=] survives injection intact). Reader accepts both base64 and legacy plain JSON, so existing configs keep working until re-saved. Applied on both the dashboard (writer/reader) and the Cloud Function (container reader). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Remove the confusing active-model name label from the toolbar. - Rewrite the chat layout as a proper flex column: .chatContainer is a fixed box below the toolbar (top:127px), .chatWindow is the single scroll area (flex:1 + min-height:0), and .chatForm is a static bottom child. Removes the conflicting 100vh-60px heights + padding-top:127 hack that broke scrolling and let the warning overlap the toolbar. - Chat input is now a <textarea>: Enter sends, Shift+Enter inserts a newline; grows with content up to 160px then scrolls. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Code blocks render via CodeSnippet (PrismJS + line-numbers plugin), but the highlight JS never runs (markdown is server-rendered to a string), leaving a light theme and an empty line-numbers gutter — the two-tone/banded look. Override within the chat to a clean dark block: dark bg, removed gutter padding, no theme text-shadow, horizontal scroll, and hide the (empty) line-numbers rows. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the broken PrismJS/CodeSnippet rendering (light theme + empty line-numbers gutter, since Prism's JS never runs on server-rendered markdown) with the same read-only Monaco block used by Cloud Code / App Overview (AppOverviewCodeEditorBlock: dark theme, language header, copy button, auto-height). formatMessageContent now splits fenced code blocks out and renders them as Monaco; surrounding prose still goes through Markdown. Agent bubbles widened to 85% so code is readable. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The agent can write and explain example code freely, but it can't read or deploy the app's actual Cloud Code. Tighten the system prompt so it suggests the Back4App MCP ONLY when the user wants to deploy, read their live Cloud Code, or apply changes — and never brings it up just to write a snippet or answer a question. Prevents over-suggesting the MCP out of context. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…estions When the agent points users to the MCP for deploy/read of live Cloud Code, give the exact link https://www.back4app.com/mcp. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
New Pull Request Checklist
Issue Description
Closes: FILL_THIS_OUT
Approach
TODOs before merging