示例#1
0
import { computed } from '@ember/object';
import Resource from '@rancher/ember-api-store/models/resource';

var LaunchConfig = Resource.extend({
  displayEnvironmentVars: computed('launchConfig.environment', function() {
    var envs = [];
    var environment = this.get('launchConfig.environment') || {};

    Object.keys(environment).forEach((key) => {
      envs.pushObject({
        key,
        value: environment[key]
      })
    });

    return envs;
  }),
});

export default LaunchConfig;
示例#2
0
文件: target.js 项目: rancher/ui
import { reference } from '@rancher/ember-api-store/utils/denormalize';

export default Resource.extend({
  project: reference('projectId'),

  projectName: computed('project', function() {
    return get(this, 'project.displayName');
  }),

  clusterName: computed('project.cluster', function() {
    return get(this, 'project.cluster.displayName');
  }),

  clusterId: computed('projectId', function() {
    let { projectId } = this;

    return projectId.split(':')[0];
  }),

  appLink: computed('projectId', 'appId', function() {
    const { projectId } = this;

    if (projectId) {
      return `${ projectId.split(':')[1] }:${ this.appId }`;
    }

    return null;
  }),

});
示例#3
0
文件: scalehost.js 项目: rancher/ui
import Resource from '@rancher/ember-api-store/models/resource';

export default Resource.extend({
  hostSelectorStr: function() {
    let all = this.get('hostSelector') || [];

    return Object.keys(all).map((key) => {
      let val = all[key];

      return key + (val ? `=${  val }` : '');
    })
      .join(', ');
  }.property('hostSelector'),

  validationErrors() {
    let errors = this._super(...arguments);
    let min = parseInt(this.get('min'), 10);
    let max = parseInt(this.get('max'), 10);

    if ( min && max && min > max ) {
      errors.push('"Minimum Scale" cannot be greater than "Maximum Scale"');
    }

    return errors;
  }
});
示例#4
0
文件: certificate.js 项目: rancher/ui
export default Resource.extend({
  router:     service(),
  intl:   service(),

  state: 'active',

  issuedDate: computed('issuedAt', function() {
    return new Date(get(this, 'issuedAt'));
  }),

  expiresDate: computed('expiresAt', function() {
    return new Date(get(this, 'expiresAt'));
  }),

  expiresSoon: computed('expiresDate', function() {
    var diff = (get(this, 'expiresDate')).getTime() - (new Date()).getTime();
    var days = diff / (86400 * 1000);

    return days <= 8;
  }),

  displayIssuer: computed('issuer', function() {
    return (get(this, 'issuer') || '').split(/,/)[0].replace(/^CN=/i, '');
  }),

  // All the SANs that aren't the CN
  displaySans: computed('cn', 'subjectAlternativeNames.[]', function() {
    const sans = get(this, 'subjectAlternativeNames') || '';
    const cn = get(this, 'cn') || '';

    if ( !sans ) {
      return [];
    }

    return sans.removeObject(cn)
      .filter((san) => (`${ san }`).indexOf('@') === -1);
  }),

  // The useful SANs; Removes "domain.com" when the cert is for "www.domain.com"
  countableSans: computed('displaySans.[]', 'cn', function() {
    var sans = get(this, 'displaySans').slice();

    if ( get(this, 'cn') ) {
      sans.pushObject(get(this, 'cn'));
    }

    var commonBases = sans.filter((name) => name.indexOf('*.') === 0 || name.indexOf('www.') === 0).map((name) => name.substr(name.indexOf('.')));

    return get(this, 'displaySans').slice()
      .removeObjects(commonBases);
  }),

  // "cn.com and 5 others" (for table view)
  displayDomainName: computed('cn', 'countableSans.length', function() {
    const intl = get(this, 'intl');
    const cn = get(this, 'cn');

    if ( !cn ) {
      return intl.t('generic.none');
    }

    const sans = get(this, 'countableSans.length');
    const wildcard = cn.substr(0, 1) === '*';

    let key;

    if ( wildcard ) {
      if ( sans ) {
        key = 'certificatesPage.domainNames.wildcardWithSan'
      } else {
        key = 'certificatesPage.domainNames.wildcardSingle'
      }
    } else if ( sans ) {
      key = 'certificatesPage.domainNames.withSan';
    } else {
      key = 'certificatesPage.domainNames.single';
    }

    return intl.t(key, {
      cn,
      sans
    });
  }),

  // "user-provided-name (cn-if-different-than-user-name.com + 5 others)"
  displayDetailedName: computed('displayName', 'cn', 'countableSans.length', function() {
    var name = get(this, 'displayName');
    var cn = get(this, 'cn');
    var sans = get(this, 'countableSans.length');
    var out = name;

    var more = '';

    if ( cn ) {
      if ( cn !== name ) {
        more += cn;
      }

      if ( sans > 0 ) {
        more += ` + ${  sans  } other${  sans === 1 ? '' : 's' }`;
      }
    }

    if ( more ) {
      out += ` (${  more  })`;
    }

    return out;
  }),
  actions: {
    edit() {
      get(this, 'router').transitionTo('authenticated.project.certificates.detail.edit', get(this, 'id'));
    },
  },

});
示例#5
0
import C from 'ui/utils/constants';
import PrincipalReference from 'ui/mixins/principal-reference';

