Customising

Most changes need no code at all: your own fields, your own lists, added from the form that needs them. The ones that do need code have an obvious place to go.

Custom fields

Custom fields, grouped by the kind of record they belong to. Custom fields, grouped by the kind of record they belong to.

Settings → Custom fields adds fields of your own to the records you keep — an account tier on a customer, a purchase order number on an invoice, a billing code on a project. The screen lists every kind of record that accepts them, each with its fields: the Label (a red star when it is required, and its help text under it), the Type, the Key it is stored under, and badges for In lists, On PDFs, Client visible and Inactive.

Fields can be added to twenty-one kinds of record:

AreaRecords
CRMLeads, customers, contacts
SalesProposals, estimates, contracts, credit notes, subscriptions, invoices, payments, items, expenses
DeliveryProjects, tasks, timesheets
SupportTickets, knowledge base articles
Staff and the restStaff, calendar events, goals, surveys

Adding a field

Adding a field. Choices appear only for a dropdown or a multi-select. Adding a field. Choices appear only for a dropdown or a multi-select.
  1. Press Add field.
  2. Fill in the form (below) and press Add field. The list reloads with the new field under its record type.
FieldWhat it does
Attach toRequired. The kind of record the field belongs to. It cannot be changed afterwards.
Field typeRequired: Single line text, Paragraph text, Number, Date, Dropdown, Multi-select, Checkbox, Web address or Email address. Each checks what is typed into it: a web address must be one, a number must be a number.
LabelRequired, up to 120 characters. What people see beside the box. The key is made from it (Purchase order number becomes purchase_order_number) and must be unique on that record type — the same label can be used on leads and on invoices.
Display orderA number; lower comes first on the form.
ChoicesDropdown and multi-select only: one choice per line. Blank lines and repeats are dropped. A dropdown refuses a value that is not one of its choices.
Default valueOptional. Filled in on a new record's form.
Help textOptional, up to 255 characters. Shown under the box.
RequiredThe record's form cannot be saved without it.
ActiveOn for a new field. An inactive field disappears from forms and lists, but what was recorded in it is kept.
Show in list viewsAdds a column for it to the record's list, and to that list's export.
Show on PDF documentsPrints it on the record's PDF — see Printing custom fields.
Visible in the client portalFor customer and contact fields: asked on the customer portal's registration form, where registration is open.

A checkbox field reads Yes or No wherever it is shown.

Changing a field

Editing a field: the record type and the key stay as they are. Editing a field: the record type and the key stay as they are.

The button opens the same form. Everything can be changed except Attach to and the key, which the form shows under the label (Stored under the key …, which does not change): every value already recorded is filed under them, and changing either would quietly detach those values. Renaming the label therefore changes only what people see. Press Save changes.

Deleting a field

The button, then confirm. Deleting a field also deletes every value already recorded against it, on every record, and that cannot be undone. To stop using a field but keep what it holds, untick Active instead.

Where the fields appear

An active field appears on its record's form, and on the record's page where it has one. For the newer record types:

RecordFilled in onShown on
Itemsthe item form under Itemsthe items list (fields with "Show in list views"), the items export, and on PDFs under every document line added from the item (fields with "Show on PDF documents")
Timesheetsthe "Log time" formthe timesheets list and its export
Calendar eventsthe event formthe event's panel on the calendar
Goalsthe goal formthe goal's card
Paymentsthe Record payment form on an invoicethe payment on the invoice page, the payments list and its export
Surveysthe new-survey form and the survey's settingsthe survey's results page

Printing custom fields

Tick Show on PDF documents on a field to print it. Invoices, estimates, proposals and credit notes print their own fields beside the dates at the top; contracts print theirs with the contract details; item fields print under the lines they were added as. On the other records the switch has no effect, because they have no PDF.

The lists you file things under

One of the seven lists. Entries can also be added from the form that needs them. One of the seven lists. Entries can also be added from the form that needs them.

Seven lists decide how records are grouped, and every one of them is chosen from a dropdown somewhere in the application:

ListChosen onManaged at
Project categoriesProjects, project templatesSettings → Project categories
Expense categoriesExpenses, recurring expensesSettings → Expense categories
Item groupsThe item librarySettings → Item groups
Contract typesContracts, contract templatesSettings → Contracts & signing
Leave typesLeave applicationsSettings → Leave types
Knowledge base categoriesArticles, videosKnowledge Base → New category
DepartmentsTickets, canned replies, ticket templates, mailboxesSettings → Support desk
The item library: what you sell, at what rate, filed into groups. The item library: what you sell, at what rate, filed into groups.

Adding one without losing your place

