Started using htmx for dynmical fileds, now need to implment it sitewide, or make an formular for address only let's see

master
Kerem Yollu 10 months ago
parent 81b21bc69b
commit a3858ff048

79
web/$

@ -0,0 +1,79 @@
from flask import render_template, url_for, flash, redirect, request, Blueprint
from flask_login import login_required, current_user
from minibase.app import db
import minibase.theme as theme
from minibase.blueprints.company.models import Companies
import minibase.blueprints.database.utils as dbUtils
import minibase.blueprints.main.utils as mainUtils
import minibase.blueprints.geography.utils as geoUtils
import minibase.blueprints.company.utils as companyUtils
from minibase.blueprints.company.forms import updateCompanyForm
from minibase.blueprints.user.utils import save_picture
from flask_wtf import FlaskForm
# Declaring a blueprint
company = Blueprint('company', __name__, template_folder='templates')
@company.route("/list", methods=['GET', 'POST'])
def list():
page=request.args.get('page', 1, type=int)
table=dbUtils.table_printable_paginate(Companies, page, 20, 'edit/', 'id')
return(render_template('view.html', theme=theme, table=table, title="Companies"))
@company.route("/edit/<int:companyId>", methods=['GET', 'POST'])
@login_required
def edit_company(companyId):
if id:
form = updateCompanyForm()
company = companyUtils.queryById(companyId)
form.city.choices = [(row.id, row.name) for row in geoUtils.queryCiytNamesOfStateWithDefId(company.city_id, company.state_id)]
form.state.choices = [(row.id, row.name) for row in geoUtils.queryStateNamesOfCuntryWithDefId(company.state_id, company.country_id)]
form.country.choices = [(row.id, row.name) for row in geoUtils.queryCountryNamesWithDefault(company.country_id)]
form.industry.choices = [(row.id, row.name) for row in mainUtils.queryIndustryNamesWithDefault(company.industry_id)]
form.legal_entity.choices = [(row.id, row.name) for row in companyUtils.queryLegalEntityNames()]
form.type.choices = [(row.id, row.name) for row in companyUtils.queryTypeNames()]
form.relation.choices = [(row.id, row.name) for row in companyUtils.queryRelationNames()]
form.status.choices = [(row.id, row.name) for row in companyUtils.queryStatusNames()]
if form.validate_on_submit():
comp = Companies(
name = form.name.data,
street = form.street.data,
website = form.website.data,
street_no = form.street_no.data,
post_code = form.post_code.data,
city_id = form.city.data,
state_id = form.state.data,
country_id = form.country.data,
industry_id = form.industry.data,
legal_entity_id = form.legal_entity.data,
type_id = form.type.data,
relation_id = form.relation.data,
status_id = form.status.data,
comment = form.comment.data)
flash('Company Has been successfully updated', 'success')
return redirect(url_for('company.edit', companyId))
elif request.method == 'GET':
form.name.data = company.name
form.website.data = company.website
form.street.data = company.street
form.street_no.data = company.street_no
form.post_code.data = company.post_code
form.comment.data = company.comment
# This could be very interesting but neds more time to think !
#for field in form:
# if field.name != 'csrf_token' and hasattr(company, field.name):
# attr = getattr(company, field.name)
# field.data = attr
image_file = url_for('static', filename='pics/' + companyUtils.queryImageById(companyId))
return render_template('company/account.html',
theme=theme,
image_file=image_file,
form=form)
else:
flash('You need to select a company id', 'alarm')
return redirect(url_for('company.list'))

@ -49,6 +49,7 @@ def create_app():
from minibase.blueprints.user.routes import user from minibase.blueprints.user.routes import user
from minibase.blueprints.errors.routes import errors from minibase.blueprints.errors.routes import errors
from minibase.blueprints.company.routes import company from minibase.blueprints.company.routes import company
from minibase.blueprints.geography.routes import geography
# (BLUEPRINTS) Registering the blueprints. # (BLUEPRINTS) Registering the blueprints.
# Giving them theie ulr_prefixes that will define their links on the webBrowser. # Giving them theie ulr_prefixes that will define their links on the webBrowser.
@ -56,6 +57,7 @@ def create_app():
app.register_blueprint(user, url_prefix='/user') app.register_blueprint(user, url_prefix='/user')
app.register_blueprint(errors, url_prefix='/errors') app.register_blueprint(errors, url_prefix='/errors')
app.register_blueprint(company, url_prefix='/company') app.register_blueprint(company, url_prefix='/company')
app.register_blueprint(geography, url_prefix='/geography')
# (APP) Returning the initialised app # (APP) Returning the initialised app
return app return app

