diff --git a/src/components/ConfigEditor.vue b/src/components/ConfigEditor.vue
index e213ee1b7..14e0544c9 100644
--- a/src/components/ConfigEditor.vue
+++ b/src/components/ConfigEditor.vue
@@ -44,7 +44,6 @@
required: true,
},
categories: Array,
- descriptions: Object,
extendedFields: Object,
},
computed: {
@@ -76,26 +75,24 @@
},
methods: {
componentFromField(field) {
+ if (field.format === 'flags') return InputFlag;
+ if (field.enum) return InputEnum;
+
switch (field.type) {
case 'string':
- case 'uint64':
return InputString;
case 'boolean':
return InputBoolean;
- case 'uint32':
- case 'uint16':
- case 'byte':
+ case 'integer':
return InputNumber;
- case 'flag':
- return InputFlag;
- case 'enum':
- return InputEnum;
- case 'hashSet':
- case 'list':
- if (['enum'].includes(field.values.type)) return field.type === 'list' ? InputList : InputSet;
- if (['byte', 'uint16', 'uint32', 'uint64', 'string'].includes(field.values.type)) return InputTag;
- return InputUnknown;
- case 'dictionary':
+ case 'array':
+ if (field.items.enum) {
+ if (field.uniqueItems) return InputSet;
+ return InputList;
+ }
+
+ return InputTag;
+ case 'object':
return InputDictionary;
default:
return InputUnknown;
@@ -150,16 +147,16 @@
diff --git a/src/components/ConfigFields/Input.vue b/src/components/ConfigFields/Input.vue
index 3e9b95193..831808f82 100644
--- a/src/components/ConfigFields/Input.vue
+++ b/src/components/ConfigFields/Input.vue
@@ -13,7 +13,7 @@
currentValue: true,
},
data() {
- const initialValue = typeof this.currentValue !== 'undefined' ? this.currentValue : this.schema.defaultValue;
+ const initialValue = typeof this.currentValue !== 'undefined' ? this.currentValue : null;
return {
value: typeof initialValue === 'object' ? JSON.parse(JSON.stringify(initialValue)) : initialValue,
@@ -21,9 +21,6 @@
};
},
computed: {
- defaultValue() {
- return this.schema.defaultValue;
- },
label() {
return this.schema.label || this.schema.param || this.schema.paramName;
},
@@ -31,7 +28,7 @@
return this.schema.paramName;
},
placeholder() {
- return this.schema.placeholder || this.schema.defaultValue;
+ return this.schema.placeholder;
},
description() {
return this.schema.description;
diff --git a/src/components/ConfigFields/InputDictionary.vue b/src/components/ConfigFields/InputDictionary.vue
index 2521fef33..5a41b045c 100644
--- a/src/components/ConfigFields/InputDictionary.vue
+++ b/src/components/ConfigFields/InputDictionary.vue
@@ -4,23 +4,17 @@
@@ -41,20 +35,18 @@
};
},
computed: {
- keyIsString() {
- return ['string', 'uint64'].includes(this.schema.key.type);
+ availableEnumValues() {
+ return this.enumValues;
},
- valueIsEnum() {
- return this.schema.value.type === 'enum';
+ enumValues() {
+ return Object.entries(this.schema.additionalProperties['x-definition']).map(([label, value]) => ({ label, value }));
},
- valueAvailableEnumValues() {
- const availableEnumValues = [];
-
- for (const key of Object.keys(this.schema.value.values)) {
- availableEnumValues.push(this.schema.value.values[key]);
- }
-
- return availableEnumValues;
+ resolveValue() {
+ return value => {
+ const enumValue = this.enumValues.find(({ value: enumValue }) => value === enumValue);
+ if (!enumValue) return value;
+ return enumValue.label;
+ };
},
},
created() {
@@ -66,12 +58,7 @@
return null;
},
getDefaultValue() {
- if (this.valueIsEnum) return this.valueAvailableEnumValues[0];
- return null;
- },
- resolveValue(value) {
- if (!this.valueIsEnum) return value;
- return Object.keys(this.schema.value.values).find(key => this.schema.value.values[key] === value);
+ return this.availableEnumValues[0].value;
},
addElement() {
if ((!this.elementValue && this.elementValue !== 0) || (!this.elementKey && this.elementKey !== 0)) return;
diff --git a/src/components/ConfigFields/InputEnum.vue b/src/components/ConfigFields/InputEnum.vue
index 87cacd89d..10faf0ec7 100644
--- a/src/components/ConfigFields/InputEnum.vue
+++ b/src/components/ConfigFields/InputEnum.vue
@@ -4,9 +4,7 @@
@@ -21,13 +19,8 @@
name: 'input-enum',
mixins: [Input],
computed: {
- values() {
- return this.schema.values;
- },
- },
- methods: {
- isLastValue(value) {
- return value === Math.max(...Object.values(this.values));
+ enums() {
+ return Object.entries(this.schema['x-definition']).map(([label, value]) => ({ label, value }));
},
},
};
diff --git a/src/components/ConfigFields/InputFlag.vue b/src/components/ConfigFields/InputFlag.vue
index 7d37994a0..04528f684 100644
--- a/src/components/ConfigFields/InputFlag.vue
+++ b/src/components/ConfigFields/InputFlag.vue
@@ -4,11 +4,11 @@
@@ -37,13 +40,13 @@
},
computed: {
isString() {
- return ['string', 'uint64'].includes(this.schema.values.type);
+ return ['string'].includes(this.schema.items.type);
},
isNumber() {
- return ['uint32', 'uint16'].includes(this.schema.values.type);
+ return ['integer'].includes(this.schema.items.type);
},
errors() {
- if (Object.prototype.hasOwnProperty.call(validator, this.schema.values.type)) return validator[this.schema.values.type](this.element);
+ if (validator.hasOwnProperty(this.schema.items.type)) return validator[this.schema.items.type](this.element);
return [];
},
isValid() {
@@ -72,7 +75,7 @@
this.element = '';
},
onKeyDown($event) {
- const charCode = ($event.which) ? $event.which : $event.keyCode;
+ const charCode = $event.which ? $event.which : $event.keyCode;
if ([9, 13, 188, 32].includes(charCode)) {
this.addElement();
diff --git a/src/utils/fetchConfigSchema.js b/src/utils/fetchConfigSchema.js
deleted file mode 100644
index 69f0b5feb..000000000
--- a/src/utils/fetchConfigSchema.js
+++ /dev/null
@@ -1,115 +0,0 @@
-import * as http from '../plugins/http';
-
-const cachedTypeDefinitions = new Map();
-const cachedStructureDefinitions = new Map();
-
-const subtypeRegex = /\[[^\]]+]/g;
-
-function resolveSubtypes(type) {
- const subtypes = type.match(subtypeRegex);
- if (!subtypes) return [];
- return subtypes.map(subtype => subtype.slice(1, subtype.length - 1));
-}
-
-async function getStructureDefinition(type) {
- if (cachedStructureDefinitions.has(type)) return cachedStructureDefinitions.get(type);
-
- const structureDefinition = http.get(`structure/${encodeURIComponent(type)}`);
- cachedStructureDefinitions.set(type, structureDefinition);
-
- return structureDefinition;
-}
-
-async function getTypeDefinition(type) {
- if (cachedTypeDefinitions.has(type)) return cachedTypeDefinitions.get(type);
-
- const typeDefinition = http.get(`type/${encodeURIComponent(type)}`);
- cachedTypeDefinitions.set(type, typeDefinition);
-
- return typeDefinition;
-}
-
-async function resolveType(type) {
- const subtypes = resolveSubtypes(type);
-
- switch (type.split('`')[0]) {
- case 'System.Boolean':
- return { type: 'boolean' };
- case 'System.String':
- return { type: 'string' };
- case 'System.Byte':
- return { type: 'byte' };
- case 'System.UInt32':
- return { type: 'uint32' };
- case 'System.UInt16':
- return { type: 'uint16' };
- case 'System.Collections.Generic.HashSet':
- case 'System.Collections.Immutable.ImmutableHashSet':
- return { type: 'hashSet', values: await resolveType(subtypes[0]) };
- case 'System.Collections.Immutable.ImmutableList':
- return { type: 'list', values: await resolveType(subtypes[0]) };
- case 'System.UInt64':
- return { type: 'uint64' };
- case 'System.Collections.Generic.Dictionary':
- case 'System.Collections.Immutable.ImmutableDictionary':
- return { type: 'dictionary', key: await resolveType(subtypes[0]), value: await resolveType(subtypes[1]) };
- default: // Complex type
- return unwindType(type);
- }
-}
-
-async function unwindObject(type, typeDefinition) {
- const resolvedStructure = {
- type: 'object',
- body: {},
- };
-
- const [structureDefinition, resolvedTypes] = await Promise.all([
- getStructureDefinition(type),
- Promise.all(Object.keys(typeDefinition.Body).map(async param => ({ param, type: await resolveType(typeDefinition.Body[param]) }))),
- ]);
-
- for (const { param, type } of resolvedTypes) {
- const paramName = typeDefinition.Body[param] !== 'System.UInt64' ? param : `s_${param}`;
-
- resolvedStructure.body[param] = {
- defaultValue: structureDefinition[param],
- paramName,
- param,
- ...type,
- };
- }
-
- return resolvedStructure;
-}
-
-function parseEnumValues(rawValues) {
- const enumValues = {};
-
- for (const key of Object.keys(rawValues)) {
- enumValues[key] = parseInt(rawValues[key], 10);
- }
-
- return enumValues;
-}
-
-async function unwindType(type) {
- if (type === 'ArchiSteamFarm.BotConfig') getStructureDefinition(type); // Dirty trick, but 30% is 30%
- const typeDefinition = await getTypeDefinition(type);
-
- switch (typeDefinition.Properties.BaseType) {
- case 'System.Object':
- return unwindObject(type, typeDefinition);
- case 'System.Enum':
- return {
- type: (typeDefinition.Properties.CustomAttributes || []).includes('System.FlagsAttribute') ? 'flag' : 'enum',
- values: parseEnumValues(typeDefinition.Body),
- };
- default: {
- const structureDefinition = await getStructureDefinition(type);
- return { type: 'unknown', typeDefinition, structureDefinition };
- }
- }
-}
-
-export default unwindType;
diff --git a/src/utils/swagger/dereference.js b/src/utils/swagger/dereference.js
new file mode 100644
index 000000000..9bd8c378d
--- /dev/null
+++ b/src/utils/swagger/dereference.js
@@ -0,0 +1,23 @@
+import { cloneDeep, get, isObject } from 'lodash-es';
+
+function isRef(node) {
+ return node.$ref;
+}
+
+function resolveRef(path, schema) {
+ const lodashPath = path.substr(2).replace(/\//g, '.');
+ return get(schema, lodashPath);
+}
+
+function resolve(tree, schema) {
+ for (const key of Object.keys(tree)) {
+ if (isRef(tree[key])) tree[key] = resolveRef(tree[key].$ref, schema);
+ if (isObject(tree[key])) resolve(tree[key], schema);
+ }
+}
+
+export function dereference(schema) {
+ const localSchema = cloneDeep(schema);
+ resolve(localSchema, localSchema);
+ return localSchema;
+}
diff --git a/src/utils/swagger/parse.js b/src/utils/swagger/parse.js
new file mode 100644
index 000000000..73f3d9057
--- /dev/null
+++ b/src/utils/swagger/parse.js
@@ -0,0 +1,24 @@
+import axios from 'axios';
+import { dereference } from './dereference';
+
+const endpoint = 'http://localhost:8080/swagger/ASF/swagger.json';
+let schema;
+
+async function getSchema() {
+ if (schema) return schema;
+
+ // We save the PROMISE, not the VALUE, in a variable.
+ // This is very important, as ALL future calls will retrieve this promise (including those made while promise is still pending).
+ // Such approach, ensures no duplicated HTTP calls are made.
+ schema = axios.get(endpoint)
+ .then(response => response.data)
+ .then(schema => dereference(schema));
+
+ return schema
+}
+
+export async function getType(name) {
+ const schema = await getSchema()
+ const { [name]: type } = schema.components.schemas;
+ return type.properties;
+}
diff --git a/src/views/GlobalConfig.vue b/src/views/GlobalConfig.vue
index 10ef3c1f7..4c1b75a51 100644
--- a/src/views/GlobalConfig.vue
+++ b/src/views/GlobalConfig.vue
@@ -7,8 +7,7 @@
-
-
+