The + beside the Category dropdown, pressed on the projects screen: a name and a colour, over whatever you were doing. The + beside the Category dropdown, pressed on the projects screen: a name and a colour, over whatever you were doing.

Every one of those dropdowns has a + beside it (its tooltip says, for example, Add project category). It opens a short form over whatever you were already filling in:

Press Add. The new entry appears in the dropdown, already chosen, with the form underneath exactly as you left it. Nothing is lost and nothing has to be started again. Cancel closes the short form and changes nothing. Manage the whole list in Settings., at the foot of the short form, is a link that opens the screen where the whole list is kept, in a new tab, so the form you were filling in stays as it was.

The + is shown only to somebody whose role allows Settings → edit. These lists are not only labels — a role can be limited to certain project categories, for instance — so inventing one is a different question from using one. Everybody else sees the dropdown exactly as before.

The short form is deliberately short, and says so at its foot: Manage the whole list in Settings. Descriptions, ordering, whether a leave type is paid (a leave type added here is paid and needs approval), which department is the default (one added here never is) — all of that stays on the list's own Settings screen.

Removing one

A list entry that still has records filed under it cannot be removed. The records would keep their work but lose their grouping, quietly dropping out of every report that totals by category — and, for project categories, out of every role limited to certain ones. Move them first, then remove it.

Adding a list of your own is a single entry in config/categories.php: the model, its table, a label, and whether it carries a colour. Both the dropdown component and the endpoint behind the + read that file, so nothing else has to be written.

Appearance

Settings → Appearance sets the accent colour, light or dark default and every colour around them, keeps named themes, dresses the sign-in page and adds your own CSS and JavaScript; the logos and favicon are uploaded under Settings → Company. See Appearance. The whole interface is driven by CSS custom properties, so changing the accent recolours everything consistently — including the charts.

The custom properties are declared at the top of public/assets/css/app.css. Rather than editing that file, which an update replaces, put your own rules under Appearance → Custom code.

The config files

A lot of behaviour lives in plain PHP arrays rather than in code:

FileControls
config/zenta.phpApplication name, version and theme defaults.
config/navigation.phpThe sidebar: order, icons, labels, which permission each item needs.
config/permissions.phpEvery module, its abilities and the scopes it supports.
config/custom-fields.phpWhich records accept custom fields, and the field types.
config/categories.phpThe lists that have a + beside their dropdown.
config/modules.phpWhat each switch under Settings → Modules reaches.
config/settings.phpEvery setting and its default.
config/tenancy.phpSaaS mode and how workspaces are resolved.
Run php artisan config:clear after editing a config file if you have cached your configuration. Otherwise the old values keep being used.

Language

Every string in the interface goes through Laravel's translation helper, and the translations are JSON files in lang/. The workspace language, the languages on offer and right-to-left layout are set under Settings → Localization; adding a language of your own is described in Languages.

Adding your own module

The application is deliberately made of reusable pieces. A new module usually needs:

  1. A migration with a tenant_id column.
  2. A model using BelongsToTenant, and ScopedByPermission if it should respect scopes.
  3. An entry in config/permissions.php.
  4. An entry in config/navigation.php.
  5. A controller and views, following any existing module as a template.

Traits worth knowing about:

TraitGives you
BelongsToTenantAutomatic workspace scoping on every query.
ScopedByPermissionvisibleTo($user, 'module') — filters by the person's scope.
HasCustomFieldsCustom field support, and the <x-custom-fields> component.
HasLineItemsDocument lines, totals, discounts and taxes.
HasAttachmentsFile uploads against the record.
HasTagsFree-form labels, with filtering.
Keep your changes upgrade-friendly. New files of your own survive an update untouched. Edits to shipped files do not — they are overwritten. Where you can, add rather than edit, or write a plugin.

Addresses on this page

For reference and for anyone scripting against the panel. Everything here needs somebody signed in to the workspace whose role allows it; anybody else is refused.

MethodAddressWhat it does
GETadmin/settings/custom-fieldsThe custom fields, by record type.
GETadmin/settings/custom-fields/createThe Add field form, in a pop-up.
POSTadmin/settings/custom-fieldsAdds a field.
GETadmin/settings/custom-fields/{custom_field}/editThe edit form, in a pop-up.
PUTadmin/settings/custom-fields/{custom_field}Saves a field; its record type and key stay as they were.
DELETEadmin/settings/custom-fields/{custom_field}Deletes a field and every value recorded against it.
GETadmin/categories/createThe short form behind a dropdown's +, with kind (a key from config/categories.php) and target (the dropdown to fill). Used by the page itself.
POSTadmin/categoriesAdds the entry and hands back its id and name for the dropdown. Used by the page itself.