@ -8,12 +8,12 @@ class updateCompanyForm(FlaskForm): # Defines the form class to be used for the
name = StringField('Name', validators=[DataRequired(), Length(min=3, max=100)]) name = StringField('Name', validators=[DataRequired(), Length(min=3, max=100)])
website = URLField('Website', validators=[DataRequired(), Length(min=3, max=100)]) website = URLField('Website', validators=[DataRequired(), Length(min=3, max=100)])
country = SelectField('Country', validators=[DataRequired()])
city = SelectField('City', validators=[DataRequired()])
post_code = IntegerField('Post', validators=[DataRequired()])
state = SelectField('State', validators=[])
street = StringField('Street', validators=[DataRequired()]) street = StringField('Street', validators=[DataRequired()])
street_no = IntegerField('No', validators=[DataRequired()]) street_no = IntegerField('No', validators=[DataRequired()])
post_code = IntegerField('Post', validators=[DataRequired()])
city = SelectField('City', validators=[DataRequired()])
state = SelectField('State', validators=[DataRequired()])
country = SelectField('Country', validators=[DataRequired()])
industry = SelectField('Industry', validators=[DataRequired()]) industry = SelectField('Industry', validators=[DataRequired()])
legal_entity= SelectField('Legal Entity', validators=[DataRequired()]) legal_entity= SelectField('Legal Entity', validators=[DataRequired()])
type = SelectField('Type', validators=[DataRequired()]) type = SelectField('Type', validators=[DataRequired()])
@ -25,7 +25,6 @@ class updateCompanyForm(FlaskForm): # Defines the form class to be used for the
submit = SubmitField('Update') submit = SubmitField('Update')
# Queries to be made in order to validate the form : If username exists # Queries to be made in order to validate the form : If username exists
def validate_companyName(self, company_name): def validate_companyName(self, company_name):
company = companyUtils.queryByNameFirst(company_name) company = companyUtils.queryByNameFirst(company_name)

