fix(frontend) prevent notification showing Object Object EE-1745 (#5778)

* fix(frontend) prevent notification showing Object Object EE-1745

* fix(frontend) fix notification args in wrong order EE-1745

* fix(rbac) add metrics rbac for regular users EE-1745

Co-authored-by: Simon Meng <simon.meng@portainer.io>
pull/5877/head
cong meng 2021-10-12 10:37:07 +13:00 committed by GitHub
parent d93d88fead
commit 6a67e8142d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 45 additions and 35 deletions

View File

@ -18,6 +18,11 @@ func getPortainerUserDefaultPolicies() []rbacv1.PolicyRule {
Resources: []string{"storageclasses"}, Resources: []string{"storageclasses"},
APIGroups: []string{"storage.k8s.io"}, APIGroups: []string{"storage.k8s.io"},
}, },
{
Verbs: []string{"list"},
Resources: []string{"namespaces", "pods"},
APIGroups: []string{"metrics.k8s.io"},
},
} }
} }

View File

@ -68,7 +68,7 @@ angular.module('portainer.docker').controller('ServicesDatatableActionsControlle
Notifications.success('Service successfully updated', service.Name); Notifications.success('Service successfully updated', service.Name);
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to force update service', service.Name); Notifications.error('Failure', err, 'Unable to force update service' + service.Name);
}) })
.finally(function final() { .finally(function final() {
--actionCount; --actionCount;

View File

@ -501,7 +501,7 @@ angular.module('portainer.docker').controller('ServiceController', [
ServiceService.update(service, config, 'previous') ServiceService.update(service, config, 'previous')
.then(function (data) { .then(function (data) {
if (data.message && data.message.match(/^rpc error:/)) { if (data.message && data.message.match(/^rpc error:/)) {
Notifications.error(data.message, 'Error'); Notifications.error('Failure', data, 'Error');
} else { } else {
Notifications.success('Success', 'Service successfully rolled back'); Notifications.success('Success', 'Service successfully rolled back');
$scope.cancelChanges({}); $scope.cancelChanges({});
@ -550,7 +550,7 @@ angular.module('portainer.docker').controller('ServiceController', [
ServiceService.update(service, config).then( ServiceService.update(service, config).then(
function (data) { function (data) {
if (data.message && data.message.match(/^rpc error:/)) { if (data.message && data.message.match(/^rpc error:/)) {
Notifications.error(data.message, 'Error'); Notifications.error('Failure', data, 'Error');
} else { } else {
Notifications.success('Service successfully updated', 'Service updated'); Notifications.success('Service successfully updated', 'Service updated');
} }

View File

@ -95,7 +95,7 @@ class KubernetesClusterController {
await this.getResourceUsage(this.endpoint.Id); await this.getResourceUsage(this.endpoint.Id);
} }
} catch (err) { } catch (err) {
this.Notifications.error('Failure', 'Unable to retrieve applications', err); this.Notifications.error('Failure', err, 'Unable to retrieve applications');
} finally { } finally {
this.state.applicationsLoading = false; this.state.applicationsLoading = false;
} }
@ -116,7 +116,7 @@ class KubernetesClusterController {
}, new KubernetesResourceReservation()); }, new KubernetesResourceReservation());
this.resourceUsage = clusterResourceUsage; this.resourceUsage = clusterResourceUsage;
} catch (err) { } catch (err) {
this.Notifications.error('Failure', 'Unable to retrieve cluster resource usage', err); this.Notifications.error('Failure', err, 'Unable to retrieve cluster resource usage');
} }
} }

View File

@ -345,7 +345,7 @@ class KubernetesNodeController {
this.resourceUsage.CPU = KubernetesResourceReservationHelper.parseCPU(node.usage.cpu); this.resourceUsage.CPU = KubernetesResourceReservationHelper.parseCPU(node.usage.cpu);
this.resourceUsage.Memory = KubernetesResourceReservationHelper.megaBytesValue(node.usage.memory); this.resourceUsage.Memory = KubernetesResourceReservationHelper.megaBytesValue(node.usage.memory);
} catch (err) { } catch (err) {
this.Notifications.error('Failure', 'Unable to retrieve node resource usage', err); this.Notifications.error('Failure', err, 'Unable to retrieve node resource usage');
} }
} }

View File

@ -361,7 +361,7 @@ class KubernetesResourcePoolController {
}, new KubernetesResourceReservation()); }, new KubernetesResourceReservation());
this.state.resourceUsage = namespaceResourceUsage; this.state.resourceUsage = namespaceResourceUsage;
} catch (err) { } catch (err) {
this.Notifications.error('Failure', 'Unable to retrieve namespace resource usage', err); this.Notifications.error('Failure', err, 'Unable to retrieve namespace resource usage');
} }
} }

View File

