Dicas para Uso de Plone 6/Volto
Algumas anotações enquanto estudava Plone 6 e Volto. Não pretende ser 100% completa, mas indicar onde conseguir mais ajuda sobre alguns tópicos.
A documentação aqui pode estar desatualizada em virtude da grande velocidade de desenvolvimento do Plone/Volto!
Projeto
A instalação do Plone cria um projeto "monorepo", contendo backend, frontend e devops.
Vários comandos make
podem ser disparados da raiz do projeto ou de dentro do diretório correspondente. Por exemplo, para iniciar o backend:
# da raiz
~/projeto$ make backend-start
# do diretório backend
~/projeto/backend$ make start
Addons
A filosofia do desenvolvimento Plone é que todo o desenvolvimento deve feito dentro de addons.
O monorepo é criado seguindo esta filosofia, conforme a tabela abaixo:
/backend |
Configuração para subir o backend: porta, dependências, addons externos, etc |
/backend/src |
Addons internos ao repositório |
/backend/src/<nome-projeto> |
Addon principal, criado na instalação |
/frontend |
Configuração para subir o frontend: dependências, addons externos, etc |
/frontend/packages |
Addons internos ao repositório |
/frontend/packages/volto-<nome-projeto> |
Addon principal, criado na instalação |
Addons de backend normalmente (via de regra?) são instalados na interface web do site para fazer seus efeitos.
Uma dúvida minha é se isto é estritamente necessário ou apenas recomendado
Criando um novo projeto
pipx run cookieplone project
make install
Docs - Install Plone with cookieplone Training - Plone Deployment
Backend
O backend é o verdadeiro plone. Escrito em python, tem como base o conjunto de bibliotecas zope
.
A documentação é sofrida e espalhada entre os sites do plone
e as várias bibliotecas zope
. Be afraid.
ZCML
Boa parte da configuração do backend é através de arquivos XML com extensão zcml.
O arquivo configure.zcml
do diretório base de cada addon é lido automaticamente. Outros arquivos .zcml
do addon deve ser incluídos a partir deste, usando a diretiva <include>
.
Algumas diretivas usadas:
<include> |
Indica outro arquivo zcml a ser lido |
<genericsetup:registerProfile> |
Define um conjunto de zcml que vai ser executado quando o addon for instalado ou desinstalado |
<configlet> |
Cria um item de painel de controle. |
<browser:page> |
Define uma "página". Até o momento, só sei que se usa para indicar o conteúdo de um item de painel de controle criado com <configlet> |
<records> |
Cria dados no registry do Plone. Por exemplo, dados referentes a um item customizado de painel de controle. |
<plone:service> |
Define um endpoint de api |
Permissões
Em algumas das diretivas, é necessário especificar a permissão que o item sendo definido terá. As permissões mais comuns são:
Permissão | Descrição |
---|---|
zope2.View |
Visualizar conteúdo. Não precisa estar logado no site. Comum em chamadas de API. |
cmf.ManagePortal |
Gerenciar portal. Comum em itens de painel de controle. |
cmf.ModifyPortalContent |
Gerenciar conteúdo. Permite criar e alterar páginas, etc. |
Documentação na versão 5 do plone
Arquivos De Interesse
instance.yaml |
Use para gerenciar addons |
mx.ini |
Use para incluir repositórios git externos ao monorepo na estrutura de diretórios |
Receitas
Apontando para repositório externo
Ao desenvolver um addon reutilizável, o próprio costuma ter um repositório git separado. Para isto, usa-se o mxdev.
Passos:
-
Configure o arquivo
backend/requirements.txt
, colocando o nome do add-on:interlegis.barra-acessibilidade-backend
-
Configure o arquivo
backend/instance.yaml
:default_context: zcml_package_includes: project_title, interlegis.barra-acessibilidade-backend
-
Configure o arquivo
backend/mx.ini
:[interlegis.barra-acessibilidade-backend] url = https://github.com/collective/example.contenttype.git pushurl = git@github.com:collective/example.contenttype.git extras = test branch = feature-7 ´´´
-
make backend-build
na raiz do projeto para baixar o conteúdo do git.
docs, install an add-on from source
Instalar Addon
-
Adicionar uma linha em
backend/pyproject.toml
para o addon, no itemdependencies
. -
Acrescente
<include package="plonegovbr.socialmedia" />
no arquivodependencies.zcml
(fica dentro do seu addon padrão, no diretóriosrc
) -
make backend-build
(no diretório raiz) -
Para adicionar o addon automaticamente, sem precisar refazer a base de dados, acrescente a seguinte linha no arquivo
metadata.xml
, dentro deprofiles
:
<dependency>profile-plonegovbr.socialmedia:default</dependency>
Note o
profile-
e:default
. São obrigatórios.
Na documentação, ao invés do passo2, recomenda-se acrescentar o addon em
backend/instance.yaml
, no itemzcml_package_includes
. Mas isto mexe na base do projeto e o recomendável é incluir o addon no seu addon padrão.
Criando item de painel de controle
Frequentemente é necessário também criar um endpoint para acessar o que foi configurado no painel de controle.
Há duas formas de definir algo no painel de controle:
-
Definir interface detalhando os dados do painel de controle
Não consegui achar um projeto com exemplo desta forma, mas é a forma que está explicada na documentação e nos treinamentos.
Checklist típica (os arquivos não precisam ser exatamente esses, é só uma sugestão):
- Criar um schema no arquivo
interfaces.py
, detalhando os campos desejados. - Incluir uma tag
<configlet>
nos profiles de instalação e desinstalação do item de painel de controle, arquivocontrolpanel.xml
. O atributoappId
deve coincidir nos dois arquivos. - Criar um registro no Registry para a configuração, nos profiles de instalação e desinstalação. Arquivo
registry.xml
ouregistry/main.xml
. Usa-se a tag<records>
. - Criar uma página pra responder o item, arquivo
controlpanel/configure.zcml
(tagbrowser:page
) econtrolpanel/controlpanel.py
. - Criar um adapter pro Volto conseguir ver o item. Crie a tag
<adapter>
, em geral no arquivorestapi/configure.zcml
.
Documentação, Control Panels Training "Mastering Plone", add custom control panel Documentação dos tipos
- Criar um schema no arquivo
-
Definir interface apenas com uma string, de forma que os dados sejam guardados como json. Neste caso, define-se um widget no frontend para editar este json. Esta forma é mais comum nos addons do "Awesome Volto".
Checklist típica (os arquivos não precisam ser exatamente esses, é só uma sugestão):
- Criar um schema no arquivo
interfaces.py
. Neste caso, o schema só contém um item, so tipoSourceText
. - Incluir uma tag
<configlet>
nos profiles de instalação e desinstalação do item de painel de controle, arquivocontrolpanel.xml
. O atributoappId
deve coincidir nos dois arquivos. - Criar um registro no Registry para a configuração, nos profiles de instalação e desinstalação. Arquivo
registry.xml
ouregistry/main.xml
. Usa-se a tag<records>
. - Criar uma página pra responder o item, arquivo
controlpanel/configure.zcml
(tagbrowser:page
) econtrolpanel/controlpanel.py
. - Criar um adapter pro Volto conseguir ver o item. Crie a tag
<adapter>
, em geral no arquivorestapi/configure.zcml
.
Projetos de exemplo:
- eea.banner (usado pelo addon de frontend
volto-banner
) - collective.volto.subfooter
- Redturtle Editable Footer
- Criar um schema no arquivo
Docs, Control Panels (bem limitado)
Troubleshooting
-
Item aparece no plone clássico e não aparece no Volto.
O Volto exige os atributos
action_id
eappId
da tag<configlet>
. Além disso, não se esqueça do<adapter>
.
Criando um endpoint para ser usado no frontend
Passos, grosso modo. Veja os exemplos para ter uma ideia melhor.
-
Se já não existir, crie um diretório
restapi
dentro da raiz do backend. O nome não importa, masrestapi
segue o padrão dos projetos que vi. -
Use
<include>
noconfigure.zcml
da raiz para incluir o diretório recém-criado. -
Crie um arquivo
configure.zcml
dentro do diretório. Use a diretiva<plone:service>
para criar o endpoint. -
Crie um arquivo python, exemplo
get.py
, dentro do diretório. Lá deve ser implementada uma classe para devolver os dados desejados. -
No caso de dados guardados em como string e que se deseja servir como json, pode ser necessário um serializer/deserializer. Ainda não sei como funcionam....
Projetos de exemplo:
- eea.banner (usado pelo volto-banner)
- collective.volto.cookieconsent
Behaviors para configuração do site
"Behaviors" são schemas que pode ser atachados em tipos de conteúdo, acrescentando campos a eles. São excelentes para acrescentar configuração ao tipo de conteúdo Plone Site
, que representa o site como um todo. Desta forma, não é necessário mexer com itens de painel de controle.
Passo-a-passo para incluir configuração no Plone Site
:
- Crie o schema com a configuração a ser incluída. É comum criar um diretório
behaviors
no seu addon padrão.
# tema.py
from plone.autoform.interfaces import IFormFieldProvider
from plone.supermodel import model
from zope.interface import provider
from zope import schema
from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm
THEMES = SimpleVocabulary([
SimpleTerm(value="modern", title="Modern"),
SimpleTerm(value="solarized", title="Solarized"),
SimpleTerm(value="darcula", title="Darcula"),
])
@provider(IFormFieldProvider)
class IThemeSettings(model.Schema):
theme = schema.Choice(
title="Tema do portal",
vocabulary=THEMES,
required=True,
description="Tema do Portal",
default="modern"
)
- Crie um arquivo
configure.zcml
para registrar o seu behavior:
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser"
xmlns:plone="http://namespaces.plone.org/plone"
xmlns:zcml="http://namespaces.zope.org/zcml"
i18n_domain="kitconcept.intranet"
>
<!-- este include é necessário para "habilitar" a funcionalidade de behaviors -->
<include
package="plone.behavior"
file="meta.zcml"
/>
<plone:behavior
name="portalmodelo.tema"
title="Tema do Portal"
description="Escolhe o tema do portal"
provides=".tema.IThemeSettings"
/>
</configure>
- em
provides
, coloque o nome do arquivo python ("tema" neste caso) e do schema (IThemeSettings
) - em
name
, coloque um identificador para o behavior. Será usado no passo de atachar o behavior.
- Acrescente o diretório
behaviors
noconfigure.zcml
da raiz do seu addon padrão:
<include package=".behaviours" />
Não é óbvio, mas o ponto de entrada do diretório "behaviors" é o arquivo
behaviors/configure.zcml
- Atache o behavior no tipo de conteúdo. Para isto, crie um arquivo em
profiles/default/types/Plone_Site.xml
O nome do arquivo é uma pegadinha. Tem de usar "_" no lugar de " ", se o tipo de conteúdo tiver espaços.
Use o
name
do behavior na tagelement
<?xml version="1.0"?>
<!-- aqui dentro do XML, deve ser usado o nome do tipo de conteúdo com " ", não com "_" -->
<object name="Plone Site" meta_type="Dexterity FTI">
<property name="behaviors" purge="false">
<element value="portalmodelo.tema" />
</property>
</object>
Como tudo que mexe dentro de profiles, é necessário ou recriar o site (
DELETE_EXISTING=1 make backend-create-site
) ou fazer um passo de atualização de dados (migration
)
Mais coisas são possíveis na definição do schema (sub-títulos, usar widgets customizados, etc). Veja o código do volto-light-theme para ideias.
Frontend (Volto)
O frontend é chamado de Volto. Escrito em react/javascript, é feito para substituir o antigo frontend do plone (feito em python, direto no backend).
Arquivos De Interesse
package.json |
Use para gerenciar addons |
volto.config.js |
Também usado para gerenciar addons |
index.ts ou index.js |
Ponto para aplicar configuração (applyConfig ) |
Receitas
Apontando para repositório externo
Ao desenvolver um addon reutilizável, o próprio costuma ter um repositório git separado. Para isto, usa-se o mrs developer.
Passos:
-
Configure o arquivo
frontend/package.json
:{ "name": "my-volto-project", "addons": [ "name-of-add-on" ] }
``
-
Configure o arquivo
frontend/mrs.developer.json
:{ ... outros ..., "meu-addon": { "output": "./packages/barra-acessibilidade", "package": "<nome do package, exemplo '@interlegis/barra-acessibilidade'", "url": "git@github.com:interlegis/barra-acessibilidade.git", "https": "https://github.com/interlegis/barra-acessibilidade.git", "tag": "<versão, exemplo '1.0'>" } } ´´´
-
make install
no diretóriofrontend
.
Docs, Install an add-on in development mode in Volto 18
Instalar Addon
-
Acrescente o addon em
frontend/packages/<seu addon base>/package.json
."addons": [ "@kitconcept/volto-light-theme" ], "dependencies": { ""@kitconcept/volto-light-theme": "7.0.0-alpha.25" },
-
Se for um tema, como o
volto-light-theme
, faça-o ser o tema default, emfrontend/volto.config.js
:const theme = '@kitconcept/volto-light-theme';
-
No diretório do frontend, use
make install
.
Na documentação, tá um pouco diferente, mas coloquei aqui a forma como aprendemos no treinamento.
Utilizando uma API definida no backend
O Volto utiliza react-redux
para acessar o backend.
Passos (usando o projeto volto-banner
como exemplos:
Colocando um componente em todas as páginas
Use a opção appExtras
ao configurar o add-on. Veja no exemplo do addon volto-banner
abaixo.
O componente é incluído no final da página, por default (acho). Se quiser posicionar em outro lugar, use react-portal
, como no exemplo.
Exemplo: addon volto-banner
:
Colocando um componente em todas as páginas, com slots
Mais simples, especialmente se estiver usando volto-light-theme
:
No seu ponto de instalação de configuração (´index.ts´, por exemplo), use:
config.registerSlotComponent({
name: 'BarraAcessibilidade',
slot: 'aboveHeader',
component: BarraAcessibilidade,
});
Documentação base Documentação do volto light theme
Definindo interface de painel de controle no frontend
A criação de painel de controle normalmente é através de interface no backend e o Volto monta os controles necessários para a edição dos itens desta interface.
Uma outra opção é definir no backend a interface como uma string (contendo um json) e definir no frontend um widget para editar este json. Esta opção possibilita layouts mais complexos.
Exemplos:
CSS customizado
O volto tem dois arquivos que são pontos para inclusão de CSS customizado, localizados dentro do seu pacote, em src/theme
:
Arquivo | Nota |
---|---|
_main.scss |
CSS geral e importação de outros arquivos |
_variables.scss |
definição de variáveis CSS |
Importação de arquivos
Use:
@import '_arquivo'
Este comando procura por _arquivo.scss
(SASS) ou _arquivo.css
. O underscore na frente é uma convenção, para dizer que o arquivo é só para import.
Variáveis de Volto Light Theme
Além dos behaviors
de tema explicados mais abaixo, pode-se configurar as cores do volto-light-theme
definindo algumas variáveis de CSS. Listo algumas abaixo:
Variável | Nota |
---|---|
--header-background , --header-foreground |
Cores do cabeçalho |
--footer-background , --footer-foreground |
Cores do rodapé |
--accent-color , --accent-foreground-color |
Cor de destaque, usado para definir variáveis para o menu de hamburguer, breadcrumbs e search |
E várias outras. Use o developer tools para descobrir mais. Não tem documentação.
Cores dos blocos (isto é do corpo da página)
Por default, é definido hard-coded e para serem alteradas, deve-se usar a configuração em index.ts
:
config.blocks.themes = [
{
style: {
'--theme-color': 'var(--body-background-color)', // Block Wrapper
'--theme-high-contrast-color': '#ecebeb', // Cards in Grid block
'--theme-foreground-color': 'var(--body-foreground-color)',
'--theme-low-contrast-foreground-color': '#555555',
},
name: 'default',
label: 'Default',
},
{
style: {
'--theme-color': '#ecebeb',
'--theme-high-contrast-color': '#fff',
'--theme-foreground-color': '#000',
'--theme-low-contrast-foreground-color': '#555555',
},
name: 'grey',
label: 'Grey',
},
];
Se forem usadas variáveis de CSS nesta parte, as variáveis podem ser definidas nos arquivos CSS descritos acima, mantendo o código mais organizado.
Retirando partes da tela no volto-light-theme
O volto-light-theme facilita a customização do site, retirando partes da tela, como o "colophon" (onde tem a licença, etc). Para isto, use:
config.unRegisterSlotComponent('postFooter', 'Colophon', 0);
Para ver o que pode ser retirado, olhe o arquivo slots.ts no código-fonte.
Insights
Itens de Painel de Controle
Os itens de painel de controle que aparecem no Volto não são simplesmente os itens definidos no backend. Uma parte foi redesenvolvida em React e está hard-coded e outra parte vem do backend.
Itens Oriundos do Backend
Estes itens estão definidos em controlpanel.xml do produto base CMFPlone. Note que nem todos os itens listados aqui são servidos pela API. Por exemplo, os painéis marcados com permissão Manage Portal
não estavam sendo retornados nos meus testes. O endereço da API é ++api++/@controlpanels
.
Estes itens também são filtrados no Volto, após o fetch. Para fazer uma filtragem customizada, coloque a função de filtragem na configuração do Volto. Exemplo abaixo:
const filterControlPanels = (controlpanels = []) => {
const HIDDEN_CONTROL_PANELS = ['markup', 'content-rules', 'language', 'security'];
return controlpanels.filter(
(controlpanel) =>
!HIDDEN_CONTROL_PANELS.includes(controlpanel['@id'].split('/').pop()),
);
};
// Na instalação do seu addon (index.ts, por exemplo)
function applyConfig(config: ConfigType) {
config.settings.filterControlPanels = filterControlPanels;
}
Por default, o Volto filtra os itens "markup" e "content-rules"
Itens de Painel de Controle que normalmente aparecem no Volto e vem do backend:
Nome | Url | Id | Permission |
---|---|---|---|
Buscar | search | SearchSettings | Plone Site Setup: Search |
Data e Hora | date-and-time | DateAndTime | Plone Site Setup: Site |
MailHost | Plone Site Setup: Mail | ||
Idioma | language | LanguageSettings | Plone Site Setup: Language |
Navegação | navigation | NavigationSettings | Plone Site Setup: Navigation |
Site | site | PloneReconfig | Plone Site Setup: Site |
Volto Settings | volto-settings | VoltoSettings | Manage Portal |
Editar | editing | EditingSettings | Plone Site Setup: Editing |
Manipulação de Imagem | imaging | ImagingSettings | Plone Site Setup: Imaging |
Tipos de Conteúdo | dexterity-types | dexterity-types | Manage Portal |
Configurações de Usuários e Grupos | usergroup | UsersGroupsSettings | Plone Site Setup: Users And Groups |
Segurança | security | SecuritySettings | Plone Site Setup: Security |
Mudando permissões de itens
Uma outra forma de restringir o acesso aos itens é mudar sua permissão no backend. Para isto, crie um arquivo ´controlpanel.xml´ no seu profile, repetindo o item de painel de controle, mas mudando a permissão:
<?xml version="1.0" encoding="utf-8"?>
<object xmlns:i18n="http://xml.zope.org/namespaces/i18n" name="portal_controlpanel">
<configlet action_id="LanguageSettings"
appId="Plone"
category="plone-general"
condition_expr=""
icon_expr="string:flag"
title="Language"
url_expr="string:${portal_url}/@@language-controlpanel"
visible="True"
i18n:attributes="title"
>
<!-- Era "Plone Site Setup: Language" no original -->
<permission>Manage portal</permission>
</configlet>
</object>
Como toda alteração de profile, isto requer reiniciar o banco de dados ou criar uma passo de atualização de dados.
Itens hard-coded
Uma parte dos itens é feita diretamente em React. Alguns são itens que existem no Plone Clássico e outras não.
Nome | Id |
---|---|
Complementos | addons |
Regras de conteúdo | rules |
Gerenciamento de URL | aliases |
Relacionamentos | relations |
Moderar comentários | moderate-comments |
Usuários | users |
Participação de Usuários em Grupos | usergroupmembership |
Grupos | groups |
Banco de dados | database |
Desfazer | undo |
Para filtrar estes itens, é necessário sobrepor ("shadowing") o código original do Volto. Para isto:
- Crie um arquivo
Controlpanels.jsx´ no diretório ´src/customizations/volto/components/manage/Controlpanels
. - Copie o código original do volto lá. Você pode pegar o conteúdo aqui.
- Procure por um item no formato abaixo e comente:
/* Filtrando o item de painel de controle "database" (Banco de Dados)
{
'@id': '/database',
group: intl.formatMessage(messages.general),
title: intl.formatMessage(messages.database),
}
*/
Configurações de Tema do Volto Light Theme
As novas versões do Volto Light Theme permitem a configuração de cor, logo do site, etc.
Por algum motivo, esta configuração não é default! É necessário acrescentar os behaviors no tipo Plone Site
(que representa o site inteiro).
Para isto, crie o arquivo descrito aqui.
É necessário recriar o site para que tenha efeito.