mirror of
https://git.proxmox.com/git/pve-manager
synced 2025-07-24 13:49:30 +00:00

it's somewhat redundant as onbe is already at the realm view, but for panel titles it slightly helps if one doesn't have to string together such "clues" oneself, i.e., it's easier to see where one is - e.g., if switching from some other task back to the web UI again, and we have enough space here, so we ain't winning anything if keeping it short. Also add an emptyText to the grid, mostly as view's without anything always look a bit off (like an error happened on load and one forgot to mask) Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
422 lines
9.4 KiB
JavaScript
422 lines
9.4 KiB
JavaScript
Ext.define('PVE.dc.RealmSyncJobView', {
|
|
extend: 'Ext.grid.Panel',
|
|
alias: 'widget.pveRealmSyncJobView',
|
|
|
|
stateful: true,
|
|
stateId: 'grid-realmsyncjobs',
|
|
|
|
emptyText: Ext.String.format(gettext('No {0} configured'), gettext('Realm Sync Job')),
|
|
|
|
controller: {
|
|
xclass: 'Ext.app.ViewController',
|
|
|
|
addRealmSyncJob: function(button) {
|
|
let me = this;
|
|
Ext.create(`PVE.dc.RealmSyncJobEdit`, {
|
|
autoShow: true,
|
|
listeners: {
|
|
destroy: () => me.reload(),
|
|
},
|
|
});
|
|
},
|
|
|
|
editRealmSyncJob: function() {
|
|
let me = this;
|
|
let view = me.getView();
|
|
let selection = view.getSelection();
|
|
if (!selection || selection.length < 1) {
|
|
return;
|
|
}
|
|
|
|
Ext.create(`PVE.dc.RealmSyncJobEdit`, {
|
|
jobid: selection[0].data.id,
|
|
autoShow: true,
|
|
listeners: {
|
|
destroy: () => me.reload(),
|
|
},
|
|
});
|
|
},
|
|
|
|
runNow: function() {
|
|
let me = this;
|
|
let view = me.getView();
|
|
let selection = view.getSelection();
|
|
if (!selection || selection.length < 1) {
|
|
return;
|
|
}
|
|
|
|
let params = selection[0].data;
|
|
let realm = params.realm;
|
|
|
|
let propertiesToDelete = ['comment', 'realm', 'id', 'type', 'schedule', 'last-run', 'next-run', 'enabled'];
|
|
for (const prop of propertiesToDelete) {
|
|
delete params[prop];
|
|
}
|
|
|
|
Proxmox.Utils.API2Request({
|
|
url: `/access/domains/${realm}/sync`,
|
|
params,
|
|
waitMsgTarget: view,
|
|
method: 'POST',
|
|
success: function(response, options) {
|
|
let upid = response.result.data;
|
|
let win = Ext.create('Proxmox.window.TaskProgress', {
|
|
upid: upid,
|
|
taskDone: () => { me.reload(); },
|
|
});
|
|
win.show();
|
|
},
|
|
failure: function(response, opts) {
|
|
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
|
|
},
|
|
});
|
|
},
|
|
|
|
reload: function() {
|
|
this.getView().getStore().load();
|
|
},
|
|
},
|
|
|
|
store: {
|
|
autoLoad: true,
|
|
id: 'realm-syncs',
|
|
proxy: {
|
|
type: 'proxmox',
|
|
url: '/api2/json/cluster/jobs/realm-sync',
|
|
},
|
|
},
|
|
|
|
viewConfig: {
|
|
getRowClass: (record, _index) => record.get('enabled') ? '' : 'proxmox-disabled-row',
|
|
},
|
|
|
|
columns: [
|
|
{
|
|
header: gettext('Enabled'),
|
|
width: 80,
|
|
dataIndex: 'enabled',
|
|
sortable: true,
|
|
align: 'center',
|
|
stopSelection: false,
|
|
renderer: Proxmox.Utils.renderEnabledIcon,
|
|
},
|
|
{
|
|
text: gettext('Name'),
|
|
flex: 1,
|
|
dataIndex: 'id',
|
|
hidden: true,
|
|
},
|
|
{
|
|
text: gettext('Realm'),
|
|
width: 200,
|
|
dataIndex: 'realm',
|
|
},
|
|
{
|
|
header: gettext('Schedule'),
|
|
width: 150,
|
|
dataIndex: 'schedule',
|
|
},
|
|
{
|
|
text: gettext('Next Run'),
|
|
dataIndex: 'next-run',
|
|
width: 150,
|
|
renderer: PVE.Utils.render_next_event,
|
|
},
|
|
{
|
|
header: gettext('Comment'),
|
|
dataIndex: 'comment',
|
|
renderer: Ext.htmlEncode,
|
|
sorter: (a, b) => (a.data.comment || '').localeCompare(b.data.comment || ''),
|
|
flex: 1,
|
|
},
|
|
],
|
|
|
|
tbar: [
|
|
{
|
|
text: gettext('Add'),
|
|
handler: 'addRealmSyncJob',
|
|
},
|
|
{
|
|
text: gettext('Edit'),
|
|
xtype: 'proxmoxButton',
|
|
handler: 'editRealmSyncJob',
|
|
disabled: true,
|
|
},
|
|
{
|
|
xtype: 'proxmoxStdRemoveButton',
|
|
baseurl: `/api2/extjs/cluster/jobs/realm-sync`,
|
|
callback: 'reload',
|
|
},
|
|
{
|
|
xtype: 'proxmoxButton',
|
|
handler: 'runNow',
|
|
disabled: true,
|
|
text: gettext('Run Now'),
|
|
},
|
|
],
|
|
|
|
listeners: {
|
|
itemdblclick: 'editRealmSyncJob',
|
|
},
|
|
|
|
initComponent: function() {
|
|
var me = this;
|
|
|
|
me.callParent();
|
|
|
|
Proxmox.Utils.monStoreErrors(me, me.getStore());
|
|
},
|
|
});
|
|
|
|
Ext.define('PVE.dc.RealmSyncJobEdit', {
|
|
extend: 'Proxmox.window.Edit',
|
|
mixins: ['Proxmox.Mixin.CBind'],
|
|
|
|
subject: gettext('Realm Sync Job'),
|
|
onlineHelp: 'pveum_ldap_sync',
|
|
|
|
// don't focus the schedule field on edit
|
|
defaultFocus: 'field[name=id]',
|
|
|
|
cbindData: function() {
|
|
let me = this;
|
|
me.isCreate = !me.jobid;
|
|
me.jobid = me.jobid || "";
|
|
let url = '/api2/extjs/cluster/jobs/realm-sync';
|
|
me.url = me.jobid ? `${url}/${me.jobid}` : url;
|
|
me.method = me.isCreate ? 'POST' : 'PUT';
|
|
if (!me.isCreate) {
|
|
me.subject = `${me.subject}: ${me.jobid}`;
|
|
}
|
|
return {};
|
|
},
|
|
|
|
submitUrl: function(url, values) {
|
|
return this.isCreate ? `${url}/${values.id}` : url;
|
|
},
|
|
|
|
controller: {
|
|
xclass: 'Ext.app.ViewController',
|
|
|
|
updateDefaults: function(_field, newValue) {
|
|
let me = this;
|
|
|
|
['scope', 'enable-new', 'schedule'].forEach((reference) => {
|
|
me.lookup(reference)?.setDisabled(false);
|
|
});
|
|
|
|
// only update on create
|
|
if (!me.getView().isCreate) {
|
|
return;
|
|
}
|
|
Proxmox.Utils.API2Request({
|
|
url: `/access/domains/${newValue}`,
|
|
success: function(response) {
|
|
// first reset the fields to their default
|
|
['acl', 'entry', 'properties'].forEach(opt => {
|
|
me.lookup(`remove-vanished-${opt}`)?.setValue(false);
|
|
});
|
|
me.lookup('enable-new')?.setValue('1');
|
|
me.lookup('scope')?.setValue(undefined);
|
|
|
|
let options = response?.result?.data?.['sync-defaults-options'];
|
|
if (options) {
|
|
let parsed = PVE.Parser.parsePropertyString(options);
|
|
if (parsed['remove-vanished']) {
|
|
let opts = parsed['remove-vanished'].split(';');
|
|
for (const opt of opts) {
|
|
me.lookup(`remove-vanished-${opt}`)?.setValue(true);
|
|
}
|
|
delete parsed['remove-vanished'];
|
|
}
|
|
for (const [name, value] of Object.entries(parsed)) {
|
|
me.lookup(name)?.setValue(value);
|
|
}
|
|
}
|
|
},
|
|
});
|
|
},
|
|
},
|
|
|
|
items: [
|
|
{
|
|
xtype: 'inputpanel',
|
|
|
|
cbind: {
|
|
isCreate: '{isCreate}',
|
|
},
|
|
|
|
onGetValues: function(values) {
|
|
let me = this;
|
|
|
|
let vanished_opts = [];
|
|
['acl', 'entry', 'properties'].forEach((prop) => {
|
|
if (values[`remove-vanished-${prop}`]) {
|
|
vanished_opts.push(prop);
|
|
}
|
|
delete values[`remove-vanished-${prop}`];
|
|
});
|
|
|
|
if (!values.id && me.isCreate) {
|
|
values.id = 'realmsync-' + Ext.data.identifier.Uuid.Global.generate().slice(0, 13);
|
|
}
|
|
|
|
if (vanished_opts.length > 0) {
|
|
values['remove-vanished'] = vanished_opts.join(';');
|
|
} else {
|
|
values['remove-vanished'] = 'none';
|
|
}
|
|
|
|
PVE.Utils.delete_if_default(values, 'node', '');
|
|
|
|
if (me.isCreate) {
|
|
delete values.delete; // on create we cannot delete values
|
|
}
|
|
|
|
return values;
|
|
},
|
|
|
|
column1: [
|
|
{
|
|
xtype: 'pmxDisplayEditField',
|
|
editConfig: {
|
|
xtype: 'pmxRealmComboBox',
|
|
storeFilter: rec => rec.data.type === 'ldap' || rec.data.type === 'ad',
|
|
},
|
|
listConfig: {
|
|
emptyText: `<div class="x-grid-empty">${gettext('No LDAP/AD Realm found')}</div>`,
|
|
},
|
|
cbind: {
|
|
editable: '{isCreate}',
|
|
},
|
|
listeners: {
|
|
change: 'updateDefaults',
|
|
},
|
|
fieldLabel: gettext('Realm'),
|
|
name: 'realm',
|
|
reference: 'realm',
|
|
},
|
|
{
|
|
xtype: 'pveCalendarEvent',
|
|
fieldLabel: gettext('Schedule'),
|
|
disabled: true,
|
|
allowBlank: false,
|
|
name: 'schedule',
|
|
reference: 'schedule',
|
|
},
|
|
{
|
|
xtype: 'proxmoxcheckbox',
|
|
fieldLabel: gettext('Enable'),
|
|
name: 'enabled',
|
|
reference: 'enabled',
|
|
uncheckedValue: 0,
|
|
defaultValue: 1,
|
|
checked: true,
|
|
},
|
|
],
|
|
|
|
column2: [
|
|
{
|
|
xtype: 'proxmoxKVComboBox',
|
|
name: 'scope',
|
|
reference: 'scope',
|
|
disabled: true,
|
|
fieldLabel: gettext('Scope'),
|
|
value: '',
|
|
emptyText: gettext('No default available'),
|
|
deleteEmpty: false,
|
|
allowBlank: false,
|
|
comboItems: [
|
|
['users', gettext('Users')],
|
|
['groups', gettext('Groups')],
|
|
['both', gettext('Users and Groups')],
|
|
],
|
|
},
|
|
{
|
|
xtype: 'proxmoxKVComboBox',
|
|
value: '1',
|
|
deleteEmpty: false,
|
|
disabled: true,
|
|
allowBlank: false,
|
|
comboItems: [
|
|
['1', Proxmox.Utils.yesText],
|
|
['0', Proxmox.Utils.noText],
|
|
],
|
|
name: 'enable-new',
|
|
reference: 'enable-new',
|
|
fieldLabel: gettext('Enable new'),
|
|
},
|
|
],
|
|
|
|
columnB: [
|
|
{
|
|
xtype: 'fieldset',
|
|
title: gettext('Remove Vanished Options'),
|
|
items: [
|
|
{
|
|
xtype: 'proxmoxcheckbox',
|
|
fieldLabel: gettext('ACL'),
|
|
name: 'remove-vanished-acl',
|
|
reference: 'remove-vanished-acl',
|
|
boxLabel: gettext('Remove ACLs of vanished users and groups.'),
|
|
},
|
|
{
|
|
xtype: 'proxmoxcheckbox',
|
|
fieldLabel: gettext('Entry'),
|
|
name: 'remove-vanished-entry',
|
|
reference: 'remove-vanished-entry',
|
|
boxLabel: gettext('Remove vanished user and group entries.'),
|
|
},
|
|
{
|
|
xtype: 'proxmoxcheckbox',
|
|
fieldLabel: gettext('Properties'),
|
|
name: 'remove-vanished-properties',
|
|
reference: 'remove-vanished-properties',
|
|
boxLabel: gettext('Remove vanished properties from synced users.'),
|
|
},
|
|
],
|
|
},
|
|
{
|
|
xtype: 'proxmoxtextfield',
|
|
name: 'comment',
|
|
fieldLabel: gettext('Job Comment'),
|
|
cbind: {
|
|
deleteEmpty: '{!isCreate}',
|
|
},
|
|
autoEl: {
|
|
tag: 'div',
|
|
'data-qtip': gettext('Description of the job'),
|
|
},
|
|
},
|
|
{
|
|
xtype: 'displayfield',
|
|
reference: 'defaulthint',
|
|
value: gettext('Default sync options can be set by editing the realm.'),
|
|
userCls: 'pmx-hint',
|
|
hidden: true,
|
|
},
|
|
],
|
|
},
|
|
],
|
|
|
|
initComponent: function() {
|
|
let me = this;
|
|
me.callParent();
|
|
if (me.jobid) {
|
|
me.load({
|
|
success: function(response, options) {
|
|
let values = response.result.data;
|
|
|
|
if (values['remove-vanished']) {
|
|
let opts = values['remove-vanished'].split(';');
|
|
for (const opt of opts) {
|
|
values[`remove-vanished-${opt}`] = 1;
|
|
}
|
|
}
|
|
me.down('inputpanel').setValues(values);
|
|
},
|
|
});
|
|
}
|
|
},
|
|
});
|