@ -15,7 +15,7 @@ from flask_wtf import FlaskForm
# Declaring a blueprint # Declaring a blueprint
company = Blueprint('company', __name__, template_folder='templates') company = Blueprint('company', __name__, template_folder='templates')
@company.route("/list", methods=['GET', 'POST']) @company.route("/", methods=['GET', 'POST'])
def list(): def list():
page=request.args.get('page', 1, type=int) page=request.args.get('page', 1, type=int)
table=dbUtils.table_printable_paginate(Companies, page, 20, 'edit/', 'id') table=dbUtils.table_printable_paginate(Companies, page, 20, 'edit/', 'id')
@ -25,58 +25,57 @@ def list():
@company.route("/edit/<int:companyId>", methods=['GET', 'POST']) @company.route("/edit/<int:companyId>", methods=['GET', 'POST'])
@login_required @login_required
def edit_company(companyId): def edit_company(companyId):
if id: if companyId:
company = Companies.query.get_or_404(companyId)
form = updateCompanyForm() form = updateCompanyForm()
company = companyUtils.queryById(companyId)
form.city.choices = [(row.id, row.name) for row in geoUtils.queryCiytNamesOfStateWithDefId(company.city_id, company.state_id)] form.city.choices = [(row.id, row.name) for row in geoUtils.queryCiytNamesOfStateWithDefId(company.city_id, company.state_id)]
form.state.choices = [(row.id, row.name) for row in geoUtils.queryStateNamesOfCuntryWithDefId(company.state_id, company.country_id)] form.state.choices = [(row.id, row.name) for row in geoUtils.queryStateNamesOfCuntryWithDefId(company.state_id, company.country_id)]
form.country.choices = [(row.id, row.name) for row in geoUtils.queryCountryNamesWithDefault(company.country_id)] form.country.choices = [(row.id, row.name) for row in geoUtils.queryCountryNamesWithDefault(company.country_id)]
form.industry.choices = [(row.id, row.name) for row in mainUtils.queryIndustryNamesWithDefault(company.industry_id)] form.industry.choices = [(row.id, row.name) for row in mainUtils.queryIndustryNamesWithDefault(company.industry_id)]
form.legal_entity.choices = [(row.id, row.name) for row in companyUtils.queryLegalEntityNames()] form.legal_entity.choices = [(row.id, row.name) for row in companyUtils.queryLegalEntityNamesWithDefault(company.legal_entity_id)]
form.type.choices = [(row.id, row.name) for row in companyUtils.queryTypeNames()] form.type.choices = [(row.id, row.name) for row in companyUtils.queryTypeNamesWithDefault(company.type_id)]
form.relation.choices = [(row.id, row.name) for row in companyUtils.queryRelationNames()] form.relation.choices = [(row.id, row.name) for row in companyUtils.queryRelationNamesWithDefault(company.relation_id)]
form.status.choices = [(row.id, row.name) for row in companyUtils.queryStatusNames()] form.status.choices = [(row.id, row.name) for row in companyUtils.queryStatusNamesWithDefault(company.status_id)]
if form.validate_on_submit(): if form.validate_on_submit():
comp = Companies( company.name = form.name.data
name = form.name.data, company.street = form.street.data
street = form.street.data, company.website = form.website.data
website = form.website.data, company.street_no = form.street_no.data
street_no = form.street_no.data, company.post_code = form.post_code.data
post_code = form.post_code.data, company.city_id = form.city.data
city_id = form.city.data, company.state_id = form.state.data
state_id = form.state.data, company.country_id = form.country.data
country_id = form.country.data, company.industry_id = form.industry.data
industry_id = form.industry.data, company.legal_entity_id = form.legal_entity.data
legal_entity_id = form.legal_entity.data, company.type_id = form.type.data
type_id = form.type.data, company.relation_id = form.relation.data
relation_id = form.relation.data, company.status_id = form.status.data
status_id = form.status.data, company.comment = form.comment.data
comment = form.comment.data) flash('Company Has been successfully updated', 'success')
flash('Company Has been successfully updated', 'success') return redirect(url_for('company.edit', companyId=companyId))
return redirect(url_for('company.edit', companyId))
elif request.method == 'GET': elif request.method == 'GET':
form.name.data = company.name form.name.data = company.name
form.website.data = company.website form.website.data = company.website
form.street.data = company.street form.street.data = company.street
form.street_no.data = company.street_no form.street_no.data = company.street_no
form.post_code.data = company.post_code form.post_code.data = company.post_code
form.comment.data = company.comment form.comment.data = company.comment
# This could be very interesting but neds more time to think ! form.legal_entity.data = company.legal_entity.name
#for field in form: form.type.data = company.type.name
# if field.name != 'csrf_token' and hasattr(company, field.name):
# attr = getattr(company, field.name)
# field.data = attr
image_file = url_for('static', filename='pics/' + companyUtils.queryImageById(companyId))
mylist = [['name','website','industry'], ['street','street_no','city','state','country'], 'timestamp'] image_file = url_for('static', filename='pics/' + companyUtils.queryImageById(companyId))
return render_template('company/account.html', return render_template('company/account.html',
theme=theme, theme=theme,
image_file=image_file, image_file=image_file,
itemList=mylist,
form=form) form=form)
else: else:
flash('You need to select a company id', 'alarm') flash('You need to select a company id', 'alarm')
return redirect(url_for('company.list')) return redirect(url_for('company./'))
# This could be very interesting but neds more time to think !
#for field in form:
# if field.name != 'csrf_token' and hasattr(company, field.name):
# attr = getattr(company, field.name)
# field.data = attr

