mirror of https://github.com/rancher/dashboard.git
249 lines
6.4 KiB
Vue
249 lines
6.4 KiB
Vue
<script>
|
|
import BackLink from '@shell/components/BackLink';
|
|
import PromptChangePassword from '@shell/components/PromptChangePassword';
|
|
import { MANAGEMENT, NORMAN } from '@shell/config/types';
|
|
import { SETTING } from '@shell/config/settings';
|
|
import Loading from '@shell/components/Loading';
|
|
import Principal from '@shell/components/auth/Principal';
|
|
import BackRoute from '@shell/mixins/back-link';
|
|
import { mapGetters } from 'vuex';
|
|
|
|
import { Banner } from '@components/Banner';
|
|
import ResourceTable from '@shell/components/ResourceTable';
|
|
import CopyToClipboardText from '@shell/components/CopyToClipboardText';
|
|
import TabTitle from '@shell/components/TabTitle';
|
|
|
|
const API_ENDPOINT = '/v3';
|
|
|
|
export default {
|
|
components: {
|
|
CopyToClipboardText, BackLink, Banner, PromptChangePassword, Loading, ResourceTable, Principal, TabTitle
|
|
},
|
|
mixins: [BackRoute],
|
|
async fetch() {
|
|
this.canChangePassword = await this.calcCanChangePassword();
|
|
|
|
if (this.apiKeySchema) {
|
|
this.rows = await this.$store.dispatch('rancher/findAll', { type: NORMAN.TOKEN });
|
|
}
|
|
|
|
// Get all settings - the API host setting may not be set, so this avoids a 404 request if we look for the specific setting
|
|
const allSettings = await this.$store.dispatch('management/findAll', { type: MANAGEMENT.SETTING });
|
|
const apiHostSetting = allSettings.find((i) => i.id === SETTING.API_HOST);
|
|
const serverUrlSetting = allSettings.find((i) => i.id === SETTING.SERVER_URL);
|
|
|
|
this.apiHostSetting = apiHostSetting?.value;
|
|
this.serverUrlSetting = serverUrlSetting?.value;
|
|
},
|
|
data() {
|
|
return {
|
|
apiHostSetting: null,
|
|
serverUrlSetting: null,
|
|
rows: null,
|
|
canChangePassword: false
|
|
};
|
|
},
|
|
computed: {
|
|
...mapGetters({ t: 'i18n/t' }),
|
|
|
|
apiKeyheaders() {
|
|
return this.apiKeySchema ? this.$store.getters['type-map/headersFor'](this.apiKeySchema) : [];
|
|
},
|
|
|
|
// Port of Ember code for API Url - see: https://github.com/rancher/ui/blob/8e07c492673171731f3b26af14c978bc103d1828/lib/shared/addon/endpoint/service.js#L58
|
|
apiUrlBase() {
|
|
let setting = this.apiHostSetting;
|
|
|
|
if (setting && setting.indexOf('http') !== 0) {
|
|
setting = `http://${ setting }`;
|
|
}
|
|
|
|
// Use Server Setting URL if the api host setting is not set
|
|
let url = setting || this.serverUrlSetting;
|
|
|
|
// If the URL is relative, add on the current base URL from the browser
|
|
if ( url.indexOf('http') !== 0 ) {
|
|
url = `${ window.location.origin }/${ url.replace(/^\/+/, '') }`;
|
|
}
|
|
|
|
// URL must end in a single slash
|
|
url = `${ url.replace(/\/+$/, '') }/`;
|
|
|
|
return url;
|
|
},
|
|
|
|
apiUrl() {
|
|
const base = this.apiUrlBase;
|
|
const path = API_ENDPOINT.replace(/^\/+/, '');
|
|
|
|
return `${ base }${ path }`;
|
|
},
|
|
|
|
apiKeySchema() {
|
|
try {
|
|
return this.$store.getters[`rancher/schemaFor`](NORMAN.TOKEN);
|
|
} catch (e) {}
|
|
|
|
return null;
|
|
},
|
|
|
|
principal() {
|
|
const principalId = this.$store.getters['auth/principalId'];
|
|
const principal = this.$store.getters['rancher/byId'](NORMAN.PRINCIPAL, principalId);
|
|
|
|
if (!principal) {
|
|
console.error('Failed to find principal with id: ', principalId); // eslint-disable-line no-console
|
|
}
|
|
|
|
return principal || {};
|
|
},
|
|
|
|
apiKeys() {
|
|
// Filter out tokens that are not API Keys and are not expired UI Sessions
|
|
const isApiKey = (key) => {
|
|
const labels = key.labels;
|
|
const expired = key.expired;
|
|
const current = key.current;
|
|
|
|
return ( !expired || !labels || !labels['ui-session'] ) && !current;
|
|
};
|
|
|
|
return !this.rows ? [] : this.rows.filter(isApiKey);
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
addKey() {
|
|
this.$router.push({ name: 'account-create-key' });
|
|
},
|
|
async calcCanChangePassword() {
|
|
if (!this.$store.getters['auth/enabled']) {
|
|
return false;
|
|
}
|
|
|
|
if (this.principal.provider === 'local') {
|
|
return !!this.principal.loginName;
|
|
}
|
|
|
|
const users = await this.$store.dispatch('rancher/findAll', {
|
|
type: NORMAN.USER,
|
|
opt: { url: '/v3/users', filter: { me: true } }
|
|
});
|
|
|
|
if (users && users.length === 1) {
|
|
return !!users[0].username;
|
|
}
|
|
|
|
return false;
|
|
},
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<Loading v-if="$fetchState.pending" />
|
|
<div v-else>
|
|
<BackLink :link="backLink" />
|
|
<h1>
|
|
<TabTitle breadcrumb="vendor-only">
|
|
{{ t('accountAndKeys.title') }}
|
|
</TabTitle>
|
|
</h1>
|
|
|
|
<h2 v-t="'accountAndKeys.account.title'" />
|
|
<div class="account">
|
|
<Principal
|
|
:value="principal.id"
|
|
:use-muted="false"
|
|
:show-labels="true"
|
|
/>
|
|
<div>
|
|
<button
|
|
v-if="canChangePassword"
|
|
type="button"
|
|
class="btn role-primary"
|
|
data-testid="account_change_password"
|
|
@click="$refs.promptChangePassword.show(true)"
|
|
>
|
|
{{ t("accountAndKeys.account.change") }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<PromptChangePassword ref="promptChangePassword" />
|
|
|
|
<hr>
|
|
<div class="keys-header">
|
|
<div>
|
|
<h2 v-t="'accountAndKeys.apiKeys.title'" />
|
|
<div class="api-url">
|
|
<span>{{ t("accountAndKeys.apiKeys.apiEndpoint") }}</span>
|
|
<CopyToClipboardText :text="apiUrl" />
|
|
</div>
|
|
</div>
|
|
<button
|
|
v-if="apiKeySchema"
|
|
class="btn role-primary add mb-20"
|
|
data-testid="account_create_api_keys"
|
|
@click="addKey"
|
|
>
|
|
{{ t('accountAndKeys.apiKeys.add.label') }}
|
|
</button>
|
|
</div>
|
|
<div
|
|
v-if="apiKeySchema"
|
|
class="keys"
|
|
>
|
|
<ResourceTable
|
|
:schema="apiKeySchema"
|
|
:rows="apiKeys"
|
|
:headers="apiKeyheaders"
|
|
key-field="id"
|
|
data-testid="api_keys_list"
|
|
:search="true"
|
|
:row-actions="true"
|
|
:table-actions="true"
|
|
/>
|
|
</div>
|
|
<div v-else>
|
|
<Banner
|
|
color="warning"
|
|
:label="t('accountAndKeys.apiKeys.notAllowed')"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang='scss' scoped>
|
|
hr {
|
|
margin: 20px 0;
|
|
}
|
|
|
|
.account {
|
|
display: flex;
|
|
justify-content: space-between
|
|
}
|
|
|
|
.keys-header {
|
|
display: flex;
|
|
div {
|
|
flex: 1;
|
|
}
|
|
}
|
|
|
|
.keys {
|
|
display: flex;
|
|
flex-direction: column;
|
|
.add {
|
|
align-self: flex-end;
|
|
}
|
|
}
|
|
|
|
.api-url {
|
|
display: flex;
|
|
|
|
> span {
|
|
margin-right: 6px;
|
|
}
|
|
}
|
|
</style>
|