-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bulk user import #949
Merged
Merged
bulk user import #949
Changes from 1 commit
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
4605d39
feat: first version of user import
dodumosu d5dd379
feat: add task description, form validation
dodumosu e80c524
fix: don't instantiate form twice
dodumosu 5483c4b
fix: fix issue with not rendering error message
dodumosu acf1abe
chore: add explainer
dodumosu 17005a9
chore: remove whitespace
dodumosu ce3b74f
fix: make email lookup case-insensitive
dodumosu 43efe3d
chore: remove task label
dodumosu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
feat: add task description, form validation
- Loading branch information
commit d5dd379f58ce3e67f23ffdea01c138b39c0a099c
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
{% from 'admin/locations_header_form.html' import render_mapping_form %} | ||
{{ render_mapping_form(form) }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<div class="alert alert-danger alert-dismissible fade show" role="alert"> | ||
{% trans %}<strong>There was a problem</strong> with your submission. Please correct the errors and re-submit.{% endtrans %} | ||
{% if error_msgs -%} | ||
<ul id="error-list" class="mb-0 mt-1"> | ||
{%- for error_msg in error_msgs %} | ||
<li>{{ error_msg }}</li> | ||
{% endfor -%} | ||
</ul> | ||
<button type="button" class="close" data-dismiss="alert" aria-label="{{ _('Close') }}"> | ||
<span aria-hidden="true">×</span> | ||
</button> | ||
{%- endif %} | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
{% extends "admin/model/list.html" %} | ||
|
||
{% block model_menu_bar_after_filters %} | ||
<li class="nav-item"><a href="#" class="nav-link" id="open-wizard">{{ _('Bulk import') }}</a></li> | ||
{% endblock %} | ||
|
||
{% block head_css %} | ||
{{ super() }} | ||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/bootstrap-wizard.css') }}"> | ||
{% endblock head_css %} | ||
|
||
|
||
{% block body %} | ||
{{ super() }} | ||
|
||
<!-- IMPORT WIZARD --> | ||
<div id="import-wizard" class="wizard" data-title="{{ _('Import Users') }}"> | ||
<!-- step #1 --> | ||
<div class="wizard-card" data-cardname="uploadFile"> | ||
<h3>{{ _('Upload File') }}</h3> | ||
<div class="wizard-input-section"> | ||
<form action="{{ url_for('user.import_users') }}" enctype="multipart/form-data" method="post" id="upload-form"> | ||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" /> | ||
<div class="custom-file"> | ||
<input type="file" class="custom-file-input upload" id="uploadFile" name="spreadsheet"> | ||
<label for="uploadFile" class="custom-file-label" data-browse="{{ _('Browse') }}">{{ _('Choose file') }}</label> | ||
<small class="form-text text-muted" id="uploadFileHelptext">{{ _('Only .csv, .xls and .xlsx files') }}</small> | ||
</div> | ||
</form> | ||
</div> | ||
</div> | ||
|
||
<!-- step #2 --> | ||
<div class="wizard-card pr-0" data-cardname="mapFields"> | ||
<h3>{{ _('Map Fields') }}</h3> | ||
<div class="wizard-input-section overflow-auto"></div> | ||
</div> | ||
|
||
<div class="wizard-card" data-cardname="finalize"> | ||
<h3>{{ _('Finalize') }}</h3> | ||
<div class="wizard-input-section"> | ||
<div class="alert alert-info"> | ||
<span class="create-server-name">{% trans %}Click the <strong>Submit</strong> button to begin the import process.{% endtrans %}</span> | ||
</div> | ||
</div> | ||
|
||
<div class="wizard-failure"> | ||
<div class="alert alert-danger"> | ||
{% trans %}There was a problem submitting the form. Please try again in a minute.{% endtrans %} | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
{% endblock body %} | ||
|
||
{% block tail_js %} | ||
{{ super() }} | ||
<script type="text/javascript" src="{{ url_for('static', filename='js/bootstrap-wizard.min.js') }}"></script> | ||
<script type="text/javascript" src="{{ url_for('static', filename='js/jquery.form.js') }}"></script> | ||
<script type="text/javascript"> | ||
$(function() { | ||
var wizard = $('#import-wizard').wizard({ | ||
keyboard : true, | ||
contentHeight : 500, | ||
contentWidth : 700, | ||
showCancel: true, | ||
backdrop: true, | ||
buttons: {'cancelText': "{{ _('Cancel') }}", | ||
'nextText': "{{ _('Next') }}", | ||
'backText': "{{ _('Back') }}", | ||
'submitText': "{{ _('Submit') }}", | ||
'submittingText': "{{ _('Submitting...') }}"} | ||
}); | ||
|
||
wizard.on('closed', function() { | ||
wizard.reset(); | ||
var uploadFile = document.getElementById('uploadFile'); | ||
uploadFile.value = '' | ||
uploadFile.dispatchEvent(new Event('change')); | ||
$('#uploadFile').removeClass('is-invalid'); | ||
$('#uploadFileHelptext').removeClass('invalid-feedback'); | ||
}); | ||
|
||
wizard.cards['uploadFile'].on('validate', function (card) { | ||
var cont = true; | ||
$('#upload-form').ajaxSubmit({ | ||
async: false, | ||
error: function (data) { | ||
input = card.el.find("#uploadFile"); | ||
input_helptext = card.el.find('#uploadFileHelptext'); | ||
input.addClass('is-invalid'); | ||
input_helptext.removeClass('text-muted'); | ||
input_helptext.addClass('invalid-feedback'); | ||
cont = false; | ||
}, | ||
success: function (data) { | ||
$('.wizard-input-section', wizard.cards['mapFields'].el).html(data); | ||
$('.wizard-input-section').height(wizard.dimensions.cardContainer - 85); | ||
cont = true; | ||
} | ||
}); | ||
return cont; | ||
}); | ||
|
||
wizard.cards['mapFields'].on('validate', function (card) { | ||
var cont = false; | ||
|
||
$.ajax({ | ||
type: 'POST', | ||
url: $('#form-action').val(), | ||
data: wizard.serialize(), | ||
async: false, | ||
beforeSend: function (xhr) { xhr.setRequestHeader('X-Validate', '1'); }, | ||
}).done(function (response) { | ||
cont = true; | ||
}).fail(function (data) { | ||
$('#form-action-errors', wizard.cards['mapFields'].el).html(data.responseText); | ||
$('#form-action-errors', wizard.cards['mapFields'].el).removeClass('d-none'); | ||
cont = false; | ||
}); | ||
|
||
return cont; | ||
}); | ||
|
||
wizard.on("submit", function(wizard) { | ||
$.ajax({ | ||
type: 'POST', | ||
url: $('#form-action').val(), | ||
data: wizard.serialize() | ||
}).done(function (response) { | ||
wizard.trigger("success"); | ||
wizard.hideButtons(); | ||
wizard._submitting = false; | ||
wizard.submitSuccess(); | ||
wizard.updateProgressBar(0); | ||
wizard.close(); | ||
}).fail(function (data) { | ||
wizard.submitFailure(); | ||
wizard.showButtons(); | ||
}); | ||
}); | ||
|
||
$('#open-wizard').click(function(e) { | ||
e.preventDefault(); | ||
wizard.reset(); | ||
var uploadFile = document.getElementById('uploadFile'); | ||
uploadFile.value = '' | ||
uploadFile.dispatchEvent(new Event('change')); | ||
$('#uploadFile').removeClass('is-invalid'); | ||
$('#uploadFileHelptext').removeClass('invalid-feedback'); | ||
wizard.show(); | ||
}); | ||
}); | ||
</script> | ||
{% endblock tail_js %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably related to another PR and shouldn't be included here.