@ -1,4 +1,5 @@
from minibase.blueprints.company.models import Companies, Company_legal_entities, Company_types, Company_status, Company_relations from minibase.blueprints.company.models import Companies, Company_legal_entities, Company_types, Company_status, Company_relations
import minibase.blueprints.database.utils as dbUtils
def queryByNameFirst(cname): def queryByNameFirst(cname):
@ -34,16 +35,36 @@ def queryLegalEntityNames():
return choices return choices
def queryLegalEntityNamesWithDefault(defId):
choices = dbUtils.queryNameWithDefaultId(Company_legal_entities, defId)
return choices
def queryTypeNames(): def queryTypeNames():
choices = Company_types.query.order_by(Company_types.name.asc()) choices = Company_types.query.order_by(Company_types.name.asc())
return choices return choices
def queryTypeNamesWithDefault(defId):
choices = dbUtils.queryNameWithDefaultId(Company_types, defId)
return choices
def queryRelationNames(): def queryRelationNames():
choices = Company_relations.query.order_by(Company_relations.name.asc()) choices = Company_relations.query.order_by(Company_relations.name.asc())
return choices return choices
def queryRelationNamesWithDefault(defId):
choices = dbUtils.queryNameWithDefaultId(Company_relations, defId)
return choices
def queryStatusNames(): def queryStatusNames():
choices = Company_status.query.order_by(Company_status.name.asc()) choices = Company_status.query.order_by(Company_status.name.asc())
return choices return choices
def queryStatusNamesWithDefault(defId):
choices = dbUtils.queryNameWithDefaultId(Company_status, defId)
return choices

@ -0,0 +1,11 @@
from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileAllowed
from wtforms import StringField, SubmitField, URLField, IntegerField, SelectField
from wtforms.validators import DataRequired, Length, Email, EqualTo, ValidationError
import minibase.blueprints.company.utils as companyUtils
class LocationForm(FlaskForm):
country = SelectField('Country', validators=[DataRequired()])
city = SelectField('City', validators=[DataRequired()])
submit = SubmitField('Update')

@ -0,0 +1,52 @@
from flask import render_template, url_for, flash, redirect, request, Blueprint
from minibase.app import db
import minibase.theme as theme
import minibase.blueprints.database.utils as dbUtils
import minibase.blueprints.main.utils as mainUtils
import minibase.blueprints.geography.utils as geoUtils
from minibase.blueprints.geography.models import City, State
from minibase.blueprints.geography.forms import LocationForm
from flask_wtf import FlaskForm
# Declaring a blueprint
geography = Blueprint('geography', __name__, template_folder='templates')
@geography.route('/test', methods=["GET", "POST"])
def test():
print("hello")
form = LocationForm()
form.country.choices = [(row.id, row.name) for row in geoUtils.queryCountryNamesWithDefault(-1)]
if form.country.data:
form.city.choices = [(row.id, row.name) for row in geoUtils.queryCiytNamesOfStateWithDefId(form.country.data.id)]
else:
form.city.choices = [(row.id, row.name) for row in City.query.filter(None).all()]
if form.validate_on_submit():
print(form.country.data.name)
print(form.city.data.name)
return render_template("geography/index.html",
form=form,
theme=theme)
@geography.route("/get_cities", methods=['GET', 'POST'])
def get_cities():
country_id = request.args.get("country", type=int)
cities = City.query.filter_by(country_id=country_id).all()
print(len(cities))
if len(cities) == 0:
cities = 'Non Awailable'
return render_template("geography/city_options.html", cities=cities)
@geography.route("/get_states", methods=['GET', 'POST'])
def get_states():
country_id = request.args.get("country", type=int)
cities = State.query.filter_by(country_id=country_id).all()
print(len(cities))
if len(cities) == 0:
cities = 'Non Awailable'
return render_template("geography/city_options.html", cities=cities)

@ -0,0 +1,3 @@
{% for city in cities %}
<option value="{{ city.id }}">{{ city.name }}</option>
{% endfor %}

@ -0,0 +1,12 @@
{% extends "base.html" %}
{% block content %}
<form method="POST" action="" enctype="multipart/form-data">>
<fieldset class="form-group">
{{ form.hidden_tag() }}
{{ form.country(**{"hx-get": "get_cities", "hx-target": "#city"}) }}
{{ form.city }}
<button>Submit</button>
</fieldset>
</form>
{% endblock content %}