export default Resource.extend(PrincipalReference, {
  type:         'projectRoleTemplateBinding',
  canEdit:      false,
  project:      reference('projectId'),
  roleTemplate: reference('roleTemplateId'),
  user:         reference('userId', 'user'),
  displayName:  computed('name', 'id', function() {
    let name = get(this, 'name');

    if ( name ) {
      return name;
    }

    return `(${  get(this, 'id')  })`;
  }),
  isCustom: computed('roleTemplateId', function() {
    return !C.BASIC_ROLE_TEMPLATE_ROLES.includes(get(this, 'roleTemplateId'));
  }),

  principalId: computed('userPrincipalId', 'groupPrincipalId', function() {
    return get(this, 'groupPrincipalId') || get(this, 'userPrincipalId') || null;
  }),

  canRemove: computed('links.remove', 'name', function() {
    return !!get(this, 'links.remove') && get(this, 'name') !== 'creator';
  }),
});
示例#6
0
import Resource from '@rancher/ember-api-store/models/resource';
import { reference } from '@rancher/ember-api-store/utils/denormalize';

export default Resource.extend({
  canRemove:  false,
  globalRole: reference('globalRoleId', 'globalRole'),
});
示例#7
0
文件: globaldns.js 项目: rancher/ui
export default Resource.extend({
  router: service(),
  scope:  service(),

  multiClusterApp: reference('multiClusterAppId', 'multiClusterApp'),

  target: computed('multiClusterAppId', 'projectIds.[]',  function() {
    // returns either a single multiClusterAppId or an array of project target ids
    const out = {
      type: null,
      data: null,
    };

    const multiClusterAppId = get(this, 'multiClusterAppId');
    const projectIds        = get(this, 'projectIds');

    if (multiClusterAppId && !projectIds) {
      setProperties(out, {
        type: 'single',
        data: multiClusterAppId
      });
    } else if (projectIds && projectIds.length && !multiClusterAppId) {
      setProperties(out, {
        type: 'multi',
        data: projectIds
      });
    }

    return out;
  }),


  linkedProjects: computed('projectIds.[]', 'scope.allProjects.@each.{id}', function() {
    const allProjects = get(this, 'scope.allProjects') || [];
    const projectIds  = get(this, 'projectIds') || [];

    const myProjects = [];

    projectIds.forEach( (projectId) => {
      let match = allProjects.findBy('id', projectId);

      if (match) {
        next(() => {
          set(match, 'accessible', true);
          myProjects.pushObject(match);
        });
      } else {
        next(() => {
          myProjects.pushObject({
            id:         projectId,
            accessible: false,
          });
        });
      }
    });

    return myProjects;
  }),

  canEdit: computed('links.update', function() {
    return !!get(this, 'links.update');
  }),

  canRemove: computed('links.remove', function() {
    return !!get(this, 'links.remove');
  }),

  actions: {
    edit() {
      this.router.transitionTo('global-admin.global-dns.entries.new', { queryParams: { id: this.id } } );
    }
  },

});
示例#8
0
export default Resource.extend({
  clusterStore: service(),
  router:       service(),

  type:      'storageClass',
  state: 'active',

  isDefault: computed('annotations', function() {
    const annotations = get(this, 'annotations') || {};

    return annotations[DEFAULT_ANNOTATION] === 'true' ||
      annotations[BETA_ANNOTATION] === 'true';
  }),

  availableActions: computed('isDefault', function() {
    const isDefault = get(this, 'isDefault');

    let out = [
      {
        label:   'action.makeDefault',
        icon:    'icon icon-star-fill',
        action:  'makeDefault',
        enabled: !isDefault
      },
      {
        label:   'action.resetDefault',
        icon:    'icon icon-star-line',
        action:  'resetDefault',
        enabled: isDefault
      },
    ];

    return out;
  }),

  displayProvisioner: computed('provisioner', 'intl.locale', function() {
    const intl = get(this, 'intl');
    const provisioner = get(this, 'provisioner');
    const entry = PROVISIONERS.findBy('value', provisioner)

    if ( provisioner && entry ) {
      const key = `storageClass.${ entry.name }.title`;

      if ( intl.exists(key) ) {
        return intl.t(key);
      }
    }

    return provisioner;
  }),
  actions: {
    makeDefault() {
      const cur = get(this, 'clusterStore').all('storageClass')
        .filterBy('isDefault', true);
      const promises = [];

      cur.forEach((sc) => {
        promises.push(sc.setDefault(false));
      });

      all(promises).then(() => {
        this.setDefault(true);
      });
    },

    resetDefault() {
      this.setDefault(false)
    },

    edit() {
      get(this, 'router').transitionTo('authenticated.cluster.storage.classes.detail.edit', get(this, 'id'));
    },
  },

  setDefault(on) {
    let annotations = get(this, 'annotations');

    if ( !annotations ) {
      annotations = {};
      set(this, 'annotations', annotations);
    }

    if ( on ) {
      annotations[DEFAULT_ANNOTATION] = 'true';
      annotations[BETA_ANNOTATION] = 'true';
    } else {
      annotations[DEFAULT_ANNOTATION] = 'false';
      annotations[BETA_ANNOTATION] = 'false';
    }

    this.save();
  },

});
示例#9
0
文件: secret.js 项目: rancher/ui
import { computed, get } from '@ember/object';
import Resource from '@rancher/ember-api-store/models/resource';

