Repository navigation
v4.1.0
The first release of Dito.js 4, which includes the withdrawn 4.0.0, so these notes list all changes since 3.5.0. The admin is rebuilt around its data: forms, dialogs and panels keep their edits, dirty state and errors also for fields that aren't rendered, nested forms edit drafts, and callbacks receive typed contexts instead of components. See Upgrading to 4.x for what apps need to change.
Behaviour changes
- admin: The value hooks are renamed:
format()→formatValue(),parse()→parseValue(),compute()→computeValue()andprocess()→serializeValue(). The old names throw, exceptformat()on date and color types, whereformatis the format setting: rename these by hand, see Value hooks. - admin: Schemas can't define
methods,computed,watchanddata, and handlers likeonClick()oritemLabel()are called with their context only, without the component asthis: use plain functions,onChange()and module state, see Methods, computed, watch and data. - admin: Schema options, see Schema options; the old options throw:
formatsof the date types isformat, and the date strings of loaded data becomeDateobjects.- Trees open their items with
collapsed: falseinstead ofopen: true.collapsedistrueby default and can be a callback. relatetakes the key to relate options by, e.g.relate: 'code', instead ofrelateBy, andgroupByisoptions.group.format: 'name'of the color type is removed: use a hex format, e.g.'hex'.nestedonly works on sections and panels.- Options that were never read are removed from the types, e.g.
defaultSortanddefaultScopeof sources andidKeyof forms.
- admin: Relative paths in
options.dataPathand in thedataPathof thecomputed,dataandhiddentypes are relative to the item instead of the field, so they need one../less:'../authors'becomes'authors'. Thematchofvalidate()resolves the same way, and..above the root throws. - admin: Events, see Event handlers:
- Declare handlers as
on…properties, e.g.onClick().events: {}is deprecated until 6.0, and anon…handler of the same event wins over it. - An
onClick()on the submit or cancel buttons of forms and dialogs replaces their default handler: callcontext.submit(),context.closeForm()orcontext.closeDialog()from it. - Forms fire
onSuccess()after saving, withcontext.isCreating, and nested formsonApply()when they apply their draft, instead ofcreateandsubmit, which throw. onToggle()withcontext.collapsedreplacesonOpen()withcontext.open.inputfires for each edit in all types and bubbles likechange. Returningfalsefrom a handler of either stops it from bubbling.- Date, datetime and time fields fire
changeonce the edit is done. - Errors thrown by handlers reach
onError()as they are, instead of wrapped in anAggregateError: readerror.message.
- Declare handlers as
- admin: Contexts, see Contexts:
- Contexts don't expose components anymore, e.g.
componentorformComponent: what callbacks used them for are context members, listed under New. - Renamed members:
query→routeQuery,index→valueIndex,processedItem→serializedItemandprocessedRootItem→serializedRootItem.sourceComponent.queryiscontext.sourceQuery. dialogComponent.resolve(value)iscontext.closeDialog(value),formComponent.setData(data)andschemaComponent.resetData()arecontext.resetItem(data)andcontext.resetItem(), and the validation members of components arecontext.validate(),isValid()andclearErrors().dialogComponent.reject(),applyCleanChanges(),filterData(),navigateToComponent()andnavigateToRouteComponent()are removed.context.navigate()resolves to whether the navigation happened, andgetResourceUrl()without arguments throws when there is no resource.- Each context describes its own
item, withitemDataPath,itemIndexandparentItem: in the events of forms and sections and in list buttons, 3.5 gave those of the item one level up.context.valueisundefinedthere. - In panels with their own data,
itemis the panel's data androotItemthe page's. In dialogs,rootItemis the dialog's data. onSuccess()andonError()of submit buttons get the same context as theironClick().
- Contexts don't expose components anymore, e.g.
- admin: Code outside of callbacks reaches the admin's services through
admin.context, and itssettingsreplacewindow.dito, see Admin services.closeNotifications(),rootComponent,registerLoading(),meta.apiandmeta.schemaof routes, andapi.baseare removed:dito.baseis the base of the routes. - admin: Custom components don't get
DitoMixinandTypeMixinanymore: they receiveschema,contextandmodelValue, and emitupdate:modelValueandchange, see Custom components. The admin's own components are internal, and their actions, e.g.request()andnavigate(), are context members. - admin: Types are defined with
defineType(descriptor)instead ofadmin.register(), with renamed options, andprocessSchema(),processValue()andgetTypeValidations()aresetupSchema(),serializeValue()andgetValidations(), see Custom types. - admin: TypeScript types, see TypeScript types:
SchemaOpenisSchemaToggleandOpenEventHandlerisToggleEventHandler.HTTPVerb(useHttpMethod), the mixin types and the types of component instances are removed.- Many types are renamed and keep working as deprecated aliases, e.g.
DitoContext→SchemaContext,DitoGlobal→GlobalConfigandForm→FormSchema. - The types follow what the admin reads, and options that were missing are typed.
- server: TypeScript types:
HTTPMethodisHttpMethod, as a deprecated alias.ApiConfighas nodateFormatandresources: setresourceson the admin'sapi. Custom keywords receiveinstancePathinstead ofdataPath. The types follow what the server reads, e.g.Authorizetakes settings by action name, and options that were missing are typed. - admin:
.dito-form-nestedandDitoFormNestedare.dito-form--embeddedandDitoFormEmbedded, and the deprecated$pulldown-*SCSS variables are removed. - ui:
$ease-put-quintis$ease-out-quint,.dito-trigger-disabledis.dito-trigger--disabled, and.dito-popup-{placement}is.dito-popup--{placement}. - ui:
DitoDatePicker,DitoTimePickerandDitoDateTimePickeremitchangeonce the edit is done, andupdate:modelValuefor each value. ThedisabledDate,disabledHour,disabledMinuteanddisabledSecondprops are removed, see UI. - ui:
DitoButtonwith averband withouttextis labelled by its verb, andgetVerbButtonAttributes()doesn't takehasTextanymore. - build:
@ditojs/adminand@ditojs/uiare only published as ES modules, and all packages haveexportsmaps withimportonly:require()and imports of internal files, e.g.@ditojs/server/src/…, fail.defineViteConfig()doesn't readrollupOutputanymore, see Packages and builds. - utils:
stripTags()is removed: usestripHtml().setDataPathEntries()issetEntriesAtDataPath(), andescapeRegexp()isescapeRegExp(). - utils, server:
**in the middle of data paths, also in theassetsof models, matches zero or more levels, like in.gitignore:a/**/cmatchesa/ctoo. - server: Services and storages, see Services and storages:
Service.setup(config)isconfigure(config), and the application starts and stops its services itself: an overriddensetup()isn't called anymore.- Storages are created with
constructor(app, name, config)and named by their key inconfig.storages.app.addStorage(config, name)needs the name, and the asyncinitialize()replacessetup().
- server: Queries, see Queries:
upsert(data)saves models by the ids in the data, patching those that exist and inserting the others, instead of patching what the query matches. Itsupdateandfetchoptions are removed.- Collection
PUTandPATCHrequests reject models without ids with a 400 error, and the array forms ofpatchAndFetch()andupdateAndFetch()throw for them: create them withPOSTorinsertAndFetch(). - These methods and array inserts outside of PostgreSQL run in a transaction, so a failure rolls back the models saved before it.
- Outside of PostgreSQL, arrays passed to
insert()are inserted without their relations, as in PostgreSQL: useinsertDitoGraph()orinsertGraph()for graphs. - Text filters without an operator search like
contains, instead of not filtering.
- server: Validation, see Validation:
discriminatorkeywords are applied: each variant of theoneOfneeds a fixedtypein itsproperties.- Objects that combine parts through
allOf,anyOforoneOfwithout their ownproperties, and$refs to definitions like'#Address', reject unknown properties. SetunevaluatedProperties: trueto allow them. type: 'color'only accepts hex colors: usetype: 'string'ortype: 'object'for others.
- server: Deprecations are removed, e.g. the scope prefixes
-and#(use!and@), andTimeStampedMixin,getDitoObject(),initializedand others are renamed, see Removed deprecations and Renames. - server: The admin's HMR is served through the app's server: remove
server.hmr.portfrom the admin's Vite config. - admin: Dirty state and saving, see Dirty state and saving:
- Forms are dirty once their data is edited, until it's saved, applied or loaded again: reverting an edit leaves them dirty.
- Only writes of values that a field shows and that are saved are edits, not those of
excludefields or of sources with their own resource. Writes throughitem,parentItem,rootItemandvalueare edits; code that changes values in place callscontext.markDirty(). - Views, dialogs and panels without a button of type
submitare never dirty. - Save responses and
context.resetItem(data)merge into the data in place, so open nested forms keep their edits. - Leaving a form while it saves waits for the save, and submitting waits for uploads and loads without the 30 second limit of 3.5.
- Saving the forms of tree items' children doesn't reload the tree.
- admin: Nested forms without
mutate: trueedit a draft of their item, which OK merges into the parent and Cancel discards, see Nested forms. Open forms follow their item when it moves, and close when it's removed. - admin: Errors stay with their values when sections collapse, tabs switch and items move, and any change of a value clears them. Errors of values without a field of their own show on the field around them, and rows and tree items with errors inside are marked, see Errors.
- admin: Cells and item labels show values as their types display them, e.g. dates, and selects keep values that their options lack, showing them as unavailable. Tabs render once they're selected.
- admin: Object defaults of
api.defaultsonly fill in what schemas leave out, and the create menu of lists offers forms bycreatableonly, not by theiriforvisible. - admin: Routes, requests and the clipboard, see Routes, requests and the clipboard:
- The URLs of forms of lists in nested sections and inlined objects contain the container's name, e.g.
/books/1/contents/notes/2, and tree items with a resource are addressed by id. request({ cache: 'local' })caches while the route is shown, and dialogs have their own local cache.- Pasting writes the copied values into the item, which keeps its id and position, and copied related items get new temporary ids.
- The URLs of forms of lists in nested sections and inlined objects contain the container's name, e.g.
New
- admin: Context members for what callbacks used components for, e.g.
isDirty,isCreating,validate(match),isValid(match),clearErrors(match),markDirty(),resetItem(data),submit(),closeForm(),closeDialog(value),showDialog()andgetSchemaValue(), see New features.matchtakes data paths with*and**, regular expressions or functions. - admin: Values:
deserializeValue()converts stored values to edited ones, andserializeValue()returningundefinedleaves out the key. Types can define both.serializedItemandserializedRootItemare available in all callbacks.
- admin: Events:
- Handlers of bubbled events receive
currentDataPath, the data path of the component whose handler runs. - Forms fire
onCancel(), and a value returned from theironSuccess()oronError()suppresses the notification. - Trees fire
onToggle()withcontext.collapsed.
- Handlers of bubbled events receive
- admin:
itemLabelanditemLabelTexthold the label of the form's item in all callbacks inside a form, and option labels receivecontext.isSelected. - admin: Type descriptors can state
rendersLabel,submitsDataandhasEmbeddedForms, display values withgetDisplayValue(), load options withgetOptionsDataSchema(), and take an array astype. - admin: Custom components are typed with
CustomComponentPropsandCustomComponentEmits, can emitfocusandblur, and receiveerrorsElementId. - admin:
multipleof uploads,linesof textareas and markups, andplaceholderof multiselects take callbacks, lists withwrapPrimitivessupport routed forms, and panels withnested: truehold their values under their name. - admin: The types
AdminContext,AdminUserandTypeDescriptor, and the SCSS variable$error-bar-width. - server:
ApiConfighasformatsandtimeout, andApiResourcehasmethod,idandquery. - utils:
resolveDataPath(dataPath, path)resolvespathrelative todataPath.
Fixes
- admin, nested forms:
- Applying a nested form no longer drops or serializes values twice, and cancelling it leaves no temporary ids in the parent.
- Removing an item before an open nested form's item no longer switches the form and drops its edits.
- Copying no longer carries other items' ids into pasted items.
- admin, routes and resources:
- Lists in forms shared by several views, lists with their own
path, lists in nested sections, and lists with names likesourceURLsopen the right forms. - Lists linked to views with several components get correct edit links and can create items.
- Relative resources resolve against the nearest form or list with a resource, e.g.
pages/1instead ofpages/pages/1in trees.
- Lists in forms shared by several views, lists with their own
- admin, events:
- The
on…handlers of sections fire, andclickevents of buttons bubble through all schemas above. onError()of buttons that callscontext.notify()replaces the default notification.
- The
- admin, fields:
markupedits that don't blur the editor, e.g. links, are written right away, and the focus returns to the editor after the link dialog.- Saving with an error in a collapsed section or inlined form opens it and focuses the field.
rules: { name: false }removes the rule.- The
ifof components of panels with their own data only runs with that data.
- admin, other:
spinner: nullhides the header's spinner, andadmin.elholds the mounted element.showDialog()works withoutbuttonsorcomponents.creatablecallbacks that return{ label, query }work for lists, and the create button of sources with a singledisabledform is disabled.- Lists with
columnsas an array label their items by the first column. - Tree items with
nullchildren sort as empty lists.
- utils:
isEmpty()checks the size ofMapandSetand never treats dates as empty.setValueAtDataPath()errors print the path with/.isCreditCard()no longer accepts numbers that only start like a card number.debounceAsync()keeps working aftercancel()and withimmediate.getEntriesAtDataPath()no longer adds a trailing slash for trailing wildcards, which wroteassetsto the wrong key.
- server, controllers:
authorize: falseon an action or controller denies access, where it was skipped.- The
authorizeof aUsersControllerdoesn't apply tologin,logoutandsession, and logins of users without a password hash fail with 401 instead of 500. allow: ['*']oncollectionandmemberroutes all actions.{ from: 'member' }parameters are left out of parameter validation.- Controllers that override
relationskeep the relation and member actions of their base. CollectionControlleris exported.
- server, models:
UserMixinhashes passwords of a custompasswordProperty, and calls thesetup()of the model it extends.- Foreign keys that relations add to related models no longer go missing when the related model is registered first.
upsertAndFetch()and the array forms ofpatchAndFetch()andupdateAndFetch()return all saved rows regardless of thedefaultscope.hooksaccept arrays of handlers.- A JSON Schema
requiredarray on a property no longer makes the property itself required. getPropertyOrRelationAtDataPath()leaves array wildcards out of relation expressions (#214).
- server, other:
db:create_migrationcreates valid columns fortype: 'asset', model types,type: 'color'and$refproperties, usesincrements()only for integer keys, and names join table columns like the relations do.db:seedexits with an error code when a seed fails.- The
assetsandloggeroptions of one application no longer change the defaults of later ones. - Files uploaded to S3 storages without
urlget the S3 url.
Internal
- The admin is written in TypeScript where it was rebuilt, and its components use
setup()and composables instead of mixins.