mirror of https://github.com/rancher/dashboard.git
249 lines
7.6 KiB
Vue
249 lines
7.6 KiB
Vue
<script>
|
|
import { mapGetters } from 'vuex';
|
|
import ContainerResourceLimit from '@/components/ContainerResourceLimit';
|
|
import CreateEditView from '@/mixins/create-edit-view';
|
|
import CruResource from '@/components/CruResource';
|
|
import Labels from '@/components/form/Labels';
|
|
import LabeledSelect from '@/components/form/LabeledSelect';
|
|
import ResourceQuota from '@/components/form/ResourceQuota';
|
|
import Tab from '@/components/Tabbed/Tab';
|
|
import Tabbed from '@/components/Tabbed';
|
|
import NameNsDescription from '@/components/form/NameNsDescription';
|
|
import { MANAGEMENT } from '@/config/types';
|
|
import { NAME } from '@/config/product/explorer';
|
|
import { PROJECT_ID } from '@/config/query-params';
|
|
import ProjectMembershipEditor from '@/components/form/Members/ProjectMembershipEditor';
|
|
import { canViewProjectMembershipEditor } from '@/components/form/Members/ProjectMembershipEditor.vue';
|
|
import { NAME as HARVESTER } from '@/config/product/harvester';
|
|
|
|
const HARVESTER_TYPES = [
|
|
{
|
|
key: 'limitsCpu',
|
|
units: 'cpu',
|
|
labelKey: 'resourceQuota.limitsCpu'
|
|
},
|
|
{
|
|
key: 'limitsMemory',
|
|
units: 'memory',
|
|
labelKey: 'resourceQuota.limitsMemory'
|
|
},
|
|
{
|
|
key: 'requestsCpu',
|
|
units: 'cpu',
|
|
labelKey: 'resourceQuota.requestsCpu'
|
|
},
|
|
{
|
|
key: 'requestsMemory',
|
|
units: 'memory',
|
|
labelKey: 'resourceQuota.requestsMemory'
|
|
},
|
|
];
|
|
|
|
export default {
|
|
components: {
|
|
ContainerResourceLimit, CruResource, Labels, LabeledSelect, NameNsDescription, ProjectMembershipEditor, ResourceQuota, Tabbed, Tab
|
|
},
|
|
|
|
mixins: [CreateEditView],
|
|
async fetch() {
|
|
if ( this.$store.getters['management/canList'](MANAGEMENT.POD_SECURITY_POLICY_TEMPLATE) ) {
|
|
this.allPSPs = await this.$store.dispatch('management/findAll', { type: MANAGEMENT.POD_SECURITY_POLICY_TEMPLATE });
|
|
}
|
|
},
|
|
data() {
|
|
this.$set(this.value, 'spec', this.value.spec || {});
|
|
this.$set(this.value.spec, 'podSecurityPolicyTemplateId', this.value.status?.podSecurityPolicyTemplateId || '');
|
|
|
|
return {
|
|
allPSPs: [],
|
|
projectRoleTemplateBindingSchema: this.$store.getters[`management/schemaFor`](MANAGEMENT.PROJECT_ROLE_TEMPLATE_BINDING),
|
|
createLocation: {
|
|
name: 'c-cluster-product-resource-create',
|
|
params: {
|
|
product: NAME,
|
|
resource: MANAGEMENT.PROJECT_ROLE_TEMPLATE_BINDING,
|
|
},
|
|
query: { [PROJECT_ID]: this.project?.id?.replace('/', ':') }
|
|
},
|
|
resource: MANAGEMENT.PROJECT_ROLE_TEMPLATE_BINDING,
|
|
saveBindings: null,
|
|
membershipHasOwner: false,
|
|
membershipUpdate: {},
|
|
HARVESTER_TYPES
|
|
};
|
|
},
|
|
computed: {
|
|
...mapGetters(['currentCluster']),
|
|
|
|
canManageMembers() {
|
|
return canViewProjectMembershipEditor(this.$store);
|
|
},
|
|
|
|
isK3s() {
|
|
return (this.currentCluster?.spec?.kubernetesVersion || '').includes('k3s');
|
|
},
|
|
|
|
pspOptions() {
|
|
if ( this.isK3s || !this.currentCluster.spec.defaultPodSecurityPolicyTemplateName ) {
|
|
return null;
|
|
}
|
|
|
|
const out = [{ label: this.t('project.psp.default'), value: '' }];
|
|
|
|
if ( this.allPSPs ) {
|
|
for ( const pspt of this.allPSPs ) {
|
|
out.push({
|
|
label: pspt.nameDisplay,
|
|
value: pspt.id,
|
|
});
|
|
}
|
|
}
|
|
|
|
const cur = this.value.status?.podSecurityPolicyTemplateId;
|
|
|
|
if ( cur && !out.find(x => x.value === cur) ) {
|
|
out.unshift({ label: this.t('project.psp.current', { value: cur }), value: cur });
|
|
}
|
|
|
|
return out;
|
|
},
|
|
|
|
isHarvester() {
|
|
return this.$store.getters['currentProduct'].inStore === HARVESTER;
|
|
},
|
|
|
|
resourceQuotaLabel() {
|
|
if (this.isHarvester) {
|
|
return this.t('project.vmDefaultResourceLimit');
|
|
}
|
|
|
|
return this.t('project.containerDefaultResourceLimit');
|
|
},
|
|
},
|
|
watch: {
|
|
hasOwner() {
|
|
this.errors = this.hasOwner ? [] : [this.t('project.haveOneOwner')];
|
|
}
|
|
},
|
|
created() {
|
|
this.$set(this.value.metadata, 'namespace', this.$store.getters['currentCluster'].id);
|
|
this.$set(this.value, 'spec', this.value.spec || {});
|
|
this.$set(this.value.spec, 'containerDefaultResourceLimit', this.value.spec.containerDefaultResourceLimit || {});
|
|
},
|
|
methods: {
|
|
async save(saveCb) {
|
|
try {
|
|
if ( this.value.spec?.resourceQuota?.limit && !Object.keys(this.value.spec.resourceQuota.limit).length ) {
|
|
delete this.value.spec.resourceQuota.limit;
|
|
}
|
|
|
|
if ( this.value.spec?.resourceQuota && !Object.keys(this.value.spec.resourceQuota).length ) {
|
|
delete this.value.spec.resourceQuota;
|
|
}
|
|
|
|
if ( this.value.spec?.namespaceDefaultResourceQuota?.limit && !Object.keys(this.value.spec.namespaceDefaultResourceQuota.limit).length ) {
|
|
delete this.value.spec.namespaceDefaultResourceQuota.limit;
|
|
}
|
|
|
|
if ( this.value.spec?.namespaceDefaultResourceQuota && !Object.keys(this.value.spec.namespaceDefaultResourceQuota).length ) {
|
|
delete this.value.spec.namespaceDefaultResourceQuota;
|
|
}
|
|
|
|
const savedProject = await this.value.save();
|
|
|
|
if (this.membershipUpdate.save) {
|
|
this.membershipUpdate.save(savedProject.id);
|
|
}
|
|
|
|
saveCb(true);
|
|
this.$router.replace(this.value.listLocation);
|
|
} catch (ex) {
|
|
this.errors.push(ex);
|
|
saveCb(false);
|
|
}
|
|
},
|
|
|
|
onHasOwnerChanged(hasOwner) {
|
|
this.$set(this, 'membershipHasOwner', hasOwner);
|
|
},
|
|
|
|
onMembershipUpdate(update) {
|
|
this.$set(this, 'membershipUpdate', update);
|
|
}
|
|
},
|
|
};
|
|
</script>
|
|
<template>
|
|
<CruResource
|
|
class="project"
|
|
:done-route="'c-cluster-product-projectsnamespaces'"
|
|
:errors="errors"
|
|
:mode="mode"
|
|
:resource="value"
|
|
:subtypes="[]"
|
|
:can-yaml="false"
|
|
@error="e=>errors = e"
|
|
@finish="save"
|
|
@cancel="done"
|
|
>
|
|
<NameNsDescription
|
|
v-model="value"
|
|
:mode="mode"
|
|
:namespaced="false"
|
|
description-key="spec.description"
|
|
name-key="spec.displayName"
|
|
:normalize-name="false"
|
|
/>
|
|
<div class="row">
|
|
<div class="col span-12">
|
|
<LabeledSelect
|
|
v-if="pspOptions"
|
|
v-model="value.spec.podSecurityPolicyTemplateId"
|
|
class="psp"
|
|
:mode="mode"
|
|
:options="pspOptions"
|
|
:label="t('project.psp.label')"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<Tabbed :side-tabs="true">
|
|
<Tab v-if="canManageMembers" name="members" :label="t('project.members.label')" :weight="10">
|
|
<ProjectMembershipEditor :mode="mode" :parent-id="value.id" @has-owner-changed="onHasOwnerChanged" @membership-update="onMembershipUpdate" />
|
|
</Tab>
|
|
<Tab name="resource-quotas" :label="t('project.resourceQuotas')" :weight="9">
|
|
<ResourceQuota v-model="value" :mode="mode" :type-override="isHarvester ? HARVESTER_TYPES : []" />
|
|
</Tab>
|
|
<Tab name="container-default-resource-limit" :label="resourceQuotaLabel" :weight="8">
|
|
<ContainerResourceLimit v-model="value.spec.containerDefaultResourceLimit" :mode="mode" :show-tip="false" :register-before-hook="registerBeforeHook" />
|
|
</Tab>
|
|
<Tab
|
|
name="labels-and-annotations"
|
|
label-key="generic.labelsAndAnnotations"
|
|
:weight="7"
|
|
>
|
|
<Labels
|
|
default-container-class="labels-and-annotations-container"
|
|
:value="value"
|
|
:mode="mode"
|
|
:display-side-by-side="false"
|
|
/>
|
|
</Tab>
|
|
</Tabbed>
|
|
</CruResource>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
.project {
|
|
::v-deep {
|
|
.tabs {
|
|
min-width: 250px;
|
|
}
|
|
}
|
|
|
|
.psp {
|
|
position: relative;
|
|
top: -20px;
|
|
}
|
|
}
|
|
</style>
|