Skip to content

Commit

Permalink
Integrate new schemaDefinitions endpoint (rancher#10141)
Browse files Browse the repository at this point in the history
* resource edit AS yaml

* fix cruresource (yaml from form)
- lazy load the schemaDefinitions when needed, avoids sync all to createYaml before we have an async chance to fetch schemaDefinitions

* Fix questions
- there are only four places we use questions, none of which use schema, this is just to be safe

* cluster scan, plugins/fieldsForDriver, defaultFor, validationErrors

* pathExistsInSchema
- used to optionally show conditions tab/list in resource detail view
- logs of things in ingress list/edit

* createPopulated / defaultFor
defaultFor requires resourceFields, it's only used by createPopulated in one place to support machine configs without components

* wip

* WIP MONITORING.SPOOFED
- these aren't spoofed types, but secondary schemas
- testing fix blocked, primary schema's have resourceFields

* Move steve specific (resourceField) code to steve models
- create models for steve schemas and apply to cluster and management stores
- move resoureField based validationto steve model
- move pathExistsInSchema to steve store getter
- don't fetch schemaDefinitions on start up when saving prefs (not needed and blocking)

* comments / improvements

* (untested) refactoring

* Fix alertmanager definitions, add retry definition fetch

* Fix pathExistsInSchema for path length > 2

* Fix questions that accept schemas
- tested by adding Questions to random page and the node schema

* Fix to saving configmap part 1
- the save works but doesn't show data. the yaml is the same as before. debug info added

* Validation by resourceFields is a norman specific thing, so make it such

* small refactor

* Tidying up

* Remove rebase junk

* fix linting and unit tests

* fix unit tests

* fix linting from fix for test....

* Tidying up, fix alertmanagerconfig

* Remove unit test todos

* add unit tests for resource fields

* sdssdf

* Add unit tests for pathExistsInSchema

* JS --> TS

* Store schemas in local singleton cache to avoid hitting store

* fix minor changes from review

* cruresource changes following review
- improvement - remove spurious canDiff
- createResourceYaml - pass in resource to use instead of calc in code

* WIP changes to parseType

* Fix generic cloud credential and node driver forms

* handle missing reactivity given schema definitions not in store

* fix and add unit tests for `parseType`

* Fix create-yaml test

* Changes following review
- improved comments
- SchemaDefinitionCache is now per store (and is reset as such)
- typeRef now uses parseType

* Fix dep loop by moving route based helps in auth out to utils file

* fix unit tests

* Changes following review
  • Loading branch information
richard-cox authored Feb 28, 2024
1 parent ec9247c commit b464d15
Show file tree
Hide file tree
Showing 56 changed files with 1,410 additions and 484 deletions.
27 changes: 18 additions & 9 deletions shell/cloud-credential/generic.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ import CreateEditView from '@shell/mixins/create-edit-view';
import KeyValue from '@shell/components/form/KeyValue';
import { Banner } from '@components/Banner';
import { simplify, iffyFields, likelyFields } from '@shell/store/plugins';
import Loading from '@shell/components/Loading';
export default {
components: { KeyValue, Banner },
mixins: [CreateEditView],
components: {
KeyValue, Banner, Loading
},
mixins: [CreateEditView],
props: {
driverName: {
Expand All @@ -15,19 +18,19 @@ export default {
}
},
data() {
async fetch() {
let keyOptions = [];
const normanType = this.$store.getters['plugins/credentialFieldForDriver'](this.driverName);
const normanSchema = this.$store.getters['rancher/schemaFor'](`${ normanType }credentialconfig`);
const { normanSchema } = this;
if ( normanSchema?.resourceFields ) {
keyOptions = Object.keys(normanSchema.resourceFields);
} else {
keyOptions = this.$store.getters['plugins/fieldNamesForDriver'](this.driverName);
keyOptions = await this.$store.getters['plugins/fieldNamesForDriver'](this.driverName);
}
// Prepopulate empty values for keys that sound like they're cloud-credential-ey
this.keyOptions = keyOptions;
const keys = [];
for ( const k of keyOptions ) {
Expand All @@ -43,11 +46,16 @@ export default {
this.value.setData(k, '');
}
}
},
data() {
const normanType = this.$store.getters['plugins/credentialFieldForDriver'](this.driverName);
const normanSchema = this.$store.getters['rancher/schemaFor'](`${ normanType }credentialconfig`);
return {
hasSupport: !!normanSchema,
keyOptions,
errors: null,
normanSchema,
};
},
Expand All @@ -67,7 +75,8 @@ export default {
</script>
<template>
<div>
<Loading v-if="$fetchState.pending" />
<div v-else>
<Banner
v-if="!hasSupport"
color="info"
Expand Down
55 changes: 38 additions & 17 deletions shell/components/CruResource.vue
Original file line number Diff line number Diff line change
Expand Up @@ -158,27 +158,39 @@ export default {
},
data(props) {
const yaml = this.createResourceYaml();
this.$on('createNamespace', (e) => {
// When createNamespace is set to true,
// the UI will attempt to create a new namespace
// before saving the resource.
this.createNamespace = e;
});
const inStore = this.$store.getters['currentStore'](this.resource);
const schema = this.$store.getters[`${ inStore }/schemaFor`](this.resource.type);
return {
isCancelModal: false,
createNamespace: false,
showAsForm: this.$route.query[AS] !== _YAML,
resourceYaml: yaml,
initialYaml: yaml,
/**
* Initialised on demand (given that it needs to make a request to fetch schema definition)
*/
resourceYaml: null,
/**
* Initialised on demand (given that it needs to make a request to fetch schema definition)
*/
initialYaml: null,
/**
* Save a copy of the initial resource. This is used to calc the initial yaml later on
*/
initialResource: clone(this.resource),
abbrSizes: {
3: '24px',
4: '18px',
5: '16px',
6: '14px'
},
schema
};
},
Expand All @@ -200,15 +212,8 @@ export default {
return this.validationPassed;
},
canDiff() {
return this.initialYaml !== this.resourceYaml;
},
canEditYaml() {
const inStore = this.$store.getters['currentStore'](this.resource);
const schema = this.$store.getters[`${ inStore }/schemaFor`](this.resource.type);
return !(schema?.resourceMethods?.includes('blocked-PUT'));
return !(this.schema?.resourceMethods?.includes('blocked-PUT'));
},
showYaml() {
Expand Down Expand Up @@ -309,8 +314,9 @@ export default {
}
},
createResourceYaml(modifiers) {
const resource = this.resource;
async createResourceYaml(modifiers, resource = this.resource) {
// Required to populate yaml comments and default values
await this.schema?.fetchResourceFields();
if ( typeof this.generateYaml === 'function' ) {
return this.generateYaml.apply(this, resource);
Expand All @@ -326,6 +332,9 @@ export default {
},
async showPreviewYaml() {
// Required to populate yaml comments and default values
await this.schema?.fetchResourceFields();
if ( this.applyHooks ) {
try {
await this.applyHooks(BEFORE_SAVE_HOOKS, CONTEXT_HOOK_EDIT_YAML);
Expand All @@ -336,7 +345,7 @@ export default {
}
}
const resourceYaml = this.createResourceYaml(this.yamlModifiers);
const resourceYaml = await this.createResourceYaml(this.yamlModifiers);
this.resourceYaml = resourceYaml;
this.showAsForm = false;
Expand Down Expand Up @@ -406,6 +415,17 @@ export default {
event.preventDefault();
}
}
},
watch: {
async showAsForm(neu) {
if (!neu) {
// Entering yaml mode
if (!this.initialYaml) {
this.initialYaml = await this.createResourceYaml(undefined, this.initialResource);
}
}
}
}
};
</script>
Expand Down Expand Up @@ -681,8 +701,9 @@ export default {
</slot>
</template>
<!------ YAML ------>
<!-- Hide this section until it's needed. This means we don't need to upfront create initialYaml -->
<section
v-else-if="showYaml"
v-else-if="showYaml && !showAsForm"
class="cru-resource-yaml-container resource-container cru__content"
>
<ResourceYaml
Expand All @@ -699,7 +720,7 @@ export default {
class="resource-container cru__content"
@error="e=>$emit('error', e)"
>
<template #yamlFooter="{yamlSave, showPreview, yamlPreview, yamlUnpreview}">
<template #yamlFooter="{yamlSave, showPreview, yamlPreview, yamlUnpreview, canDiff}">
<slot name="cru-yaml-footer">
<CruResourceFooter
class="cru__footer"
Expand Down
28 changes: 9 additions & 19 deletions shell/components/Questions/__tests__/Boolean.test.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,7 @@
import Questions from '@shell/components/Questions';
import { mount } from '@vue/test-utils';
import { _EDIT } from '@shell/config/query-params';
const defaultStubs = {
Tab: true,
Tabbed: true,
};
const defaultGetters = {
currentStore: () => 'current_store',
'management/schemaFor': jest.fn(),
'current_store/all': jest.fn(),
'i18n/t': jest.fn(),
'i18n/withFallback': jest.fn((key, args, fallback) => fallback),
};
import defaults from './utils/questions-defaults';

describe('the Boolean Component', () => {
it('input field is present', () => {
Expand All @@ -26,8 +16,8 @@ describe('the Boolean Component', () => {
}],
mode: _EDIT
},
mocks: { $store: { getters: defaultGetters } },
stubs: defaultStubs,
mocks: defaults.mocks,
stubs: defaults.stubs,
});

const inputFields = wrapper.findAll('[data-testid="boolean-input-var_name"] input[type=checkbox]');
Expand Down Expand Up @@ -56,8 +46,8 @@ describe('the Boolean Component', () => {
}],
mode: _EDIT
},
mocks: { $store: { getters: defaultGetters } },
stubs: defaultStubs,
mocks: defaults.mocks,
stubs: defaults.stubs,
});

const inputFields = wrapper.findAll('[data-testid="boolean-input-var_name"]');
Expand All @@ -82,8 +72,8 @@ describe('the Boolean Component', () => {
}],
mode: _EDIT
},
mocks: { $store: { getters: defaultGetters } },
stubs: defaultStubs,
mocks: defaults.mocks,
stubs: defaults.stubs,
});

const inputFields = wrapper.findAll('[data-testid="boolean-input-var_name"]');
Expand All @@ -108,8 +98,8 @@ describe('the Boolean Component', () => {
}],
mode: _EDIT
},
mocks: { $store: { getters: defaultGetters } },
stubs: defaultStubs,
mocks: defaults.mocks,
stubs: defaults.stubs,
});

const inputFields = wrapper.findAll('[data-testid="boolean-input-var_name"]');
Expand Down
28 changes: 9 additions & 19 deletions shell/components/Questions/__tests__/Float.test.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,7 @@
import Questions from '@shell/components/Questions';
import { mount } from '@vue/test-utils';
import { _EDIT } from '@shell/config/query-params';
const defaultStubs = {
Tab: true,
Tabbed: true,
};
const defaultGetters = {
currentStore: () => 'current_store',
'management/schemaFor': jest.fn(),
'current_store/all': jest.fn(),
'i18n/t': jest.fn(),
'i18n/withFallback': jest.fn((key, args, fallback) => fallback),
};
import defaults from './utils/questions-defaults';

describe('the float Component', () => {
it('input field is present', () => {
Expand All @@ -26,8 +16,8 @@ describe('the float Component', () => {
}],
mode: _EDIT
},
mocks: { $store: { getters: defaultGetters } },
stubs: defaultStubs,
mocks: defaults.mocks,
stubs: defaults.stubs,
});

const inputFields = wrapper.findAll('[data-testid="float-input-var_name"]');
Expand Down Expand Up @@ -56,8 +46,8 @@ describe('the float Component', () => {
}],
mode: _EDIT
},
mocks: { $store: { getters: defaultGetters } },
stubs: defaultStubs,
mocks: defaults.mocks,
stubs: defaults.stubs,
});