export default Resource.extend({
  router:   service(),

  state:    'active',
  canClone: true,

  firstKey: alias('keys.firstObject'),
  keys:     computed('data', function() {
    return Object.keys(get(this, 'data') || {}).sort();
  }),

  actions: {
    edit() {
      get(this, 'router').transitionTo('authenticated.project.secrets.detail.edit', get(this, 'id'));
    },

    clone() {
      get(this, 'router').transitionTo('authenticated.project.secrets.new', {
        queryParams: {
          id:   get(this, 'id'),
          type: get(this, 'type')
        }
      });
    }
  },

});
示例#10
0
import Resource from '@rancher/ember-api-store/models/resource';

export default Resource.extend({ type: 'azureKubernetesServiceConfig', });
示例#11
0
文件: user.js 项目: rancher/ui
export default Resource.extend({
  router:      service(),
  globalStore: service(),
  access:      service(),
  growl:       service(),

  globalRoleBindings:  hasMany('id', 'globalRoleBinding', 'userId'),
  clusterRoleBindings: hasMany('id', 'clusterRoleTemplateBinding', 'userId'),
  projectRoleBindings: hasMany('id', 'projectRoleTemplateBinding', 'userId'),

  combinedState: computed('enabled', 'state', function() {
    if ( get(this, 'enabled') === false ) {
      return 'inactive';
    } else {
      return get(this, 'state');
    }
  }),

  displayName: computed('name', 'username', 'id', function() {
    let name = get(this, 'name');

    if ( name ) {
      return name;
    }

    name = get(this, 'username');
    if ( name ) {
      return name;
    }

    return `(${  get(this, 'id')  })`;
  }),

  avatarSrc: computed('id', function() {
    return `data:image/png;base64,${  new Identicon(AWS.util.crypto.md5(this.get('id') || 'Unknown', 'hex'), 80, 0.01).toString() }`;
  }),

  hasAdmin: computed('globalRoleBindings.[]', function() {
    return get(this, 'globalRoleBindings').findBy('globalRole.isAdmin', true);
  }),

  hasCustom: computed('globalRoleBindings.[]', function() {
    return get(this, 'globalRoleBindings').findBy('globalRole.isCustom', true);
  }),

  hasUser: computed('globalRoleBindings.[]', function() {
    return get(this, 'globalRoleBindings').findBy('globalRole.isUser', true);
  }),

  hasBase: computed('globalRoleBindings.[]', function() {
    return get(this, 'globalRoleBindings').findBy('globalRole.isBase', true);
  }),

  isMe: computed('access.principal', function() {
    return get(this, 'access.principal.id') === get(this, 'id');
  }),

  availableActions: computed('enabled', 'access.providers.[]', function() {
    const on         = get(this, 'enabled') !== false;
    const { access } = this;
    const a = get(this, 'actionLinks') || {};

    return [
      {
        label:    'action.refreshAuthProviderAccess.label',
        icon:     'icon icon-refresh',
        action:   'refreshAuthProviderAccess',
        bulkable: false,
        enabled:  isRefreshAuthProviderAccessAvailable(),
      },
      {
        label:    'action.activate',
        icon:     'icon icon-play',
        action:   'activate',
        bulkable: true,
        enabled:  !on,
      },
      {
        label:    'action.deactivate',
        icon:     'icon icon-pause',
        action:   'deactivate',
        bulkable: true,
        enabled:  on,
      },
    ];

    function isRefreshAuthProviderAccessAvailable() {
      if (on &&
          get(access, 'providers') &&
          get(access, 'providers.length') > 1 &&
          a.refreshauthprovideraccess) {
        return true;
      } else {
        return false;
      }
    }
  }),

  actions: {
    deactivate() {
      next(() => {
        set(this, 'enabled', false);
        this.save().catch((err) => {
          set(this, 'enabled', true);
          get(this, 'growl').fromError('Error deactivating user', err)
        });
      });
    },

    activate() {
      next(() => {
        set(this, 'enabled', true);
        this.save().catch((err) => {
          set(this, 'enabled', false);
          get(this, 'growl').fromError('Error activating user', err)
        });
      });
    },

    edit() {
      get(this, 'router').transitionTo('global-admin.accounts.edit', get(this, 'id'));
    },

    setPassword(password) {
      this.doAction('setpassword', { newPassword: password });
    },

    refreshAuthProviderAccess() {
      this.doAction('refreshauthprovideraccess').then(() => {
        const successTitle   = this.intl.t('action.refreshAuthProviderAccess.success.title');
        const successMessage = this.intl.t('action.refreshAuthProviderAccess.success.message');

        this.growl.success(successTitle, successMessage)
      })
        .catch((err) => {
          this.growl.fromError('Error refreshing user user auth tokens', err)
        });
    },
  },

});
示例#12
0
let PipelineExecution = Resource.extend({
  router:   service(),
  type:     'pipelineexecution',
  pipeline: reference('pipelineId', 'pipeline'),

  relevantState:    alias('executionState'),
  availableActions: computed('actionLinks.{rerun,stop}', function() {
    const a = get(this, 'actionLinks') || {};

    return [
      {
        label:    'action.rerun',
        icon:     'icon icon-refresh',
        action:   'rerun',
        enabled:  !!a.rerun,
        bulkable: true
      },
      {
        label:    'action.stop',
        icon:     'icon icon-stop',
        action:   'stop',
        enabled:  !!a.stop,
        bulkable: true
      },
      { divider: true },
    ];
  }),

  amount: computed('pipelineConfig.stages.[]', function(){
    const activity_stages = get(this, 'pipelineConfig.stages');
    let countStage = 0;
    let countStep = 0;

    for (let i = 0; i < activity_stages.length; i++) {
      const stage = activity_stages[i];

      countStage++;
      for (let j = 0; j < stage.steps.length; j++) {
        stage.steps[j];
        countStep++;
      }
    }

    return {
      countStage,
      countStep
    };
  }),

  shortCommit: computed('commit', function() {
    const commit = get(this, 'commit')

    if (commit) {
      return commit.substr(0, 8)
    }

    return '';
  }),

  startedTimeStamp: computed('started', function(){
    const time = get(this, 'started');

    return new Date(time);
  }),

  showTransitioning: computed('showTransitioningMessage', 'executionState', function() {
    return get(this, 'showTransitioningMessage') && get(this, 'executionState') !== C.STATES.ABORTED && get(this, 'executionState') !== C.STATES.FAILED;
  }),

  displayRepositoryUrl: computed('repositoryUrl', function() {
    let url = get(this, 'repositoryUrl');

    if ( url.endsWith('.git') ) {
      url = url.substr(0, url.length - 4);
    }

    return url;
  }),

  commitUrl: computed('commit', function() {
    let url = get(this, 'displayRepositoryUrl');
    const sourceCodeType = get(this, 'pipeline.sourceCodeCredential.sourceCodeType');
    const name = get(this, 'pipeline.displayName');

    switch ( sourceCodeType ) {
    case 'bitbucketserver':
      if ( name.startsWith('~') ) {
        return `${ this.bitbucketRootUrl('users') }/commits/${ get(this, 'commit') }`;
      } else {
        return `${ this.bitbucketRootUrl('projects') }/commits/${ get(this, 'commit') }`;
      }
    case 'bitbucketcloud':
      return `${ url }/commits/${ get(this, 'commit') }`;
    default:
      return `${ url }/commit/${ get(this, 'commit') }`;
    }
  }),

  branchUrl: computed('branch', function() {
    let url = get(this, 'displayRepositoryUrl');
    const sourceCodeType = get(this, 'pipeline.sourceCodeCredential.sourceCodeType');
    const name = get(this, 'pipeline.displayName');

    switch ( sourceCodeType ) {
    case 'bitbucketserver':
      if ( name.startsWith('~') ) {
        return `${ this.bitbucketRootUrl('users') }/browse?at=refs%2Fheads%2F${ get(this, 'branch') }`;
      } else {
        return `${ this.bitbucketRootUrl('projects') }/browse?at=refs%2Fheads%2F${ get(this, 'branch') }`;
      }
    case 'bitbucketcloud':
      return `${ url }/src/${ get(this, 'branch') }`;
    default:
      return `${ url }/tree/${ get(this, 'branch') }`;
    }
  }),

  duration: computed('started', 'ended', function(){
    const started = get(this, 'started');
    const ended = get(this, 'ended');

    if ( ended ) {
      const duration = new Date(ended).getTime() - new Date(started).getTime();

      return duration < 0 ? null : duration;
    }
  }),

  bitbucketRootUrl(repoType) {
    let url = get(this, 'displayRepositoryUrl');

    url = url.substr(0, get(url, 'length') - get(this, 'pipeline.displayName.length') - 5);

    return `${ url }/${ repoType }/${ get(this, 'pipeline.projectName') }/repos/${ get(this, 'pipeline.repoName') }`;
  },

  actions: {
    rerun() {
      return this.doAction('rerun').then(() => {
        const pipelineId = get(this, 'pipeline.id');
        const nextRun = get(this, 'pipeline.nextRun');

        get(this, 'router').transitionTo('authenticated.project.pipeline.pipelines.run', pipelineId, nextRun);
      });
    },

    stop() {
      return this.doAction('stop');
    },
  },

});
示例#13
0
var KontainerDriver = Resource.extend({
  intl:         service(),
  type:                'kontainerDriver',

  availableActions: computed('actionLinks.{activate,deactivate}', function() {
    let a = get(this, 'actionLinks') || {};

    return [
      {
        label:    'action.activate',
        icon:     'icon icon-play',
        action:   'activate',
        enabled:  !!a.activate,
        bulkable: true
      },
      {
        label:    'action.deactivate',
        icon:     'icon icon-pause',
        action:   'deactivate',
        enabled:  !!a.deactivate,
        bulkable: true
      },
    ];
  }),

  displayName: computed('name', 'intl.locale', function() {
    const intl = get(this, 'intl');
    const name = get(this, 'name');
    const keyByName = `kontainerDriver.displayName.${ name }`;
    const keyById = `kontainerDriver.displayName.${ get(this, 'id') }`;

    if ( name && intl.exists(keyByName) ) {
      return intl.t(keyByName);
    } if ( intl.exists(keyById) ) {
      return intl.t(keyById);
    } else if ( name ) {
      return name.capitalize();
    } else {
      return `(${  get(this, 'id')  })`;
    }
  }),

  canEdit: computed('links.update', 'builtin', function() {
    return !!get(this, 'links.update') && !get(this, 'builtin');
  }),


  hasUi: computed('hasBuiltinUi', function() {
    return !!get(this, 'uiUrl');
  }),


  actions: {
    activate() {
      return this.doAction('activate');
    },

    deactivate() {
      return this.doAction('deactivate');
    },

    edit() {
      get(this, 'modalService').toggleModal('modal-edit-driver', this);
    },
  },

});
示例#14
0
import { parseSi, formatSi } from 'shared/utils/parse-unit';
import { inject as service } from '@ember/service';

