mirror of
https://github.com/harvester/harvester-ui-extension.git
synced 2025-12-13 13:11:43 +00:00
Vue migration - remove Vuew.set & this.$set; add vue-migrate script
Signed-off-by: Francesco Torchia <francesco.torchia@suse.com>
This commit is contained in:
parent
c983ed8384
commit
ea12a81174
40
.eslintrc.js
40
.eslintrc.js
@ -13,25 +13,27 @@ module.exports = {
|
||||
],
|
||||
// add your custom rules here
|
||||
rules: {
|
||||
'dot-notation': 'off',
|
||||
'generator-star-spacing': 'off',
|
||||
'guard-for-in': 'off',
|
||||
'linebreak-style': 'off',
|
||||
'new-cap': 'off',
|
||||
'no-empty': 'off',
|
||||
'no-extra-boolean-cast': 'off',
|
||||
'no-new': 'off',
|
||||
'no-plusplus': 'off',
|
||||
'no-useless-escape': 'off',
|
||||
'nuxt/no-cjs-in-config': 'off',
|
||||
'semi-spacing': 'off',
|
||||
'space-in-parens': 'off',
|
||||
strict: 'off',
|
||||
'unicorn/no-new-buffer': 'off',
|
||||
'vue/html-self-closing': 'off',
|
||||
'vue/no-unused-components': 'warn',
|
||||
'vue/no-v-html': 'error',
|
||||
'wrap-iife': 'off',
|
||||
'dot-notation': 'off',
|
||||
'generator-star-spacing': 'off',
|
||||
'guard-for-in': 'off',
|
||||
'linebreak-style': 'off',
|
||||
'new-cap': 'off',
|
||||
'no-empty': 'off',
|
||||
'no-extra-boolean-cast': 'off',
|
||||
'no-new': 'off',
|
||||
'no-plusplus': 'off',
|
||||
'no-useless-escape': 'off',
|
||||
'nuxt/no-cjs-in-config': 'off',
|
||||
'semi-spacing': 'off',
|
||||
'space-in-parens': 'off',
|
||||
strict: 'off',
|
||||
'unicorn/no-new-buffer': 'off',
|
||||
'vue/html-self-closing': 'off',
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'vue/no-reserved-component-names': 'off',
|
||||
'vue/no-unused-components': 'warn',
|
||||
'vue/no-v-html': 'error',
|
||||
'wrap-iife': 'off',
|
||||
|
||||
'array-bracket-spacing': 'warn',
|
||||
'arrow-parens': 'warn',
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
dev
|
||||
lint
|
||||
|
||||
# compiled output
|
||||
/dist
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
"clean": "./node_modules/@rancher/shell/scripts/clean",
|
||||
"build-pkg": "./node_modules/@rancher/shell/scripts/build-pkg.sh",
|
||||
"serve-pkgs": "./node_modules/@rancher/shell/scripts/serve-pkgs",
|
||||
"vue-migrate": "scripts/vue-migrate.js",
|
||||
"publish-pkgs": "./node_modules/@rancher/shell/scripts/extension/publish",
|
||||
"parse-tag-name": "./node_modules/@rancher/shell/scripts/extension/parse-tag-name",
|
||||
"lint": "./node_modules/.bin/eslint --max-warnings 0 --ext .js,.ts,.vue ."
|
||||
|
||||
@ -3,7 +3,7 @@ import { _VIEW, _EDIT, _CREATE } from '@shell/config/query-params';
|
||||
import Tag from '@shell/components/Tag';
|
||||
|
||||
export default {
|
||||
name: 'Tags',
|
||||
name: 'DiskTags',
|
||||
|
||||
components: { Tag },
|
||||
|
||||
|
||||
@ -58,7 +58,7 @@ export default {
|
||||
},
|
||||
|
||||
removeAll() {
|
||||
this.$set(this, 'searchLabels', []);
|
||||
this['searchLabels'] = [];
|
||||
this.filterRows();
|
||||
},
|
||||
|
||||
|
||||
@ -73,7 +73,7 @@ export default {
|
||||
|
||||
upgradeMessage = currentResource ? currentResource.upgradeMessage : [];
|
||||
|
||||
this.$set(this, 'upgradeMessage', upgradeMessage);
|
||||
this['upgradeMessage'] = upgradeMessage;
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
|
||||
@ -157,7 +157,7 @@ export default {
|
||||
const preference = this.$store.getters['management/all'](STEVE.PREFERENCE)?.[0];
|
||||
|
||||
try {
|
||||
this.$set(preference.data, PREFERED_SHORTCUT_KEYS, JSON.stringify(out));
|
||||
preference.data[PREFERED_SHORTCUT_KEYS] = JSON.stringify(out);
|
||||
await preference.save();
|
||||
this.closeRecordingModal();
|
||||
buttonCb(true);
|
||||
|
||||
@ -143,6 +143,7 @@ export default {
|
||||
let out = [];
|
||||
|
||||
if (!preference?.[0]?.data) {
|
||||
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
|
||||
this.hideCustomKeysBar = true;
|
||||
|
||||
return out;
|
||||
|
||||
@ -30,7 +30,7 @@ export default {
|
||||
update() {
|
||||
const value = JSON.stringify(this.parseDefaultValue);
|
||||
|
||||
this.$set(this.value, 'value', value);
|
||||
this.value['value'] = value;
|
||||
}
|
||||
},
|
||||
|
||||
@ -39,7 +39,7 @@ export default {
|
||||
handler(neu) {
|
||||
const parseDefaultValue = JSON.parse(neu.value);
|
||||
|
||||
this.$set(this, 'parseDefaultValue', parseDefaultValue);
|
||||
this['parseDefaultValue'] = parseDefaultValue;
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
|
||||
@ -80,7 +80,7 @@ export default {
|
||||
parseDefaultValue = { type: '', endpoint: '' };
|
||||
}
|
||||
|
||||
this.$set(this, 'parseDefaultValue', parseDefaultValue);
|
||||
this['parseDefaultValue'] = parseDefaultValue;
|
||||
this.update();
|
||||
},
|
||||
deep: true
|
||||
@ -105,16 +105,16 @@ export default {
|
||||
const value = JSON.stringify(this.parseDefaultValue);
|
||||
|
||||
if (!this.parseDefaultValue.type) {
|
||||
this.$delete(this.value, 'value');
|
||||
delete this.value['value'];
|
||||
} else {
|
||||
this.$set(this.value, 'value', value);
|
||||
this.value['value'] = value;
|
||||
}
|
||||
},
|
||||
|
||||
useDefault() {
|
||||
const parseDefaultValue = { type: '', endpoint: '' };
|
||||
|
||||
this.$set(this, 'parseDefaultValue', parseDefaultValue);
|
||||
this['parseDefaultValue'] = parseDefaultValue;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -183,7 +183,7 @@ export default {
|
||||
|
||||
const value = Object.keys(out).length ? JSON.stringify(out) : '';
|
||||
|
||||
this.$set(this.value, 'value', value);
|
||||
this.value['value'] = value;
|
||||
},
|
||||
|
||||
addMirror() {
|
||||
@ -210,8 +210,8 @@ export default {
|
||||
value: {
|
||||
handler(value) {
|
||||
if (!value.value) { // useDefaultVale
|
||||
this.$set(this, 'mirrors', []);
|
||||
this.$set(this, 'configs', []);
|
||||
this['mirrors'] = [];
|
||||
this['configs'] = [];
|
||||
this.update();
|
||||
}
|
||||
},
|
||||
|
||||
@ -122,7 +122,7 @@ export default {
|
||||
|
||||
const value = this.configArr.length ? JSON.stringify(out) : '';
|
||||
|
||||
this.$set(this.value, 'value', value);
|
||||
this.value['value'] = value;
|
||||
},
|
||||
|
||||
willSave() {
|
||||
@ -172,7 +172,7 @@ export default {
|
||||
useDefault() {
|
||||
const configArr = this.parseValue(this.value.default);
|
||||
|
||||
this.$set(this, 'configArr', configArr);
|
||||
this['configArr'] = configArr;
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,11 +15,11 @@ export default {
|
||||
|
||||
methods: {
|
||||
update() {
|
||||
this.$set(this.value, 'value', String(this.terminationGracePeriodSeconds));
|
||||
this.value['value'] = String(this.terminationGracePeriodSeconds);
|
||||
},
|
||||
|
||||
useDefault() {
|
||||
this.$set(this, 'terminationGracePeriodSeconds', Number(this.value.default));
|
||||
this['terminationGracePeriodSeconds'] = Number(this.value.default);
|
||||
this.update();
|
||||
},
|
||||
},
|
||||
|
||||
@ -34,7 +34,7 @@ export default {
|
||||
update() {
|
||||
const value = JSON.stringify(this.parseDefaultValue);
|
||||
|
||||
this.$set(this.value, 'value', value);
|
||||
this.value['value'] = value;
|
||||
}
|
||||
},
|
||||
|
||||
@ -43,7 +43,7 @@ export default {
|
||||
handler(neu) {
|
||||
const parseDefaultValue = JSON.parse(neu.value);
|
||||
|
||||
this.$set(this, 'parseDefaultValue', parseDefaultValue);
|
||||
this['parseDefaultValue'] = parseDefaultValue;
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ export default {
|
||||
parseDefaultValue = { ntpServers: [] };
|
||||
}
|
||||
|
||||
this.$set(this, 'parseDefaultValue', parseDefaultValue);
|
||||
this['parseDefaultValue'] = parseDefaultValue;
|
||||
this.update();
|
||||
},
|
||||
deep: true
|
||||
@ -43,13 +43,13 @@ export default {
|
||||
useDefault() {
|
||||
const parseDefaultValue = { ntpServers: [] };
|
||||
|
||||
this.$set(this, 'parseDefaultValue', parseDefaultValue);
|
||||
this['parseDefaultValue'] = parseDefaultValue;
|
||||
},
|
||||
|
||||
update() {
|
||||
const value = JSON.stringify(this.parseDefaultValue);
|
||||
|
||||
this.$set(this.value, 'value', value);
|
||||
this.value['value'] = value;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -32,7 +32,7 @@ export default {
|
||||
update() {
|
||||
const value = JSON.stringify(this.parseDefaultValue);
|
||||
|
||||
this.$set(this.value, 'value', value);
|
||||
this.value['value'] = value;
|
||||
}
|
||||
},
|
||||
|
||||
@ -41,7 +41,7 @@ export default {
|
||||
handler(neu) {
|
||||
const parseDefaultValue = JSON.parse(neu.value);
|
||||
|
||||
this.$set(this, 'parseDefaultValue', parseDefaultValue);
|
||||
this['parseDefaultValue'] = parseDefaultValue;
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
|
||||
@ -30,11 +30,11 @@ export default {
|
||||
onKeySelectedCa(type, file) {
|
||||
const { name, value } = file;
|
||||
|
||||
this.$set(this.parseDefaultValue, type, value);
|
||||
this.$set(this, `${ type }FileName`, name);
|
||||
this.parseDefaultValue[type] = value;
|
||||
this[`${ type }FileName`] = name;
|
||||
const _value = JSON.stringify(this.parseDefaultValue);
|
||||
|
||||
this.$set(this.value, 'value', _value);
|
||||
this.value['value'] = _value;
|
||||
}
|
||||
},
|
||||
|
||||
@ -43,7 +43,7 @@ export default {
|
||||
handler(neu) {
|
||||
const parseDefaultValue = JSON.parse(neu.value);
|
||||
|
||||
this.$set(this, 'parseDefaultValue', parseDefaultValue);
|
||||
this['parseDefaultValue'] = parseDefaultValue;
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
|
||||
@ -88,7 +88,7 @@ export default {
|
||||
|
||||
const value = JSON.stringify(out);
|
||||
|
||||
this.$set(this.value, 'value', value);
|
||||
this.value['value'] = value;
|
||||
},
|
||||
|
||||
willSave() {
|
||||
|
||||
@ -114,9 +114,9 @@ export default {
|
||||
const valueString = JSON.stringify(this.parsedDefaultValue);
|
||||
|
||||
if (this.openVlan) {
|
||||
this.$set(this.value, 'value', valueString);
|
||||
this.value['value'] = valueString;
|
||||
} else {
|
||||
this.$set(this.value, 'value', '');
|
||||
this.value['value'] = '';
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@ -65,7 +65,7 @@ export default {
|
||||
update() {
|
||||
const value = JSON.stringify(this.parseDefaultValue);
|
||||
|
||||
this.$set(this.value, 'value', value);
|
||||
this.value['value'] = value;
|
||||
},
|
||||
|
||||
willSave() {
|
||||
@ -92,7 +92,7 @@ export default {
|
||||
handler(neu) {
|
||||
const parseDefaultValue = JSON.parse(neu.value);
|
||||
|
||||
this.$set(this, 'parseDefaultValue', parseDefaultValue);
|
||||
this['parseDefaultValue'] = parseDefaultValue;
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ export default {
|
||||
update() {
|
||||
const namespaceStr = this.namespaces.join(',');
|
||||
|
||||
this.$set(this.value, 'value', namespaceStr);
|
||||
this.value['value'] = namespaceStr;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@ -30,7 +30,7 @@ export default {
|
||||
update() {
|
||||
const value = JSON.stringify(this.parseDefaultValue);
|
||||
|
||||
this.$set(this.value, 'value', value);
|
||||
this.value['value'] = value;
|
||||
}
|
||||
},
|
||||
|
||||
@ -39,7 +39,7 @@ export default {
|
||||
handler(neu) {
|
||||
const parseDefaultValue = JSON.parse(neu.value);
|
||||
|
||||
this.$set(this, 'parseDefaultValue', parseDefaultValue);
|
||||
this['parseDefaultValue'] = parseDefaultValue;
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
|
||||
@ -104,7 +104,7 @@ export default {
|
||||
key-field="_key"
|
||||
v-on="$listeners"
|
||||
>
|
||||
<template slot="cell:state" slot-scope="scope" class="state-col">
|
||||
<template slot="cell:state" slot-scope="scope">
|
||||
<div class="state">
|
||||
<HarvesterVmState class="vmstate" :row="scope.row" :all-cluster-network="allClusterNetwork" />
|
||||
</div>
|
||||
|
||||
@ -87,7 +87,7 @@ export default {
|
||||
}
|
||||
|
||||
if (!this.value._type) {
|
||||
this.$set(this.value, '_type', TYPES.OPAQUE);
|
||||
this.value['_type'] = TYPES.OPAQUE;
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@ -58,7 +58,7 @@ export default {
|
||||
};
|
||||
});
|
||||
|
||||
this.$set(this, 'sshKeys', out);
|
||||
this['sshKeys'] = out;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -146,7 +146,7 @@ export default {
|
||||
handler(neu) {
|
||||
const diskRows = this.getDiskRows(neu);
|
||||
|
||||
this.$set(this, 'diskRows', diskRows);
|
||||
this['diskRows'] = diskRows;
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
|
||||
@ -69,14 +69,14 @@ export default {
|
||||
} else {
|
||||
const error = [res?.data] || exceptionToErrorsArray(res);
|
||||
|
||||
this.$set(this, 'errors', error);
|
||||
this['errors'] = error;
|
||||
buttonCb(false);
|
||||
}
|
||||
} catch (err) {
|
||||
const error = err?.data || err;
|
||||
const message = exceptionToErrorsArray(error);
|
||||
|
||||
this.$set(this, 'errors', message);
|
||||
this['errors'] = message;
|
||||
buttonCb(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,14 +69,14 @@ export default {
|
||||
} else {
|
||||
const error = [res?.data] || exceptionToErrorsArray(res);
|
||||
|
||||
this.$set(this, 'errors', error);
|
||||
this['errors'] = error;
|
||||
buttonCb(false);
|
||||
}
|
||||
} catch (err) {
|
||||
const error = err?.data || err;
|
||||
const message = exceptionToErrorsArray(error);
|
||||
|
||||
this.$set(this, 'errors', message);
|
||||
this['errors'] = message;
|
||||
buttonCb(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,14 +92,14 @@ export default {
|
||||
} else {
|
||||
const error = [res?.data] || exceptionToErrorsArray(res);
|
||||
|
||||
this.$set(this, 'errors', error);
|
||||
this['errors'] = error;
|
||||
buttonCb(false);
|
||||
}
|
||||
} catch (err) {
|
||||
const error = err?.data || err;
|
||||
const message = exceptionToErrorsArray(error);
|
||||
|
||||
this.$set(this, 'errors', message);
|
||||
this['errors'] = message;
|
||||
buttonCb(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,14 +70,14 @@ export default {
|
||||
} else {
|
||||
const error = [res?.data] || exceptionToErrorsArray(res);
|
||||
|
||||
this.$set(this, 'errors', error);
|
||||
this['errors'] = error;
|
||||
buttonCb(false);
|
||||
}
|
||||
} catch (err) {
|
||||
const error = err?.data || err;
|
||||
const message = exceptionToErrorsArray(error);
|
||||
|
||||
this.$set(this, 'errors', message);
|
||||
this['errors'] = message;
|
||||
buttonCb(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,14 +79,14 @@ export default {
|
||||
} else {
|
||||
const error = [res?.data] || exceptionToErrorsArray(res);
|
||||
|
||||
this.$set(this, 'errors', error);
|
||||
this['errors'] = error;
|
||||
buttonCb(false);
|
||||
}
|
||||
} catch (err) {
|
||||
const error = err?.data || err;
|
||||
const message = exceptionToErrorsArray(error);
|
||||
|
||||
this.$set(this, 'errors', message);
|
||||
this['errors'] = message;
|
||||
buttonCb(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,7 +72,7 @@ export default {
|
||||
const error = err?.data || err;
|
||||
const message = exceptionToErrorsArray(error);
|
||||
|
||||
this.$set(this, 'errors', message);
|
||||
this['errors'] = message;
|
||||
buttonDone(false);
|
||||
}
|
||||
},
|
||||
@ -95,7 +95,7 @@ export default {
|
||||
}
|
||||
});
|
||||
|
||||
this.$set(this, 'diskNames', diskNames);
|
||||
this['diskNames'] = diskNames;
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ export default {
|
||||
|
||||
const defaultStorage = this.$store.getters[`${ inStore }/all`](STORAGE_CLASS).find(s => s.isDefault);
|
||||
|
||||
this.$set(this, 'storageClassName', defaultStorage?.metadata?.name || 'longhorn');
|
||||
this['storageClassName'] = defaultStorage?.metadata?.name || 'longhorn';
|
||||
},
|
||||
|
||||
data() {
|
||||
@ -119,14 +119,14 @@ export default {
|
||||
} else {
|
||||
const error = [res?.data] || exceptionToErrorsArray(res);
|
||||
|
||||
this.$set(this, 'errors', error);
|
||||
this['errors'] = error;
|
||||
buttonCb(false);
|
||||
}
|
||||
} catch (err) {
|
||||
const error = err?.data || err;
|
||||
const message = exceptionToErrorsArray(error);
|
||||
|
||||
this.$set(this, 'errors', message);
|
||||
this['errors'] = message;
|
||||
buttonCb(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,7 +109,7 @@ export default {
|
||||
const name = this.$store.getters['i18n/t']('harvester.modal.migration.fields.nodeName.label');
|
||||
const message = this.$store.getters['i18n/t']('validation.required', { key: name });
|
||||
|
||||
this.$set(this, 'errors', [message]);
|
||||
this['errors'] = [message];
|
||||
buttonDone(false);
|
||||
|
||||
return;
|
||||
@ -124,7 +124,7 @@ export default {
|
||||
const error = err?.data || err;
|
||||
const message = exceptionToErrorsArray(error);
|
||||
|
||||
this.$set(this, 'errors', message);
|
||||
this['errors'] = message;
|
||||
buttonDone(false);
|
||||
}
|
||||
},
|
||||
|
||||
@ -105,14 +105,14 @@ export default {
|
||||
} else {
|
||||
const error = [res?.data] || exceptionToErrorsArray(res);
|
||||
|
||||
this.$set(this, 'errors', error);
|
||||
this['errors'] = error;
|
||||
buttonCb(false);
|
||||
}
|
||||
} catch (err) {
|
||||
const error = err?.data || err;
|
||||
const message = exceptionToErrorsArray(error);
|
||||
|
||||
this.$set(this, 'errors', message);
|
||||
this['errors'] = message;
|
||||
buttonCb(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,14 +62,14 @@ export default {
|
||||
} else {
|
||||
const error = [res?.data] || exceptionToErrorsArray(res);
|
||||
|
||||
this.$set(this, 'errors', error);
|
||||
this['errors'] = error;
|
||||
buttonCb(false);
|
||||
}
|
||||
} catch (err) {
|
||||
const error = err?.data || err;
|
||||
const message = exceptionToErrorsArray(error);
|
||||
|
||||
this.$set(this, 'errors', message);
|
||||
this['errors'] = message;
|
||||
buttonCb(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,7 +86,7 @@ export default {
|
||||
const error = err?.data || err;
|
||||
const message = exceptionToErrorsArray(error);
|
||||
|
||||
this.$set(this, 'errors', message);
|
||||
this['errors'] = message;
|
||||
buttonCb(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,7 +83,7 @@ export default {
|
||||
const error = err?.data || err;
|
||||
const message = exceptionToErrorsArray(error);
|
||||
|
||||
this.$set(this, 'errors', message);
|
||||
this['errors'] = message;
|
||||
buttonDone(false);
|
||||
}
|
||||
},
|
||||
|
||||
@ -46,7 +46,7 @@ export default {
|
||||
|
||||
const currentStorageName = this.resources[0].metadata?.annotations[HCI_ANNOTATIONS.STORAGE_CLASS];
|
||||
|
||||
this.$set(this, 'storageClassName', currentStorageName || defaultStorage?.metadata?.name || 'longhorn');
|
||||
this['storageClassName'] = currentStorageName || defaultStorage?.metadata?.name || 'longhorn';
|
||||
}
|
||||
},
|
||||
|
||||
@ -108,14 +108,14 @@ export default {
|
||||
} else {
|
||||
const error = [res?.data] || exceptionToErrorsArray(res);
|
||||
|
||||
this.$set(this, 'errors', error);
|
||||
this['errors'] = error;
|
||||
buttonCb(false);
|
||||
}
|
||||
} catch (err) {
|
||||
const error = err?.data || err;
|
||||
const message = exceptionToErrorsArray(error);
|
||||
|
||||
this.$set(this, 'errors', message);
|
||||
this['errors'] = message;
|
||||
buttonCb(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,14 +50,14 @@ export default {
|
||||
} else {
|
||||
const error = [res?.data] || exceptionToErrorsArray(res);
|
||||
|
||||
this.$set(this, 'errors', error);
|
||||
this['errors'] = error;
|
||||
buttonCb(false);
|
||||
}
|
||||
} catch (err) {
|
||||
const error = err?.data || err;
|
||||
const message = exceptionToErrorsArray(error);
|
||||
|
||||
this.$set(this, 'errors', message);
|
||||
this['errors'] = message;
|
||||
buttonCb(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,14 +61,14 @@ export default {
|
||||
} else {
|
||||
const error = [res?.data] || exceptionToErrorsArray(res);
|
||||
|
||||
this.$set(this, 'errors', error);
|
||||
this['errors'] = error;
|
||||
buttonCb(false);
|
||||
}
|
||||
} catch (err) {
|
||||
const error = err?.data || err;
|
||||
const message = exceptionToErrorsArray(error);
|
||||
|
||||
this.$set(this, 'errors', message);
|
||||
this['errors'] = message;
|
||||
buttonCb(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@ export default {
|
||||
watch: {
|
||||
valuesContentJson: {
|
||||
handler(neu) {
|
||||
this.$set(this.value.spec, 'valuesContent', jsyaml.dump(neu));
|
||||
this.value.spec['valuesContent'] = jsyaml.dump(neu);
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
|
||||
@ -191,7 +191,7 @@ export default {
|
||||
watch: {
|
||||
valuesContentJson: {
|
||||
handler(neu) {
|
||||
this.$set(this.value.spec, 'valuesContent', jsyaml.dump(neu));
|
||||
this.value.spec['valuesContent'] = jsyaml.dump(neu);
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
|
||||
@ -80,7 +80,7 @@ export default {
|
||||
watch: {
|
||||
valuesContentJson: {
|
||||
handler(neu) {
|
||||
this.$set(this.value.spec, 'valuesContent', jsyaml.dump(neu));
|
||||
this.value.spec['valuesContent'] = jsyaml.dump(neu);
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
|
||||
@ -108,7 +108,7 @@ export default {
|
||||
const inStore = this.$store.getters['currentProduct'].inStore;
|
||||
const defaultStorage = this.$store.getters[`${ inStore }/all`](STORAGE_CLASS).find( s => s.isDefault);
|
||||
|
||||
this.$set(this.valuesContent.pvcClaim, 'storageClassName', this.valuesContent?.pvcClaim?.storageClassName || defaultStorage?.metadata?.name || 'longhorn');
|
||||
this.valuesContent.pvcClaim['storageClassName'] = this.valuesContent?.pvcClaim?.storageClassName || defaultStorage?.metadata?.name || 'longhorn';
|
||||
|
||||
this.update();
|
||||
},
|
||||
|
||||
@ -5,7 +5,7 @@ import { BadgeState } from '@components/BadgeState';
|
||||
import { Banner } from '@components/Banner';
|
||||
import { RadioGroup, RadioButton } from '@components/Form/Radio';
|
||||
import HarvesterDisk from '../../mixins/harvester-disk';
|
||||
import Tags from '../../components/DiskTags';
|
||||
import DiskTags from '../../components/DiskTags';
|
||||
import { HCI } from '../../types';
|
||||
import { LONGHORN_SYSTEM } from './index';
|
||||
|
||||
@ -17,7 +17,7 @@ export default {
|
||||
Banner,
|
||||
RadioGroup,
|
||||
RadioButton,
|
||||
Tags,
|
||||
DiskTags,
|
||||
},
|
||||
|
||||
mixins: [
|
||||
@ -171,7 +171,7 @@ export default {
|
||||
<div v-if="!value.isNew">
|
||||
<div class="row">
|
||||
<div class="col span-12">
|
||||
<Tags
|
||||
<DiskTags
|
||||
v-model="value.tags"
|
||||
:label="t('harvester.host.disk.tags.label')"
|
||||
:add-label="t('harvester.host.disk.tags.addLabel')"
|
||||
|
||||
@ -92,7 +92,7 @@ export default {
|
||||
methods: {
|
||||
async saveKsmtuned() {
|
||||
this.spec.mergeAcrossNodes = this.enableMergeAcrossNodes ? 1 : 0;
|
||||
this.$set(this.ksmtuned, 'spec', this.spec);
|
||||
this.ksmtuned['spec'] = this.spec;
|
||||
|
||||
await this.ksmtuned.save().catch((reason) => {
|
||||
if (reason?.type === 'error') {
|
||||
|
||||
@ -123,8 +123,8 @@ export default {
|
||||
} else {
|
||||
const [namespace, name] = value.split('/');
|
||||
|
||||
this.$set(this.value.spec.baseboardSpec.connection.authSecretRef, 'namespace', namespace);
|
||||
this.$set(this.value.spec.baseboardSpec.connection.authSecretRef, 'name', name);
|
||||
this.value.spec.baseboardSpec.connection.authSecretRef['namespace'] = namespace;
|
||||
this.value.spec.baseboardSpec.connection.authSecretRef['name'] = name;
|
||||
}
|
||||
},
|
||||
},
|
||||
@ -135,7 +135,7 @@ export default {
|
||||
},
|
||||
|
||||
set(value) {
|
||||
this.$set(this.secret.data, 'username', base64Encode(value));
|
||||
this.secret.data['username'] = base64Encode(value);
|
||||
}
|
||||
},
|
||||
|
||||
@ -145,7 +145,7 @@ export default {
|
||||
},
|
||||
|
||||
set(value) {
|
||||
this.$set(this.secret.data, 'password', base64Encode(value));
|
||||
this.secret.data['password'] = base64Encode(value);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@ -25,7 +25,7 @@ import { _EDIT } from '@shell/config/query-params';
|
||||
import { sortBy } from '@shell/utils/sort';
|
||||
import { Banner } from '@components/Banner';
|
||||
import { HCI } from '../../types';
|
||||
import Tags from '../../components/DiskTags';
|
||||
import DiskTags from '../../components/DiskTags';
|
||||
import HarvesterDisk from './HarvesterDisk';
|
||||
import HarvesterSeeder from './HarvesterSeeder';
|
||||
import HarvesterKsmtuned from './HarvesterKsmtuned';
|
||||
@ -46,7 +46,7 @@ export default {
|
||||
ButtonDropdown,
|
||||
KeyValue,
|
||||
Banner,
|
||||
Tags,
|
||||
DiskTags,
|
||||
Loading,
|
||||
HarvesterSeeder,
|
||||
MessageLink,
|
||||
@ -546,7 +546,7 @@ export default {
|
||||
class="row mb-20"
|
||||
>
|
||||
<div class="col span-12">
|
||||
<Tags
|
||||
<DiskTags
|
||||
v-model="longhornNode.spec.tags"
|
||||
:label="t('harvester.host.tags.label')"
|
||||
:add-label="t('harvester.host.tags.addLabel')"
|
||||
|
||||
@ -49,10 +49,10 @@ export default {
|
||||
}));
|
||||
|
||||
if (this.mode !== _VIEW) {
|
||||
this.$set(this.value, 'spec', this.value.spec || {});
|
||||
this.value['spec'] = this.value.spec || {};
|
||||
|
||||
providers.forEach((provider) => {
|
||||
this.$set(this.value.spec, provider.name, this.value.spec[provider.name] || clone(provider.default));
|
||||
this.value.spec[provider.name] = this.value.spec[provider.name] || clone(provider.default);
|
||||
});
|
||||
}
|
||||
|
||||
@ -127,11 +127,11 @@ export default {
|
||||
if (!isEmpty(bufferJson)) {
|
||||
this.value.spec[this.selectedProvider].buffer = bufferJson;
|
||||
} else {
|
||||
this.$delete(this.value.spec[this.selectedProvider], 'buffer');
|
||||
delete this.value.spec[this.selectedProvider]['buffer'];
|
||||
}
|
||||
|
||||
if (this.loggingType === AUDIT_ONLY) {
|
||||
this.$set(this.value.spec, 'loggingRef', 'harvester-kube-audit-log-ref');
|
||||
this.value.spec['loggingRef'] = 'harvester-kube-audit-log-ref';
|
||||
}
|
||||
},
|
||||
tabChanged({ tab }) {
|
||||
|
||||
@ -52,9 +52,9 @@ export default {
|
||||
if ( newCloudCred ) {
|
||||
this.value.metadata.namespace = DEFAULT_WORKSPACE;
|
||||
|
||||
this.$set(this.value.metadata, 'name', '');
|
||||
this.value.metadata['name'] = '';
|
||||
|
||||
this.$set(this.value, 'data', {});
|
||||
this.value['data'] = {};
|
||||
}
|
||||
|
||||
const secretTypes = [
|
||||
@ -77,7 +77,7 @@ export default {
|
||||
});
|
||||
|
||||
if ( this.mode === _CREATE ) {
|
||||
this.$set(this.value, '_type', TYPES.OPAQUE);
|
||||
this.value['_type'] = TYPES.OPAQUE;
|
||||
}
|
||||
|
||||
return {
|
||||
@ -212,7 +212,7 @@ export default {
|
||||
|
||||
selectCustomType(type) {
|
||||
if (type !== 'custom') {
|
||||
this.$set(this.value, '_type', type);
|
||||
this.value['_type'] = type;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -39,7 +39,7 @@ export default {
|
||||
setting.canReset || !!this.value.default || this.value.canReset;
|
||||
|
||||
if (this.value.value === undefined) {
|
||||
this.$set(this.value, 'value', null);
|
||||
this.value['value'] = null;
|
||||
}
|
||||
|
||||
this.value.value = this.value.value || this.value.default || '';
|
||||
|
||||
@ -17,7 +17,7 @@ import { STORAGE_CLASS, LONGHORN } from '@shell/config/types';
|
||||
import { allHash } from '@shell/utils/promise';
|
||||
import { clone } from '@shell/utils/object';
|
||||
import { CSI_DRIVER } from '../../types';
|
||||
import Tags from '../../components/DiskTags';
|
||||
import DiskTags from '../../components/DiskTags';
|
||||
|
||||
const LONGHORN_DRIVER = 'driver.longhorn.io';
|
||||
|
||||
@ -34,7 +34,7 @@ export default {
|
||||
Tab,
|
||||
Tabbed,
|
||||
Loading,
|
||||
Tags,
|
||||
DiskTags,
|
||||
},
|
||||
|
||||
mixins: [CreateEditView],
|
||||
@ -72,11 +72,11 @@ export default {
|
||||
|
||||
const allowedTopologies = clone(this.value.allowedTopologies?.[0]?.matchLabelExpressions || []);
|
||||
|
||||
this.$set(this.value, 'parameters', this.value.parameters || {});
|
||||
this.$set(this.value, 'provisioner', this.value.provisioner || LONGHORN_DRIVER);
|
||||
this.$set(this.value, 'allowVolumeExpansion', this.value.allowVolumeExpansion || allowVolumeExpansionOptions[0].value);
|
||||
this.$set(this.value, 'reclaimPolicy', this.value.reclaimPolicy || reclaimPolicyOptions[0].value);
|
||||
this.$set(this.value, 'volumeBindingMode', this.value.volumeBindingMode || volumeBindingModeOptions[0].value);
|
||||
this.value['parameters'] = this.value.parameters || {};
|
||||
this.value['provisioner'] = this.value.provisioner || LONGHORN_DRIVER;
|
||||
this.value['allowVolumeExpansion'] = this.value.allowVolumeExpansion || allowVolumeExpansionOptions[0].value;
|
||||
this.value['reclaimPolicy'] = this.value.reclaimPolicy || reclaimPolicyOptions[0].value;
|
||||
this.value['volumeBindingMode'] = this.value.volumeBindingMode || volumeBindingModeOptions[0].value;
|
||||
|
||||
return {
|
||||
reclaimPolicyOptions,
|
||||
@ -141,7 +141,7 @@ export default {
|
||||
|
||||
watch: {
|
||||
provisionerWatch() {
|
||||
this.$set(this.value, 'parameters', {});
|
||||
this.value['parameters'] = {};
|
||||
}
|
||||
},
|
||||
|
||||
@ -159,8 +159,8 @@ export default {
|
||||
},
|
||||
|
||||
updateProvisioner(provisioner) {
|
||||
this.$set(this.value, 'provisioner', provisioner);
|
||||
this.$set(this.value, 'allowVolumeExpansion', provisioner === LONGHORN_DRIVER);
|
||||
this.value['provisioner'] = provisioner;
|
||||
this.value['allowVolumeExpansion'] = provisioner === LONGHORN_DRIVER;
|
||||
},
|
||||
|
||||
willSave() {
|
||||
@ -303,7 +303,7 @@ export default {
|
||||
/>
|
||||
</div>
|
||||
<div class="col span-8 value">
|
||||
<Tags
|
||||
<DiskTags
|
||||
v-model="scope.row.value.values"
|
||||
:add-label="t('generic.add')"
|
||||
:mode="modeOverride"
|
||||
|
||||
@ -42,13 +42,13 @@ export default {
|
||||
|
||||
data() {
|
||||
if (this.realMode === _CREATE) {
|
||||
this.$set(this.value, 'parameters', {
|
||||
this.value['parameters'] = {
|
||||
numberOfReplicas: '3',
|
||||
staleReplicaTimeout: '30',
|
||||
diskSelector: null,
|
||||
nodeSelector: null,
|
||||
migratable: 'true',
|
||||
});
|
||||
migratable: 'true'
|
||||
};
|
||||
}
|
||||
|
||||
return {};
|
||||
|
||||
@ -56,12 +56,12 @@ export default {
|
||||
|
||||
const defaultStorage = this.$store.getters[`${ inStore }/all`](STORAGE_CLASS).find(s => s.isDefault);
|
||||
|
||||
this.$set(this, 'storageClassName', this.storageClassName || defaultStorage?.metadata?.name || 'longhorn');
|
||||
this['storageClassName'] = this.storageClassName || defaultStorage?.metadata?.name || 'longhorn';
|
||||
},
|
||||
|
||||
data() {
|
||||
if ( !this.value.spec ) {
|
||||
this.$set(this.value, 'spec', { sourceType: DOWNLOAD });
|
||||
this.value['spec'] = { sourceType: DOWNLOAD };
|
||||
}
|
||||
|
||||
if (!this.value.metadata.name) {
|
||||
@ -130,7 +130,7 @@ export default {
|
||||
},
|
||||
|
||||
'value.spec.sourceType'() {
|
||||
this.$set(this, 'file', null);
|
||||
this['file'] = null;
|
||||
this.url = '';
|
||||
|
||||
if (this.$refs?.file?.value) {
|
||||
|
||||
@ -175,10 +175,10 @@ export default {
|
||||
|
||||
this.value.cleanForNew();
|
||||
this.customName = randomStr(10);
|
||||
this.$set(this.value.metadata, 'annotations', {
|
||||
this.value.metadata['annotations'] = {
|
||||
...this.value.metadata.annotations,
|
||||
[HCI_ANNOTATIONS.TEMPLATE_VERSION_CUSTOM_NAME]: this.customName
|
||||
});
|
||||
};
|
||||
|
||||
const name = this.templateValue.metadata.name || template.metadata.name;
|
||||
const namespace = this.templateValue.metadata.namespace || template.metadata.namespace;
|
||||
@ -187,7 +187,7 @@ export default {
|
||||
this.value.metadata.namespace = namespace;
|
||||
}
|
||||
|
||||
this.$set(this.value.spec, 'templateId', `${ namespace }/${ name }`);
|
||||
this.value.spec['templateId'] = `${ namespace }/${ name }`;
|
||||
const res = await this.value.save();
|
||||
|
||||
await this.saveSecret(res);
|
||||
|
||||
@ -59,7 +59,7 @@ export default {
|
||||
|
||||
const defaultStorage = this.$store.getters[`harvester/all`](STORAGE_CLASS).find( O => O.isDefault);
|
||||
|
||||
this.$set(this.value.spec, 'storageClassName', this.value?.spec?.storageClassName || defaultStorage?.metadata?.name || 'longhorn');
|
||||
this.value.spec['storageClassName'] = this.value?.spec?.storageClassName || defaultStorage?.metadata?.name || 'longhorn';
|
||||
},
|
||||
|
||||
data() {
|
||||
@ -247,7 +247,7 @@ export default {
|
||||
|
||||
this.value.setAnnotations(imageAnnotations);
|
||||
|
||||
this.$set(this.value, 'spec', spec);
|
||||
this.value['spec'] = spec;
|
||||
},
|
||||
|
||||
generateYaml() {
|
||||
|
||||
@ -73,7 +73,7 @@ export default {
|
||||
|
||||
selectedUser(val, old) {
|
||||
if ( val.includes(_NEW)) {
|
||||
this.$set(this, 'selectedUser', old);
|
||||
this['selectedUser'] = old;
|
||||
this.update();
|
||||
this.show();
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@ export default {
|
||||
},
|
||||
|
||||
updateUser(neu) {
|
||||
this.$set(this.value, 'username', neu);
|
||||
this.value['username'] = neu;
|
||||
this.update();
|
||||
},
|
||||
|
||||
|
||||
@ -40,12 +40,12 @@ export default {
|
||||
},
|
||||
|
||||
updateUser(neu) {
|
||||
this.$set(this.value, 'users', neu);
|
||||
this.value['users'] = neu;
|
||||
this.update();
|
||||
},
|
||||
|
||||
updateSSH(neu) {
|
||||
this.$set(this.value, 'sshkeys', neu);
|
||||
this.value['sshkeys'] = neu;
|
||||
this.update();
|
||||
},
|
||||
|
||||
|
||||
@ -179,7 +179,7 @@ export default {
|
||||
cancel() {
|
||||
this.cloudTemplate = '';
|
||||
this.cloudTemplateName = '';
|
||||
this.$set(this, 'errors', []);
|
||||
this['errors'] = [];
|
||||
this.isOpen = false;
|
||||
},
|
||||
|
||||
|
||||
@ -138,7 +138,7 @@ export default {
|
||||
handler(neu) {
|
||||
const hasManagementNetwork = !!neu.some(N => N.isPod);
|
||||
|
||||
this.$set(this, 'hasManagementNetwork', hasManagementNetwork);
|
||||
this['hasManagementNetwork'] = hasManagementNetwork;
|
||||
},
|
||||
immediate: true,
|
||||
deep: true
|
||||
@ -146,7 +146,7 @@ export default {
|
||||
|
||||
isSingle(neu) {
|
||||
if (!neu) {
|
||||
this.$set(this.value, 'macAddress', '');
|
||||
this.value['macAddress'] = '';
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
@ -164,7 +164,7 @@ export default {
|
||||
this.value.isPod = false;
|
||||
}
|
||||
|
||||
this.$set(this, 'isMasquerade', this.value.isPod);
|
||||
this['isMasquerade'] = this.value.isPod;
|
||||
|
||||
if (this.value.isPod) {
|
||||
this.value.type = 'masquerade';
|
||||
|
||||
@ -134,8 +134,8 @@ export default {
|
||||
},
|
||||
|
||||
changeRows(filterRows, parentSriov) {
|
||||
this.$set(this, 'filterRows', filterRows);
|
||||
this.$set(this, 'parentSriov', parentSriov);
|
||||
this['filterRows'] = filterRows;
|
||||
this['parentSriov'] = parentSriov;
|
||||
},
|
||||
|
||||
sortGenerationFn() {
|
||||
|
||||
@ -126,7 +126,7 @@ export default {
|
||||
|
||||
checkedSsh(val, old) {
|
||||
if ( val.includes(_NEW)) {
|
||||
this.$set(this, 'checkedSsh', old);
|
||||
this['checkedSsh'] = old;
|
||||
this.update();
|
||||
this.show();
|
||||
}
|
||||
|
||||
@ -89,8 +89,8 @@ export default {
|
||||
|
||||
methods: {
|
||||
changeRows(filterRows, parentSriov) {
|
||||
this.$set(this, 'filterRows', filterRows);
|
||||
this.$set(this, 'parentSriov', parentSriov);
|
||||
this['filterRows'] = filterRows;
|
||||
this['parentSriov'] = parentSriov;
|
||||
},
|
||||
|
||||
sortGenerationFn() {
|
||||
|
||||
@ -149,7 +149,7 @@ export default {
|
||||
return V;
|
||||
});
|
||||
|
||||
this.$set(this, 'rows', rows);
|
||||
this['rows'] = rows;
|
||||
},
|
||||
deep: true,
|
||||
immediate: true,
|
||||
|
||||
@ -32,7 +32,7 @@ export default {
|
||||
watch: {
|
||||
'value.type'(neu) {
|
||||
if (neu === 'cd-rom') {
|
||||
this.$set(this.value, 'bus', 'sata');
|
||||
this.value['bus'] = 'sata';
|
||||
this.update();
|
||||
}
|
||||
},
|
||||
|
||||
@ -140,7 +140,7 @@ export default {
|
||||
|
||||
'value.type'(neu) {
|
||||
if (neu === 'cd-rom') {
|
||||
this.$set(this.value, 'bus', 'sata');
|
||||
this.value['bus'] = 'sata';
|
||||
this.update();
|
||||
}
|
||||
},
|
||||
|
||||
@ -100,7 +100,7 @@ export default {
|
||||
watch: {
|
||||
'value.type'(neu) {
|
||||
if (neu === 'cd-rom') {
|
||||
this.$set(this.value, 'bus', 'sata');
|
||||
this.value['bus'] = 'sata';
|
||||
this.update();
|
||||
}
|
||||
},
|
||||
@ -143,11 +143,11 @@ export default {
|
||||
|
||||
if (this.idx === 0) {
|
||||
if (/iso$/i.test(imageResource?.imageSuffix)) {
|
||||
this.$set(this.value, 'type', 'cd-rom');
|
||||
this.$set(this.value, 'bus', 'sata');
|
||||
this.value['type'] = 'cd-rom';
|
||||
this.value['bus'] = 'sata';
|
||||
} else {
|
||||
this.$set(this.value, 'type', 'disk');
|
||||
this.$set(this.value, 'bus', 'virtio');
|
||||
this.value['type'] = 'disk';
|
||||
this.value['bus'] = 'virtio';
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,7 +165,7 @@ export default {
|
||||
message: this.$store.getters['i18n/t']('harvester.vmTemplate.tips.notExistImage.message')
|
||||
}, { root: true });
|
||||
|
||||
this.$set(this.value, 'image', '');
|
||||
this.value['image'] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,7 +87,7 @@ export default {
|
||||
watch: {
|
||||
'value.type'(neu) {
|
||||
if (neu === 'cd-rom') {
|
||||
this.$set(this.value, 'bus', 'sata');
|
||||
this.value['bus'] = 'sata';
|
||||
this.update();
|
||||
}
|
||||
},
|
||||
|
||||
@ -19,17 +19,17 @@ import KeyValue from '@shell/components/form/KeyValue';
|
||||
|
||||
import { clear } from '@shell/utils/array';
|
||||
import { clone } from '@shell/utils/object';
|
||||
import { HCI } from '../../types';
|
||||
import { RunStrategys } from '../../config/harvester-map';
|
||||
import { saferDump } from '@shell/utils/create-yaml';
|
||||
import { exceptionToErrorsArray } from '@shell/utils/error';
|
||||
import { HCI as HCI_ANNOTATIONS } from '@pkg/harvester/config/labels-annotations';
|
||||
import { BEFORE_SAVE_HOOKS, AFTER_SAVE_HOOKS } from '@shell/mixins/child-hook';
|
||||
|
||||
import VM_MIXIN from '../../mixins/harvester-vm';
|
||||
import CreateEditView from '@shell/mixins/create-edit-view';
|
||||
|
||||
import { parseVolumeClaimTemplates } from '@pkg/utils/vm';
|
||||
import VM_MIXIN from '../../mixins/harvester-vm';
|
||||
import { RunStrategys } from '../../config/harvester-map';
|
||||
import { HCI } from '../../types';
|
||||
import RestartVMDialog from '../../dialog/RestartVMDialog';
|
||||
import VirtualMachineVGpuDevices from './VirtualMachineVGpuDevices/index';
|
||||
import PciDevices from './VirtualMachinePciDevices/index';
|
||||
@ -218,7 +218,7 @@ export default {
|
||||
this.getInitConfig({
|
||||
value: cloneVersionVM, existUserData: true, fromTemplate: true
|
||||
});
|
||||
this.$set(this, 'hasCreateVolumes', []); // When using the template, all volume names need to be newly created
|
||||
this['hasCreateVolumes'] = []; // When using the template, all volume names need to be newly created
|
||||
}
|
||||
},
|
||||
|
||||
@ -261,7 +261,7 @@ export default {
|
||||
|
||||
const diskRows = this.getDiskRows(this.value);
|
||||
|
||||
this.$set(this, 'diskRows', diskRows);
|
||||
this['diskRows'] = diskRows;
|
||||
const templateId = this.$route.query.templateId;
|
||||
const templateVersionId = this.$route.query.versionId;
|
||||
|
||||
@ -317,13 +317,13 @@ export default {
|
||||
const cloneSpec = clone(this.spec);
|
||||
|
||||
for (let i = 1; i <= this.count; i++) {
|
||||
this.$set(this.value, 'spec', cloneValue.spec);
|
||||
this.$set(this, 'spec', cloneSpec);
|
||||
this.value['spec'] = cloneValue.spec;
|
||||
this['spec'] = cloneSpec;
|
||||
const suffix = i < 10 ? `0${ i }` : i;
|
||||
|
||||
this.value.cleanForNew();
|
||||
this.value.metadata.name = `${ this.namePrefix }${ join }${ suffix }`;
|
||||
this.$set(this.value.spec.template.spec, 'hostname', `${ baseHostname }${ join }${ suffix }`);
|
||||
this.value.spec.template.spec['hostname'] = `${ baseHostname }${ join }${ suffix }`;
|
||||
this.secretName = '';
|
||||
await this.parseVM();
|
||||
const basicValue = await this.$store.dispatch('harvester/clone', { resource: this.value });
|
||||
@ -380,7 +380,7 @@ export default {
|
||||
updateBeforeSave() {
|
||||
if (this.isSingle) {
|
||||
if (!this.value.spec.template.spec.hostname) {
|
||||
this.$set(this.value.spec.template.spec, 'hostname', this.value.metadata.name);
|
||||
this.value.spec.template.spec['hostname'] = this.value.metadata.name;
|
||||
}
|
||||
}
|
||||
|
||||
@ -395,7 +395,7 @@ export default {
|
||||
|
||||
validateCount(count) {
|
||||
if (count > 10) {
|
||||
this.$set(this, 'count', 10);
|
||||
this['count'] = 10;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@ -139,7 +139,7 @@ export default {
|
||||
backendServerSelector[key] = (value[key] || '').split(',');
|
||||
});
|
||||
|
||||
this.$set(this.value.spec, 'backendServerSelector', backendServerSelector);
|
||||
this.value.spec['backendServerSelector'] = backendServerSelector;
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@ -36,8 +36,8 @@ export default {
|
||||
this.canEditPSPBindings = !!pspBindingSchema;
|
||||
},
|
||||
data() {
|
||||
this.$set(this.value, 'spec', this.value.spec || {});
|
||||
this.$set(this.value.spec, 'podSecurityPolicyTemplateId', this.value.status?.podSecurityPolicyTemplateId || '');
|
||||
this.value['spec'] = this.value.spec || {};
|
||||
this.value.spec['podSecurityPolicyTemplateId'] = this.value.status?.podSecurityPolicyTemplateId || '';
|
||||
|
||||
return {
|
||||
allPSPs: [],
|
||||
@ -134,9 +134,9 @@ export default {
|
||||
}
|
||||
},
|
||||
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 || {});
|
||||
this.value.metadata['namespace'] = this.$store.getters['currentCluster'].id;
|
||||
this.value['spec'] = this.value.spec || {};
|
||||
this.value.spec['containerDefaultResourceLimit'] = this.value.spec.containerDefaultResourceLimit || {};
|
||||
},
|
||||
methods: {
|
||||
async save(saveCb) {
|
||||
@ -178,11 +178,11 @@ export default {
|
||||
},
|
||||
|
||||
onHasOwnerChanged(hasOwner) {
|
||||
this.$set(this, 'membershipHasOwner', hasOwner);
|
||||
this['membershipHasOwner'] = hasOwner;
|
||||
},
|
||||
|
||||
onMembershipUpdate(update) {
|
||||
this.$set(this, 'membershipUpdate', update);
|
||||
this['membershipUpdate'] = update;
|
||||
},
|
||||
|
||||
removeQuota(key) {
|
||||
|
||||
@ -39,8 +39,8 @@ export default {
|
||||
|
||||
methods: {
|
||||
changeRows(filterRows, searchLabels) {
|
||||
this.$set(this, 'filterRows', filterRows);
|
||||
this.$set(this, 'searchLabels', searchLabels);
|
||||
this['filterRows'] = filterRows;
|
||||
this['searchLabels'] = searchLabels;
|
||||
},
|
||||
|
||||
sortGenerationFn() {
|
||||
|
||||
@ -161,7 +161,7 @@ export default {
|
||||
|
||||
await this.$store.dispatch(`${ inStore }/findAll`, { type: HCI.VMIM });
|
||||
|
||||
this.$set(this, 'allVMIs', vmis);
|
||||
this['allVMIs'] = vmis;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@ -179,7 +179,7 @@ export default {
|
||||
key-field="_key"
|
||||
v-on="$listeners"
|
||||
>
|
||||
<template slot="cell:state" slot-scope="scope" class="state-col">
|
||||
<template slot="cell:state" slot-scope="scope">
|
||||
<div class="state">
|
||||
<HarvesterVmState class="vmstate" :row="scope.row" :all-node-network="allNodeNetworks" :all-cluster-network="allClusterNetworks" />
|
||||
</div>
|
||||
|
||||
@ -361,33 +361,33 @@ export default {
|
||||
spec.runStrategy = 'RerunOnFailure';
|
||||
}
|
||||
|
||||
this.$set(this, 'spec', spec);
|
||||
this.$set(this, 'runStrategy', runStrategy);
|
||||
this.$set(this, 'secretRef', secretRef);
|
||||
this.$set(this, 'accessCredentials', accessCredentials);
|
||||
this.$set(this, 'userScript', userData);
|
||||
this.$set(this, 'networkScript', networkData);
|
||||
this['spec'] = spec;
|
||||
this['runStrategy'] = runStrategy;
|
||||
this['secretRef'] = secretRef;
|
||||
this['accessCredentials'] = accessCredentials;
|
||||
this['userScript'] = userData;
|
||||
this['networkScript'] = networkData;
|
||||
|
||||
this.$set(this, 'sshKey', sshKey);
|
||||
this.$set(this, 'osType', osType);
|
||||
this.$set(this, 'installAgent', installAgent);
|
||||
this['sshKey'] = sshKey;
|
||||
this['osType'] = osType;
|
||||
this['installAgent'] = installAgent;
|
||||
|
||||
this.$set(this, 'cpu', cpu);
|
||||
this.$set(this, 'memory', memory);
|
||||
this.$set(this, 'reservedMemory', reservedMemory);
|
||||
this.$set(this, 'machineType', machineType);
|
||||
this.$set(this, 'terminationGracePeriodSeconds', terminationGracePeriodSeconds);
|
||||
this['cpu'] = cpu;
|
||||
this['memory'] = memory;
|
||||
this['reservedMemory'] = reservedMemory;
|
||||
this['machineType'] = machineType;
|
||||
this['terminationGracePeriodSeconds'] = terminationGracePeriodSeconds;
|
||||
|
||||
this.$set(this, 'installUSBTablet', installUSBTablet);
|
||||
this.$set(this, 'efiEnabled', efiEnabled);
|
||||
this.$set(this, 'tpmEnabled', tpmEnabled);
|
||||
this.$set(this, 'secureBoot', secureBoot);
|
||||
this['installUSBTablet'] = installUSBTablet;
|
||||
this['efiEnabled'] = efiEnabled;
|
||||
this['tpmEnabled'] = tpmEnabled;
|
||||
this['secureBoot'] = secureBoot;
|
||||
|
||||
this.$set(this, 'hasCreateVolumes', hasCreateVolumes);
|
||||
this.$set(this, 'networkRows', networkRows);
|
||||
this.$set(this, 'imageId', imageId);
|
||||
this['hasCreateVolumes'] = hasCreateVolumes;
|
||||
this['networkRows'] = networkRows;
|
||||
this['imageId'] = imageId;
|
||||
|
||||
this.$set(this, 'diskRows', diskRows);
|
||||
this['diskRows'] = diskRows;
|
||||
|
||||
this.refreshYamlEditor();
|
||||
},
|
||||
@ -556,9 +556,9 @@ export default {
|
||||
|
||||
parseOther() {
|
||||
if (!this.spec.template.spec.domain.machine) {
|
||||
this.$set(this.spec.template.spec.domain, 'machine', { type: this.machineType });
|
||||
this.spec.template.spec.domain['machine'] = { type: this.machineType };
|
||||
} else {
|
||||
this.$set(this.spec.template.spec.domain.machine, 'type', this.machineType);
|
||||
this.spec.template.spec.domain.machine['type'] = this.machineType;
|
||||
}
|
||||
|
||||
this.spec.template.spec.domain.cpu.cores = this.cpu;
|
||||
@ -681,28 +681,28 @@ export default {
|
||||
spec = this.multiVMScheduler(spec);
|
||||
}
|
||||
|
||||
this.$set(this.value.metadata, 'annotations', {
|
||||
this.value.metadata['annotations'] = {
|
||||
...this.value.metadata.annotations,
|
||||
[HCI_ANNOTATIONS.VOLUME_CLAIM_TEMPLATE]: JSON.stringify(volumeClaimTemplates),
|
||||
[HCI_ANNOTATIONS.NETWORK_IPS]: JSON.stringify(this.value.networkIps)
|
||||
});
|
||||
};
|
||||
|
||||
this.$set(this.value.metadata, 'labels', {
|
||||
this.value.metadata['labels'] = {
|
||||
...this.value.metadata.labels,
|
||||
[HCI_ANNOTATIONS.CREATOR]: 'harvester',
|
||||
[HCI_ANNOTATIONS.OS]: this.osType
|
||||
});
|
||||
};
|
||||
|
||||
this.$set(this.value, 'spec', spec);
|
||||
this.$set(this, 'spec', spec);
|
||||
this.value['spec'] = spec;
|
||||
this['spec'] = spec;
|
||||
} else if (this.resource === HCI.VM_VERSION) {
|
||||
this.$set(this.value.spec.vm, 'spec', spec);
|
||||
this.$set(this.value.spec.vm.metadata, 'annotations', { ...this.value.spec.vm.metadata.annotations, [HCI_ANNOTATIONS.VOLUME_CLAIM_TEMPLATE]: JSON.stringify(volumeClaimTemplates) });
|
||||
this.$set(this.value.spec.vm.metadata, 'labels', {
|
||||
this.value.spec.vm['spec'] = spec;
|
||||
this.value.spec.vm.metadata['annotations'] = { ...this.value.spec.vm.metadata.annotations, [HCI_ANNOTATIONS.VOLUME_CLAIM_TEMPLATE]: JSON.stringify(volumeClaimTemplates) };
|
||||
this.value.spec.vm.metadata['labels'] = {
|
||||
...this.value.spec.vm.metadata.labels,
|
||||
[HCI_ANNOTATIONS.OS]: this.osType,
|
||||
});
|
||||
this.$set(this, 'spec', spec);
|
||||
[HCI_ANNOTATIONS.OS]: this.osType
|
||||
};
|
||||
this['spec'] = spec;
|
||||
}
|
||||
},
|
||||
|
||||
@ -772,7 +772,7 @@ export default {
|
||||
networks
|
||||
};
|
||||
|
||||
this.$set(this.spec.template, 'spec', spec);
|
||||
this.spec.template['spec'] = spec;
|
||||
},
|
||||
|
||||
parseAccessCredentials() {
|
||||
@ -862,12 +862,12 @@ export default {
|
||||
},
|
||||
|
||||
updateSSHKey(neu) {
|
||||
this.$set(this, 'sshKey', neu);
|
||||
this['sshKey'] = neu;
|
||||
},
|
||||
|
||||
updateCpuMemory(cpu, memory) {
|
||||
this.$set(this, 'cpu', cpu);
|
||||
this.$set(this, 'memory', memory);
|
||||
this['cpu'] = cpu;
|
||||
this['memory'] = memory;
|
||||
},
|
||||
|
||||
parseDisk(R, index) {
|
||||
@ -1309,10 +1309,10 @@ export default {
|
||||
const index = inputs.findIndex(O => isEqual(O, USB_TABLET[0]));
|
||||
|
||||
if (hasExist && inputs.length === 1) {
|
||||
this.$delete(this.spec.template.spec.domain.devices, 'inputs');
|
||||
delete this.spec.template.spec.domain.devices['inputs'];
|
||||
} else if (hasExist) {
|
||||
inputs.splice(index, 1);
|
||||
this.$set(this.spec.template.spec.domain.devices, 'inputs', inputs);
|
||||
this.spec.template.spec.domain.devices['inputs'] = inputs;
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -1325,17 +1325,17 @@ export default {
|
||||
// set(this.spec.template.spec.domain, 'features.smm.enabled', false);
|
||||
|
||||
try {
|
||||
this.$delete(this.spec.template.spec.domain.features.smm, 'enabled');
|
||||
delete this.spec.template.spec.domain.features.smm['enabled'];
|
||||
const noKeys = Object.keys(this.spec.template.spec.domain.features.smm).length === 0;
|
||||
|
||||
if (noKeys) {
|
||||
this.$delete(this.spec.template.spec.domain.features, 'smm');
|
||||
delete this.spec.template.spec.domain.features['smm'];
|
||||
}
|
||||
} catch (e) {}
|
||||
set(this.spec.template.spec.domain, 'firmware.bootloader.efi.secureBoot', false);
|
||||
} else {
|
||||
this.$delete(this.spec.template.spec.domain, 'firmware');
|
||||
this.$delete(this.spec.template.spec.domain.features, 'smm');
|
||||
delete this.spec.template.spec.domain['firmware'];
|
||||
delete this.spec.template.spec.domain.features['smm'];
|
||||
}
|
||||
},
|
||||
|
||||
@ -1343,7 +1343,7 @@ export default {
|
||||
if (tpmEnabled) {
|
||||
set(this.spec.template.spec.domain.devices, 'tpm', {});
|
||||
} else {
|
||||
this.$delete(this.spec.template.spec.domain.devices, 'tpm');
|
||||
delete this.spec.template.spec.domain.devices['tpm'];
|
||||
}
|
||||
},
|
||||
|
||||
@ -1367,9 +1367,9 @@ export default {
|
||||
}
|
||||
|
||||
if (isEmpty(userDataJson)) {
|
||||
this.$set(this, 'userScript', undefined);
|
||||
this['userScript'] = undefined;
|
||||
} else {
|
||||
this.$set(this, 'userScript', jsyaml.dump(userDataJson));
|
||||
this['userScript'] = jsyaml.dump(userDataJson);
|
||||
}
|
||||
|
||||
this.refreshYamlEditor();
|
||||
@ -1407,11 +1407,11 @@ export default {
|
||||
updateReserved(value = {}) {
|
||||
const { memory } = value;
|
||||
|
||||
this.$set(this, 'reservedMemory', memory);
|
||||
this['reservedMemory'] = memory;
|
||||
},
|
||||
|
||||
updateTerminationGracePeriodSeconds(value) {
|
||||
this.$set(this, 'terminationGracePeriodSeconds', value);
|
||||
this['terminationGracePeriodSeconds'] = value;
|
||||
},
|
||||
},
|
||||
|
||||
@ -1444,9 +1444,9 @@ export default {
|
||||
|
||||
isWindows(val) {
|
||||
if (val) {
|
||||
this.$set(this, 'sshKey', []);
|
||||
this.$set(this, 'userScript', undefined);
|
||||
this.$set(this, 'installAgent', false);
|
||||
this['sshKey'] = [];
|
||||
this['userScript'] = undefined;
|
||||
this['installAgent'] = false;
|
||||
}
|
||||
},
|
||||
|
||||
@ -1487,7 +1487,7 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
this.$set(this, 'userScript', out);
|
||||
this['userScript'] = out;
|
||||
this.refreshYamlEditor();
|
||||
}
|
||||
this.deleteAgent = true;
|
||||
@ -1498,7 +1498,7 @@ export default {
|
||||
osType(neu) {
|
||||
const out = this.getUserData({ installAgent: this.installAgent, osType: neu });
|
||||
|
||||
this.$set(this, 'userScript', out);
|
||||
this['userScript'] = out;
|
||||
this.refreshYamlEditor();
|
||||
},
|
||||
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import Vue from 'vue';
|
||||
import { _CLONE } from '@shell/config/query-params';
|
||||
import pick from 'lodash/pick';
|
||||
import { PV, LONGHORN } from '@shell/config/types';
|
||||
@ -21,12 +20,12 @@ export default class HciPv extends HarvesterResource {
|
||||
const storageClassName =
|
||||
realMode === _CLONE ? this.spec.storageClassName : '';
|
||||
|
||||
Vue.set(this, 'spec', {
|
||||
this['spec'] = {
|
||||
accessModes,
|
||||
storageClassName,
|
||||
volumeName: '',
|
||||
resources: { requests: { storage } }
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
get availableActions() {
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import Vue from 'vue';
|
||||
import {
|
||||
DESCRIPTION,
|
||||
ANNOTATIONS_TO_IGNORE_REGEX,
|
||||
@ -64,8 +63,8 @@ export default class HciVmImage extends HarvesterResource {
|
||||
|
||||
applyDefaults(resources = this, realMode) {
|
||||
if (realMode !== _CLONE) {
|
||||
Vue.set(this.metadata, 'labels', { [HCI_ANNOTATIONS.OS_TYPE]: '', [HCI_ANNOTATIONS.IMAGE_SUFFIX]: '' });
|
||||
Vue.set(this.metadata, 'annotations', { [HCI_ANNOTATIONS.STORAGE_CLASS]: '' });
|
||||
this.metadata['labels'] = { [HCI_ANNOTATIONS.OS_TYPE]: '', [HCI_ANNOTATIONS.IMAGE_SUFFIX]: '' };
|
||||
this.metadata['annotations'] = { [HCI_ANNOTATIONS.STORAGE_CLASS]: '' };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import Vue from 'vue';
|
||||
import { find, pickBy, omitBy } from 'lodash';
|
||||
import {
|
||||
AS, MODE, _VIEW, _CONFIG, _UNFLAG, _EDIT
|
||||
@ -110,7 +109,7 @@ export default class HciVmTemplateVersion extends HarvesterResource {
|
||||
}
|
||||
};
|
||||
|
||||
Vue.set(this, 'spec', spec);
|
||||
this['spec'] = spec;
|
||||
}
|
||||
|
||||
get canDelete() {
|
||||
@ -272,6 +271,6 @@ export default class HciVmTemplateVersion extends HarvesterResource {
|
||||
return matchesSomeRegex(key, LABELS_TO_IGNORE_REGEX);
|
||||
});
|
||||
|
||||
Vue.set(this.spec.vm.spec.template.metadata, 'labels', { ...wasIgnored, ...val });
|
||||
this.spec.vm.spec.template.metadata['labels'] = { ...wasIgnored, ...val };
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import Vue from 'vue';
|
||||
import SteveModel from '@shell/plugins/steve/steve-class';
|
||||
import { HCI } from '@shell/config/labels-annotations';
|
||||
|
||||
@ -16,7 +15,7 @@ export default class NetworkAttachmentDef extends SteveModel {
|
||||
})
|
||||
};
|
||||
|
||||
Vue.set(this, 'spec', spec);
|
||||
this.spec = spec;
|
||||
}
|
||||
|
||||
get parseConfig() {
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import Vue from 'vue';
|
||||
import { load } from 'js-yaml';
|
||||
import { omitBy, pickBy } from 'lodash';
|
||||
|
||||
@ -264,8 +263,8 @@ export default class VirtVm extends HarvesterResource {
|
||||
};
|
||||
|
||||
if (realMode !== _CLONE) {
|
||||
Vue.set(this.metadata, 'annotations', { [HCI_ANNOTATIONS.VOLUME_CLAIM_TEMPLATE]: '[]' });
|
||||
Vue.set(this, 'spec', spec);
|
||||
this.metadata['annotations'] = { [HCI_ANNOTATIONS.VOLUME_CLAIM_TEMPLATE]: '[]' };
|
||||
this['spec'] = spec;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1057,6 +1056,6 @@ export default class VirtVm extends HarvesterResource {
|
||||
return matchesSomeRegex(key, LABELS_TO_IGNORE_REGEX);
|
||||
});
|
||||
|
||||
Vue.set(this.spec.template.metadata, 'labels', { ...wasIgnored, ...val });
|
||||
this.spec.template.metadata['labels'] = { ...wasIgnored, ...val };
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import Vue from 'vue';
|
||||
import { clone } from '@shell/utils/object';
|
||||
import HarvesterResource from '@pkg/harvester/models/harvester';
|
||||
import { HCI } from '@pkg/harvester/types';
|
||||
@ -14,8 +13,8 @@ export default class HciLB extends HarvesterResource {
|
||||
spec.selector = spec.selector || {};
|
||||
spec.selector.network = spec.selector.network || '';
|
||||
|
||||
Vue.set(this, 'spec', spec);
|
||||
Vue.set(this, 'metadata', meta);
|
||||
this['spec'] = spec;
|
||||
this['metadata'] = meta;
|
||||
}
|
||||
|
||||
get customValidationRules() {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
// eslint-disable-next-line import/named
|
||||
import { Location } from 'vue-router';
|
||||
import ExplorerProjectsNamespaces from '@shell/components/ExplorerProjectsNamespaces.vue';
|
||||
import { MANAGEMENT, NAMESPACE } from '@shell/config/types';
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import Vue from 'vue';
|
||||
import Parse from 'url-parse';
|
||||
import { HCI } from '../types';
|
||||
import { PRODUCT_NAME } from '../config/harvester';
|
||||
@ -42,7 +41,7 @@ const mutations = {
|
||||
uploadEnd(state, value) {
|
||||
const filtered = state.uploadingImages.filter(l => l !== value);
|
||||
|
||||
Vue.set(state, 'uploadingImages', filtered);
|
||||
state['uploadingImages'] = filtered;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
683
scripts/vue-migrate.js
Normal file
683
scripts/vue-migrate.js
Normal file
@ -0,0 +1,683 @@
|
||||
#!/usr/bin/node
|
||||
/* eslint-disable no-console */
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const glob = require('glob');
|
||||
const semver = require('semver');
|
||||
/**
|
||||
* Init logger
|
||||
*/
|
||||
const stats = {
|
||||
libraries: [],
|
||||
node: [],
|
||||
githubActions: [],
|
||||
nvmrc: [],
|
||||
webpack: [],
|
||||
jest: [],
|
||||
router: [],
|
||||
resolution: [],
|
||||
eslint: [],
|
||||
vueSyntax: [],
|
||||
style: [],
|
||||
total: [],
|
||||
};
|
||||
const ignore = [
|
||||
'**/node_modules/**',
|
||||
'**/dist/**',
|
||||
'**/scripts/vue-migrate.js',
|
||||
'docusaurus/**',
|
||||
'storybook-static/**',
|
||||
'storybook/**',
|
||||
];
|
||||
const nodeRequirement = '20.0.0';
|
||||
const isDry = process.argv.includes('--dry');
|
||||
const isVerbose = process.argv.includes('--verbose');
|
||||
const removePlaceholder = 'REMOVE';
|
||||
const params = { paths: null };
|
||||
|
||||
/**
|
||||
* Package updates
|
||||
* Files: package.json
|
||||
*/
|
||||
const packageUpdates = () => {
|
||||
const files = glob.sync(params.paths || '**/package.json', { ignore });
|
||||
|
||||
files.forEach((file) => {
|
||||
let content = fs.readFileSync(file, 'utf8');
|
||||
const toReplaceNode = false;
|
||||
|
||||
// TODO: Refactor and loop?
|
||||
const [librariesContent, replaceLibraries] = packageUpdatesLibraries(file, content);
|
||||
|
||||
if (replaceLibraries.length) {
|
||||
content = librariesContent;
|
||||
printContent(file, `Updating`, replaceLibraries);
|
||||
stats.libraries.push(file);
|
||||
}
|
||||
|
||||
const [nodeContent, replaceNode] = packageUpdatesEngine(file, content);
|
||||
|
||||
if (replaceNode.length) {
|
||||
printContent(file, `Updating node`, replaceNode);
|
||||
content = nodeContent;
|
||||
stats.node.push(file);
|
||||
}
|
||||
|
||||
const [resolutionContent, replaceResolution] = packageUpdatesResolution(file, content);
|
||||
|
||||
if (replaceResolution.length) {
|
||||
printContent(file, `Updating resolution`, replaceResolution);
|
||||
content = resolutionContent;
|
||||
stats.libraries.push(file);
|
||||
}
|
||||
|
||||
if (replaceLibraries || toReplaceNode || replaceResolution) {
|
||||
stats.total.push(file);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Verify package vue related libraries versions
|
||||
*/
|
||||
const packageUpdatesLibraries = (file, oldContent) => {
|
||||
let content = oldContent;
|
||||
let parsedJson = JSON.parse(content);
|
||||
const replaceLibraries = [];
|
||||
const types = ['dependencies', 'devDependencies', 'peerDependencies'];
|
||||
// [Library name, new version or new library, new library version]
|
||||
const librariesUpdates = [
|
||||
['@nuxt/babel-preset-app', removePlaceholder],
|
||||
['@types/jest', '^29.5.2'],
|
||||
['@typescript-eslint/eslint-plugin', '~5.4.0'],
|
||||
['@typescript-eslint/parser', '~5.4.0'],
|
||||
['@vue/cli-plugin-babel', '~5.0.0'],
|
||||
['@vue/cli-plugin-e2e-cypress', '~5.0.0'],
|
||||
['@vue/cli-plugin-eslint', '~5.0.0'],
|
||||
['@vue/cli-plugin-router', '~5.0.0'],
|
||||
['@vue/cli-plugin-typescript', '~5.0.0'],
|
||||
['@vue/cli-plugin-unit-jest', '~5.0.0'],
|
||||
['@vue/cli-plugin-vuex', '~5.0.0'],
|
||||
['@vue/cli-service', '~5.0.0'],
|
||||
['@vue/eslint-config-typescript', '~9.1.0'],
|
||||
['@vue/vue2-jest', '@vue/vue3-jest', '^27.0.0-alpha.1'],
|
||||
['@vue/test-utils', '~2.0.0-0'],
|
||||
['core-js', '3.25.3'],
|
||||
['cache-loader', '^4.1.0'],
|
||||
['node-polyfill-webpack-plugin', '^3.0.0'],
|
||||
['portal-vue', '~3.0.0'],
|
||||
['require-extension-hooks-babel', '1.0.0'],
|
||||
['require-extension-hooks-vue', '3.0.0'],
|
||||
['require-extension-hooks', '0.3.3'],
|
||||
['sass-loader', '~12.0.0'],
|
||||
['typescript', '~4.5.5'],
|
||||
['vue-router', '~4.0.3'],
|
||||
['vue-virtual-scroll-list', 'vue3-virtual-scroll-list', '0.2.1'],
|
||||
['vue', '~3.2.13'],
|
||||
['vuex', '~4.0.0'],
|
||||
['xterm', '5.2.1'],
|
||||
];
|
||||
|
||||
// Loop through each type of dependencies since many often not correctly placed or hard to track
|
||||
types.forEach((type) => {
|
||||
if (parsedJson[type]) {
|
||||
librariesUpdates.forEach(([library, newVersion, newLibraryVersion]) => {
|
||||
if (parsedJson[type][library]) {
|
||||
const version = semver.coerce(parsedJson[type][library]);
|
||||
|
||||
if (newVersion === removePlaceholder) {
|
||||
// Remove library
|
||||
replaceLibraries.push([library, [parsedJson[type][library], removePlaceholder]]);
|
||||
delete parsedJson[type][library];
|
||||
content = JSON.stringify(parsedJson, null, 2);
|
||||
writeContent(file, content);
|
||||
} else if (newLibraryVersion) {
|
||||
// Replace with a new library if present, due breaking changes in Vue3
|
||||
replaceLibraries.push([library, [parsedJson[type][library], newVersion, newLibraryVersion]]);
|
||||
content = content.replaceAll(`"${ library }": "${ parsedJson[type][library] }"`, `"${ newVersion }": "${ newLibraryVersion }"`);
|
||||
parsedJson = JSON.parse(content);
|
||||
writeContent(file, content);
|
||||
} else if (version && semver.lt(version, semver.coerce(newVersion))) {
|
||||
// Update library version if outdated
|
||||
replaceLibraries.push([library, [parsedJson[type][library], newVersion]]);
|
||||
content = content.replaceAll(`"${ library }": "${ parsedJson[type][library] }"`, `"${ library }": "${ newVersion }"`);
|
||||
parsedJson = JSON.parse(content);
|
||||
writeContent(file, content);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return [content, replaceLibraries];
|
||||
};
|
||||
|
||||
/**
|
||||
* Verify package engines node to latest
|
||||
*/
|
||||
const packageUpdatesEngine = (file, oldContent) => {
|
||||
let content = oldContent;
|
||||
let parsedJson = JSON.parse(content);
|
||||
const replaceNode = [];
|
||||
|
||||
// Verify package engines node to latest
|
||||
if (parsedJson.engines) {
|
||||
const outdated = semver.lt(semver.coerce(parsedJson.engines.node), semver.coerce(nodeRequirement));
|
||||
|
||||
if (outdated) {
|
||||
replaceNode.push([parsedJson.engines.node, nodeRequirement]);
|
||||
content = content.replaceAll(`"node": "${ parsedJson.engines.node }"`, `"node": ">=${ nodeRequirement }"`);
|
||||
parsedJson = JSON.parse(content);
|
||||
writeContent(file, content);
|
||||
}
|
||||
}
|
||||
|
||||
return [content, replaceNode];
|
||||
};
|
||||
|
||||
/**
|
||||
* Add resolutions for VueCLI
|
||||
*/
|
||||
const packageUpdatesResolution = (file, oldContent) => {
|
||||
let content = oldContent;
|
||||
let parsedJson = JSON.parse(content);
|
||||
const replaceResolution = [];
|
||||
const resolutions = [
|
||||
['@vue/cli-service/html-webpack-plugin', '^5.0.0'],
|
||||
['**/webpack', removePlaceholder],
|
||||
];
|
||||
|
||||
// Verify package engines node to latest
|
||||
if (parsedJson.resolutions) {
|
||||
resolutions.forEach(([library, newVersion]) => {
|
||||
if (newVersion === removePlaceholder) {
|
||||
delete parsedJson.resolutions[library];
|
||||
content = JSON.stringify(parsedJson, null, 2);
|
||||
parsedJson = JSON.parse(content);
|
||||
writeContent(file, content);
|
||||
} else if (!parsedJson.resolutions[library]) {
|
||||
// Add resolution if not present
|
||||
parsedJson.resolutions[library] = newVersion;
|
||||
content = JSON.stringify(parsedJson, null, 2);
|
||||
parsedJson = JSON.parse(content);
|
||||
writeContent(file, content);
|
||||
} else {
|
||||
// Ensure resolution version is up to date
|
||||
const outdated = semver.lt(semver.coerce(parsedJson.resolutions[library]), semver.coerce(newVersion));
|
||||
|
||||
if (outdated) {
|
||||
replaceResolution.push([parsedJson.engines.node, nodeRequirement]);
|
||||
content = content.replaceAll(`"${ library }": "${ parsedJson.resolutions[library] }"`, `"${ library }": "${ newVersion }"`);
|
||||
parsedJson = JSON.parse(content);
|
||||
writeContent(file, content);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return [content, replaceResolution];
|
||||
};
|
||||
|
||||
/**
|
||||
* GitHub Actions updates
|
||||
* Files: .github/workflows/**.yml
|
||||
*
|
||||
* Verify GitHub Actions use of current node version, e.g. node-version: '<18'
|
||||
*/
|
||||
const gitHubActionsUpdates = () => {
|
||||
const files = glob.sync(params.paths || '.github/workflows/**.{yml,yaml}', { ignore });
|
||||
|
||||
files.forEach((file) => {
|
||||
let content = fs.readFileSync(file, 'utf8');
|
||||
const nodeVersionMatches = content.matchAll(/node-version: \'([0-9.x]+)\'/g);
|
||||
const toReplace = [];
|
||||
|
||||
// Check all the node occurrences within the test file
|
||||
if (nodeVersionMatches) {
|
||||
for (const matches of nodeVersionMatches) {
|
||||
for (const match of matches) {
|
||||
const nodeVersion = semver.coerce(match);
|
||||
|
||||
if (nodeVersion && semver.lt(nodeVersion, semver.coerce(nodeRequirement))) {
|
||||
content = content.replaceAll(`node-version: '${ match }'`, `node-version: '20.x'`);
|
||||
|
||||
writeContent(file, content);
|
||||
toReplace.push([match, nodeRequirement]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (toReplace.length) {
|
||||
printContent(file, `Updating node`, toReplace);
|
||||
stats.githubActions.push(file);
|
||||
stats.total.push(file);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* NVM updates
|
||||
* Files: .nvmrc
|
||||
*
|
||||
* Verify presence of .nvmrc, create one if none, update if any
|
||||
*/
|
||||
const nvmUpdates = () => {
|
||||
const files = glob.sync(params.paths || '**/.nvmrc', { ignore });
|
||||
const nvmRequirement = 20;
|
||||
|
||||
files.forEach((file) => {
|
||||
if (file) {
|
||||
let content = fs.readFileSync(file, 'utf8');
|
||||
const nodeVersionMatch = content.match(/([0-9.x]+)/g);
|
||||
const nodeVersion = semver.coerce(nodeVersionMatch[0]);
|
||||
|
||||
// Ensure node version is up to date
|
||||
if (nodeVersion && semver.lt(nodeVersion, semver.coerce(nodeRequirement))) {
|
||||
printContent(file, `Updating node ${ [nodeVersionMatch[0], nvmRequirement] }`);
|
||||
content = content.replaceAll(nodeVersionMatch[0], nvmRequirement);
|
||||
|
||||
writeContent(file, content);
|
||||
stats.nvmrc.push(file);
|
||||
stats.total.push(file);
|
||||
}
|
||||
} else {
|
||||
writeContent('.nvmrc', nvmRequirement);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Vue config update
|
||||
* Files: vue.config.js
|
||||
*
|
||||
* Verify vue.config presence of deprecated Webpack5 options
|
||||
* - devServer.public: 'path' -> client: { webSocketURL: 'path' }
|
||||
*/
|
||||
const vueConfigUpdates = () => {
|
||||
const files = glob.sync(params.paths || 'vue.config**.js', { ignore });
|
||||
|
||||
files.forEach((file) => {
|
||||
const content = fs.readFileSync(file, 'utf8');
|
||||
|
||||
// Verify vue.config presence of deprecated Webpack5 options
|
||||
if (content.includes('devServer.public: \'path\'')) {
|
||||
stats.webpack.push(file);
|
||||
stats.total.push(file);
|
||||
// TODO: Add replacement
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Vue syntax update (to do not mix with tests)
|
||||
* Files: .vue, .js, .ts (not .spec.ts, not .test.ts)
|
||||
*/
|
||||
const vueSyntaxUpdates = () => {
|
||||
const files = glob.sync(params.paths || '**/*.{vue,js,ts}', { ignore: [...ignore, '**/*.spec.ts', '**/__tests__/**', '**/*.test.ts', 'jest.setup.js', '**/*.d.ts', '**/vue-shim.ts'] });
|
||||
const replacementCases = [
|
||||
// Prioritize set and delete to be converted since removed in Vue3
|
||||
[/\=\> Vue\.set\((.*?),\s*(.*?),\s*(.*?)\)/g, (_, obj, prop, val) => `=> (${ obj.trim() }[${ prop.trim() }] = ${ val.trim() })`, 'removed and unnecessary due new reactivity https://vuejs.org/guide/extras/reactivity-in-depth.html'],
|
||||
[/\=\> Vue\.set\((.*?),\s*'([^']*?)',\s*\{([\s\S]*?)\}\)/g, (_, obj, prop, val) => `=> (${ obj.trim() }['${ prop }'] = {${ val.trim() }})`, 'removed and unnecessary due new reactivity https://vuejs.org/guide/extras/reactivity-in-depth.html'],
|
||||
[/\=\> Vue\.set\((.*?),\s*'([^']*?)',\s*(.*?)\)/g, (_, obj, prop, val) => `=> (${ obj.trim() }.${ prop } = ${ val.trim() })`, 'removed and unnecessary due new reactivity https://vuejs.org/guide/extras/reactivity-in-depth.html'],
|
||||
|
||||
[/Vue\.set\((.*?),\s*(.*?),\s*(.*?)\)/g, (_, obj, prop, val) => `${ obj.trim() }[${ prop.trim() }] = ${ val.trim() }`, 'removed and unnecessary due new reactivity https://vuejs.org/guide/extras/reactivity-in-depth.html'],
|
||||
[/Vue\.set\((.*?),\s*'([^']*?)',\s*\{([\s\S]*?)\}\)/g, (_, obj, prop, val) => `${ obj.trim() }['${ prop }'] = {${ val.trim() }}`, 'removed and unnecessary due new reactivity https://vuejs.org/guide/extras/reactivity-in-depth.html'],
|
||||
[/Vue\.set\((.*?),\s*'([^']*?)',\s*(.*?)\)/g, (_, obj, prop, val) => `${ obj.trim() }.${ prop } = ${ val.trim() }`, 'removed and unnecessary due new reactivity https://vuejs.org/guide/extras/reactivity-in-depth.html'],
|
||||
[/Vue\.delete\((.*?),\s*(.*?)\)/g, (_, obj, prop) => `delete ${ obj.trim() }[${ prop.trim() }]`, 'removed and unnecessary due new reactivity https://vuejs.org/guide/extras/reactivity-in-depth.html'],
|
||||
|
||||
[/\=\> this\.\$set\((.*?),\s*(.*?),\s*(.*?)\)/g, (_, obj, prop, val) => `=> (${ obj.trim() }[${ prop.trim() }] = ${ val.trim() })`, 'removed and unnecessary due new reactivity https://vuejs.org/guide/extras/reactivity-in-depth.html'],
|
||||
[/\=\> this\.\$set\((.*?),\s*'([^']*?)',\s*\{([\s\S]*?)\}\)/g, (_, obj, prop, val) => `=> (${ obj.trim() }['${ prop }'] = {${ val.trim() }})`, 'removed and unnecessary due new reactivity https://vuejs.org/guide/extras/reactivity-in-depth.html'],
|
||||
[/\=\> this\.\$set\((.*?),\s*'([^']*?)',\s*(.*?)\)/g, (_, obj, prop, val) => `=> (${ obj.trim() }.${ prop } = ${ val.trim() })`, 'removed and unnecessary due new reactivity https://vuejs.org/guide/extras/reactivity-in-depth.html'],
|
||||
|
||||
[/this.\$set\((.*?),\s*'([^']*?)',\s*(.*?)\)/g, (_, obj, prop, val) => obj.trim() === 'this' ? `this['${ prop }'] = ${ val }` : `${ obj.trim() }['${ prop }'] = ${ val }`, 'removed and unnecessary due new reactivity https://vuejs.org/guide/extras/reactivity-in-depth.html'],
|
||||
|
||||
[/this\.\$set\((.*?),\s*(.*?),\s*(.*?)\)/g, (_, obj, prop, val) => `${ obj.trim() }[${ prop.trim() }] = ${ val.trim() }`, 'removed and unnecessary due new reactivity https://vuejs.org/guide/extras/reactivity-in-depth.html'],
|
||||
[/this\.\$set\((.*?),\s*'([^']*?)',\s*\{([\s\S]*?)\}\)/g, (_, obj, prop, val) => `${ obj.trim() }['${ prop }'] = {${ val.trim() }}`, 'removed and unnecessary due new reactivity https://vuejs.org/guide/extras/reactivity-in-depth.html'],
|
||||
[/this\.\$set\((.*?),\s*'([^']*?)',\s*(.*?)\)/g, (_, obj, prop, val) => `${ obj.trim() }.${ prop } = ${ val.trim() }`, 'removed and unnecessary due new reactivity https://vuejs.org/guide/extras/reactivity-in-depth.html'],
|
||||
[/this\.\$delete\((.*?),\s*(.*?)\)/g, (_, obj, prop) => `delete ${ obj.trim() }[${ prop.trim() }]`, 'removed and unnecessary due new reactivity https://vuejs.org/guide/extras/reactivity-in-depth.html'],
|
||||
|
||||
// Replace imports for all the cases where createApp is needed, before the rest of the replacements
|
||||
[/import Vue from 'vue';?/g, `import { createApp } from \'vue\';\nconst vueApp = createApp({});`, `https://v3-migration.vuejs.org/breaking-changes/global-api.html#a-new-global-api-createapp`],
|
||||
[`new Vue(`, `createApp(`, `https://v3-migration.vuejs.org/breaking-changes/global-api.html#a-new-global-api-createapp`],
|
||||
[`Vue.config`, `vueApp.config`, `https://v3-migration.vuejs.org/breaking-changes/global-api.html#a-new-global-api-createapp`],
|
||||
[`Vue.directive`, `vueApp.directive`, `https://v3-migration.vuejs.org/breaking-changes/global-api.html#a-new-global-api-createapp`],
|
||||
[`Vue.filter(`, `vueApp.filter(`, `https://v3-migration.vuejs.org/breaking-changes/global-api.html#a-new-global-api-createapp`],
|
||||
[`Vue.mixin(`, `vueApp.mixin(`, `https://v3-migration.vuejs.org/breaking-changes/global-api.html#a-new-global-api-createapp`],
|
||||
[`Vue.component(`, `vueApp.component(`, `https://v3-migration.vuejs.org/breaking-changes/global-api.html#a-new-global-api-createapp`],
|
||||
[`Vue.use(`, `vueApp.use(`, `https://v3-migration.vuejs.org/breaking-changes/global-api.html#a-new-global-api-createapp`],
|
||||
[`Vue.prototype`, `vueApp.config.globalProperties`, `https://v3-migration.vuejs.org/breaking-changes/global-api.html#a-new-global-api-createapp`],
|
||||
['Vue.util', '', 'Vue.util is private and no longer available https://v3-migration.vuejs.org/migration-build.html#partially-compatible-with-caveats'],
|
||||
// [`Vue.extend`, removePlaceholder, 'https://v3-migration.vuejs.org/breaking-changes/global-api.html#vue-extend-removed'],
|
||||
// [`Vue.extend`, `createApp({})`], // (mixins)
|
||||
|
||||
[`vue-virtual-scroll-list`, `vue3-virtual-scroll-list`, 'library update'],
|
||||
|
||||
[`Vue.nextTick`, `nextTick`, 'https://v3-migration.vuejs.org/breaking-changes/global-api-treeshaking.html#global-api-treeshaking'],
|
||||
[`this.nextTick`, `nextTick`, 'https://v3-migration.vuejs.org/breaking-changes/global-api-treeshaking.html#global-api-treeshaking'],
|
||||
// TODO: Add missing import
|
||||
|
||||
[/( {4,}default)\(\)\s*\{([\s\S]*?)this\.([\s\S]*?\}\s*\})/g, (_, before, middle, after) => `${ before }(props) {${ middle }props.${ after }`, 'https://v3-migration.vuejs.org/breaking-changes/props-default-this.html'],
|
||||
[`value=`, `modelValue=`],
|
||||
[`@input=`, `@update:modelValue=`],
|
||||
// [`v-bind.sync=`, `:modelValue=`, `https://v3-migration.vuejs.org/breaking-changes/v-model.html#using-v-bind-sync`],
|
||||
// ['v-model=', ':modelValue=', ''],
|
||||
[`click.native`, `click`, `https://v3-migration.vuejs.org/breaking-changes/v-model.html#using-v-bind-sync`],
|
||||
[`v-on="$listeners"`, removePlaceholder, `removed and integrated with $attrs https://v3-migration.vuejs.org/breaking-changes/listeners-removed.html`],
|
||||
[`:listeners="$listeners"`, `:v-bind="$attrs"`, `removed and integrated with $attrs https://v3-migration.vuejs.org/breaking-changes/listeners-removed.html`],
|
||||
|
||||
[/this\.\$scopedSlots\[(\w+)\]|this\.\$scopedSlots\.(\w+)/, (match, key1, key2) => `this.$slots.${ key1 || key2 }()`, `(many components loop through them) https://v3-migration.vuejs.org/breaking-changes/slots-unification.html`],
|
||||
[` $scopedSlots`, ` $slots`, `(many components loop through them) https://v3-migration.vuejs.org/breaking-changes/slots-unification.html`],
|
||||
[/slot="(\w+:\w+)"\s+slot-scope="(\w+)"/g, `$1="$2"`, `not mentioned in migration https://vuejs.org/guide/components/slots.html#scoped-slots`],
|
||||
[/this\.\$slots\['([^']+)'\]/g, `this.$slots[\'$1\']()`, `not mentioned in migration https://vuejs.org/guide/components/slots.html#scoped-slots`],
|
||||
// [/this\.\$slots\.([^']+)'/g, `this.$slots.$1()`, `not mentioned in migration https://vuejs.org/guide/components/slots.html#scoped-slots`],
|
||||
// [/this\.\$slots(?!\s*\(\))(\b|\?|['"\[])/g, `this.$slots()$1`, `https://eslint.vuejs.org/rules/require-slots-as-functions.html`], // TODO: Add exception for existing brackets
|
||||
|
||||
// Portals are now Vue3 Teleports
|
||||
[/<portal|<portal-target|<\/portal|<\/portal-target/g, '', `https://v3.vuejs.org/guide/teleport.html`],
|
||||
|
||||
// TODO: probably requires JSDom
|
||||
// [/<template v-for="([\s\S]*?)">\s*<([\s\S]*?)\s*([\s\S]*?):key="([\s\S]*?)"([\s\S]*?)<\/([\s\S]*?)>\s*<\/template>/gs, '<template v-for="$1" :key="$4"><$3 $5>$6</$7>\n</template>', `https://v3-migration.vuejs.org/breaking-changes/key-attribute.html#with-template-v-for`],
|
||||
// [/(<\w+(?!.*?v-for=)[^>]*?)\s*:key="[^"]*"\s*([^>]*>)/g, '$1$2', `https://v3-migration.vuejs.org/breaking-changes/key-attribute.html#with-template-v-for`],
|
||||
[/(<\w+[^>v\-for]*?):key="[^"]*"\s*([^>]*>)/g, '$1$2', `https://v3-migration.vuejs.org/breaking-changes/key-attribute.html#with-template-v-for`],
|
||||
[/(\<\w+\s+(?:[^>]*?\s+)?v-for="\(.*?,\s*(\w+)\s*\).*?")(?:\s*:key=".*"\s*)?([^>]*>)/g, '$1 :key="$2"$3', `https://v3-migration.vuejs.org/breaking-changes/key-attribute.html#with-template-v-for`],
|
||||
[/(\<\w+\s+(?:[^>]*?\s+)?)v-for="(?!\*?\s+.*?\s+.*?)([^,]+?)\s+in\s+([^"]+?)"(?:\s*:key=".*"\s*)?([^>]*>)/g, '$1 v-for="($2, i) in $3" :key="i" $4', `https://v3-migration.vuejs.org/breaking-changes/key-attribute.html#with-template-v-for`],
|
||||
|
||||
// TODO: except for <components /> elements, probably requires JSDom
|
||||
// [' is=', ``, `https://v3-migration.vuejs.org/breaking-changes/custom-elements-interop.html#customized-built-in-elements`],
|
||||
// [' :is=', ``, `https://v3-migration.vuejs.org/breaking-changes/custom-elements-interop.html#customized-built-in-elements`],
|
||||
|
||||
// Directive updates
|
||||
// [`bind(`, '', `beforeMount( but there's too many bind cases https://v3-migration.vuejs.org/breaking-changes/custom-directives.html`], // TODO: Restrict to directives and context
|
||||
// [`update(`, '', `removed, also common term https://v3-migration.vuejs.org/breaking-changes/custom-directives.html`], // TODO: Restrict to directives and context
|
||||
[`inserted(`, `mounted(`, 'https://v3-migration.vuejs.org/breaking-changes/custom-directives.html'],
|
||||
[`componentUpdated(`, `updated(`, 'https://v3-migration.vuejs.org/breaking-changes/custom-directives.html'],
|
||||
[`unbind`, `unmounted`, 'https://v3-migration.vuejs.org/breaking-changes/custom-directives.html'],
|
||||
|
||||
// [`propsData (app creation)`, ``, `use second argument of createApp({}) https://v3-migration.vuejs.org/breaking-changes/props-data.html`],
|
||||
[`@hook:lifecycleHook`, `@vue:lifecycleHook`, `https://v3-migration.vuejs.org/breaking-changes/vnode-lifecycle-events.html`],
|
||||
|
||||
// Nuxt and initalize case only
|
||||
// TODO: Use eventbus replacement as temporary solution?
|
||||
[`$on('event', callback)`, '', `no migration, existing lib, https://v3-migration.vuejs.org/breaking-changes/events-api.html`],
|
||||
[`$off('event', callback)`, '', `no migration, existing lib, https://v3-migration.vuejs.org/breaking-changes/events-api.html`],
|
||||
[`$once('event', callback)`, '', `no migration, existing lib, https://v3-migration.vuejs.org/breaking-changes/events-api.html`],
|
||||
|
||||
// [`$children`, ``, `no migration, $refs are suggested as communication https://v3-migration.vuejs.org/breaking-changes/children.html`],
|
||||
|
||||
// Vuex
|
||||
[`new Vuex.Store(`, `createStore(`, 'To install Vuex to a Vue instance, pass the store instead of Vuex https://vuex.vuejs.org/guide/migrating-to-4-0-from-3-x.html#installation-process'],
|
||||
[`import Vuex from 'vuex'`, `import { createStore } from 'vuex'`, 'To install Vuex to a Vue instance, pass the store instead of Vuex https://vuex.vuejs.org/guide/migrating-to-4-0-from-3-x.html#installation-process'],
|
||||
|
||||
// Extra cases TBD (it seems like we already use the suggested way for arrays)
|
||||
// watch option used on arrays not triggered by mutations https://v3-migration.vuejs.org/breaking-changes/watch.html
|
||||
];
|
||||
|
||||
replaceCases('vueSyntax', files, replacementCases, `Updating Vue syntax`);
|
||||
};
|
||||
|
||||
/**
|
||||
* Vue Router
|
||||
* Files: .vue, .js, .ts
|
||||
*/
|
||||
const routerUpdates = () => {
|
||||
const files = glob.sync(params.paths || '**/*.{vue,js,ts}', { ignore });
|
||||
const replacementCases = [
|
||||
[`import Router from 'vue-router'`, `import { createRouter } from 'vue-router'`],
|
||||
[`Vue.use(Router)`, `const router = createRouter({})`],
|
||||
// [`currentRoute`, '', 'The currentRoute property is now a ref() https://router.vuejs.org/guide/migration/#The-currentRoute-property-is-now-a-ref-'],
|
||||
[/import\s*\{([^}]*)\s* RouteConfig\s*([^}]*)\}\s*from\s*'vue-router'/g, (match, before, after) => `import {${ before.trim() } RouteRecordRaw ${ after.trim() }} from 'vue-router'`],
|
||||
[/import\s*\{([^}]*)\s* Location\s*([^}]*)\}\s*from\s*'vue-router'/g, (match, before, after) => `import {${ before.trim() } RouteLocation ${ after.trim() }} from 'vue-router'`],
|
||||
['imported Router', ''],
|
||||
['router.name', '', 'now string | Symbol'],
|
||||
[`mode: \'history\'`, 'history: createWebHistory()'],
|
||||
// ['getMatchedComponents', '', 'https://router.vuejs.org/guide/migration/#Removal-of-router-getMatchedComponents-'],
|
||||
];
|
||||
|
||||
replaceCases('router', files, replacementCases, `Updating Vue Router`);
|
||||
};
|
||||
|
||||
/**
|
||||
* Jest update
|
||||
* https://test-utils.vuejs.org/migration
|
||||
* Files: .spec.js, .spec.ts, .test.js, .test.ts
|
||||
*/
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const jestUpdates = () => {
|
||||
const files = glob.sync(params.paths || '**/*.{test.js,test.ts}', { ignore });
|
||||
|
||||
const cases = [
|
||||
['config.mocks.$myGlobal', '', ''],
|
||||
['createLocalVue', '', 'https://test-utils.vuejs.org/migration/#No-more-createLocalVue'],
|
||||
['new Vuex.Store', '', ''],
|
||||
['store', '', ''],
|
||||
['propsData', 'props', 'https://test-utils.vuejs.org/migration/#propsData-is-now-props'],
|
||||
['localVue.extend({})', '', ''],
|
||||
['Vue.nextTick', '', ''],
|
||||
['$destroy', '$unmount', 'https://test-utils.vuejs.org/migration/#destroy-is-now-unmount-to-match-Vue-3'],
|
||||
['mocks', '', 'https://test-utils.vuejs.org/migration/#mocks-and-stubs-are-now-in-global'],
|
||||
['stubs', '', 'https://test-utils.vuejs.org/migration/#mocks-and-stubs-are-now-in-global'],
|
||||
['mixins', '', 'https://test-utils.vuejs.org/migration/#mocks-and-stubs-are-now-in-global'],
|
||||
['plugins', '', 'https://test-utils.vuejs.org/migration/#mocks-and-stubs-are-now-in-global'],
|
||||
['component', '', 'https://test-utils.vuejs.org/migration/#mocks-and-stubs-are-now-in-global'],
|
||||
['directives', '', 'https://test-utils.vuejs.org/migration/#mocks-and-stubs-are-now-in-global'],
|
||||
['slots', '', 'slots‘s scope is now exposed as params https://test-utils.vuejs.org/migration/#slots-s-scope-is-now-exposed-as-params'],
|
||||
['scopedSlots', '', 'scopedSlots is now merged with slots https://test-utils.vuejs.org/migration/#scopedSlots-is-now-merged-with-slots'],
|
||||
['parentComponent', '', 'deprecated '],
|
||||
['contains', 'find', 'deprecated '],
|
||||
['config.global.renderStubDefaultSlot = false', '', ''],
|
||||
['findAll().at(0)', '', '']
|
||||
];
|
||||
|
||||
replaceCases('jest', files, cases, `Updating Jest`);
|
||||
};
|
||||
|
||||
/**
|
||||
* Jest config updates
|
||||
* Files: jest.config.js, .json, .ts
|
||||
*
|
||||
* /node_modules/@vue/vue2-jest --> reference needs new library version
|
||||
*/
|
||||
const jestConfigUpdates = () => {
|
||||
const files = glob.sync(params.paths || '**/jest.config.{js,ts,json}', { ignore });
|
||||
const cases = [
|
||||
['/node_modules/@vue/vue2-jest', '/node_modules/@vue/vue3-jest']
|
||||
];
|
||||
|
||||
replaceCases('jest', files, cases, `Updating Jest config`);
|
||||
};
|
||||
|
||||
/**
|
||||
* ESLint Updates
|
||||
* Files: .eslintrc.js, .eslintrc.json, .eslintrc.yml
|
||||
*/
|
||||
const eslintUpdates = () => {
|
||||
const files = glob.sync(params.paths || '**/.eslintrc.*{js,json,yml}', { ignore });
|
||||
// Add cases introduced with new recommended settings
|
||||
const replacePlugins = [
|
||||
['plugin:vue/essential', 'plugin:vue/vue3-essential'],
|
||||
['plugin:vue/strongly-recommended', 'plugin:vue/vue3-strongly-recommended'],
|
||||
['plugin:vue/recommended', 'plugin:vue/vue3-recommended']
|
||||
];
|
||||
const newRules = {
|
||||
'vue/one-component-per-file': 'off',
|
||||
'vue/no-deprecated-slot-attribute': 'off',
|
||||
'vue/require-explicit-emits': 'off',
|
||||
'vue/v-on-event-hyphenation': 'off',
|
||||
};
|
||||
|
||||
files.forEach((file) => {
|
||||
let content = fs.readFileSync(file, 'utf8');
|
||||
const matchedCases = [];
|
||||
|
||||
replacePlugins.forEach(([text, replacement]) => {
|
||||
const isCase = content.includes(text);
|
||||
|
||||
if (isCase) {
|
||||
content = content.replaceAll(text, replacement);
|
||||
matchedCases.push([text, replacement]);
|
||||
|
||||
writeContent(file, content);
|
||||
}
|
||||
});
|
||||
|
||||
// Add the new rules if they don't exist
|
||||
const eslintConfigPath = path.join(__dirname, `../${ file }`);
|
||||
const eslintConfig = require(eslintConfigPath);
|
||||
|
||||
Object.keys(newRules).forEach((rule) => {
|
||||
if (!eslintConfig.rules[rule]) {
|
||||
eslintConfig.rules[rule] = newRules[rule];
|
||||
matchedCases.push(rule);
|
||||
}
|
||||
});
|
||||
writeContent(eslintConfigPath, `module.exports = ${ JSON.stringify(eslintConfig, null, 2) }`);
|
||||
|
||||
if (matchedCases.length) {
|
||||
printContent(file, `Updating ESLint`, matchedCases);
|
||||
stats.eslint.push(file);
|
||||
stats.total.push(file);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* TS Updates
|
||||
* Files: tsconfig*.json
|
||||
*
|
||||
* Add information about TS issues, recommend @ts-nocheck as temporary solution
|
||||
*/
|
||||
const tsUpdates = () => {
|
||||
console.warn('TS checks are stricter and may require to be fixed manually.',
|
||||
'Use @ts-nocheck to give you time to fix them.',
|
||||
'Add exception to your ESLint config to avoid linting errors.');
|
||||
// TODO: Add case
|
||||
};
|
||||
|
||||
/**
|
||||
* Styles updates
|
||||
*/
|
||||
const stylesUpdates = () => {
|
||||
const files = glob.sync(params.paths || '**/*.{vue, scss}', { ignore });
|
||||
const cases = [
|
||||
['::v-deep', ':deep()'],
|
||||
];
|
||||
|
||||
replaceCases('style', files, cases, `Updating styles`);
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to write content
|
||||
*/
|
||||
const writeContent = (...args) => {
|
||||
if (!isDry) {
|
||||
fs.writeFileSync(...args);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to print content
|
||||
*/
|
||||
const printContent = (...args) => {
|
||||
if (isVerbose) {
|
||||
console.log(...args);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Replace all cases for the provided files
|
||||
*/
|
||||
const replaceCases = (fileType, files, replacementCases, printText) => {
|
||||
files.forEach((file) => {
|
||||
const matchedCases = [];
|
||||
let content = fs.readFileSync(file, 'utf8');
|
||||
|
||||
replacementCases.forEach(([text, replacement, notes]) => {
|
||||
// Simple text
|
||||
if (typeof text === 'string') {
|
||||
if (content.includes(text)) {
|
||||
// Exclude cases without replacement
|
||||
if (replacement) {
|
||||
// Remove discontinued functionalities which do not break
|
||||
content = content.replaceAll(text, replacement === removePlaceholder ? '' : replacement);
|
||||
}
|
||||
if (!matchedCases.includes(`${ text }, ${ replacement }, ${ notes }`)) {
|
||||
matchedCases.push(`${ text }, ${ replacement }, ${ notes }`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Regex case
|
||||
// TODO: Fix issue not replacing all
|
||||
// eslint-disable-next-line no-lonely-if
|
||||
if (text.test(content) && replacement) {
|
||||
content = content.replace(new RegExp(text, 'g'), replacement);
|
||||
if (!matchedCases.includes(`${ text }, ${ replacement }, ${ notes }`)) {
|
||||
matchedCases.push(`${ text }, ${ replacement }, ${ notes }`);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (matchedCases.length) {
|
||||
writeContent(file, content);
|
||||
printContent(file, printText, matchedCases);
|
||||
stats[fileType].push(file);
|
||||
stats.total.push(file);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Print log
|
||||
*/
|
||||
const printLog = () => {
|
||||
if (process.argv.includes('--files')) {
|
||||
console.dir(stats, { compact: true });
|
||||
}
|
||||
|
||||
const statsCount = Object.entries(stats).reduce((acc, [key, value]) => ({
|
||||
...acc,
|
||||
[key]: value.length
|
||||
}), {});
|
||||
|
||||
console.table(statsCount);
|
||||
|
||||
if (process.argv.includes('--log')) {
|
||||
fs.writeFileSync('stats.json', JSON.stringify(stats, null, 2));
|
||||
}
|
||||
};
|
||||
|
||||
const setParams = () => {
|
||||
const args = process.argv.slice(2);
|
||||
const paramKeys = ['paths'];
|
||||
|
||||
args.forEach((val) => {
|
||||
paramKeys.forEach((key) => {
|
||||
if (val.startsWith(`--${ key }=`)) {
|
||||
params[key] = val.split('=')[1];
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Init application
|
||||
*/
|
||||
(function() {
|
||||
setParams();
|
||||
|
||||
packageUpdates();
|
||||
gitHubActionsUpdates();
|
||||
nvmUpdates();
|
||||
vueConfigUpdates();
|
||||
vueSyntaxUpdates();
|
||||
routerUpdates();
|
||||
// jestUpdates();
|
||||
jestConfigUpdates();
|
||||
eslintUpdates();
|
||||
tsUpdates();
|
||||
stylesUpdates();
|
||||
|
||||
printLog();
|
||||
})();
|
||||
Loading…
x
Reference in New Issue
Block a user