const inputFields = wrapper.findAll('[data-testid="float-input-var_name"]');
Expand All @@ -82,8 +72,8 @@ describe('the float Component', () => {
}],
mode: _EDIT
},
mocks: { $store: { getters: defaultGetters } },
stubs: defaultStubs,
mocks: defaults.mocks,
stubs: defaults.stubs,
});

const inputFields = wrapper.findAll('[data-testid="float-input-var_name"]');
Expand All @@ -108,8 +98,8 @@ describe('the float Component', () => {
}],
mode: _EDIT
},
mocks: { $store: { getters: defaultGetters } },
stubs: defaultStubs,
mocks: defaults.mocks,
stubs: defaults.stubs,
});

const inputFields = wrapper.findAll('[data-testid="float-input-var_name"]');
Expand Down
28 changes: 9 additions & 19 deletions shell/components/Questions/__tests__/Int.test.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,7 @@
import Questions from '@shell/components/Questions';
import { mount } from '@vue/test-utils';
import { _EDIT } from '@shell/config/query-params';
const defaultStubs = {
Tab: true,
Tabbed: true,
};
const defaultGetters = {
currentStore: () => 'current_store',
'management/schemaFor': jest.fn(),
'current_store/all': jest.fn(),
'i18n/t': jest.fn(),
'i18n/withFallback': jest.fn((key, args, fallback) => fallback),
};
import defaults from './utils/questions-defaults';