var PersistentVolumeClaim = Resource.extend({
  clusterStore:     service(),
  type:             'persistentVolumeClaim',
  canEdit:      false,

  storageClass:     reference('storageClassId', 'storageClass', 'clusterStore'),
  persistentVolume: reference('volumeId', 'persistentVolume', 'clusterStore'),
  namespace:        reference('namespaceId', 'namespace', 'clusterStore'),

  sizeBytes: computed('status.capacity.storage', function() {
    const str = get(this, 'status.capacity.storage');

    if ( str ) {
      return parseSi(str, 1024);
    }
  }),

  displaySize: computed('sizeBytes', function() {
    const bytes = get(this, 'sizeBytes');

    if ( bytes ) {
      return formatSi(bytes, 1024, 'iB', 'B');
    }
  }),
});

export default PersistentVolumeClaim;
示例#15
0
文件: ingress.js 项目: rancher/ui
export default Resource.extend({
  clusterStore:  service(),
  router:        service(),

  type:          'ingress',

  canClone:      true,
  canHaveLabels: true,

  namespace:     reference('namespaceId', 'namespace', 'clusterStore'),

  targets: computed('*****@*****.**', function() {
    const out = [];
    const store = get(this, 'store');

    let tlsHosts = [];

    (get(this, 'tls') || []).forEach((entry) => {
      tlsHosts.addObjects(entry.hosts || []);
    });
    tlsHosts = tlsHosts.uniq();


    let def = get(this, 'defaultBackend');

    if ( def ) {
      addRow(null, null, def);
    }

    (get(this, 'rules') || []).forEach((rule) => {
      let entries = get(rule, 'paths') || [];

      entries.forEach((entry) => {
        addRow(rule.host, get(entry, 'path'), entry);
      });
    });

    function addRow(host, path, entry) {
      let reference;

      if ( entry.serviceId ) {
        reference = store.getById('service', entry.serviceId);
        out.push({
          host,
          tls:       tlsHosts.includes(host),
          path,
          reference: entry.serviceId,
          service:   reference,
        });
      } else if ( entry.workloadIds ) {
        (entry.workloadIds || []).forEach((id) => {
          reference = store.getById('workload', id);
          out.push({
            host,
            tls:       tlsHosts.includes(host),
            path,
            reference: id,
            workload:  reference,
          });
        });
      }
    }

    return out;
  }),

  displayKind: computed('intl.locale', function() {
    const intl = get(this, 'intl');

    return intl.t('model.ingress.displayKind');
  }),
  actions:      {
    edit() {
      get(this, 'router').transitionTo('ingresses.run', {
        queryParams: {
          ingressId: get(this, 'id'),
          upgrade:   true,
        }
      });
    },

    clone() {
      get(this, 'router').transitionTo('ingresses.run', {
        queryParams: {
          ingressId: get(this, 'id'),
          upgrade:   false,
        }
      });
    },
  },

});
示例#16
0
文件: token.js 项目: rancher/ui
export default Resource.extend({
  growl:       service(),

  state: computed('expired', function() {
    if ( get(this, 'expired') ) {
      return 'expired';
    }

    return 'active';
  }),

  availableActions: computed('enabled', function() { // eslint-disable-line

    return [
      {
        label:      'action.activate',
        icon:       'icon icon-play',
        action:     'activate',
        // enabled: !this.enabled,
        enabled:    false, // backend was supposed to be ready but its not ready, when it is flip this switch and bingo bango yor're off to the races
        bulkable:   false
      },
      {
        label:      'action.deactivate',
        icon:       'icon icon-pause',
        action:     'deactivate',
        // enabled: this.enabled,
        enabled:    false, // backend was supposed to be ready but its not ready, when it is flip this switch and bingo bango yor're off to the races
        bulkable:   false
      },
    ];
  }),

  actions: {
    deactivate() {
      next(() => {
        set(this, 'enabled', false);
        this.save().catch((err) => {
          set(this, 'enabled', true);
          get(this, 'growl').fromError('Error deactivating token', err)
        });
      });
    },

    activate() {
      next(() => {
        set(this, 'enabled', true);
        this.save().catch((err) => {
          set(this, 'enabled', false);
          get(this, 'growl').fromError('Error activating token', err)
        });
      });
    },
  },
});