Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
adrianq committed Jun 16, 2021
2 parents 6096623 + da9d3d0 commit e4f95dd
Show file tree
Hide file tree
Showing 24 changed files with 463 additions and 188 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "d2-user-extended-app",
"version": "0.6.0",
"version": "0.7.0",
"description": "DHIS2 Extended User app",
"main": "src/index.html",
"license": "GPL-3.0",
Expand Down
30 changes: 29 additions & 1 deletion src/List/List.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,7 @@ const List = React.createClass({
<ImportExport
d2={d2}
columns={settings.get("visibleTableColumns")}
allColumns={allColumns}
filterOptions={listFilterOptions}
onImport={this._openImportTable}
maxUsers={this.maxImportUsers}
Expand Down Expand Up @@ -551,7 +552,8 @@ const List = React.createClass({
) : null}
</div>

{this.state.orgunitassignment.open ? (
{this.state.orgunitassignment.open &&
this.state.orgunitassignment.field === "organisationUnits" ? (
<OrgUnitDialog
models={this.state.orgunitassignment.users}
open={true}
Expand All @@ -561,6 +563,32 @@ const List = React.createClass({
roots={this.state.orgunitassignment.roots}
onOrgUnitAssignmentSaved={this._orgUnitAssignmentSaved}
onOrgUnitAssignmentError={this._orgUnitAssignmentError}
filteringByNameLabel={this.getTranslation(
"filter_organisation_units_capture_by_name"
)}
orgUnitsSelectedLabel={this.getTranslation(
"organisation_units_capture_selected"
)}
/>
) : null}

{this.state.orgunitassignment.open &&
this.state.orgunitassignment.field === "dataViewOrganisationUnits" ? (
<OrgUnitDialog
models={this.state.orgunitassignment.users}
open={true}
onRequestClose={this._closeOrgUnitDialog}
title={this.state.orgunitassignment.title}
field={this.state.orgunitassignment.field}
roots={this.state.orgunitassignment.roots}
onOrgUnitAssignmentSaved={this._orgUnitAssignmentSaved}
onOrgUnitAssignmentError={this._orgUnitAssignmentError}
filteringByNameLabel={this.getTranslation(
"filter_organisation_units_output_by_name"
)}
orgUnitsSelectedLabel={this.getTranslation(
"organisation_units_output_selected"
)}
/>
) : null}

Expand Down
17 changes: 9 additions & 8 deletions src/List/context.actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,36 +98,37 @@ const contextActions = [
primary: true,
},
{
name: "copyInUser",
name: "copy_in_user",
multiple: false,
icon: "content_copy",
onClick: user => copyInUserStore.setState({ user, open: true }),
allowed: checkAccess(["update"]),
},
{
name: "assignToOrgUnitsCapture",
name: "assign_to_org_units_capture",
multiple: true,
icon: "business",
onClick: users => assignToOrgUnits(users, "organisationUnits", "assignToOrgUnitsCapture"),
onClick: users =>
assignToOrgUnits(users, "organisationUnits", "assign_to_org_units_capture"),
allowed: checkAccess(["update"]),
},
{
name: "assignToOrgUnitsOutput",
name: "assign_to_org_units_output",
multiple: true,
icon: "business",
onClick: users =>
assignToOrgUnits(users, "dataViewOrganisationUnits", "assignToOrgUnitsOutput"),
assignToOrgUnits(users, "dataViewOrganisationUnits", "assign_to_org_units_output"),
allowed: checkAccess(["update"]),
},
{
name: "assignRoles",
name: "assign_roles",
multiple: true,
icon: "assignment",
onClick: users => userRolesAssignmentDialogStore.setState({ users, open: true }),
allowed: checkAccess(["update"]),
},
{
name: "assignGroups",
name: "assign_groups",
icon: "group_add",
multiple: true,
onClick: users => userGroupsAssignmentDialogStore.setState({ users, open: true }),
Expand Down Expand Up @@ -161,7 +162,7 @@ const contextActions = [
onClick: datasets => deleteUserStore.delete(datasets),
},
{
name: "replicateUser",
name: "replicate_user",
icon: "content_copy",
multiple: false,
allowed: hasReplicateAuthority,
Expand Down
12 changes: 6 additions & 6 deletions src/List/list.store.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import Store from "d2-ui/lib/store/Store";
import _ from "lodash";

import appState from "../App/appStateStore";
import { getList } from "../models/userHelpers";
import { getUserList } from "../models/userList";

const orderForQuery = modelName =>
modelName === "organisationUnitLevel" ? "level:ASC" : "name:iasc";

const columns = [
export const columns = [
{ name: "username", sortable: false },
{ name: "firstName", sortable: true },
{ name: "surname", sortable: true },
Expand Down Expand Up @@ -40,11 +40,11 @@ export default Store.create({
this.listSourceSubject
.concatAll()
.combineLatest(columnObservable)
.subscribe(([modelCollection, columns]) => {
.subscribe(([usersResponse, columns]) => {
this.setState({
tableColumns: columns,
pager: modelCollection.pager,
list: modelCollection.toArray().map(user => ({
pager: usersResponse.pager,
list: usersResponse.users.map(user => ({
...user,
...(!user.userCredentials
? {}
Expand Down Expand Up @@ -98,7 +98,7 @@ export default Store.create({
filter(options, complete, error) {
getD2().then(d2 => {
const { filters, ...listOptions } = options;
const listSearchPromise = getList(d2, filters, listOptions);
const listSearchPromise = getUserList(d2, filters, listOptions);
this.listSourceSubject.onNext(Observable.fromPromise(listSearchPromise));
complete(`list with filters '${filters}' is loading`);
});
Expand Down
7 changes: 6 additions & 1 deletion src/List/organisation-unit-dialog/OrgUnitDialog.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ class OrgUnitDialog extends React.Component {
}

render() {
const { root, title, models } = this.props;
const { root, title, models, filteringByNameLabel, orgUnitsSelectedLabel } = this.props;

const styles = {
dialog: {
minWidth: 875,
Expand Down Expand Up @@ -144,6 +145,8 @@ class OrgUnitDialog extends React.Component {
roots={this.props.roots}
selected={this.state.selected}
intersectionPolicy={true}
filteringByNameLabel={filteringByNameLabel}
orgUnitsSelectedLabel={orgUnitsSelectedLabel}
/>
</Dialog>
);
Expand All @@ -158,6 +161,8 @@ OrgUnitDialog.propTypes = {
title: PropTypes.string.isRequired,
onOrgUnitAssignmentSaved: PropTypes.func.isRequired,
onOrgUnitAssignmentError: PropTypes.func.isRequired,
filteringByNameLabel: PropTypes.string.isRequired,
orgUnitsSelectedLabel: PropTypes.string.isRequired,
};

OrgUnitDialog.contextTypes = {
Expand Down
2 changes: 1 addition & 1 deletion src/components/CopyInUserDialog.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { getPayload } from "../models/userHelpers";
function getTitle(getTranslation, users) {
const usernames = users && users.map(user => user.userCredentials.username);
const info = usernames ? _m.joinString(getTranslation, usernames, 3, ", ") : "...";
return getTranslation("copyInUser") + ": " + info;
return getTranslation("copy_in_user") + ": " + info;
}

function CopyInUserDialog(props, context) {
Expand Down
51 changes: 42 additions & 9 deletions src/components/ImportExport.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import FileSaver from "file-saver";
import moment from "moment";
import fileDialog from "file-dialog";

import { exportToCsv, importFromCsv } from "../models/userHelpers";
import { exportToCsv, exportTemplateToCsv, importFromCsv } from "../models/userHelpers";
import snackActions from "../Snackbar/snack.actions";
import ModalLoadingMask from "./ModalLoadingMask.component";

Expand All @@ -23,6 +23,12 @@ class ImportExport extends React.Component {
onImport: PropTypes.func.isRequired,
maxUsers: PropTypes.number.isRequired,
settings: PropTypes.object.isRequired,
allColumns: PropTypes.arrayOf(
React.PropTypes.shape({
text: PropTypes.string.isRequired,
value: PropTypes.string.isRequired,
})
).isRequired,
};

state = { isMenuOpen: false, anchorEl: null, isProcessing: false };
Expand Down Expand Up @@ -64,17 +70,33 @@ class ImportExport extends React.Component {

try {
const csvString = await exportToCsv(d2, columns, filterOptions, { orgUnitsField });
const blob = new Blob([csvString], { type: "text/plain;charset=utf-8" });
const datetime = moment().format("YYYY-MM-DD_HH-mm-ss");
const filename = `users-${datetime}.csv`;
FileSaver.saveAs(blob, filename);
snackActions.show({ message: `${this.t("table_exported")}: ${filename}` });
this.saveCsv(csvString, "users");
} finally {
this.closeMenu();
this.setState({ isProcessing: false });
}
};

exportEmptyTemplate = async () => {
this.setState({ isProcessing: true });

try {
const csvString = await exportTemplateToCsv(d2);
this.saveCsv(csvString, "empty-user-template");
} finally {
this.closeMenu();
this.setState({ isProcessing: false });
}
};

saveCsv = (contents, name) => {
const blob = new Blob([contents], { type: "text/plain;charset=utf-8" });
const datetime = moment().format("YYYY-MM-DD_HH-mm-ss");
const filename = `${name}-${datetime}.csv`;
FileSaver.saveAs(blob, filename);
snackActions.show({ message: `${this.t("table_exported")}: ${filename}` });
};

importFromCsv = () => {
const { onImport, maxUsers, settings } = this.props;
const orgUnitsField = settings.get("organisationUnitsField");
Expand All @@ -95,7 +117,13 @@ class ImportExport extends React.Component {
render() {
const { d2 } = this.props;
const { isMenuOpen, anchorEl, isProcessing } = this.state;
const { popoverConfig, closeMenu, importFromCsv, exportToCsvAndSave } = this;
const {
popoverConfig,
closeMenu,
importFromCsv,
exportToCsvAndSave,
exportEmptyTemplate,
} = this;
const { t } = this;

return (
Expand All @@ -120,13 +148,18 @@ class ImportExport extends React.Component {
<Menu>
<MenuItem
leftIcon={<ExportIcon />}
primaryText={t("import")}
onClick={importFromCsv}
/>
<MenuItem
leftIcon={<ImportIcon />}
primaryText={t("export")}
onClick={exportToCsvAndSave}
/>
<MenuItem
leftIcon={<ImportIcon />}
primaryText={t("import")}
onClick={importFromCsv}
primaryText={t("export_empty_template")}
onClick={exportEmptyTemplate}
/>
</Menu>
</Popover>
Expand Down
15 changes: 15 additions & 0 deletions src/components/ImportTable.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,20 @@ class ImportTable extends React.Component {
/>
),
});
} else if (field === "disabled") {
return {
name: field,
component: Toggle,
props: {
name: field,
defaultToggled: value,
onToggle: (event, isInputChecked) => {
this.onUpdateField(user.id, field, isInputChecked);
},
style: { width: "100%" },
},
validators,
};
} else {
const extraProps = { changeEvent: "onBlur" };
return this.getTextField(field, value, {
Expand Down Expand Up @@ -496,6 +510,7 @@ class ImportTable extends React.Component {
organisationUnits: templateUser.attributes.organisationUnits,
dataViewOrganisationUnits: templateUser.attributes.dataViewOrganisationUnits,
email: templateUser.attributes.email,
disabled: templateUser.attributes.disabled,
};
} else {
newUser = {
Expand Down
24 changes: 19 additions & 5 deletions src/components/MultipleSelector.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,16 @@ class MultipleSelector extends React.Component {
}

titleByField = {
userGroups: "assignGroups",
userRoles: "assignRoles",
organisationUnitsCapture: "assignToOrgUnitsCapture",
dataViewOrganisationUnits: "assignToOrgUnitsOutput",
userGroups: "assign_groups",
userRoles: "assign_roles",
organisationUnits: "assign_to_org_units_capture",
dataViewOrganisationUnits: "assign_to_org_units_output",
};

renderForm() {
const { field, options, orgUnitRoots } = this.props;
const { selected } = this.state;
const t = this.getTranslation.bind(this);

switch (field) {
case "userGroups":
Expand All @@ -102,7 +103,18 @@ class MultipleSelector extends React.Component {
onChange={this.onMultiSelectChange}
/>
);
case "organisationUnitsCapture":
case "organisationUnits":
return (
<OrgUnitForm
onRequestClose={this.closeDialog}
onChange={this.onOrgUnitsChange}
roots={orgUnitRoots}
selected={selected}
intersectionPolicy={false}
filteringByNameLabel={t("filter_organisation_units_capture_by_name")}
orgUnitsSelectedLabel={t("organisation_units_capture_selected")}
/>
);
case "dataViewOrganisationUnits":
return (
<OrgUnitForm
Expand All @@ -111,6 +123,8 @@ class MultipleSelector extends React.Component {
roots={orgUnitRoots}
selected={selected}
intersectionPolicy={false}
filteringByNameLabel={t("filter_organisation_units_output_by_name")}
orgUnitsSelectedLabel={t("organisation_units_output_selected")}
/>
);
default:
Expand Down
Loading

0 comments on commit e4f95dd

Please sign in to comment.