Skip to content

Pre production2 - #831

Open
charles-ramos wants to merge 37 commits into
production2from
pre-production2
Open

Pre production2#831
charles-ramos wants to merge 37 commits into
production2from
pre-production2

Conversation

@charles-ramos

Copy link
Copy Markdown
Member

New Pull Request Checklist

Issue Description

Closes: FILL_THIS_OUT

Approach

TODOs before merging

  • Add tests
  • Add changes to documentation (guides, repository pages, in-code descriptions)

charles-ramos and others added 30 commits August 21, 2026 22:42
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>
charles-ramos and others added 7 commits August 24, 2026 14:42
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant