custom fields finish

This commit is contained in:
sadnub
2021-03-29 15:14:20 -04:00
parent 5d6e6f9441
commit 91f89f5a33
22 changed files with 419 additions and 100 deletions

View File

@@ -0,0 +1,19 @@
# Generated by Django 3.1.7 on 2021-03-29 02:51
import django.contrib.postgres.fields
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('agents', '0032_agentcustomfield'),
]
operations = [
migrations.AddField(
model_name='agentcustomfield',
name='multiple_value',
field=django.contrib.postgres.fields.ArrayField(base_field=models.TextField(blank=True, null=True), blank=True, default=list, null=True, size=None),
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 3.1.7 on 2021-03-29 03:01
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('agents', '0033_agentcustomfield_multiple_value'),
]
operations = [
migrations.AddField(
model_name='agentcustomfield',
name='checkbox_value',
field=models.BooleanField(blank=True, default=False),
),
]

View File

@@ -0,0 +1,23 @@
# Generated by Django 3.1.7 on 2021-03-29 17:09
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('agents', '0034_agentcustomfield_checkbox_value'),
]
operations = [
migrations.RenameField(
model_name='agentcustomfield',
old_name='checkbox_value',
new_name='bool_value',
),
migrations.RenameField(
model_name='agentcustomfield',
old_name='value',
new_name='string_value',
),
]

View File

@@ -5,6 +5,7 @@ import time
from collections import Counter
from distutils.version import LooseVersion
from typing import Any
from django.contrib.postgres.fields import ArrayField
import msgpack
import validators
@@ -851,4 +852,23 @@ class AgentCustomField(models.Model):
on_delete=models.CASCADE,
)
value = models.TextField(null=True, blank=True)
string_value = models.TextField(null=True, blank=True)
bool_value = models.BooleanField(blank=True, default=False)
multiple_value = ArrayField(
models.TextField(null=True, blank=True),
null=True,
blank=True,
default=list,
)
def __str__(self):
return self.field
@property
def value(self):
if self.field.type == "multiple":
return self.multiple_value
elif self.field.type == "checkbox":
return self.bool_value
else:
return self.string_value

View File

@@ -122,7 +122,20 @@ class AgentTableSerializer(serializers.ModelSerializer):
class AgentCustomFieldSerializer(serializers.ModelSerializer):
class Meta:
model = AgentCustomField
fields = "__all__"
fields = (
"id",
"field",
"agent",
"value",
"string_value",
"bool_value",
"multiple_value",
)
extra_kwargs = {
"string_value": {"write_only": True},
"bool_value": {"write_only": True},
"multiple_value": {"write_only": True},
}
class AgentEditSerializer(serializers.ModelSerializer):

View File

@@ -108,17 +108,9 @@ def edit_agent(request):
for field in request.data["custom_fields"]:
# get custom field for validation
obj = CustomField.objects.get(pk=field["field"])
custom_field = field
custom_field["agent"] = agent.id # type: ignore
if obj.default_value and field.value == obj.default_value:
continue
custom_field = {
"value": field["value"],
"field": field["field"],
"agent": agent.id, # type: ignore
}
if AgentCustomField.objects.filter(
field=field["field"], agent=agent.id # type: ignore
):

View File

@@ -0,0 +1,24 @@
# Generated by Django 3.1.7 on 2021-03-29 02:51
import django.contrib.postgres.fields
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('clients', '0012_deployment_created'),
]
operations = [
migrations.AddField(
model_name='clientcustomfield',
name='multiple_value',
field=django.contrib.postgres.fields.ArrayField(base_field=models.TextField(blank=True, null=True), blank=True, default=list, null=True, size=None),
),
migrations.AddField(
model_name='sitecustomfield',
name='multiple_value',
field=django.contrib.postgres.fields.ArrayField(base_field=models.TextField(blank=True, null=True), blank=True, default=list, null=True, size=None),
),
]

View File

