Skip to content

Commit

Permalink
Merged current master with tag 1.0.0 branch
Browse files Browse the repository at this point in the history
  • Loading branch information
indiclinic committed Feb 1, 2024
2 parents 61f50f3 + 233d56d commit f0ad599
Show file tree
Hide file tree
Showing 161 changed files with 5,127 additions and 757 deletions.
26 changes: 26 additions & 0 deletions .github/scripts/transifex.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/bash

function command_exists() {
command -v "$1" >/dev/null 2>&1
}

if ! command_exists tx; then
echo "Transifex CLI is not installed. Installing..."
curl -o- https://raw.githubusercontent.com/transifex/cli/master/install.sh | bash
mv tx /usr/local/bin/tx
fi

if [ ! -f .tx/config ]; then
echo "Transifex config file (.tx/config) not found in the repository."
exit 1
fi

echo "Pushing translation source file to Transifex..."
tx push -s

if [ $? -ne 0 ]; then
echo "Error: Transifex push failed. Please check the error message above."
exit 1
else
echo "Translation source file successfully pushed to Transifex."
fi
5 changes: 5 additions & 0 deletions .github/workflows/build_publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ jobs:
run: cd ui && yarn cache clean && /bin/bash ./scripts/package.sh
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Push Translations to Transifex
run: |
bash .github/scripts/transifex.sh
env:
TX_TOKEN: ${{ secrets.TX_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to DockerHub
Expand Down
107 changes: 79 additions & 28 deletions .tx/config
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,94 @@
host = https://www.transifex.com

[o:openmrs:p:bahmni:r:admin-app]
file_filter = ui/app/i18n/admin/locale_<lang>.json
source_file = ui/app/i18n/admin/locale_en.json
source_lang = en
type = KEYVALUEJSON
file_filter = ui/app/i18n/admin/locale_<lang>.json
source_file = ui/app/i18n/admin/locale_en.json
source_lang = en
type = KEYVALUEJSON
replace_edited_strings = false
keep_translations = false

[o:openmrs:p:bahmni:r:adt-app]
file_filter = ui/app/i18n/adt/locale_<lang>.json
source_file = ui/app/i18n/adt/locale_en.json
source_lang = en
type = KEYVALUEJSON
file_filter = ui/app/i18n/adt/locale_<lang>.json
source_file = ui/app/i18n/adt/locale_en.json
source_lang = en
type = KEYVALUEJSON
replace_edited_strings = false
keep_translations = false

[o:openmrs:p:bahmni:r:appointments-app]
file_filter = ui/app/i18n/appointments/locale_<lang>.json
source_file = ui/app/i18n/appointments/locale_en.json
type = KEYVALUEJSON
minimum_perc = 0
resource_name = Appointments App
replace_edited_strings = false
keep_translations = false

[o:openmrs:p:bahmni:r:clinical-app]
file_filter = ui/app/i18n/clinical/locale_<lang>.json
source_file = ui/app/i18n/clinical/locale_en.json
source_lang = en
type = KEYVALUEJSON
file_filter = ui/app/i18n/clinical/locale_<lang>.json
source_file = ui/app/i18n/clinical/locale_en.json
source_lang = en
type = KEYVALUEJSON
replace_edited_strings = false
keep_translations = false

[o:openmrs:p:bahmni:r:document-upload-app]
file_filter = ui/app/i18n/document-upload/locale_<lang>.json
source_file = ui/app/i18n/document-upload/locale_en.json
type = KEYVALUEJSON
minimum_perc = 0
resource_name = Document Upload App
replace_edited_strings = false
keep_translations = false

[o:openmrs:p:bahmni:r:home-app]
file_filter = ui/app/i18n/home/locale_<lang>.json
source_file = ui/app/i18n/home/locale_en.json
source_lang = en
type = KEYVALUEJSON
file_filter = ui/app/i18n/home/locale_<lang>.json
source_file = ui/app/i18n/home/locale_en.json
source_lang = en
type = KEYVALUEJSON
replace_edited_strings = false
keep_translations = false

[o:openmrs:p:bahmni:r:ipd-app]
file_filter = ui/app/i18n/ipd/locale_<lang>.json
source_file = ui/app/i18n/ipd/locale_en.json
type = KEYVALUEJSON
minimum_perc = 0
resource_name = IPD App
replace_edited_strings = false
keep_translations = false

[o:openmrs:p:bahmni:r:orders-app]
file_filter = ui/app/i18n/orders/locale_<lang>.json
source_file = ui/app/i18n/orders/locale_en.json
source_lang = en
type = KEYVALUEJSON
file_filter = ui/app/i18n/orders/locale_<lang>.json
source_file = ui/app/i18n/orders/locale_en.json
source_lang = en
type = KEYVALUEJSON
replace_edited_strings = false
keep_translations = false

[o:openmrs:p:bahmni:r:ot-app]
file_filter = ui/app/i18n/ot/locale_<lang>.json
source_file = ui/app/i18n/ot/locale_en.json
type = KEYVALUEJSON
minimum_perc = 0
resource_name = OT App
replace_edited_strings = false
keep_translations = false

[o:openmrs:p:bahmni:r:registration-app]
file_filter = ui/app/i18n/registration/locale_<lang>.json
source_file = ui/app/i18n/registration/locale_en.json
source_lang = en
type = KEYVALUEJSON
file_filter = ui/app/i18n/registration/locale_<lang>.json
source_file = ui/app/i18n/registration/locale_en.json
source_lang = en
type = KEYVALUEJSON
replace_edited_strings = false
keep_translations = false

[o:openmrs:p:bahmni:r:reports-app]
file_filter = ui/app/i18n/reports/locale_<lang>.json
source_file = ui/app/i18n/reports/locale_en.json
source_lang = en
type = KEYVALUEJSON
file_filter = ui/app/i18n/reports/locale_<lang>.json
source_file = ui/app/i18n/reports/locale_en.json
source_lang = en
type = KEYVALUEJSON
replace_edited_strings = false
keep_translations = false

41 changes: 27 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@
blog writeup: [Bahmni EMR - 1 M lines of code](https://medium.com/bahmni-blog/bahmni-emr-1million-lines-of-open-source-code-87e610e9a4ec)
4. This code needs help in migrating to React. If you are interested in helping, please ping the
Bahmni team on Slack (`#community` channel).
5. All Epics, Stories, Bugs, etc are tracked in [JIRA](https://bahmni.atlassian.net/secure/RapidBoard.jspa?rapidView=25&projectKey=BAH&quickFilter=66).
6. To Run Bahmni locally you will need a Vagrant setup. See this [documentation](https://bahmni.atlassian.net/wiki/spaces/BAH/pages/14712841/Bahmni+Virtual+Box).
5. All Epics, Stories, Bugs, etc are tracked in [JIRA: Volunteer Board](https://bahmni.atlassian.net/secure/RapidBoard.jspa?rapidView=25&projectKey=BAH&quickFilter=66).
6. To Run Bahmni locally you should use Docker option of Bahmni or Vagrant option. Docker is recommended.

# Build

1. This build requires Node, npm, yarn, grunt and compass.
2. You can see the [travis-ci build](https://travis-ci.org/Bahmni/openmrs-module-bahmniapps) to understand the build commands that get executed.
3. You can also see the go-cd build [Bahmni_MRS_v0_93](https://ci-server.mybahmni.org/go/tab/build/detail/Bahmni_MRS_v0_93/Latest/BuildStage/1/BahmniApps) pipeline to see in-depth build steps.
### Notes
1. This build requires Node, npm, yarn, grunt and compass (ruby).
2. You can see the [Github Action Build](https://github.com/Bahmni/openmrs-module-bahmniapps/actions/workflows/build_publish.yml) to see what commands get executed.

### One time installation:

Expand All @@ -32,21 +32,26 @@ These steps need to performed ONLY the FIRST TIME you set up this code.
4. Install Compass:
- Compass compiles SASS/SCSS into CSS.
- Requires ruby (It's recommended to install ruby also using rvm. See install [rvm with ruby](https://stackify.com/rvm-how-to-get-started-and-manage-your-ruby-installations/)).
- Ruby version: 2.6.6
- Ruby version: 2.6.6
- Once ruby is installed, you can install compass using: `gem install compass`

### Build commands

Run these commands from within the `ui` sub-folder.
**NOTE:** Run these commands from within the `ui` sub-folder.

1. `yarn install`
2. `yarn ci` (will internally trigger grunt)
3. If build is successful, the `dist` folder has the set of files to be deployed in Apache (or in Vagrant).

### Docker (Hot Deploy)

1. If you are using Bahmni Docker, then you can hot deploy your app by following these steps: [Bahmni Web Configurations Docker (Wiki)](https://bahmni.atlassian.net/wiki/spaces/BAH/pages/3117449349/Bahmni-Web+Configurations+docker)

### Vagrant (Hot Deploy)

1. You can also sym-link the `/var/www/bahmniapps` folder in Vagrant to `{CODE_DIR}/ui/app/` folder so that JS changes are reflected immediately.


### Debugging AngularJS App

1. To be able to debug Bahmni frontend please read this post: [Debugging AngularJS](https://www.newline.co/ng-book/p/Debugging-AngularJS/)
Expand All @@ -60,32 +65,40 @@ Resources to build the following docker images can be found in the [package](/pa

## Prevent Search Engines from Indexing the homepage

>⚠️ : Search Engines are able to index the Bahmni installation homepage.

>⚠️ : Search Engines are able to index the Bahmni App homepage.
This behaviour can be prevented by:

1. **Adding a “noindex” metatag:**
1. **Adding a “noindex” metatag:**

The following tag should be inserted in the `<head>` section of the homepage's HTML markup:

```
<meta name=”robots” content=”noindex”>
```

Additionally, in order to both _de-index_ the homepage and not follow the links, use the `noindex` with the `nofollow` metatag:

```
<meta name=”robots” content=”noindex,nofollow”>
```
> The same is already done [here](https://github.com/Bahmni/openmrs-module-bahmniapps/blob/master/package/docker/index.html#L5)

> The same is already done [here](https://github.com/Bahmni/openmrs-module-bahmniapps/blob/master/package/docker/index.html#L5)
>
2. **Using an X-ROBOTS-TAG HTTP HEADER:**

An `X-Robots-Tag` can be added to the HTTP response header. It has basically the same effect as a `noindex` tag, but with the additional options to specify conditions for different search engines. For more information, please see Google’s guide [here](https://developers.google.com/search/docs/advanced/robots/robots_meta_tag). Here are examples of X-Robots-Tag for specific functions:

- To de-index a web page:

```
Header set X-Robots-Tag "noindex, nofollow"
```
> The same is already done [here](https://github.com/Bahmni/openmrs-module-bahmniapps/blob/master/package/docker/httpd.conf#L32)

> The same is already done [here](https://github.com/Bahmni/openmrs-module-bahmniapps/blob/master/package/docker/httpd.conf#L32)
>
### SNOMED Integration Support

openmrs-module-bahmniapps also integrates with SNOMED for terminology lookup and CDSS. More details can be found in [this](https://bahmni.atlassian.net/wiki/spaces/BAH/pages/3132686337/SNOMED+FHIR+Terminology+Server+Integration+with+Bahmni) Wiki link
7 changes: 7 additions & 0 deletions ui/app/admin/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ angular.module('admin')
data: {
backLinks: [{label: "Home", state: "admin.dashboard", icon: "fa-home"}]
}
}).state('admin.fhirExport', {
url: '/fhirExport',
templateUrl: 'views/fhirExport.html',
controller: 'FHIRExportController',
data: {
backLinks: [{label: "Home", state: "admin.dashboard", icon: "fa-home"}]
}
});
$httpProvider.defaults.headers.common['Disable-WWW-Authenticate'] = true;
$bahmniTranslateProvider.init({app: 'admin', shouldMerge: true});
Expand Down
108 changes: 108 additions & 0 deletions ui/app/admin/controllers/fhirExportController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
'use strict';

angular.module('bahmni.admin')
.controller('FHIRExportController', ['$rootScope', '$scope', '$q', '$http', '$translate', 'messagingService', 'fhirExportService', function ($rootScope, $scope, $q, $http, $translate, messagingService, fhirExportService) {
var DateUtil = Bahmni.Common.Util.DateUtil;

var convertToLocalDate = function (date) {
var localDate = DateUtil.parseLongDateToServerFormat(date);
return DateUtil.getDateTimeInSpecifiedFormat(localDate, 'MMMM Do, YYYY [at] h:mm:ss A');
};

var subtractDaysFromToday = function (minusDays) {
const currentDate = new Date();
currentDate.setDate(currentDate.getDate() - minusDays);
return currentDate;
};

$scope.startDate = subtractDaysFromToday(30);
$scope.endDate = subtractDaysFromToday(0);

$scope.anonymise = true;

var isLoggedInUserPrivileged = function (expectedPrivileges) {
var currentPrivileges = _.map($rootScope.currentUser.privileges, function (privilege) {
return privilege.name;
});
var hasPrivilege = expectedPrivileges.some(function (privilege) {
return currentPrivileges.indexOf(privilege) !== -1;
});
return hasPrivilege;
};

var hasInsufficientPrivilegeForPlainExport = function () {
var plainExportPrivileges = [Bahmni.Common.Constants.plainFhirExportPrivilege];
var hasPlainExportPrivilege = isLoggedInUserPrivileged(plainExportPrivileges);
return !hasPlainExportPrivilege;
};
$scope.isCheckboxDisabled = hasInsufficientPrivilegeForPlainExport();

var isUserPrivilegedForFhirExport = function () {
var defaultExportPrivileges = [Bahmni.Common.Constants.fhirExportPrivilege, Bahmni.Common.Constants.plainFhirExportPrivilege];
return isLoggedInUserPrivileged(defaultExportPrivileges);
};
$scope.hasExportPrivileges = isUserPrivilegedForFhirExport();

$scope.loadFhirTasksForPrivilegedUsers = function () {
var deferred = $q.defer();
$scope.tasks = [];
if (isUserPrivilegedForFhirExport()) {
fhirExportService.getUuidForAnonymiseConcept().then(function (response) {
$scope.uuid = response && response.data && response.data.results && response.data.results[0] && response.data.results[0].uuid || null;
});
fhirExportService.loadFhirTasks().then(function (response) {
if (response.data && response.data.entry) {
var fhirExportTasks = response.data.entry.filter(function (task) {
return task.resource.basedOn && task.resource.basedOn.some(function (basedOn) {
return basedOn.reference === $scope.uuid;
});
});
$scope.tasks = fhirExportTasks.map(function (task) {
task.resource.authoredOn = convertToLocalDate(task.resource.authoredOn);
return task;
});
deferred.resolve();
}
}).catch(function (error) {
deferred.reject(error);
});
}
return deferred.promise;
};

$scope.loadFhirTasksForPrivilegedUsers();

$scope.exportFhirData = function () {
var deferred = $q.defer();
var startDate = DateUtil.getDateWithoutTime($scope.startDate);
var endDate = DateUtil.getDateWithoutTime($scope.endDate);
var anonymise = $scope.anonymise;
var username = $rootScope.currentUser.username;

fhirExportService.export(username, startDate, endDate, anonymise).success(function () {
fhirExportService.submitAudit(username, startDate, endDate, anonymise).success(function () {
messagingService.showMessage("info", $translate.instant("EXPORT_PATIENT_REQUEST_SUBMITTED"));
$scope.loadFhirTasksForPrivilegedUsers();
deferred.resolve();
});
}).catch(function (error) {
messagingService.showMessage("error", $translate.instant("EXPORT_PATIENT_REQUEST_SUBMIT_ERROR"));
console.error("FHIR Export request failed");
deferred.reject(error);
});
return deferred.promise;
};

$scope.extractAttribute = function (array, searchValue, attributeToExtract) {
var foundElement = array && array.find(function (inputElement) { return inputElement.type.text === searchValue; });
if (foundElement && foundElement.hasOwnProperty(attributeToExtract)) {
return foundElement[attributeToExtract];
}
return null;
};

$scope.extractBoolean = function (array, searchValue, attributeToExtract) {
var booleanStr = $scope.extractAttribute(array, searchValue, attributeToExtract);
return booleanStr && booleanStr.toLowerCase() === "true";
};
}]);
3 changes: 2 additions & 1 deletion ui/app/admin/controllers/orderTemplateController.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
'drug': {
'name': drug.name,
'uuid': drug.uuid,
'form': drug.dosageForm.display
'form': drug.dosageForm.display,
'drugReferenceMaps': drug.drugReferenceMaps || []
},
'value': drug.name
};
Expand Down
Loading

0 comments on commit f0ad599

Please sign in to comment.