@ -1,5 +1,6 @@
import _ from 'lodash-es'; import _ from 'lodash-es';
import toastr from 'toastr'; import toastr from 'toastr';
import lodash from 'lodash-es';
angular.module('portainer.app').factory('Notifications', [ angular.module('portainer.app').factory('Notifications', [
'$sanitize', '$sanitize',
@ -15,31 +16,35 @@ angular.module('portainer.app').factory('Notifications', [
toastr.warning($sanitize(_.escape(text)), $sanitize(title), { timeOut: 6000 }); toastr.warning($sanitize(_.escape(text)), $sanitize(title), { timeOut: 6000 });
}; };
service.error = function (title, e, fallbackText) { function pickErrorMsg(e) {
var msg = fallbackText; const props = [
if (e.err && e.err.data && e.err.data.details && typeof e.err.data.details === 'string') { 'err.data.details',
msg = e.err.data.details; 'err.data.message',
} else if (e.err && e.err.data && e.err.data.message) { 'data.details',
msg = e.err.data.message; 'data.message',
} else if (e.data && e.data.details) { 'data.content',
msg = e.data.details; 'data.error',
} else if (e.data && e.data.message) { 'message',
msg = e.data.message; 'err.data[0].message',
} else if (e.data && e.data.content) { 'err.data.err',
msg = e.data.content; 'data.err',
} else if (e.data && e.data.error) { 'msg',
msg = e.data.error; ];
} else if (e.message) {
msg = e.message; let msg = '';
} else if (e.err && e.err.data && e.err.data.length > 0 && e.err.data[0].message) {
msg = e.err.data[0].message; lodash.forEach(props, (prop) => {
} else if (e.err && e.err.data && e.err.data.err) { const val = lodash.get(e, prop);
msg = e.err.data.err; if (typeof val === 'string') {
} else if (e.data && e.data.err) { msg = msg || val;
msg = e.data.err;
} else if (e.msg) {
msg = e.msg;
} }
});
return msg;
}
service.error = function (title, e, fallbackText) {
const msg = pickErrorMsg(e) || fallbackText;
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.error(e); console.error(e);

View File

@ -61,7 +61,7 @@ class InitEndpointController {
case PortainerEndpointConnectionTypes.AGENT: case PortainerEndpointConnectionTypes.AGENT:
return this.createAgentEndpoint(); return this.createAgentEndpoint();
default: default:
this.Notifications.error('Failure', 'Unable to determine which action to do to create environment'); this.Notifications.error('Failure', null, 'Unable to determine which action to do to create environment');
} }
} }

View File

@ -20,7 +20,7 @@ export default class WizardAciController {
// Check name is duplicated or not // Check name is duplicated or not
let nameUsed = await this.NameValidator.validateEnvironmentName(name); let nameUsed = await this.NameValidator.validateEnvironmentName(name);
if (nameUsed) { if (nameUsed) {
this.Notifications.error('Failure', true, 'This name is been used, please try another one'); this.Notifications.error('Failure', null, 'This name is been used, please try another one');
return; return;
} }
await this.EndpointService.createAzureEndpoint(name, azureApplicationId, azureTenantId, azureAuthenticationKey, groupId, tagIds); await this.EndpointService.createAzureEndpoint(name, azureApplicationId, azureTenantId, azureAuthenticationKey, groupId, tagIds);

View File

@ -65,7 +65,7 @@ export default class WizardDockerController {
// Check name is duplicated or not // Check name is duplicated or not
const nameUsed = await this.NameValidator.validateEnvironmentName(name); const nameUsed = await this.NameValidator.validateEnvironmentName(name);
if (nameUsed) { if (nameUsed) {
this.Notifications.error('Failure', true, 'This name is been used, please try another one'); this.Notifications.error('Failure', null, 'This name is been used, please try another one');
return; return;
} }
switch (type) { switch (type) {

View File

@ -33,7 +33,7 @@ export default class WizardKubernetesController {
// Check name is duplicated or not // Check name is duplicated or not
let nameUsed = await this.NameValidator.validateEnvironmentName(name); let nameUsed = await this.NameValidator.validateEnvironmentName(name);
if (nameUsed) { if (nameUsed) {
this.Notifications.error('Failure', true, 'This name is been used, please try another one'); this.Notifications.error('Failure', null, 'This name is been used, please try another one');
return; return;
} }
await this.addRemoteEndpoint(name, creationType, url, publicUrl, groupId, tagIds, tls, tlsSkipVerify, tlsSkipClientVerify, tlsCaFile, tlsCertFile, tlsKeyFile); await this.addRemoteEndpoint(name, creationType, url, publicUrl, groupId, tagIds, tls, tlsSkipVerify, tlsSkipClientVerify, tlsCaFile, tlsCertFile, tlsKeyFile);