codekingpro/portable-devtools
114k
1/////////////////////////////////////////////////////////////2//3// pgAdmin 4 - PostgreSQL Tools4//5// Copyright (C) 2013 - 2024, The pgAdmin Development Team6// This software is released under the PostgreSQL Licence7//8//////////////////////////////////////////////////////////////9 10import gettext from 'sources/gettext';11import BaseUISchema from 'sources/SchemaView/base_schema.ui';12import { isEmptyString } from 'sources/validators';13import { CLOUD_PROVIDERS } from './cloud_constants';14 15class BigAnimalClusterTypeSchema extends BaseUISchema {16 17 constructor(fieldOptions = {}, initValues = {}) {18 super({19 oid: undefined,20 project: '',21 cluster_type: '',22 replicas: 0,23 provider: '',24 ...initValues25 });26 27 this.fieldOptions = {28 ...fieldOptions,29 };30 this.initValues = initValues;31 }32 33 get idAttribute() {34 return 'oid';35 }36 37 validate(data, setErrMsg) {38 if (data.cluster_type == 'ha' && data.replicas == 0) {39 setErrMsg('replicas', gettext('Please select number of stand by replicas.'));40 return true;41 }42 return false;43 }44 45 get baseFields() {46 return [47 { id: 'project',48 label: gettext('Project'),49 mode: ['create'],50 noEmpty: true,51 type: () => {52 return {53 type: 'select',54 options: this.fieldOptions.projects55 };56 },57 58 },59 {60 id: 'cluster_type', label: gettext('Cluster type'), noEmpty: true,61 type: () => {62 return {63 type: 'toggle',64 options: [65 {'label': gettext('Single Node'), value: 'single'},66 {'label': gettext('High Availability'), value: 'ha'},67 {'label': gettext('Extreme High Availability'), value: 'eha'},68 ],69 };70 },71 }, {72 id: 'replicas', label: gettext('Number of standby replicas'), type: 'select',73 mode: ['create'], deps: ['cluster_type'],74 controlProps: { allowClear: false },75 helpMessage: gettext('Adding standby replicas will increase your number of CPUs, as well as your cost.'),76 options: [77 {'label': gettext('1'), 'value': 1},78 {'label': gettext('2'), 'value': 2},79 ],80 disabled: (state) => {81 return state.cluster_type != 'ha';82 }83 }, { id: 'provider', label: gettext('Cluster provider'), noEmpty: true,84 deps:['project'],85 type: (state) => {86 return {87 type: 'select',88 options: state.project89 ? () => this.fieldOptions.providers(state.project)90 : [],91 optionsReloadBasis: state.project,92 allowClear: false,93 };94 }95 },96 ];97 }98}99 100class BigAnimalInstanceSchema extends BaseUISchema {101 constructor(fieldOptions = {}, initValues={}) {102 super({103 oid: undefined,104 instance_type: '',105 instance_series: '',106 instance_size: '',107 ...initValues108 });109 110 this.fieldOptions = {111 ...fieldOptions,112 };113 114 this.initValues = initValues;115 }116 117 get idAttribute() {118 return 'oid';119 }120 121 get baseFields() {122 return [123 {124 id: 'instance_type', label: gettext('Instance type'),125 mode: ['create'],126 deps: [['region']],127 type: (state) => {128 return {129 type: 'select',130 options: ()=>this.fieldOptions.instance_types(state.region, state.provider),131 optionsReloadBasis: state.region,132 optionsLoaded: (options) => { state.instanceData = options; },133 controlProps: {134 allowClear: false,135 filter: (options) => {136 if (options.length == 0) return;137 let _types = _.uniq(_.map(options, 'category')),138 _options = [];139 _.forEach(_types, (region) => {140 _options.push({141 'label': region,142 'value': region143 });144 });145 return _options;146 },147 }148 };149 },150 noEmpty: true,151 },{152 id: 'instance_series', label: gettext('Instance series'),153 mode: ['create'], deps: ['instance_type'],154 type: (state) => {155 return {156 type: 'select',157 options: state.instanceData,158 optionsReloadBasis: state.instance_type,159 controlProps: {160 allowClear: false,161 filter: (options) => {162 if (options.length == 0) return;163 let _types = _.filter(options, {'category': state.instance_type}),164 _options = [];165 _types = _.uniq(_.map(_types, 'familyName'));166 _.forEach(_types, (value) => {167 _options.push({168 'label': value,169 'value': value170 });171 });172 return _options;173 },174 }175 };176 },177 noEmpty: true,178 },{179 id: 'instance_size', label: gettext('Instance size'),180 mode: ['create'], deps: ['instance_series'],181 type: (state) => {182 return {183 type: 'select',184 options: state.instanceData,185 optionsReloadBasis: state.instance_series,186 controlProps: {187 allowClear: false,188 filter: (options) => {189 if (options.length == 0) return;190 let _types = _.filter(options, {'familyName': state.instance_series}),191 _options = [];192 _.forEach(_types, (value) => {193 _options.push({194 'label': value.instanceTypeName + ' (' + value.cpu + 'vCPU, ' + value.ram + 'GB RAM)',195 'value': value.instanceTypeName + ' (' + value.cpu + 'vCPU, ' + value.ram + 'GB RAM)' + '||' + value.instanceTypeId,196 });197 });198 return _options;199 },200 }201 };202 }, noEmpty: true,203 },204 ];205 }206}207 208 209class BigAnimalVolumeSchema extends BaseUISchema {210 constructor(fieldOptions = {}, initValues = {}) {211 super({212 oid: undefined,213 volume_type: '',214 volume_properties: '',215 volume_size: 4,216 volume_IOPS: '',217 disk_throughput: 125,218 ...initValues219 });220 221 this.fieldOptions = {222 ...fieldOptions,223 };224 this.initValues = initValues;225 this.volumeType = '';226 }227 228 get idAttribute() {229 return 'oid';230 }231 232 validate(data, setErrMsg) {233 if (!data.provider.includes(CLOUD_PROVIDERS.AWS) && isEmptyString(data.volume_properties)) {234 setErrMsg('volume_properties', gettext('Please select volume properties.'));235 return true;236 }237 if (data.provider.includes(CLOUD_PROVIDERS.AWS)) {238 if (!isEmptyString(data.volume_size)) {239 if( data.volume_type != 'io2' && (data.volume_size < 1 || data.volume_size > 16384)) {240 setErrMsg('volume_size', gettext('Please enter the volume size in the range between 1 to 16384.'));241 return true;242 }243 if (data.volume_type == 'io2' && (data.volume_size < 4 || data.volume_size > 16384)) {244 setErrMsg('volume_size', gettext('Please enter the volume size in the range between 4 to 16384.'));245 return true;246 }247 }248 if (isEmptyString(data.volume_IOPS)) {249 setErrMsg('volume_IOPS', gettext('Please enter volume IOPS.'));250 return true;251 }252 else if (!isEmptyString(data.volume_IOPS)) {253 if(data.volume_type == 'io2' && (data.volume_IOPS < 100 || data.volume_IOPS > Math.min(data.volume_size*500, 64000))) {254 let errMsg = 'Please enter the volume IOPS in the range between 100 to ' + Math.min(data.volume_size*500, 64000) + '.';255 setErrMsg('volume_IOPS', gettext(errMsg));256 return true;257 }258 if(data.volume_type == 'gp3' && (data.volume_IOPS < 3000 || data.volume_IOPS > Math.min(Math.max(data.volume_size*500, 3000), 16000))) {259 let errMsg = 'Please enter the volume IOPS in the range between 3000 to ' + Math.min(Math.max(data.volume_size*500, 3000), 16000) + '.';260 setErrMsg('volume_IOPS', gettext(errMsg));261 return true;262 }263 }264 if ( data.volume_type === 'gp3' && !isEmptyString(data.disk_throughput) && (data.disk_throughput < 125 || data.disk_throughput > Math.min( ((data.volume_IOPS - 3000)/100*25 + 750) , 1000))) {265 let errMsg = 'Please enter the Disk throughput in the range between 125 to ' + Math.min( ((data.volume_IOPS - 3000)/100*25+750) , 1000) + '.';266 setErrMsg('disk_throughput', gettext(errMsg));267 return true;268 }269 }270 return false;271 }272 273 get baseFields() {274 let obj = this;275 return [276 {277 id: 'volume_type', label: gettext('Volume type'),278 mode: ['create'], deps: [['region'], ['instance_series']],279 type: (state) => {280 return {281 type: 'select',282 options: ()=>this.fieldOptions.volume_types(state.region, state.provider),283 optionsReloadBasis: state.region,284 controlProps: {285 allowClear: false,286 filter: (options) => {287 if (options.length == 0) return;288 return options.filter((option) => {289 return (option.supportedInstanceFamilyNames.includes(state.instance_series));290 });291 },292 }293 };294 }, noEmpty: true,295 },{296 id: 'volume_properties', label: gettext('Volume properties'),297 mode: ['create'], deps: ['volume_type', 'provider'],298 type: (state) => {299 return {300 type: 'select',301 options: ()=>this.fieldOptions.volume_properties(state.region, state.provider, state.volume_type),302 optionsReloadBasis: state.volume_type,303 };304 },305 visible: (state) => {306 return state.provider === CLOUD_PROVIDERS.AZURE;307 },308 }, {309 id: 'volume_size', label: gettext('Size'), type: 'text',310 mode: ['create'], noEmpty: true, deps: ['volume_type'],311 depChange: (state, source)=> {312 obj.volumeType = state.volume_type;313 if (source[0] !== 'volume_size') {314 if(state.volume_type == 'io2') {315 return {volume_size: 4};316 } else {317 return {volume_size: 1};318 }319 }320 },321 visible: (state) => {322 return state.provider?.includes(CLOUD_PROVIDERS.AWS);323 },324 helpMessage: obj.volumeType == 'io2' ? gettext('Size (4-16,384 GiB)') : gettext('Size (1-16,384 GiB)')325 }, {326 id: 'volume_IOPS', label: gettext('IOPS'), type: 'text',327 mode: ['create'],328 visible: (state) => {329 return state.provider?.includes(CLOUD_PROVIDERS.AWS);330 }, deps: ['volume_type'],331 depChange: (state, source) => {332 obj.volumeType = state.volume_type;333 if (source[0] !== 'volume_IOPS') {334 if (state.provider.includes(CLOUD_PROVIDERS.AWS)) {335 if(state.volume_type === 'io2') {336 return {volume_IOPS: 100};337 } else {338 return {volume_IOPS: 3000};339 }340 } else {341 return {volume_IOPS: 120};342 }343 }344 },345 },{346 id: 'disk_throughput', label: gettext('Disk throughput'), type: 'text',347 mode: ['create'],348 deps : ['volume_type'],349 visible: (state) => {350 return state.provider?.includes(CLOUD_PROVIDERS.AWS) && state.volume_type === 'gp3';351 }352 }353 ];354 }355}356 357 358class BigAnimalDatabaseSchema extends BaseUISchema {359 constructor(fieldOptions = {}, initValues = {}) {360 super({361 oid: undefined,362 password: '',363 confirm_password: '',364 database_type: '',365 postgres_version: '',366 high_availability: false,367 replicas: 0,368 ...initValues369 });370 371 this.fieldOptions = {372 ...fieldOptions,373 };374 this.initValues = initValues;375 }376 377 378 validate(data, setErrMsg) {379 if(!isEmptyString(data.password) && !isEmptyString(data.confirm_password)380 && data.password != data.confirm_password) {381 setErrMsg('confirm_password', gettext('Passwords do not match.'));382 return true;383 }384 if (!isEmptyString(data.confirm_password) && data.confirm_password.length < 12) {385 setErrMsg('confirm_password', gettext('Password must be 12 characters or more.'));386 return true;387 }388 if (data.high_availability && (isEmptyString(data.replicas) || data.replicas <= 0)) {389 setErrMsg('replicas', gettext('Please select number of stand by replicas.'));390 return true;391 }392 return false;393 }394 395 get idAttribute() {396 return 'oid';397 }398 399 get baseFields() {400 return [401 {402 id: 'gid', label: gettext('pgAdmin server group'), type: 'select',403 options: this.fieldOptions.server_groups,404 mode: ['create'],405 controlProps: { allowClear: false },406 noEmpty: true,407 }, {408 id: 'database_type', label: gettext('Database type'), mode: ['create'],409 type: 'select',410 options: this.fieldOptions.db_types,411 noEmpty: true, orientation: 'vertical',412 },{413 id: 'postgres_version', label: gettext('Database version'),414 mode: ['create'], noEmpty: true, deps: ['database_type'],415 type: (state) => {416 return {417 type: 'select',418 options: ()=>this.fieldOptions.db_versions(this.initValues.cluster_type, state.database_type),419 optionsReloadBasis: state.database_type,420 };421 },422 },{423 id: 'password', label: gettext('Database password'), type: 'password',424 mode: ['create'], noEmpty: true, controlProps: { autoComplete: 'new-password' }425 },{426 id: 'confirm_password', label: gettext('Confirm password'), type: 'password',427 mode: ['create'], noEmpty: true,428 },429 430 ];431 }432}433 434 435class BigAnimalClusterSchema extends BaseUISchema {436 constructor(fieldOptions = {}, initValues = {}) {437 super({438 oid: undefined,439 name: '',440 region: '',441 cloud_type: 'public',442 biganimal_public_ip: initValues.hostIP,443 disk_throughput: 125,444 ...initValues445 });446 447 this.fieldOptions = {448 ...fieldOptions,449 };450 this.initValues = initValues;451 452 this.instance_types = new BigAnimalInstanceSchema({453 instance_types: this.fieldOptions.instance_types,454 });455 this.volume_types = new BigAnimalVolumeSchema({456 volume_types: this.fieldOptions.volume_types,457 volume_properties: this.fieldOptions.volume_properties458 });459 }460 461 get idAttribute() {462 return 'oid';463 }464 465 get baseFields() {466 return [467 {468 id: 'name', label: gettext('Cluster name'), type: 'text',469 mode: ['create'], noEmpty: true,470 },{471 id: 'region', label: gettext('Region'),472 controlProps: { allowClear: false },473 noEmpty: true,474 mode: ['create'],475 dep: [this.initValues.provider],476 type: () => {477 return {478 type: 'select',479 options: ()=>this.fieldOptions.regions()480 };481 },482 },{483 id: 'biganimal_public_ip', label: gettext('Public IP range'), type: 'text',484 mode: ['create'],485 helpMessage: gettext('IP address range for allowed inbound traffic, for example: 127.0.0.1/32. Add multiple IP addresses/ranges separated with commas. Leave blank for 0.0.0.0/0'),486 },{487 type: 'nested-fieldset', label: gettext('Instance Type'),488 mode: ['create'], deps: ['region'],489 schema: this.instance_types,490 },{491 type: 'nested-fieldset', label: gettext('Storage'),492 mode: ['create'], deps: ['region'],493 schema: this.volume_types,494 }495 ];496 }497}498 499 500export {501 BigAnimalClusterSchema,502 BigAnimalDatabaseSchema,503 BigAnimalClusterTypeSchema504};505 