@ -2,12 +2,14 @@ from minibase.blueprints.geography.models import Country, City, State, Region, S
import minibase.blueprints.database.utils as dbUtils import minibase.blueprints.database.utils as dbUtils
from sqlalchemy import case from sqlalchemy import case
def queryCountryNames(): def queryCountryNames():
choices = Country.query.order_by(Country.name.asc()) choices = Country.query.order_by(Country.name.asc())
return choices return choices
def queryCountryNamesWithDefault(defId): def queryCountryNamesWithDefault(defId):
choices = dbUtils.queryNameWithDefaultId(Country,defId) choices = dbUtils.queryNameWithDefaultId(Country, defId)
return choices return choices
@ -15,8 +17,15 @@ def queryStateNames():
choices = State.query.order_by(State.name.asc()) choices = State.query.order_by(State.name.asc())
return choices return choices
def queryStateNamesWithDefault(defId): def queryStateNamesWithDefault(defId):
choices = dbUtils.queryNameWithDefaultId(State,defId) choices = dbUtils.queryNameWithDefaultId(State, defId)
return choices
def queryStateNamesOfCuntryWithDefId(defId, Filterid):
table = State
choices = table.query.order_by(case((table.id == defId, 0), else_=1), table.name.asc()).filter_by(country_id=Filterid)
return choices return choices
@ -24,16 +33,13 @@ def queryCityNames():
choices = City.query.order_by(City.name.asc()) choices = City.query.order_by(City.name.asc())
return choices return choices
def queryCityNamesWithDefault(defId): def queryCityNamesWithDefault(defId):
choices = dbUtils.queryNameWithDefaultId(City,defId) choices = dbUtils.queryNameWithDefaultId(City, defId)
return choices return choices
def queryCiytNamesOfStateWithDefId(defId, Filterid):
table=City
choices = table.query.order_by(case((table.id == defId, 0),else_=1), table.name.asc()).filter_by(state_id=Filterid)
return choices
def queryStateNamesOfCuntryWithDefId(defId, Filterid): def queryCiytNamesOfStateWithDefId(defId, Filterid):
table=State table = City
choices = table.query.order_by(case((table.id == defId, 0),else_=1), table.name.asc()).filter_by(country_id=Filterid) choices = table.query.order_by(case((table.id == defId, 0), else_=1), table.name.asc()).filter_by(state_id=Filterid)
return choices return choices

