diff --git a/pb/__init__.py b/pb/__init__.py
index 1740b99..c8d5bdf 100644
--- a/pb/__init__.py
+++ b/pb/__init__.py
@@ -130,7 +130,7 @@ def site_map():
# **************************
# WEB FORMS
# **************************
-from pb.forms import StudyForm, StudyTable, InvestigatorForm, StudyDetailsForm
+from pb.forms import StudyForm, StudyTable, InvestigatorForm, StudyDetailsForm, ConfirmDeleteForm
from pb.models import Study, RequiredDocument, Investigator, StudySchema, RequiredDocumentSchema, InvestigatorSchema, \
StudyDetails, StudyDetailsSchema
@@ -156,7 +156,7 @@ def new_study():
study = Study()
study.study_details = StudyDetails()
_update_study(study, form)
- flash('Study created successfully!')
+ flash('Study created successfully!', 'success')
return redirect_home()
return render_template(
@@ -182,7 +182,7 @@ def edit_study(study_id):
form.Q_COMPLETE.checked = True
if request.method == 'POST':
_update_study(study, form)
- flash('Study updated successfully!')
+ flash('Study updated successfully!', 'success')
return redirect_home()
return render_template(
'form.html',
@@ -205,7 +205,7 @@ def new_investigator(study_id):
investigator.set_type(form.INVESTIGATORTYPE.data)
db.session.add(investigator)
db.session.commit()
- flash('Investigator created successfully!')
+ flash('Investigator created successfully!', 'success')
return redirect_home()
return render_template(
@@ -218,21 +218,81 @@ def new_investigator(study_id):
)
-@app.route('/del_investigator/', methods=['GET'])
+@app.route('/del_investigator/', methods=['GET', 'POST'])
def del_investigator(inv_id):
- db.session.query(Investigator).filter(Investigator.id == inv_id).delete()
- db.session.commit()
+ inv_id = int(inv_id)
+ inv_model = db.session.query(Investigator).filter(Investigator.id == inv_id).first()
+ if inv_model is None:
+ flash('Investigator not found.', 'warn')
+ return redirect_home()
+
+ uid = inv_model.NETBADGEID
+ study_id = int(inv_model.STUDYID)
+ form = ConfirmDeleteForm(request.form, obj=inv_model)
+
+ if request.method == 'GET':
+ action = BASE_HREF + "/del_investigator/%i" % inv_id
+ title = "Delete Investigator #%i?" % inv_id
+ details = "Are you sure you want to delete Investigator '%s' from Study %i?" % (uid, study_id)
+
+ return render_template(
+ 'form.html',
+ form=form,
+ action=action,
+ title=title,
+ details=details,
+ description_map=description_map,
+ base_href=BASE_HREF
+ )
+
+ if request.method == 'POST':
+ if form.confirm and form.confirm.data:
+ db.session.query(Investigator).filter(Investigator.id == inv_id).delete()
+ db.session.commit()
+ flash('Investigator %s deleted from Study %i.' % (uid, study_id), 'success')
+ else:
+ flash('Delete canceled.', 'info')
+
return redirect_home()
-@app.route('/del_study/', methods=['GET'])
+@app.route('/del_study/', methods=['GET', 'POST'])
def del_study(study_id):
- db.session.query(RequiredDocument).filter(RequiredDocument.STUDYID == study_id).delete()
- db.session.query(Investigator).filter(Investigator.STUDYID == study_id).delete()
- db.session.query(StudyDetails).filter(StudyDetails.STUDYID == study_id).delete()
- db.session.query(Study).filter(Study.STUDYID == study_id).delete()
- db.session.commit()
- return redirect_home()
+ study_id = int(study_id)
+ study_model = db.session.query(Study).filter(Study.STUDYID == study_id).first()
+ if study_model is None:
+ flash('Study not found.', 'warn')
+ return redirect_home()
+
+ form = ConfirmDeleteForm(request.form, obj=study_model)
+
+ if request.method == 'GET':
+ action = BASE_HREF + "/del_study/%i" % study_id
+ title = "Delete Study #%i?" % study_id
+ details = "Are you sure you want to delete Study '%s'?" % study_model.TITLE
+
+ return render_template(
+ 'form.html',
+ form=form,
+ action=action,
+ title=title,
+ details=details,
+ description_map=description_map,
+ base_href=BASE_HREF
+ )
+
+ if request.method == 'POST':
+ if form.confirm and form.confirm.data:
+ db.session.query(RequiredDocument).filter(RequiredDocument.STUDYID == study_id).delete()
+ db.session.query(Investigator).filter(Investigator.STUDYID == study_id).delete()
+ db.session.query(StudyDetails).filter(StudyDetails.STUDYID == study_id).delete()
+ db.session.query(Study).filter(Study.STUDYID == study_id).delete()
+ db.session.commit()
+ flash('Study %i deleted.' % study_id, 'success')
+ else:
+ flash('Delete canceled.', 'info')
+
+ return redirect_home()
def _update_study(study, form):
@@ -274,7 +334,7 @@ def study_details(study_id):
form.populate_obj(study_details)
db.session.add(study_details)
db.session.commit()
- flash('Study updated successfully!')
+ flash('Study updated successfully!', 'success')
return redirect_home()
return render_template(
'form.html',
diff --git a/pb/forms.py b/pb/forms.py
index b40b64a..5546a6a 100644
--- a/pb/forms.py
+++ b/pb/forms.py
@@ -28,6 +28,10 @@ class StudyDetailsForm(ModelForm, FlaskForm):
model = StudyDetails
+class ConfirmDeleteForm(FlaskForm):
+ confirm = BooleanField('Yes, really delete', default='checked',
+ false_values=(False, 'false', 0, '0'))
+
class RequirementsTable(Table):
AUXDOCID = Col('Code')
AUXDOC = Col('Name')
@@ -51,11 +55,6 @@ class StudyTable(Table):
anchor_attrs={'class': 'btn btn-icon btn-primary', 'title': 'Edit Study'},
th_html_attrs={'class': 'mat-icon text-center', 'title': 'Edit Study'}
)
- delete = LinkCol(
- 'delete', 'del_study', url_kwargs=dict(study_id='STUDYID'),
- anchor_attrs={'class': 'btn btn-icon btn-warn', 'title': 'Delete Study'},
- th_html_attrs={'class': 'mat-icon text-center', 'title': 'Delete Study'}
- )
details = LinkCol(
'ballot', 'study_details', url_kwargs=dict(study_id='STUDYID'),
anchor_attrs={'class': 'btn btn-icon btn-default', 'title': 'Edit Questions'},
@@ -73,4 +72,9 @@ class StudyTable(Table):
Q_COMPLETE = BoolCol('Complete?')
requirements = NestedTableCol('Requirements', RequirementsTable)
investigators = NestedTableCol('Investigators', InvestigatorsTable)
+ delete = LinkCol(
+ 'delete', 'del_study', url_kwargs=dict(study_id='STUDYID'),
+ anchor_attrs={'class': 'btn btn-icon btn-warn', 'title': 'Delete Study'},
+ th_html_attrs={'class': 'mat-icon text-center', 'title': 'Delete Study'}
+ )
diff --git a/pb/static/scss/app.scss b/pb/static/scss/app.scss
index 5a04bb1..ede0626 100644
--- a/pb/static/scss/app.scss
+++ b/pb/static/scss/app.scss
@@ -22,6 +22,11 @@ $color-warn: #DF1E43;
$color-warn-light: scale-color($color-warn, $lightness: +30%);
$color-warn-dark: scale-color($color-warn, $lightness: -30%);
+// success (Green)
+$color-success: #64B343;
+$color-success-light: scale-color($color-success, $lightness: +30%);
+$color-success-dark: scale-color($color-success, $lightness: -30%);
+
$font-size-default: 16px;
$font-size-lg: 24px;
$font-size-md: 16px;
@@ -242,3 +247,42 @@ select.multi {
}
}
+.alert {
+ padding: 20px;
+ background-color: $color-gray;
+ color: white;
+ margin-bottom: 15px;
+ opacity: 1;
+ border-radius: 5px;
+ transform: scale3d(1, 1, 1);
+ transition: all 0.5s ease-in-out;
+
+ &.warn { background-color: $color-warn; }
+ &.success { background-color: $color-success; }
+ &.info { background-color: $color-gray-light; color: black; }
+
+ .btn-close {
+ margin-left: 15px;
+ color: white;
+ font-weight: bold;
+ float: right;
+ font-size: 22px;
+ line-height: 20px;
+ cursor: pointer;
+ transition: 0.3s;
+
+ &:hover {
+ color: black;
+ }
+ }
+
+ &.fade-out {
+ opacity: 0;
+ }
+
+ &.shrink {
+ transform: scale3d(0, 0, 0);
+ padding: 0;
+ margin: 0;
+ }
+}
diff --git a/templates/index.html b/templates/index.html
index a5e2264..93cd6bf 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -17,19 +17,31 @@
New Study
-{% with messages = get_flashed_messages() %}
+{% with messages = get_flashed_messages(with_categories=True) %}
{% if messages %}
-
- {% for message in messages %}
- - {{ message }}
- {% endfor %}
-
+ {% for category, message in messages %}
+
+ ×
+ {{ message }}
+
+ {% endfor %}
{% endif %}
{% endwith %}
Current Studies
{{ table }}
+
+
+