describe('the Int Component', () => {
it('input field is present', () => {
Expand All @@ -26,8 +16,8 @@ describe('the Int Component', () => {
}],
mode: _EDIT
},
mocks: { $store: { getters: defaultGetters } },
stubs: defaultStubs,
mocks: defaults.mocks,
stubs: defaults.stubs,
});

const inputFields = wrapper.findAll('[data-testid="int-input-var_name"]');
Expand Down Expand Up @@ -56,8 +46,8 @@ describe('the Int Component', () => {
}],
mode: _EDIT
},
mocks: { $store: { getters: defaultGetters } },
stubs: defaultStubs,
mocks: defaults.mocks,
stubs: defaults.stubs,
});

const inputFields = wrapper.findAll('[data-testid="int-input-var_name"]');
Expand All @@ -82,8 +72,8 @@ describe('the Int Component', () => {
}],
mode: _EDIT
},
mocks: { $store: { getters: defaultGetters } },
stubs: defaultStubs,
mocks: defaults.mocks,
stubs: defaults.stubs,
});

const inputFields = wrapper.findAll('[data-testid="int-input-var_name"]');
Expand All @@ -108,8 +98,8 @@ describe('the Int Component', () => {
}],
mode: _EDIT
},
mocks: { $store: { getters: defaultGetters } },
stubs: defaultStubs,
mocks: defaults.mocks,
stubs: defaults.stubs,
});

const inputFields = wrapper.findAll('[data-testid="int-input-var_name"]');
Expand Down
Loading

0 comments on commit b464d15

Please sign in to comment.