@@ -0,0 +1,23 @@
# Generated by Django 3.1.7 on 2021-03-29 03:01
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('clients', '0013_auto_20210329_0251'),
]
operations = [
migrations.AddField(
model_name='clientcustomfield',
name='checkbox_value',
field=models.BooleanField(blank=True, default=False),
),
migrations.AddField(
model_name='sitecustomfield',
name='checkbox_value',
field=models.BooleanField(blank=True, default=False),
),
]

View File

@@ -0,0 +1,27 @@
# Generated by Django 3.1.7 on 2021-03-29 17:09
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('clients', '0014_auto_20210329_0301'),
]
operations = [
migrations.RenameField(
model_name='clientcustomfield',
old_name='checkbox_value',
new_name='bool_value',
),
migrations.RenameField(
model_name='clientcustomfield',
old_name='value',
new_name='string_value',
),
migrations.RemoveField(
model_name='sitecustomfield',
name='value',
),
]

View File

@@ -0,0 +1,23 @@
# Generated by Django 3.1.7 on 2021-03-29 18:27
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('clients', '0015_auto_20210329_1709'),
]
operations = [
migrations.RenameField(
model_name='sitecustomfield',
old_name='checkbox_value',
new_name='bool_value',
),
migrations.AddField(
model_name='sitecustomfield',
name='string_value',
field=models.TextField(blank=True, null=True),
),
]

View File

@@ -1,6 +1,7 @@
import uuid
from django.db import models
from django.contrib.postgres.fields import ArrayField
from agents.models import Agent
from logs.models import BaseAuditModel
@@ -250,7 +251,26 @@ class ClientCustomField(models.Model):
on_delete=models.CASCADE,
)
value = models.TextField(null=True, blank=True)
string_value = models.TextField(null=True, blank=True)
bool_value = models.BooleanField(blank=True, default=False)
multiple_value = ArrayField(
models.TextField(null=True, blank=True),
null=True,
blank=True,
default=list,
)
def __str__(self):
return self.field.name
@property
def value(self):
if self.field.type == "multiple":
return self.multiple_value
elif self.field.type == "checkbox":
return self.bool_value
else:
return self.string_value
class SiteCustomField(models.Model):
@@ -266,4 +286,23 @@ class SiteCustomField(models.Model):
on_delete=models.CASCADE,
)
value = models.TextField(null=True, blank=True)
string_value = models.TextField(null=True, blank=True)
bool_value = models.BooleanField(blank=True, default=False)
multiple_value = ArrayField(
models.TextField(null=True, blank=True),
null=True,
blank=True,
default=list,
)
def __str__(self):
return self.field.name
@property
def value(self):
if self.field.type == "multiple":
return self.multiple_value
elif self.field.type == "checkbox":
return self.bool_value
else:
return self.string_value

View File

@@ -6,7 +6,20 @@ from .models import Client, ClientCustomField, Deployment, Site, SiteCustomField
class SiteCustomFieldSerializer(ModelSerializer):
class Meta:
model = SiteCustomField
fields = "__all__"
fields = (
"id",
"field",
"site",
"value",
"string_value",
"bool_value",
"multiple_value",
)
extra_kwargs = {
"string_value": {"write_only": True},
"bool_value": {"write_only": True},
"multiple_value": {"write_only": True},
}
class SiteSerializer(ModelSerializer):
@@ -35,7 +48,20 @@ class SiteSerializer(ModelSerializer):
class ClientCustomFieldSerializer(ModelSerializer):
class Meta:
model = ClientCustomField
fields = "__all__"
fields = (
"id",
"field",
"client",
"value",
"string_value",
"bool_value",
"multiple_value",
)
extra_kwargs = {
"string_value": {"write_only": True},
"bool_value": {"write_only": True},
"multiple_value": {"write_only": True},
}
class ClientSerializer(ModelSerializer):

View File

