diff --git a/.github/scripts/transifex.sh b/.github/scripts/transifex.sh deleted file mode 100755 index 9266188bd5..0000000000 --- a/.github/scripts/transifex.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/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 - -if [ "$1" == "push" ]; then - echo "Pushing translation source file to Transifex..." - tx push -s -elif [ "$1" == "pull" ]; then - echo "Pulling translations from Transifex..." - tx pull -t -s --mode reviewed --use-git-timestamps -else - echo "Invalid operation. Please specify either 'push' or 'pull'." - exit 1 -fi - -if [ $? -ne 0 ]; then - echo "Error: Transifex operation failed. Please check the error message above." - exit 1 -else - echo "Transifex operation completed successfully." -fi diff --git a/.github/workflows/build_publish.yml b/.github/workflows/build_publish.yml index fd8f38883a..f0df9c0654 100644 --- a/.github/workflows/build_publish.yml +++ b/.github/workflows/build_publish.yml @@ -45,7 +45,10 @@ jobs: uses: docker/setup-qemu-action@v2 - name: Push Translations to Transifex run: | - bash .github/scripts/transifex.sh push + curl -o transifex.sh https://raw.githubusercontent.com/Bahmni/bahmni-infra-utils/main/transifex.sh + chmod +x transifex.sh + ./transifex.sh push + rm transifex.sh env: TX_TOKEN: ${{ secrets.TX_TOKEN }} - name: Set up Docker Buildx diff --git a/.github/workflows/pull_translations.yml b/.github/workflows/pull_translations.yml index 26bdf6cbb2..8b14703710 100644 --- a/.github/workflows/pull_translations.yml +++ b/.github/workflows/pull_translations.yml @@ -18,7 +18,10 @@ jobs: - name: Pull Translations from Transifex run: | - bash .github/scripts/transifex.sh pull + curl -o transifex.sh https://raw.githubusercontent.com/Bahmni/bahmni-infra-utils/main/transifex.sh + chmod +x transifex.sh + ./transifex.sh pull + rm transifex.sh env: TX_TOKEN: ${{ secrets.TX_TOKEN }} diff --git a/ui/app/common/domain/services/visitDocumentService.js b/ui/app/common/domain/services/visitDocumentService.js index 2c64dab0d4..c4cb310e86 100644 --- a/ui/app/common/domain/services/visitDocumentService.js +++ b/ui/app/common/domain/services/visitDocumentService.js @@ -84,4 +84,4 @@ angular.module('bahmni.common.domain') } return "not_supported"; }; - }]); \ No newline at end of file + }]); diff --git a/ui/app/common/ui-helper/services/messagingService.js b/ui/app/common/ui-helper/services/messagingService.js index b7c1652cce..b127a70e73 100644 --- a/ui/app/common/ui-helper/services/messagingService.js +++ b/ui/app/common/ui-helper/services/messagingService.js @@ -11,7 +11,7 @@ angular.module('bahmni.common.uiHelper') this.showMessage = function (level, message, errorEvent) { var messageObject = {'value': '', 'isServerError': false}; - messageObject.value = message.replace(/\[|\]|null/g, ''); + messageObject.value = message ? message.replace(/\[|\]|null/g, '') : " "; if (errorEvent) { messageObject.isServerError = true; if (!self.messages[level].length) { diff --git a/ui/app/i18n/admin/locale_es.json b/ui/app/i18n/admin/locale_es.json index 3e9a9c4882..d6a0f08743 100644 --- a/ui/app/i18n/admin/locale_es.json +++ b/ui/app/i18n/admin/locale_es.json @@ -1,5 +1,5 @@ { - "userName": "Username", + "userName": "Nombre de Usuario", "password": "Password", "location": "Location", "login": "Login", diff --git a/ui/app/i18n/document-upload/locale_en.json b/ui/app/i18n/document-upload/locale_en.json index 77d50d2b43..8b5648a938 100644 --- a/ui/app/i18n/document-upload/locale_en.json +++ b/ui/app/i18n/document-upload/locale_en.json @@ -33,5 +33,6 @@ "VISIT_FROM_LABEL": "From:", "VISIT_TO_LABEL": "To:", "FILE_TYPE_NOT_SUPPORTED_MESSAGE": "File type is not supported", - "FILE_SIZE_LIMIT_EXCEEDED_MESSAGE": "File size limit exceeded. Please upload a file less than {{maxAllowedSize}} MB." + "FILE_SIZE_LIMIT_EXCEEDED_MESSAGE": "File size limit exceeded. Please upload a file less than {{maxAllowedSize}} MB.", + "SIZE_LIMIT_EXCEEDED_MESSAGE": "File size limit exceeded. Please upload a smaller file" } diff --git a/ui/package.json b/ui/package.json index 13fd8c3e93..2497f411ff 100644 --- a/ui/package.json +++ b/ui/package.json @@ -60,7 +60,7 @@ "@bower_components/jasmine": "pivotal/jasmine#>=2", "@bower_components/jasmine-jquery": "velesin/jasmine-jquery#2.1.0", "@bower_components/q": "kriskowal/q#1.0.1", - "bahmni-form-controls": "^0.93.12", + "bahmni-form-controls": "^0.93.16", "eslint-config-angular": "^0.5.0", "eslint-config-semistandard": "^7.0.0", "eslint-config-standard": "^6.2.1", diff --git a/ui/test/unit/common/domain/services/visitDocumentService.spec.js b/ui/test/unit/common/domain/services/visitDocumentService.spec.js index f370bf8555..348370d2c3 100644 --- a/ui/test/unit/common/domain/services/visitDocumentService.spec.js +++ b/ui/test/unit/common/domain/services/visitDocumentService.spec.js @@ -1,7 +1,7 @@ "use strict"; describe("visitDocumentService", function () { - var _$http, _provide, visitDocumentService, _auditLogService, _configurations; + var _$http, _provide, visitDocumentService, _auditLogService, _configurations, messagingService, translate, roundToNearestHalf; beforeEach(function () { module('bahmni.common.domain'); module(function ($provide) { @@ -14,11 +14,15 @@ describe("visitDocumentService", function () { _configurations = jasmine.createSpyObj("configurations", ["encounterConfig"]); _configurations.encounterConfig.and.returnValue(encounterConfig); _provide = $provide; + messagingService = jasmine.createSpyObj('messagingService', ['showMessage', 'clearAll']); + translate = jasmine.createSpyObj('$translate', ['instant']); }); inject(function () { _provide.value('$http', _$http); _provide.value('auditLogService', _auditLogService); _provide.value('configurations', _configurations); + _provide.value('messagingService', messagingService); + _provide.value('$translate', translate); }); inject(function (_visitDocumentService_) { visitDocumentService = _visitDocumentService_; @@ -156,6 +160,46 @@ describe("visitDocumentService", function () { expect(_auditLogService.log).toHaveBeenCalledWith(visitDocuments.patientUuid, 'EDIT_ENCOUNTER', {encounterUuid: visitDocumentResponse.encounterUuid, encounterType: "Patient Document"}, "Patient Document"); }); + it('should throw error when uploading files greater than maximum allowed size', function (done) { + var file = "data:image/jpeg;base64asldkjfldasflladsfjaldsfkdsaklf"; + var patientUuid = "test-patient-uuid"; + var encounterTypeName = "test-encounter-name"; + var fileName = "test-file.jpeg"; + var fileType = "image"; + var data = {error: {message: "The file size exceeds the maximum allowed limit"}}; + var maxAllowedSize = 7; + + _$http.post.and.returnValue(specUtil.respondWithPromise(Q, {error: data})); + + visitDocumentService.saveFile(file, patientUuid, encounterTypeName, fileName, fileType).then(function (response) { + fail("The success callback should not be called"); + }).catch(function (error) { + expect(error.data.error.message).toEqual(data.error.message); + expect(messagingService.showMessage).toHaveBeenCalledWith("error", jasmine.any(String)); + expect(messagingService.showMessage.calls.argsFor(0)[1]).toContain(maxAllowedSize * 0.70); + }).finally(done); + }); + + describe("roundToNearestHalf", function () { + beforeEach(inject(function() { + roundToNearestHalf = function (value) { + var floorValue = Math.floor(value); + if ((value - floorValue) < 0.5) { + return floorValue; + } + return floorValue + 0.5; + }; + })); + it('should round to nearest half when value is greater than or equal to 0.5', function() { + expect(roundToNearestHalf(3.7)).toBe(3.5); + expect(roundToNearestHalf(6.9)).toBe(6.5); + expect(roundToNearestHalf(4.2)).toBe(4); + expect(roundToNearestHalf(7.4)).toBe(7); + expect(roundToNearestHalf(4.5)).toBe(4.5); + expect(roundToNearestHalf(5.5)).toBe(5.5); + }); + }); + describe("getFileType", function () { it("should give file type as pdf for pdf mime type", function () { expect(visitDocumentService.getFileType("image/jpeg")).toBe("image"); diff --git a/ui/test/unit/common/util/dateUtil.spec.js b/ui/test/unit/common/util/dateUtil.spec.js index 83faa67822..eaa4cad7e7 100644 --- a/ui/test/unit/common/util/dateUtil.spec.js +++ b/ui/test/unit/common/util/dateUtil.spec.js @@ -277,6 +277,52 @@ describe('DateUtil', function () { }); describe("formatDateWithoutTime", function () { + it("should take a long representation of date and format", function () { + var date = new Date(1427803080000); + expect(dateUtil.formatDateWithoutTimeToLocal(1427803080000)).toEqual(moment(date).format(clientDateDisplayFormat)); + }); + + it("should take a string representation of date and format", function () { + var date = new Date(); + expect(dateUtil.formatDateWithoutTimeToLocal(moment(date).format(dateFormat))).toEqual(moment(date).format(clientDateDisplayFormat)); + }); + + it("should not break for undefined and return null", function () { + expect(dateUtil.formatDateWithoutTimeToLocal(undefined)).toBeNull(); + }); + + it("should return the original string if it cannot be formatted", function () { + expect(dateUtil.formatDateWithoutTimeToLocal("Recent")).toBe("Recent"); + }); + + it('should return formatted date without time for valid date input', function() { + var validDate = "2023-07-13"; + var expectedOutput = moment(validDate).format(clientDateDisplayFormat); + var formattedDate = Bahmni.Common.Util.DateUtil.formatDateWithoutTime(validDate); + expect(formattedDate).toBe(expectedOutput); + }); + + it('should return formatted date without time for array date input', function() { + var validDate = [2024,2,25,6,30]; + var expectedOutput = moment(validDate).format(clientDateDisplayFormat); + var formattedDate = Bahmni.Common.Util.DateUtil.formatDateWithoutTime(validDate); + expect(formattedDate).toBe(expectedOutput); + }); + + it('should return the same input for invalid date input', function() { + var invalidDate = "invalid_date"; + var formattedDate = Bahmni.Common.Util.DateUtil.formatDateWithoutTime(invalidDate); + expect(formattedDate).toBe(invalidDate); + }); + + it('should return null for null input', function() { + var nullInput = null; + var formattedDate = Bahmni.Common.Util.DateUtil.formatDateWithoutTime(nullInput); + expect(formattedDate).toBeNull(); + }); + }); + + describe('formatDateWithoutTimeToLocal', function() { it("should take a long representation of date and format", function () { var date = new Date(1427803080000); expect(dateUtil.formatDateWithoutTime("1427803080000")).toEqual(moment(date).format(clientDateDisplayFormat)); @@ -294,6 +340,32 @@ describe('DateUtil', function () { it("should return the original string if it cannot be formatted", function () { expect(dateUtil.formatDateWithoutTime("Recent")).toBe("Recent"); }); + + it('should return formatted date without time for valid date input', function() { + var validDate = "2023-07-13"; + var expectedOutput = moment(validDate).format(clientDateDisplayFormat); + var formattedDate = Bahmni.Common.Util.DateUtil.formatDateWithoutTimeToLocal(validDate); + expect(formattedDate).toBe(expectedOutput); + }); + + it('should return formatted date without time for array date input', function() { + var validDate = [2024,2,25,6,30]; + var expectedOutput = moment(validDate).format(clientDateDisplayFormat); + var formattedDate = Bahmni.Common.Util.DateUtil.formatDateWithoutTimeToLocal(validDate); + expect(formattedDate).toBe(expectedOutput); + }); + + it('should return the same input for invalid date input', function() { + var invalidDate = "invalid_date"; + var formattedDate = Bahmni.Common.Util.DateUtil.formatDateWithoutTimeToLocal(invalidDate); + expect(formattedDate).toBe(invalidDate); + }); + + it('should return null for null input', function() { + var nullInput = null; + var formattedDate = Bahmni.Common.Util.DateUtil.formatDateWithoutTimeToLocal(nullInput); + expect(formattedDate).toBeNull(); + }); }); describe("formatTime", function () { @@ -310,11 +382,84 @@ describe('DateUtil', function () { it("should not break for undefined and return null", function () { expect(dateUtil.formatTime(undefined)).toBeNull(); }); + it("should return the original string if it cannot be formatted", function () { expect(dateUtil.formatTime("Recent")).toBe("Recent"); }) + + it('should return formatted time for valid date input', function() { + var validDate = "2023-07-13T10:30:00"; + var expectedOutput = moment(validDate).format(clientTimeDisplayFormat); + var formattedTime = Bahmni.Common.Util.DateUtil.formatTime(validDate); + expect(formattedTime).toBe(expectedOutput); + }); + + it('should return formatted time for array date input', function() { + var validDate = [2024,2,25,6,30]; + var expectedOutput = moment(validDate).format(clientDateDisplayFormat); + var formattedDate = Bahmni.Common.Util.DateUtil.formatDateWithoutTimeToLocal(validDate); + expect(formattedDate).toBe(expectedOutput); + }); + + it('should return the same input for invalid date input', function() { + var invalidDate = "invalid_date"; + var formattedTime = Bahmni.Common.Util.DateUtil.formatTime(invalidDate); + expect(formattedTime).toBe(invalidDate); + }); + + it('should return null for null input', function() { + var nullInput = null; + var formattedTime = Bahmni.Common.Util.DateUtil.formatTime(nullInput); + expect(formattedTime).toBeNull(); + }); }); + describe('formatTimeToLocal', function() { + it("should take a long representation of date and format", function () { + var date = new Date(1427803080000); + expect(dateUtil.formatTime("1427803080000")).toEqual(moment.utc(date).local().format(clientTimeDisplayFormat)); + }); + + it("should take a string representation of date and format", function () { + var date = new Date(); + expect(dateUtil.formatTime(moment(date).format(dateFormat))).toEqual(moment.utc(date).local().format(clientTimeDisplayFormat)); + }); + + it("should not break for undefined and return null", function () { + expect(dateUtil.formatTime(undefined)).toBeNull(); + }); + + it("should return the original string if it cannot be formatted", function () { + expect(dateUtil.formatTime("Recent")).toBe("Recent"); + }) + + it('should return formatted time in local timezone for valid date input', function() { + var validDate = "2023-07-13T10:30:00"; + var expectedOutput = moment.utc(validDate).local().format(clientTimeDisplayFormat); + var formattedTime = Bahmni.Common.Util.DateUtil.formatTimeToLocal(validDate); + expect(formattedTime).toBe(expectedOutput); + }); + + it('should return formatted time for array date input', function() { + var validDate = [2024,2,25,6,30]; + var expectedOutput = moment.utc(validDate).local().format(clientTimeDisplayFormat); + var formattedDate = Bahmni.Common.Util.DateUtil.formatTimeToLocal(validDate); + expect(formattedDate).toBe(expectedOutput); + }); + + it('should return the same input for invalid date input', function() { + var invalidDate = "invalid_date"; + var formattedTime = Bahmni.Common.Util.DateUtil.formatTimeToLocal(invalidDate); + expect(formattedTime).toBe(invalidDate); + }); + + it('should return null for null input', function() { + var nullInput = null; + var formattedTime = Bahmni.Common.Util.DateUtil.formatTimeToLocal(nullInput); + expect(formattedTime).toBeNull(); + }); + }); + describe("diffInDays", function () { it("should return 0 for difference of same date", function () { var date = new Date('2015', '7', '14', '12');