Wrap up steps for new table wizard

it actually works.. :)  needs more polish, but will let usage drive that
This commit is contained in:
Lance Edgar 2023-01-15 22:52:01 -06:00
parent 68ed5942e6
commit f4bc280da7
2 changed files with 258 additions and 29 deletions

View file

@ -26,10 +26,10 @@
Enter Details Enter Details
</h3> </h3>
<b-field label="Schema Branch" horizontal <b-field label="Schema Branch"
message="Leave this set to your custom app branch, unless you know what you're doing."> message="Leave this set to your custom app branch, unless you know what you're doing.">
<b-select v-model="tableBranch"> <b-select v-model="alembicBranch">
<option v-for="branch in branchOptions" <option v-for="branch in alembicBranchOptions"
:key="branch" :key="branch"
:value="branch"> :value="branch">
{{ branch }} {{ branch }}
@ -260,7 +260,7 @@
</h3> </h3>
<b-field label="Schema Branch" horizontal> <b-field label="Schema Branch" horizontal>
{{ tableBranch }} {{ alembicBranch }}
</b-field> </b-field>
<b-field label="Table Name" horizontal> <b-field label="Table Name" horizontal>
@ -306,7 +306,8 @@
<b-step-item step="3" <b-step-item step="3"
value="review-model" value="review-model"
label="Review Model"> label="Review Model"
clickable>
<h3 class="is-size-3 block"> <h3 class="is-size-3 block">
Review Model Review Model
</h3> </h3>
@ -404,12 +405,18 @@
:disabled="!modelImported"> :disabled="!modelImported">
Model class looks good! Model class looks good!
</b-button> </b-button>
<b-button icon-pack="fas"
icon-left="arrow-right"
@click="activeStep = 'write-revision'">
Skip
</b-button>
</div> </div>
</b-step-item> </b-step-item>
<b-step-item step="4" <b-step-item step="4"
value="write-revision" value="write-revision"
label="Write Revision"> label="Write Revision"
clickable>
<h3 class="is-size-3 block"> <h3 class="is-size-3 block">
Write Revision Write Revision
</h3> </h3>
@ -417,9 +424,25 @@
You said the model class looked good, so next we will generate You said the model class looked good, so next we will generate
a revision script, used to modify DB schema. a revision script, used to modify DB schema.
</p> </p>
<p class="block">
TODO: write revision script here <b-field label="Schema Branch"
</p> message="Leave this set to your custom app branch, unless you know what you're doing.">
<b-select v-model="alembicBranch">
<option v-for="branch in alembicBranchOptions"
:key="branch"
:value="branch">
{{ branch }}
</option>
</b-select>
</b-field>
<b-field label="Message"
message="Human-friendly brief description of the changes">
<b-input v-model="revisionMessage"></b-input>
</b-field>
<br />
<div class="buttons"> <div class="buttons">
<b-button icon-pack="fas" <b-button icon-pack="fas"
icon-left="arrow-left" icon-left="arrow-left"
@ -429,8 +452,14 @@
<b-button type="is-primary" <b-button type="is-primary"
icon-pack="fas" icon-pack="fas"
icon-left="save" icon-left="save"
@click="writeRevisionScript()"
:disabled="writingRevisionScript">
{{ writingRevisionScript ? "Working, please wait..." : "Generate revision script" }}
</b-button>
<b-button icon-pack="fas"
icon-left="arrow-right"
@click="activeStep = 'review-revision'"> @click="activeStep = 'review-revision'">
Write revision script to file Skip
</b-button> </b-button>
</div> </div>
</b-step-item> </b-step-item>
@ -441,7 +470,19 @@
<h3 class="is-size-3 block"> <h3 class="is-size-3 block">
Review Revision Review Revision
</h3> </h3>
<p class="block">TODO: review revision script here</p>
<p class="block">
Revision script was generated to file:
</p>
<p class="block is-family-code" style="padding-left: 3rem;">
{{ revisionScript }}
</p>
<p class="block">
Please review that code and adjust to your liking.
</p>
<div class="buttons"> <div class="buttons">
<b-button icon-pack="fas" <b-button icon-pack="fas"
icon-left="arrow-left" icon-left="arrow-left"
@ -459,11 +500,16 @@
<b-step-item step="6" <b-step-item step="6"
value="upgrade-db" value="upgrade-db"
label="Upgrade DB"> label="Upgrade DB"
clickable>
<h3 class="is-size-3 block"> <h3 class="is-size-3 block">
Upgrade DB Upgrade DB
</h3> </h3>
<p class="block">TODO: upgrade DB here</p> <p class="block">
You said the revision script looked good, so next we will use
it to upgrade your actual database.
</p>
<div class="buttons"> <div class="buttons">
<b-button icon-pack="fas" <b-button icon-pack="fas"
icon-left="arrow-left" icon-left="arrow-left"
@ -472,20 +518,72 @@
</b-button> </b-button>
<b-button type="is-primary" <b-button type="is-primary"
icon-pack="fas" icon-pack="fas"
icon-left="check" icon-left="arrow-up"
@click="activeStep = 'review-db'"> @click="upgradeDB()"
Upgrade database :disabled="upgradingDB">
{{ upgradingDB ? "Working, please wait..." : "Upgrade database" }}
</b-button> </b-button>
</div> </div>
</b-step-item> </b-step-item>
<b-step-item step="7" <b-step-item step="7"
value="review-db" value="review-db"
label="Review DB"> label="Review DB"
clickable>
<h3 class="is-size-3 block"> <h3 class="is-size-3 block">
Review DB Review DB
</h3> </h3>
<p class="block">TODO: review DB here</p>
<p class="block">
At this point your new table should be present in the DB.
Test below.
</p>
<div class="card block">
<header class="card-header">
<p class="card-header-title">
Table Status
</p>
</header>
<div class="card-content">
<div class="content">
<div class="level">
<div class="level-left">
<div class="level-item">
<span v-if="!tableCheckAttempted">
check not yet attempted
</span>
<span v-if="tableCheckAttempted && !tableCheckProblem"
class="has-text-success has-text-weight-bold">
table exists!
</span>
<span v-if="tableCheckProblem"
class="has-text-danger">
{{ tableCheckProblem }}
</span>
</div>
</div>
<div class="level-right">
<div class="level-item">
<b-field horizontal label="Table Name">
<b-input v-model="tableName"></b-input>
</b-field>
</div>
<div class="level-item">
<b-button type="is-primary"
icon-pack="fas"
icon-left="redo"
@click="tableCheck()">
Test for Table
</b-button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="buttons"> <div class="buttons">
<b-button icon-pack="fas" <b-button icon-pack="fas"
icon-left="arrow-left" icon-left="arrow-left"
@ -495,7 +593,8 @@
<b-button type="is-primary" <b-button type="is-primary"
icon-pack="fas" icon-pack="fas"
icon-left="check" icon-left="check"
@click="activeStep = 'commit-code'"> @click="activeStep = 'commit-code'"
:disabled="!tableCheckAttempted || tableCheckProblem">
DB looks good! DB looks good!
</b-button> </b-button>
</div> </div>
@ -507,19 +606,26 @@
<h3 class="is-size-3 block"> <h3 class="is-size-3 block">
Commit Code Commit Code
</h3> </h3>
<p class="block">TODO: commit changes here</p>
<p class="block">
Hope you're having a great day.
</p>
<p class="block">
Don't forget to commit code changes to your source repo.
</p>
<div class="buttons"> <div class="buttons">
<b-button icon-pack="fas" <b-button icon-pack="fas"
icon-left="arrow-left" icon-left="arrow-left"
@click="activeStep = 'review-db'"> @click="activeStep = 'review-db'">
Back Back
</b-button> </b-button>
<b-button type="is-primary" <once-button type="is-primary"
icon-pack="fas" tag="a" :href="tableURL"
icon-left="check" icon-left="arrow-right"
@click="alert('TODO: redirect to table view')"> :text="`Show me my new table: ${'$'}{tableName}`">
Code changes are committed! </once-button>
</b-button>
</div> </div>
</b-step-item> </b-step-item>
</b-steps> </b-steps>
@ -530,9 +636,9 @@
<script type="text/javascript"> <script type="text/javascript">
ThisPageData.activeStep = null ThisPageData.activeStep = null
ThisPageData.branchOptions = ${json.dumps(branch_name_options)|n} ThisPageData.alembicBranchOptions = ${json.dumps(branch_name_options)|n}
ThisPageData.tableBranch = ${json.dumps(branch_name)|n} ThisPageData.alembicBranch = ${json.dumps(branch_name)|n}
ThisPageData.tableName = '${rattail_app.get_table_prefix()}_widget' ThisPageData.tableName = '${rattail_app.get_table_prefix()}_widget'
ThisPageData.tableModelName = '${rattail_app.get_class_prefix()}Widget' ThisPageData.tableModelName = '${rattail_app.get_class_prefix()}Widget'
ThisPageData.tableModelTitle = 'Widget' ThisPageData.tableModelTitle = 'Widget'
@ -620,7 +726,7 @@
let url = '${url('{}.write_model_file'.format(route_prefix))}' let url = '${url('{}.write_model_file'.format(route_prefix))}'
let params = { let params = {
branch_name: this.tableBranch, branch_name: this.alembicBranch,
table_name: this.tableName, table_name: this.tableName,
model_name: this.tableModelName, model_name: this.tableModelName,
model_title: this.tableModelTitle, model_title: this.tableModelTitle,
@ -662,10 +768,65 @@
} else { } else {
this.modelImportProblem = false this.modelImportProblem = false
this.modelImported = true this.modelImported = true
this.revisionMessage = `add table for ${'$'}{this.tableModelTitlePlural}`
} }
}) })
} }
ThisPageData.writingRevisionScript = false
ThisPageData.revisionMessage = null
ThisPageData.revisionScript = null
ThisPage.methods.writeRevisionScript = function() {
this.writingRevisionScript = true
let url = '${url('{}.write_revision_script'.format(route_prefix))}'
let params = {
branch: this.alembicBranch,
message: this.revisionMessage,
}
this.submitForm(url, params, response => {
this.writingRevisionScript = false
this.revisionScript = response.data.script
this.activeStep = 'review-revision'
}, response => {
this.writingRevisionScript = false
})
}
ThisPageData.upgradingDB = false
ThisPage.methods.upgradeDB = function() {
this.upgradingDB = true
let url = '${url('{}.upgrade_db'.format(route_prefix))}'
let params = {}
this.submitForm(url, params, response => {
this.upgradingDB = false
this.activeStep = 'review-db'
}, response => {
this.upgradingDB = false
})
}
ThisPageData.tableCheckAttempted = false
ThisPageData.tableCheckProblem = null
ThisPageData.tableURL = null
ThisPage.methods.tableCheck = function() {
let url = '${url('{}.check_table'.format(route_prefix))}'
let params = {table_name: this.tableName}
this.submitForm(url, params, response => {
if (response.data.problem) {
this.tableCheckProblem = response.data.problem
} else {
this.tableURL = response.data.url
}
this.tableCheckAttempted = true
})
}
</script> </script>
</%def> </%def>

