[pbs-devel] [PATCH proxmox-backup v8 27/45] ui: add s3 client selector and bucket field for s3 backend setup
Christian Ebner
c.ebner at proxmox.com
Sat Jul 19 14:28:48 CEST 2025
On 7/18/25 12:02 PM, Lukas Wagner wrote:
>
>
> On 2025-07-15 14:53, Christian Ebner wrote:
>> In order to be able to create datastore with an s3 object store
>> backend. Implements a s3 client selector and exposes it in the
>> datastore edit window, together with the additional bucket name field
>> to associate with the datastore's s3 backend.
>>
>> Signed-off-by: Christian Ebner <c.ebner at proxmox.com>
>> ---
>> changes since version 7:
>> - use field endpoint insteand of host, fixing the selector listing
>>
>> www/Makefile | 1 +
>> www/form/S3ClientSelector.js | 33 +++++++++++++++++++++++++++
>> www/window/DataStoreEdit.js | 44 ++++++++++++++++++++++++++++++++++++
>> 3 files changed, 78 insertions(+)
>> create mode 100644 www/form/S3ClientSelector.js
>>
>> diff --git a/www/Makefile b/www/Makefile
>> index 767713c75..410e9f3e0 100644
>> --- a/www/Makefile
>> +++ b/www/Makefile
>> @@ -42,6 +42,7 @@ JSSRC= \
>> Schema.js \
>> form/TokenSelector.js \
>> form/AuthidSelector.js \
>> + form/S3ClientSelector.js \
>> form/RemoteSelector.js \
>> form/RemoteTargetSelector.js \
>> form/DataStoreSelector.js \
>> diff --git a/www/form/S3ClientSelector.js b/www/form/S3ClientSelector.js
>> new file mode 100644
>> index 000000000..243484909
>> --- /dev/null
>> +++ b/www/form/S3ClientSelector.js
>> @@ -0,0 +1,33 @@
>> +Ext.define('PBS.form.S3ClientSelector', {
>> + extend: 'Proxmox.form.ComboGrid',
>> + alias: 'widget.pbsS3ClientSelector',
>> +
>> + allowBlank: false,
>> + autoSelect: false,
>> + valueField: 'id',
>> + displayField: 'id',
>> +
>> + store: {
>> + model: 'pmx-s3client',
>> + autoLoad: true,
>> + sorters: 'id',
>> + },
>> +
>> + listConfig: {
>> + columns: [
>> + {
>> + header: gettext('S3 Client ID'),
>> + sortable: true,
>> + dataIndex: 'id',
>> + renderer: Ext.String.htmlEncode,
>> + flex: 1,
>> + },
>> + {
>> + header: gettext('Endpoint'),
>> + sortable: true,
>> + dataIndex: 'endpoint',
>> + flex: 1,
>> + },
>> + ],
>> + },
>> +});
>> diff --git a/www/window/DataStoreEdit.js b/www/window/DataStoreEdit.js
>> index cd94f0335..3379bf773 100644
>> --- a/www/window/DataStoreEdit.js
>> +++ b/www/window/DataStoreEdit.js
>> @@ -61,6 +61,7 @@ Ext.define('PBS.DataStoreEdit', {
>> comboItems: [
>> ['__default__', 'Local'],
>> ['removable', 'Removable'],
>> + ['s3', 'S3 (experimental)'],
>
> Missing gettext here as well
added, thanks!
>> ],
>> cbind: {
>> disabled: '{!isCreate}',
>> @@ -68,18 +69,32 @@ Ext.define('PBS.DataStoreEdit', {
>> listeners: {
>> change: function (checkbox, selected) {
>> let isRemovable = selected === 'removable';
>> + let isS3 = selected === 's3';
>>
>> let inputPanel = checkbox.up('inputpanel');
>> let pathField = inputPanel.down('[name=path]');
>> let uuidEditField = inputPanel.down('[name=backing-device]');
>> + let bucketField = inputPanel.down('[name=bucket]');
>> + let s3ClientSelector = inputPanel.down('[name=s3client]');
>>
>> uuidEditField.setDisabled(!isRemovable);
>> uuidEditField.allowBlank = !isRemovable;
>> uuidEditField.setValue('');
>>
>> + bucketField.setDisabled(!isS3);
>> + bucketField.allowBlank = !isS3;
>> + bucketField.setValue('');
>> +
>> + s3ClientSelector.setDisabled(!isS3);
>> + s3ClientSelector.allowBlank = !isS3;
>> + s3ClientSelector.setValue('');
>> +
>> if (isRemovable) {
>> pathField.setFieldLabel(gettext('Path on Device'));
>> pathField.setEmptyText(gettext('A relative path'));
>> + } else if (isS3) {
>> + pathField.setFieldLabel(gettext('Store Cache'));
>> + pathField.setEmptyText(gettext('An absolute path'));
>> } else {
>> pathField.setFieldLabel(gettext('Backing Path'));
>> pathField.setEmptyText(gettext('An absolute path'));
>
> Yup, with these additional changes I'd definitely prefer the viewModel approach mentioned earlier :)
Well... I did check this out, also based on the off-list input you gave
me on this one, but unfortunately the viewModel and binding approach
does not work just yet, since the `pmxDisplayField` xtype used for the
`path` does not implement the logic for bindings of the `fieldLabel` and
`emtpyText`. Therefore these cannot be dynamically adapted by the use of
formulas and/or view model data.
So I would like to rather do this as followup instead, to not further
delay the path series until I've figured out how to correctly add these
as bindable values in the corresponding component.
But I do see the benefits of the viewModel and formulas approach, thanks
a lot for your input on that.
>> @@ -98,6 +113,15 @@ Ext.define('PBS.DataStoreEdit', {
>> emptyText: gettext('An absolute path'),
>> validator: (val) => val?.trim() !== '/',
>> },
>> + {
>> + xtype: 'pbsS3ClientSelector',
>> + name: 's3client',
>> + fieldLabel: gettext('S3 Client ID'),
>> + disabled: true,
>> + cbind: {
>> + editable: '{isCreate}',
>> + },
>> + },
>> ],
>> column2: [
>> {
>> @@ -132,6 +156,13 @@ Ext.define('PBS.DataStoreEdit', {
>> },
>> emptyText: gettext('Device path'),
>> },
>> + {
>> + xtype: 'proxmoxtextfield',
>> + name: 'bucket',
>> + fieldLabel: gettext('Bucket'),
>> + allowBlank: false,
>> + disabled: true,
>> + },
>> ],
>> columnB: [
>> {
>> @@ -154,7 +185,20 @@ Ext.define('PBS.DataStoreEdit', {
>> if (me.isCreate) {
>> // New datastores default to using the notification system
>> values['notification-mode'] = 'notification-system';
>> +
>> + if (values.s3client) {
>> + let s3BackendConf = {
>> + type: 's3',
>> + client: values.s3client,
>> + bucket: values.bucket,
>> + };
>> + values.backend = PBS.Utils.printPropertyString(s3BackendConf);
>> + }
>> }
>> +
>> + delete values.s3client;
>> + delete values.bucket;
>> +
>> return values;
>> },
>> },
>
More information about the pbs-devel
mailing list