mirror of https://github.com/zulip/zulip.git
data export: Add UI to trigger data export.
This commit serves as the frontend piece for the "public export" webapp feature. Fixes: #11930
This commit is contained in:
parent
8ac8247dbe
commit
f623540409
|
@ -148,6 +148,7 @@
|
||||||
"settings_bots": false,
|
"settings_bots": false,
|
||||||
"settings_display": false,
|
"settings_display": false,
|
||||||
"settings_emoji": false,
|
"settings_emoji": false,
|
||||||
|
"settings_exports": false,
|
||||||
"settings_linkifiers": false,
|
"settings_linkifiers": false,
|
||||||
"settings_invites": false,
|
"settings_invites": false,
|
||||||
"settings_muting": false,
|
"settings_muting": false,
|
||||||
|
|
|
@ -56,6 +56,12 @@ set_global('settings_bots', {
|
||||||
update_bot_permissions_ui: noop,
|
update_bot_permissions_ui: noop,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
set_global('settings_exports', {
|
||||||
|
populate_exports_table: function (exports) {
|
||||||
|
return exports;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// page_params is highly coupled to dispatching now
|
// page_params is highly coupled to dispatching now
|
||||||
set_global('page_params', {test_suite: false});
|
set_global('page_params', {test_suite: false});
|
||||||
var page_params = global.page_params;
|
var page_params = global.page_params;
|
||||||
|
@ -712,6 +718,14 @@ var event_fixtures = {
|
||||||
user_id: test_user.user_id,
|
user_id: test_user.user_id,
|
||||||
status_text: 'out to lunch',
|
status_text: 'out to lunch',
|
||||||
},
|
},
|
||||||
|
realm_export: {
|
||||||
|
type: 'realm_export',
|
||||||
|
exports: {
|
||||||
|
acting_user_id: 55,
|
||||||
|
event_time: 'noon',
|
||||||
|
path: 'some_path',
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function assert_same(actual, expected) {
|
function assert_same(actual, expected) {
|
||||||
|
@ -1512,3 +1526,18 @@ with_overrides(function (override) {
|
||||||
assert.equal(status_text, 'out to lunch');
|
assert.equal(status_text, 'out to lunch');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
with_overrides(function (override) {
|
||||||
|
var event = event_fixtures.realm_export;
|
||||||
|
override('settings_exports.populate_exports_table', noop);
|
||||||
|
dispatch(event);
|
||||||
|
global.with_stub(function (stub) {
|
||||||
|
override('settings_exports.populate_exports_table', stub.f);
|
||||||
|
dispatch(event);
|
||||||
|
|
||||||
|
var args = stub.get_args('exports');
|
||||||
|
assert.equal(args.exports.acting_user_id, 55);
|
||||||
|
assert.equal(args.exports.event_time, 'noon');
|
||||||
|
assert.equal(args.exports.path, 'some_path');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
@ -838,6 +838,10 @@ run_test('set_up', () => {
|
||||||
const allow_topic_edit_label_parent = $.create('allow-topic-edit-label-parent');
|
const allow_topic_edit_label_parent = $.create('allow-topic-edit-label-parent');
|
||||||
$('#id_realm_allow_community_topic_editing_label').set_parent(allow_topic_edit_label_parent);
|
$('#id_realm_allow_community_topic_editing_label').set_parent(allow_topic_edit_label_parent);
|
||||||
|
|
||||||
|
channel.get = function (opts) {
|
||||||
|
assert.equal(opts.url, '/json/export/realm');
|
||||||
|
};
|
||||||
|
|
||||||
// TEST set_up() here, but this mostly just allows us to
|
// TEST set_up() here, but this mostly just allows us to
|
||||||
// get access to the click handlers.
|
// get access to the click handlers.
|
||||||
settings_org.maybe_disable_widgets = noop;
|
settings_org.maybe_disable_widgets = noop;
|
||||||
|
|
|
@ -174,6 +174,7 @@ import "../settings_bots.js";
|
||||||
import "../settings_muting.js";
|
import "../settings_muting.js";
|
||||||
import "../settings_sections.js";
|
import "../settings_sections.js";
|
||||||
import "../settings_emoji.js";
|
import "../settings_emoji.js";
|
||||||
|
import "../settings_exports.js";
|
||||||
import "../settings_org.js";
|
import "../settings_org.js";
|
||||||
import "../settings_users.js";
|
import "../settings_users.js";
|
||||||
import "../settings_streams.js";
|
import "../settings_streams.js";
|
||||||
|
|
|
@ -111,6 +111,7 @@ declare var settings_account: any;
|
||||||
declare var settings_bots: any;
|
declare var settings_bots: any;
|
||||||
declare var settings_display: any;
|
declare var settings_display: any;
|
||||||
declare var settings_emoji: any;
|
declare var settings_emoji: any;
|
||||||
|
declare var settings_exports: any;
|
||||||
declare var settings_invites: any;
|
declare var settings_invites: any;
|
||||||
declare var settings: any;
|
declare var settings: any;
|
||||||
declare var settings_linkifiers: any;
|
declare var settings_linkifiers: any;
|
||||||
|
|
|
@ -510,6 +510,9 @@ exports.dispatch_normal_event = function dispatch_normal_event(event) {
|
||||||
activity.redraw_user(event.user_id);
|
activity.redraw_user(event.user_id);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'realm_export':
|
||||||
|
settings_exports.populate_exports_table(event.exports);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,6 +24,7 @@ var header_map = {
|
||||||
"invites-list-admin": i18n.t("Invitations"),
|
"invites-list-admin": i18n.t("Invitations"),
|
||||||
"user-groups-admin": i18n.t("User groups"),
|
"user-groups-admin": i18n.t("User groups"),
|
||||||
"profile-field-settings": i18n.t("Profile field settings"),
|
"profile-field-settings": i18n.t("Profile field settings"),
|
||||||
|
"data-exports-admin": i18n.t("Data exports"),
|
||||||
};
|
};
|
||||||
|
|
||||||
$("body").ready(function () {
|
$("body").ready(function () {
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
var render_admin_export_list = require('../templates/admin_export_list.hbs');
|
||||||
|
|
||||||
|
var settings_exports = (function () {
|
||||||
|
|
||||||
|
var exports = {};
|
||||||
|
|
||||||
|
var meta = {
|
||||||
|
loaded: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.reset = function () {
|
||||||
|
meta.loaded = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.populate_exports_table = function (exports) {
|
||||||
|
if (!meta.loaded) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var exports_table = $('#admin_exports_table').expectOne();
|
||||||
|
exports_table.find('tr.export_row').remove();
|
||||||
|
_.each(exports, function (data) {
|
||||||
|
if (data.export_data.deleted_timestamp === undefined) {
|
||||||
|
exports_table.append(render_admin_export_list({
|
||||||
|
realm_export: {
|
||||||
|
id: data.id,
|
||||||
|
acting_user: people.my_full_name(data.acting_user_id),
|
||||||
|
// Convert seconds -> milliseconds
|
||||||
|
event_time: timerender.last_seen_status_from_date(
|
||||||
|
new XDate(data.export_time * 1000)
|
||||||
|
),
|
||||||
|
path: data.export_data.export_path,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.set_up = function () {
|
||||||
|
meta.loaded = true;
|
||||||
|
|
||||||
|
$("#export-data").on('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
var export_status = $('#export_status');
|
||||||
|
|
||||||
|
channel.post({
|
||||||
|
url: '/json/export/realm',
|
||||||
|
success: function () {
|
||||||
|
ui_report.success(i18n.t("Export started. Check back in a few minutes."), export_status);
|
||||||
|
},
|
||||||
|
error: function (xhr) {
|
||||||
|
ui_report.error(i18n.t("Export failed"), xhr, export_status);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Do an initial population of the table
|
||||||
|
channel.get({
|
||||||
|
url: '/json/export/realm',
|
||||||
|
success: function (data) {
|
||||||
|
exports.populate_exports_table(data.exports);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.admin_exports_table').on('click', '.delete', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
var btn = $(this);
|
||||||
|
|
||||||
|
channel.del({
|
||||||
|
url: '/json/export/realm/' + encodeURIComponent(btn.attr('data-export-id')),
|
||||||
|
error: function (xhr) {
|
||||||
|
ui_report.generic_row_button_error(xhr, btn);
|
||||||
|
},
|
||||||
|
// No success function, since UI updates are done via server_events
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return exports;
|
||||||
|
}());
|
||||||
|
if (typeof modules !== 'undefined') {
|
||||||
|
module.exports = settings_exports;
|
||||||
|
}
|
||||||
|
window.settings_exports = settings_exports;
|
|
@ -46,6 +46,7 @@ exports.initialize = function () {
|
||||||
load_func_dict.set('invites-list-admin', settings_invites.set_up);
|
load_func_dict.set('invites-list-admin', settings_invites.set_up);
|
||||||
load_func_dict.set('user-groups-admin', settings_user_groups.set_up);
|
load_func_dict.set('user-groups-admin', settings_user_groups.set_up);
|
||||||
load_func_dict.set('profile-field-settings', settings_profile_fields.set_up);
|
load_func_dict.set('profile-field-settings', settings_profile_fields.set_up);
|
||||||
|
load_func_dict.set('data-exports-admin', settings_exports.set_up);
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.load_settings_section = function (section) {
|
exports.load_settings_section = function (section) {
|
||||||
|
@ -72,6 +73,7 @@ exports.load_settings_section = function (section) {
|
||||||
exports.reset_sections = function () {
|
exports.reset_sections = function () {
|
||||||
is_loaded.clear();
|
is_loaded.clear();
|
||||||
settings_emoji.reset();
|
settings_emoji.reset();
|
||||||
|
settings_exports.reset();
|
||||||
settings_linkifiers.reset();
|
settings_linkifiers.reset();
|
||||||
settings_invites.reset();
|
settings_invites.reset();
|
||||||
settings_org.reset();
|
settings_org.reset();
|
||||||
|
|
|
@ -723,13 +723,15 @@ input[type=checkbox].inline-block {
|
||||||
|
|
||||||
.add-new-emoji-box,
|
.add-new-emoji-box,
|
||||||
.add-new-user-group-box,
|
.add-new-user-group-box,
|
||||||
.add-new-alert-word-box {
|
.add-new-alert-word-box,
|
||||||
|
.add-new-export-box {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.add-new-emoji-box .new-emoji-form,
|
.add-new-emoji-box .new-emoji-form,
|
||||||
.add-new-user-group-box .new-user-group-form,
|
.add-new-user-group-box .new-user-group-form,
|
||||||
.add-new-alert-word-box .new-alert-word-form {
|
.add-new-alert-word-box .new-alert-word-form,
|
||||||
|
.add-new-export-box {
|
||||||
margin: 10px 0px;
|
margin: 10px 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1949,3 +1951,7 @@ thead .actions {
|
||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.admin_exports_table {
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
{{#with realm_export}}
|
||||||
|
<tr class="export_row" id="export_{{id}}">
|
||||||
|
<td>
|
||||||
|
<span class="acting_user">{{acting_user}}</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="export_time">{{event_time}}</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{#if path}}
|
||||||
|
<span class="export_url"><a href="{{path}}">{{t 'Download' }}</a></span>
|
||||||
|
{{else}}
|
||||||
|
<span class="export_url">{{t 'The export URL is not yet available... Check back soon.' }}</span>
|
||||||
|
{{/if}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button class="button rounded small delete btn-danger" data-export-id="{{id}}">
|
||||||
|
<i class="fa fa-trash-o" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{/with}}
|
|
@ -28,3 +28,5 @@
|
||||||
{{> user_groups_admin }}
|
{{> user_groups_admin }}
|
||||||
|
|
||||||
{{> settings/profile_field_settings_admin }}
|
{{> settings/profile_field_settings_admin }}
|
||||||
|
|
||||||
|
{{> settings/data_exports_admin }}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<div id="data-exports" class="settings-section" data-name="data-exports-admin">
|
||||||
|
<p class="alert-word-settings-note">{{#tr this}}Depending on the size of your organization, the time to complete an export can range from several minutes to an hour.{{/tr}}</p>
|
||||||
|
<h3>{{t "Data exports" }}
|
||||||
|
<a href="/help/export-your-organization" target="_blank">
|
||||||
|
<i class="fa fa-question-circle-o" aria-hidden="true"></i>
|
||||||
|
</a>
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
{{#if is_admin}}
|
||||||
|
<div class="alert" id="export_status" role="alert">
|
||||||
|
<span class="export_status_text"></span>
|
||||||
|
</div>
|
||||||
|
<form class="form-horizontal">
|
||||||
|
<div class="add-new-export-box grey-box">
|
||||||
|
<div class="wrapper">
|
||||||
|
<button type="submit" class="button rounded sea-green" id="export-data">
|
||||||
|
{{t 'Start public export' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<p class="alert-word-settings-note">{{#tr this}}Zulip also supports exporting private streams and messages under some circumstances. <a href="/help/export-your-organization" target="_blank">Read more</a>{{/tr}}</p>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{{/if}}
|
||||||
|
<p class="alert-word-settings-note">{{#tr this}}Any member with administrative access can conduct an export. Please note that individual organizations are limited to five exports per week.{{/tr}}</p>
|
||||||
|
<div class="admin-table-wrapper">
|
||||||
|
<table class="table table-condensed table-striped wrapped-table admin_exports_table">
|
||||||
|
<thead>
|
||||||
|
<th>{{t "Requesting user" }}</th>
|
||||||
|
<th>{{t "Time" }}</th>
|
||||||
|
<th>{{t "File" }}</th>
|
||||||
|
<th>{{t "Actions" }}</th>
|
||||||
|
</thead>
|
||||||
|
<tbody id="admin_exports_table" class="required-text" data-empty="{{t 'No exports.' }}"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -145,6 +145,10 @@
|
||||||
<i class="icon fa fa-user" aria-hidden="true"></i>
|
<i class="icon fa fa-user" aria-hidden="true"></i>
|
||||||
<div class="text">{{ _('Invitations') }}</div>
|
<div class="text">{{ _('Invitations') }}</div>
|
||||||
</li>
|
</li>
|
||||||
|
<li tabindex="0" data-section="data-exports-admin">
|
||||||
|
<i class="icon fa fa-database" aria-hidden="true"></i>
|
||||||
|
<div class="text">{{ _('Data exports') }}</div>
|
||||||
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if not is_admin %}
|
{% if not is_admin %}
|
||||||
<div class="collapse-settings-btn">
|
<div class="collapse-settings-btn">
|
||||||
|
|
Loading…
Reference in New Issue