@@ -57,11 +57,10 @@ class GetAddClients(APIView):
# save custom fields
if "custom_fields" in request.data.keys():
for field in request.data["custom_fields"]:
custom_field = {
"value": field["value"],
"field": field["field"],
"client": client.id,
}
custom_field = field
custom_field["client"] = client.id
serializer = ClientCustomFieldSerializer(data=custom_field)
serializer.is_valid(raise_exception=True)
serializer.save()
@@ -87,17 +86,9 @@ class GetUpdateClient(APIView):
if "custom_fields" in request.data.keys():
for field in request.data["custom_fields"]:
# get custom field for validation
obj = CustomField.objects.get(pk=field["field"])
custom_field = field
custom_field["client"] = pk
if obj.default_value and field.value == obj.default_value:
continue
custom_field = {
"value": field["value"],
"field": field["field"],
"client": pk,
}
if ClientCustomField.objects.filter(field=field["field"], client=pk):
value = ClientCustomField.objects.get(
field=field["field"], client=pk
@@ -158,11 +149,8 @@ class GetAddSites(APIView):
for field in request.data["custom_fields"]:
custom_field = {
"value": field["value"],
"field": field["field"],
"site": site.id,
}
custom_field = field
custom_field["site"] = site.id
serializer = SiteCustomFieldSerializer(data=custom_field)
serializer.is_valid(raise_exception=True)
@@ -194,17 +182,9 @@ class GetUpdateSite(APIView):
for field in request.data["custom_fields"]:
# get custom field for validation
obj = CustomField.objects.get(pk=field["field"])
custom_field = field
custom_field["site"] = pk
if obj.default_value and field.value == obj.default_value:
continue
custom_field = {
"value": field["value"],
"field": field["field"],
"site": pk,
}
if SiteCustomField.objects.filter(field=field["field"], site=pk):
value = SiteCustomField.objects.get(field=field["field"], site=pk)
serializer = SiteCustomFieldSerializer(

View File

@@ -0,0 +1,23 @@
# Generated by Django 3.1.7 on 2021-03-29 17:09
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('core', '0017_auto_20210329_1050'),
]
operations = [
migrations.RenameField(
model_name='customfield',
old_name='checkbox_value',
new_name='default_value_bool',
),
migrations.RenameField(
model_name='customfield',
old_name='default_value',
new_name='default_value_string',
),
]

View File

@@ -242,9 +242,9 @@ class CustomField(models.Model):
default=list,
)
name = models.TextField(null=True, blank=True)
default_value = models.TextField(null=True, blank=True)
required = models.BooleanField(blank=True, default=False)
checkbox_value = models.BooleanField(default=False)
default_value_string = models.TextField(null=True, blank=True)
default_value_bool = models.BooleanField(default=False)
default_values_multiple = ArrayField(
models.CharField(max_length=255, null=True, blank=True),
null=True,
@@ -257,3 +257,12 @@ class CustomField(models.Model):
def __str__(self):
return self.name
@property
def default_value(self):
if self.type == "multiple":
return self.default_values_multiple
elif self.type == "checkbox":
return self.default_value_bool
else:
return self.default_value_string

View File

@@ -1,24 +1,12 @@
<template>
<q-input
v-if="field.type === 'text'"
v-if="field.type === 'text' || field.type === 'number'"
ref="input"
outlined
dense
:label="field.name"
type="text"
:value="value"
@input="value => $emit('input', value)"
:rules="[...validationRules]"
reactive-rules
/>
<q-input
v-else-if="field.type === 'number'"
ref="input"
outlined
dense
:label="field.name"
type="number"
:type="field.type === 'text' ? 'text' : 'number'"
:hint="hintText(field)"
:value="value"
@input="value => $emit('input', value)"
:rules="[...validationRules]"
@@ -27,16 +15,29 @@
<q-toggle
v-else-if="field.type === 'checkbox'"
ref="input"
:label="field.name"
:hint="hintText(field)"
:value="value"
@input="value => $emit('input', value)"
/>
<q-input v-else-if="field.type === 'datetime'" outlined dense :value="value" @input="value => $emit('input', value)">
<q-input
v-else-if="field.type === 'datetime'"
ref="input"
:label="field.name"
:hint="hintText(field)"
outlined
dense
:value="value"
@input="value => $emit('input', value)"
:rules="[...validationRules]"
reactive-rules
>
<template v-slot:append>
<q-icon name="event" class="cursor-pointer">
<q-popup-proxy transition-show="scale" transition-hide="scale">
<q-date v-model="value" mask="YYYY-MM-DD HH:mm">
<q-date :value="value" @input="value => $emit('input', value)" mask="YYYY-MM-DD HH:mm">
<div class="row items-center justify-end">
<q-btn v-close-popup label="Close" color="primary" flat />
</div>
@@ -45,7 +46,7 @@
</q-icon>
<q-icon name="access_time" class="cursor-pointer">
<q-popup-proxy transition-show="scale" transition-hide="scale">
<q-time v-model="value" mask="YYYY-MM-DD HH:mm">
<q-time :value="value" @input="value => $emit('input', value)" mask="YYYY-MM-DD HH:mm">
<div class="row items-center justify-end">
<q-btn v-close-popup label="Close" color="primary" flat />
</div>
@@ -57,14 +58,18 @@
<q-select
v-else-if="field.type === 'single' || field.type === 'multiple'"
ref="input"
:value="value"
@input="value => $emit('input', value)"
outlined
dense
:hint="hintText(field)"
:label="field.name"
:options="field.options"
:multiple="field.type === 'multiple'"
:rules="[...validationRules]"
reactive-rules
clearable
/>
</template>
@@ -76,6 +81,13 @@ export default {
validate(...args) {
return this.$refs.input.validate(...args);
},
hintText(field) {
if (field.type === "multiple")
return field.default_values_multiple.length > 0 ? `Default value: ${field.default_values_multiple}` : "";
else if (field.type === "checkbox")
return field.default_value_bool ? `Default value: ${field.default_value_bool}` : "";
else return field.default_value_string ? `Default value: ${field.default_value_string}` : "";
},
},
computed: {
validationRules() {

View File

@@ -131,6 +131,7 @@
<q-checkbox v-model="agent.overdue_email_alert" label="Get overdue email alerts" />
<q-checkbox v-model="agent.overdue_text_alert" label="Get overdue sms alerts" />
</q-card-section>
<div class="text-h6">Custom Fields</div>
<q-card-section v-for="field in customFields" :key="field.id">
<CustomField v-model="custom_fields[field.name]" :field="field" />
</q-card-section>
@@ -202,9 +203,16 @@ export default {
for (let field of this.customFields) {
const value = r.data.custom_fields.find(value => value.field === field.id);
if (!!value) this.$set(this.custom_fields, field.name, value.value);
else if (!!field.default_value) this.$set(this.custom_fields, field.name, field.default_value);
else this.$set(this.custom_fields, field.name, "");
if (field.type === "multiple") {
if (value) this.$set(this.custom_fields, field.name, value.value);
else this.$set(this.custom_fields, field.name, []);
} else if (field.type === "checkbox") {
if (value) this.$set(this.custom_fields, field.name, value.value);
else this.$set(this.custom_fields, field.name, false);
} else {
if (value) this.$set(this.custom_fields, field.name, value.value);
else this.$set(this.custom_fields, field.name, "");
}
}
});
},
@@ -242,7 +250,10 @@ export default {
this.$emit("edited");
this.notifySuccess("Agent was edited!");
})
.catch(() => this.notifyError("Something went wrong"));
.catch(e => {
this.notifyError("Something went wrong")
console.log({e})
});
},
},
computed: {

View File

@@ -110,6 +110,7 @@ export default {
custom_fields: this.formatCustomFields(this.customFields, this.custom_fields),
};
console.log(data);
this.$axios
.put(`/clients/${this.client.id}/client/`, data)
.then(r => {
@@ -138,9 +139,16 @@ export default {
for (let field of this.customFields) {
const value = r.data.custom_fields.find(value => value.field === field.id);
if (!!value) this.$set(this.custom_fields, field.name, value.value);
else if (!!field.default_value) this.$set(this.custom_fields, field.name, field.default_value);
else this.$set(this.custom_fields, field.name, "");
if (field.type === "multiple") {
if (value) this.$set(this.custom_fields, field.name, value.value);
else this.$set(this.custom_fields, field.name, []);
} else if (field.type === "checkbox") {
if (value) this.$set(this.custom_fields, field.name, value.value);
else this.$set(this.custom_fields, field.name, false);
} else {
if (value) this.$set(this.custom_fields, field.name, value.value);
else this.$set(this.custom_fields, field.name, "");
}
}
})
.catch(e => {

View File

@@ -142,9 +142,27 @@ export default {
for (let field of this.customFields) {
const value = r.data.custom_fields.find(value => value.field === field.id);
if (!!value) this.$set(this.custom_fields, field.name, value.value);
else if (!!field.default_value) this.$set(this.custom_fields, field.name, field.default_value);
else this.$set(this.custom_fields, field.name, "");
// Set correct value for custom field
if (
field.type === "text" ||
field.type === "number" ||
field.type === "datetime" ||
field.type === "single"
) {
if (!!value) this.$set(this.custom_fields, field.name, value.value);
else if (!!field.default_value) this.$set(this.custom_fields, field.name, field.default_value);
else this.$set(this.custom_fields, field.name, "");
} else if (field.type === "multiple") {
if (!!value) this.$set(this.custom_fields, field.name, value.multiple_value);
else if (!!field.multiple_default_value)
this.$set(this.custom_fields, field.name, field.multiple_default_value);
else this.$set(this.custom_fields, field.name, []);
} else if (field.type === "checkbox") {
if (!!value) this.$set(this.custom_fields, field.name, value.checkbox_value);
else if (!!field.checkbox_default_value)
this.$set(this.custom_fields, field.name, field.checkbox_default_value);
else this.$set(this.custom_fields, field.name, false);
}
}
})
.catch(e => {

View File

@@ -9,6 +9,7 @@
</q-btn>
</q-bar>
<q-form @submit="submit">
<!-- model select -->
<q-card-section>
<q-select
label="Target"
@@ -17,13 +18,16 @@
emit-value
outlined
dense
:disable="editing"
v-model="localField.model"
:rules="[val => !!val || '*Required']"
/>
</q-card-section>
<!-- name -->
<q-card-section>
<q-input label="Name" outlined dense v-model="localField.name" :rules="[val => !!val || '*Required']" />
</q-card-section>
<!-- type select -->
<q-card-section>
<q-select
label="Field Type"
@@ -33,10 +37,12 @@
emit-value
outlined
dense
:disable="editing"
v-model="localField.type"
:rules="[val => !!val || '*Required']"
/>
</q-card-section>
<!-- input options select for single and multiple input type -->
<q-card-section v-if="localField.type === 'single' || localField.type == 'multiple'">
<q-select
dense
@@ -48,27 +54,29 @@
multiple
hide-dropdown-icon
input-debounce="0"
new-value-mode="add"
new-value-mode="add-unique"
@input="
localField.default_value = '';
localField.default_value_string = '';
localField.default_values_multiple = [];
"
/>
</q-card-section>
<q-card-section>
<!-- default value -->
<q-card-section v-if="!!localField.type">
<!-- For datetime field -->
<q-input
v-if="localField.type === 'datetime'"
outlined
dense
v-model="localField.default_value"
label="Default Value"
v-model="localField.default_value_string"
:rules="[...defaultValueRules]"
reactive-rules
>
<template v-slot:append>
<q-icon name="event" class="cursor-pointer">
<q-popup-proxy transition-show="scale" transition-hide="scale">
<q-date v-model="localField.default_value" mask="YYYY-MM-DD HH:mm">
<q-date v-model="localField.default_value_string" mask="YYYY-MM-DD HH:mm">
<div class="row items-center justify-end">
<q-btn v-close-popup label="Close" color="primary" flat />
</div>
@@ -77,7 +85,7 @@
</q-icon>
<q-icon name="access_time" class="cursor-pointer">
<q-popup-proxy transition-show="scale" transition-hide="scale">
<q-time v-model="localField.default_value" mask="YYYY-MM-DD HH:mm">
<q-time v-model="localField.default_value_string" mask="YYYY-MM-DD HH:mm">
<div class="row items-center justify-end">
<q-btn v-close-popup label="Close" color="primary" flat />
</div>
@@ -91,7 +99,7 @@
<q-toggle
v-else-if="localField.type == 'checkbox'"
label="Default Value"
v-model="localField.checkbox_value"
v-model="localField.default_value_bool"
color="green"
/>
@@ -102,7 +110,7 @@
:options="localField.options"
outlined
dense
v-model="localField.default_value"
v-model="localField.default_value_string"
:rules="[...defaultValueRules]"
reactive-rules
/>
@@ -127,7 +135,7 @@
:type="localField.type === 'text' ? 'text' : 'number'"
outlined
dense
v-model="localField.default_value"
v-model="localField.default_value_string"
:rules="[...defaultValueRules]"
reactive-rules
/>
@@ -163,9 +171,9 @@ export default {
model: "",
type: "",
options: [],
default_value: "",
required: false,
checkbox_value: false,
default_value_string: "",
default_value_bool: false,
default_values_multiple: [],
},
modelOptions: [
@@ -200,8 +208,6 @@ export default {
submit() {
this.$q.loading.show();
if (this.localField.type === "multiple") delete this.localField.default_value;
let data = {
...this.localField,
};
@@ -229,15 +235,17 @@ export default {
})
.catch(e => {
this.$q.loading.hide();
console.log({ e });
this.notifyError("There was an error adding the custom field");
});
}
},
clear() {
this.localField.options = [];
this.localField.default_value =
this.localField.type === "single" || this.localField.type === "multiple" ? [] : "";
this.localField.required = false;
this.localField.default_value_string = "";
this.localField.default_values_multiple = [];
this.localField.default_value_bool = false;
},
show() {
this.$refs.dialog.show();

View File

@@ -48,17 +48,17 @@
</q-td>
<!-- type -->
<q-td>
{{ props.row.type }}
{{ capitalize(props.row.type) }}
</q-td>
<!-- default value -->
<q-td v-if="props.row.type === 'checkbox'">
{{ props.row.checkbox_value }}
{{ props.row.default_value_bool }}
</q-td>
<q-td v-else-if="props.row.type === 'multiple'">
{{ props.row.default_values_multiple }}
<span v-if="props.row.default_values_multiple.length > 0">{{ props.row.default_values_multiple }}</span>
</q-td>
<q-td v-else>
{{ props.row.default_value }}
{{ props.row.default_value_string }}
</q-td>
<!-- required -->
<q-td>
@@ -100,7 +100,6 @@ export default {
field: "type",
align: "left",
sortable: true,
format: string => this.capitalize(string),
},
{ name: "default_value", label: "Default Value", field: "default_value", align: "left", sortable: true },
{ name: "required", label: "Required", field: "required", align: "left", sortable: true },

View File

@@ -151,12 +151,16 @@ export default {
let tempArray = []
for (let field of fields) {
let obj = { value: values[field.name], field: field.id }
tempArray.push(obj)
if (values[field.name] !== null || values[field.name] !== undefined)
if (field.type === "multiple") {
tempArray.push({ multiple_value: values[field.name], field: field.id })
} else if (field.type === "checkbox") {
tempArray.push({ bool_value: values[field.name], field: field.id })
} else {
tempArray.push({ string_value: values[field.name], field: field.id })
}
}
return tempArray
},
}
};