@ -11,6 +11,8 @@
<!-- Referencing Favicon --!> <!-- Referencing Favicon --!>
<link rel="shortcut icon" href="{{ url_for('static', filename='img/logo.png') }}"> <link rel="shortcut icon" href="{{ url_for('static', filename='img/logo.png') }}">
<script src="https://unpkg.com/htmx.org@2.0.1" integrity="sha384-QWGpdj554B4ETpJJC9z+ZHJcA/i59TyjxEPXiiUgN2WmTyV5OEZWCD6gQhgkdpB/" crossorigin="anonymous"></script>
{# Title Block : wit Minibase as defauls value : will be overwritten if anothe page has the same title block #} {# Title Block : wit Minibase as defauls value : will be overwritten if anothe page has the same title block #}
<title>{% block title %}Minibase{% endblock %}</title> <title>{% block title %}Minibase{% endblock %}</title>
</head> </head>

@ -9,6 +9,9 @@
{% include 'form/selectFieldVer.html' %} {% include 'form/selectFieldVer.html' %}
{% include 'form/dateField.html' %} {% include 'form/dateField.html' %}
{% include 'form/boolField.html' %} {% include 'form/boolField.html' %}
{% include 'form/fileField.html' %}
{% include 'form/urlField.html' %}
{% include 'form/integerField.html' %}
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</fieldset> </fieldset>

@ -0,0 +1,17 @@
{% if item.type in ['FileField'] %}
{{ item.label(class=theme.form.file_label_class, style=theme.form.file_label_style) }}
<br>
{% endif %}
{% if item.errors %}
{{ item(class=theme.form.input_error_class) }}
<div class="{{ theme.form.div_error_class }}">
{% for error in item.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{% if item.type in ['FileField'] %}
{{ item(class=theme.form.file_class, type=theme.form.file_type, style=theme.form.file_style) }}
<br>
{% endif %}
{% endif %}

@ -1,5 +1,5 @@
{% if item.type in ['SelectField'] %} {% if item.type in ['SelectField'] %}
{{ item.label(class=theme.form.input_label_class, style=theme.form.input_label_style) }} {{ item.label(class=theme.form.select_label_class, style=theme.form.select_label_style) }}
{% endif %} {% endif %}
{% if item.errors %} {% if item.errors %}
{{ item(class=theme.form.input_error_class) }} {{ item(class=theme.form.input_error_class) }}
@ -9,7 +9,9 @@
{% endfor %} {% endfor %}
</div> </div>
{% else %} {% else %}
<div class="col">
{% if item.type in ['SelectField'] %} {% if item.type in ['SelectField'] %}
{{ item(class=theme.form.select_class, type=theme.form.select_type, style=theme.form.select_style) }} {{ item(class=theme.form.select_class, type=theme.form.select_type, style=theme.form.select_style) }}
{% endif %} {% endif %}
</div>
{% endif %} {% endif %}

@ -1,10 +1,10 @@
{% if item.type in ['SelectField'] %} {% if item.type in ['SelectField'] %}
{{ item.label(class=theme.form.input_label_class, style=theme.form.input_label_style) }} {{ item.label(class=theme.form.select_label_class, style=theme.form.select_label_style) }}
<br> <br>
{% endif %} {% endif %}
{% if item.errors %} {% if item.errors %}
{{ item(class=theme.form.input_error_class) }} {{ item(class=theme.form.input_error_class) }}
<div class="{{ theme.form.div_error_class }}"> <div class="{{ theme.form.select_error_class }}">
{% for error in item.errors %} {% for error in item.errors %}
<span>{{ error }}</span> <span>{{ error }}</span>
{% endfor %} {% endfor %}

@ -10,6 +10,8 @@
</div> </div>
{% else %} {% else %}
{% if item.type in ['StringField', 'TextAreaField', 'PasswordField'] %} {% if item.type in ['StringField', 'TextAreaField', 'PasswordField'] %}
<div class="col">
{{ item(class=theme.form.input_class) }} {{ item(class=theme.form.input_class) }}
</div>
{% endif %} {% endif %}
{% endif %} {% endif %}

@ -0,0 +1,15 @@
{% if item.type in ['URLField'] %}
{{ item.label(class=theme.form.url_label_class, style=theme.form.url_label_style) }}
{% endif %}
{% if item.errors %}
{{ item(class=theme.form.url_error_class) }}
<div class="{{ theme.form.div_error_class }}">
{% for error in item.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{% if item.type in ['URLField'] %}
{{ item(class=theme.form.url_class, type=theme.form.url_type, style=theme.form.url_style) }}
{% endif %}
{% endif %}

@ -18,22 +18,45 @@ class form:
div_class = "container rounded p-4 py-4" div_class = "container rounded p-4 py-4"
div_error_class = "invalid-feedback" div_error_class = "invalid-feedback"
input_label_class = "col-form-label" default_label_class = "col-form-label"
input_label_style = "color:" + orange + "; font-size: 14pt; font-weight: bold;" default_label_style = "color:" + orange + "; font-size: 14pt; font-weight: bold;"
default_error_class = "form-control form-control-lg is-invalid"
input_label_class = default_label_class
input_label_style = default_label_style
input_class = "form-control form-control-lg" input_class = "form-control form-control-lg"
input_error_class = input_class+ " is-invalid" input_error_class = default_error_class
check_label_class = "form-check-label" check_label_class = "form-check-label"
check_label_style = "input_label_style" check_label_style = "input_label_style"
check_class = "form-check-input" check_class = "form-check-input"
file_label_class = default_label_class
file_label_style = default_label_style
file_class = input_class
file_type = "file"
file_error_class = default_error_class
url_label_class = default_label_class
url_label_style = default_label_style
url_class = input_class
url_default = "https://example.com/"
url_error_class = default_error_class
select_label_class = default_label_class
select_label_style = default_label_style
select_class = "btn btn-lg form-select"
select_style = "color:" + black + "; font-size: 14pt; background-color: " + white + ";"
submit_class = "btn btn-outline-info mb-2 mt-2" submit_class = "btn btn-outline-info mb-2 mt-2"
submit_style = "" submit_style = ""
date_label_class = default_label_class
date_label_style = default_label_style
date_class = ""
date_error_class = default_error_class
date_type = "date" date_type = "date"
select_class = "btn btn-lg dropdown-toggle"
select_style = "color:" + black + "; font-size: 14pt; background-color: " + white + ";"
class menu: class menu:
menuDict = generate_blueprint_structure('minibase/blueprints') menuDict = generate_blueprint_structure('minibase/blueprints')

Loading…
Cancel
Save