View file

@ -32,6 +32,8 @@ import warnings
import six import six
from rattail.util import simple_error
import colander import colander
from deform import widget as dfwidget from deform import widget as dfwidget
from webhelpers2.html import HTML from webhelpers2.html import HTML
@ -111,6 +113,13 @@ class TableView(MasterView):
# row_count # row_count
g.sorters['row_count'] = g.make_simple_sorter('row_count') g.sorters['row_count'] = g.make_simple_sorter('row_count')
def configure_form(self, f):
super(TableView, self).configure_form(f)
# TODO: should render this instead, by inspecting table
if not self.creating:
f.remove('versioned')
def get_instance(self): def get_instance(self):
from sqlalchemy_utils import get_mapper from sqlalchemy_utils import get_mapper
@ -205,6 +214,37 @@ class TableView(MasterView):
return {'ok': True} return {'ok': True}
def write_revision_script(self):
data = self.request.json_body
script = self.db_handler.generate_revision_script(data['branch'],
message=data['message'])
return {'ok': True,
'script': script.path}
def upgrade_db(self):
self.db_handler.upgrade_db()
return {'ok': True}
def check_table(self):
model = self.model
data = self.request.json_body
table_name = data['table_name']
table = model.Base.metadata.tables.get(table_name)
if table is None:
return {'ok': True,
'problem': "Table does not exist in model metadata!"}
try:
count = self.Session.query(table).count()
except Exception as error:
return {'ok': True,
'problem': simple_error(error)}
url = self.request.route_url('{}.view'.format(self.get_route_prefix()),
table_name=table_name)
return {'ok': True, 'url': url}
def get_row_data(self, table): def get_row_data(self, table):
data = [] data = []
for i, column in enumerate(table['table'].columns, 1): for i, column in enumerate(table['table'].columns, 1):
@ -237,6 +277,7 @@ class TableView(MasterView):
g.sorters['nullable'] = g.make_simple_sorter('nullable') g.sorters['nullable'] = g.make_simple_sorter('nullable')
g.set_renderer('description', self.render_column_description) g.set_renderer('description', self.render_column_description)
g.set_searchable('description')
def render_column_description(self, column, field): def render_column_description(self, column, field):
text = column[field] text = column[field]
@ -287,6 +328,33 @@ class TableView(MasterView):
renderer='json', renderer='json',
permission='{}.create'.format(permission_prefix)) permission='{}.create'.format(permission_prefix))
# generate revision script
config.add_route('{}.write_revision_script'.format(route_prefix),
'{}/write-revision-script'.format(url_prefix),
request_method='POST')
config.add_view(cls, attr='write_revision_script',
route_name='{}.write_revision_script'.format(route_prefix),
renderer='json',
permission='{}.create'.format(permission_prefix))
# upgrade db
config.add_route('{}.upgrade_db'.format(route_prefix),
'{}/upgrade-db'.format(url_prefix),
request_method='POST')
config.add_view(cls, attr='upgrade_db',
route_name='{}.upgrade_db'.format(route_prefix),
renderer='json',
permission='{}.create'.format(permission_prefix))
# check table
config.add_route('{}.check_table'.format(route_prefix),
'{}/check-table'.format(url_prefix),
request_method='POST')
config.add_view(cls, attr='check_table',
route_name='{}.check_table'.format(route_prefix),
renderer='json',
permission='{}.create'.format(permission_prefix))
class TablesView(TableView): class TablesView(TableView):