Skip to content

Commit

Permalink
Merge branch 'develop' into useQuery
Browse files Browse the repository at this point in the history
  • Loading branch information
nihal467 authored Sep 13, 2023
2 parents 105ca02 + cc6b570 commit c898f67
Show file tree
Hide file tree
Showing 15 changed files with 171 additions and 37 deletions.
23 changes: 12 additions & 11 deletions .github/workflows/cypress.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,22 @@ jobs:
repository: coronasafe/care
path: care

- name: Run docker compose up on care 🐳
- name: Start care docker containers 🐳
run: |
cd care
cd care
make docker_config_file=docker-compose.pre-built.yaml up
sleep 60s
while docker compose exec backend bash -c "python manage.py showmigrations 2>/dev/null | cat | grep -q '\[ \]'"; do
>&2 echo "Migrations are not yet applied - sleeping"
sleep 5
done
echo "Migrations are applied"
cd ..
- name: Load dummy data into care backend 📂
run: |
cd care
docker compose exec backend bash -c "python manage.py load_dummy_data"
cd ..
# Voluntarily kept 60 seconds delay to wait for migrations to complete.
- name: Check care is up ♻
run: curl -o /dev/null -s -w "%{http_code}\n" http://localhost:9000
Expand Down Expand Up @@ -93,10 +101,3 @@ jobs:
name: cypress-screenshots
path: cypress/screenshots

# Test run video was always captured, so this action uses "always()" condition
- name: Upload cypress videos 📹
uses: actions/upload-artifact@v3
if: always()
with:
name: cypress-videos
path: cypress/videos
12 changes: 11 additions & 1 deletion cypress/e2e/assets_spec/asset_homepage.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,18 @@ describe("Asset Tab", () => {
"Dummy Facility 1",
"INTERNAL",
"ACTIVE",
"ONVIF Camera"
"ONVIF Camera",
"Camera Loc"
);
assetFilters.clickadvancefilter();
assetFilters.clickslideoverbackbutton(); // to verify the back button doesn't clear applied filters
assetFilters.assertFacilityText("Dummy Facility 1");
assetFilters.assertAssetTypeText("INTERNAL");
assetFilters.assertAssetClassText("ONVIF");
assetFilters.assertStatusText("ACTIVE");
assetFilters.assertLocationText("Camera Locations");
assetFilters.clickadvancefilter();
assetFilters.clearFilters();
});

// Verify the pagination in the page
Expand Down
39 changes: 38 additions & 1 deletion cypress/pageobject/Asset/AssetFilters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ export class AssetFilters {
facilityName: string,
assetType: string,
assetStatus: string,
assetClass: string
assetClass: string,
assetLocation: string
) {
cy.contains("Advanced Filters").click();
cy.get("input[name='Facilities']")
Expand All @@ -27,6 +28,42 @@ export class AssetFilters {
.then(() => {
cy.get("[role='option']").contains(assetClass).click();
});
cy.get("#Facilities-location")
.click()
.type(assetLocation)
.then(() => {
cy.get("[role='option']").contains(assetLocation).click();
});
cy.contains("Apply").click();
}
clearFilters() {
cy.intercept("GET", "**/api/v1/asset/**").as("clearAssets");
cy.get("#clear-filter").click();
cy.wait("@clearAssets").its("response.statusCode").should("eq", 200);
cy.url().should("match", /\/assets$/);
}
clickadvancefilter() {
cy.intercept("GET", "**/api/v1/getallfacilities/**").as("advancefilter");
cy.get("#advanced-filter").click();
cy.wait("@advancefilter").its("response.statusCode").should("eq", 200);
}
clickslideoverbackbutton() {
cy.get("#close-slide-over").click();
}
// Assertions
assertFacilityText(text) {
cy.get("[data-testid=Facility]").should("contain", text);
}
assertAssetTypeText(text) {
cy.get("[data-testid='Asset Type']").should("contain", text);
}
assertAssetClassText(text) {
cy.get("[data-testid='Asset Class']").should("contain", text);
}
assertStatusText(text) {
cy.get("[data-testid=Status]").should("contain", text);
}
assertLocationText(text) {
cy.get("[data-testid=Location]").should("contain", text);
}
}
4 changes: 3 additions & 1 deletion cypress/pageobject/Asset/AssetSearch.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export class AssetSearchPage {
typeSearchKeyword(keyword: string) {
cy.get("#search").clear();
cy.get("#search").click().clear();
cy.get("#search").click().type(keyword);
}

Expand All @@ -9,7 +9,9 @@ export class AssetSearchPage {
}

clickAssetByName(assetName: string) {
cy.intercept("GET", "**/api/v1/asset/**").as("clearAssets");
cy.get("[data-testid='created-asset-list']").contains(assetName).click();
cy.wait("@clearAssets").its("response.statusCode").should("eq", 200);
}

verifyBadgeContent(expectedText: string) {
Expand Down
1 change: 1 addition & 0 deletions src/CAREUI/interactive/SlideOver.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export default function SlideOver({
>
<div className="flex items-center gap-2 p-2 pt-4">
<button
id="close-slide-over"
className="flex h-8 w-8 items-center justify-center rounded-lg text-2xl hover:bg-black/20"
onClick={() => {
setOpen(false);
Expand Down
3 changes: 2 additions & 1 deletion src/Common/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ export const ADMITTED_TO = [
{ id: "2", text: "ICU" },
{ id: "6", text: "Bed with oxygen support" },
{ id: "7", text: "Regular" },
{ id: "None", text: "No bed assigned" },
];

export const RESPIRATORY_SUPPORT = [
Expand Down Expand Up @@ -993,7 +994,7 @@ export const XLSXAssetImportSchema = {
return ip;
},
},
"Config: Camera Access Key": {
"Config - Camera Access Key": {
prop: "camera_access_key",
type: String,
},
Expand Down
2 changes: 1 addition & 1 deletion src/Components/Assets/AssetFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ function AssetFilter(props: any) {
<div className="w-full flex-none">
<FieldLabel>Location</FieldLabel>
<LocationSelect
name="Facilities"
name="Facilities-location"
setSelected={(selectedId) =>
handleLocationSelect((selectedId as string) || "")
}
Expand Down
20 changes: 18 additions & 2 deletions src/Components/Assets/AssetsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ const AssetsList = () => {
},
},
{
label: "Export Assets",
label: "Export Assets (JSON)",
action: () =>
authorizedForImportExport &&
listAssets({
Expand All @@ -333,7 +333,23 @@ const AssetsList = () => {
limit: totalCount,
}),
type: "json",
filePrefix: `assets_${facility?.name}`,
filePrefix: `assets_${facility?.name ?? "all"}`,
options: {
icon: <CareIcon className="care-l-export" />,
disabled: totalCount === 0 || !authorizedForImportExport,
},
},
{
label: "Export Assets (CSV)",
action: () =>
authorizedForImportExport &&
listAssets({
...qParams,
csv: true,
limit: totalCount,
}),
type: "csv",
filePrefix: `assets_${facility?.name ?? "all"}`,
options: {
icon: <CareIcon className="care-l-export" />,
disabled: totalCount === 0 || !authorizedForImportExport,
Expand Down
10 changes: 10 additions & 0 deletions src/Components/Facility/ConsultationCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import ButtonV2 from "../Common/components/ButtonV2";
import { NonReadOnlyUsers } from "../../Utils/AuthorizeFor";
import RelativeDateUserMention from "../Common/RelativeDateUserMention";
import useConfig from "../../Common/hooks/useConfig";
import Chip from "../../CAREUI/display/Chip";

interface ConsultationProps {
itemData: ConsultationModel;
Expand Down Expand Up @@ -70,6 +71,15 @@ export const ConsultationCard = (props: ConsultationProps) => {
</div>
<div className="mt-1 overflow-x-scroll whitespace-normal break-words text-sm font-medium leading-5">
{formatDateTime(itemData.admission_date)}
{itemData.is_readmission && (
<Chip
size="small"
variant="custom"
className="ml-4 border-blue-600 bg-blue-100 text-blue-600"
startIcon="l-repeat"
text="Readmission"
/>
)}
</div>
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions src/Components/Facility/models.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ export interface ConsultationModel {
cause_of_death?: string;
death_datetime?: string;
death_confirmed_doctor?: string;
is_readmission?: boolean;
}
export interface PatientStatsModel {
id?: number;
Expand Down
9 changes: 9 additions & 0 deletions src/Components/Patient/ManagePatients.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,15 @@ export const PatientManager = () => {
text="Review Missed"
/>
)}
{patient.last_consultation?.is_readmission && (
<Chip
size="small"
variant="custom"
className="border-blue-600 bg-blue-100 text-blue-600"
startIcon="l-repeat"
text="Readmission"
/>
)}
{patient.disease_status === "POSITIVE" && (
<Chip
size="small"
Expand Down
31 changes: 23 additions & 8 deletions src/Components/Patient/PatientHome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,13 @@ export const PatientHome = (props: any) => {
);
};

const isPatientEligibleForNewConsultation = (patientData: PatientModel) => {
return !patientData.last_consultation ||
patientData.last_consultation?.discharge_date
? true
: false;
};

return (
<Page
title={"Patient Details"}
Expand Down Expand Up @@ -1105,23 +1112,31 @@ export const PatientHome = (props: any) => {
<div
className={classNames(
"w-full rounded-lg border",
patientData.is_active &&
(!patientData?.last_consultation ||
patientData?.last_consultation?.discharge_date)
isPatientEligibleForNewConsultation(patientData)
? "cursor-pointer border-green-700 hover:bg-primary-400"
: "border-gray-700 text-gray-700 hover:cursor-not-allowed"
)}
onClick={() =>
patientData.is_active &&
(!patientData?.last_consultation ||
patientData?.last_consultation?.discharge_date) &&
isPatientEligibleForNewConsultation(patientData) &&
navigate(
`/facility/${patientData?.facility}/patient/${id}/consultation`
)
}
>
<div className="h-full space-y-2 rounded-lg bg-white p-4 shadow">
<div className="text-center">
<div
className={classNames(
"h-full space-y-2 rounded-lg bg-white p-4 shadow",
isPatientEligibleForNewConsultation(patientData) &&
"hover:bg-gray-200"
)}
>
<div
className={classNames(
"text-center",
isPatientEligibleForNewConsultation(patientData) &&
"text-green-700"
)}
>
<span>
<CareIcon className="care-l-chat-bubble-user text-5xl" />
</span>
Expand Down
17 changes: 13 additions & 4 deletions src/Components/Patient/PatientInfoCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export default function PatientInfoCard(props: {
</div>
)}
</div>
<div className="flex flex-col items-center gap-1 sm:flex-row lg:mb-2">
<div className="flex flex-col items-center gap-2 sm:flex-row lg:mb-2">
<Link
href={`/facility/${consultation?.facility}`}
className="font-semibold text-black hover:text-primary-600"
Expand Down Expand Up @@ -177,9 +177,18 @@ export default function PatientInfoCard(props: {
{consultation?.suggestion === "DC" && (
<>
<span className="mx-2"></span>
<span className="space-x-2">
Domiciliary Care{" "}
<CareIcon className="care-l-estate text-base text-gray-700" />
<span>
<CareIcon icon="l-estate" className="mr-1 text-gray-700" />
Domiciliary Care
</span>
</>
)}
{consultation?.is_readmission && (
<>
<span className="mx-2"></span>
<span>
<CareIcon icon="l-repeat" className="mr-1 text-gray-600" />
Readmitted
</span>
</>
)}
Expand Down
34 changes: 28 additions & 6 deletions src/Components/VitalsMonitor/HL7DeviceClient.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,31 @@
import { EventEmitter } from "events";
import { VitalsDataBase, VitalsValueBase, VitalsWaveformBase } from "./types";

const WAVEFORM_KEY_MAP: Record<string, EventName> = {
II: "ecg-waveform",
Pleth: "pleth-waveform",
Respiration: "spo2-waveform",
};
const ECG_WAVENAME_KEYS = [
"I",
"II",
"III",
"aVR",
"aVL",
"aVF",
"V1",
"V2",
"V3",
"V4",
"V5",
"V6",
] as const;

const WAVEFORM_KEY_MAP: Record<HL7VitalsWaveformData["wave-name"], EventName> =
{
Pleth: "pleth-waveform",
Respiration: "spo2-waveform",

// Maps each ECG wave name to the event "ecg-waveform"
...(Object.fromEntries(
ECG_WAVENAME_KEYS.map((key) => [key, "ecg-waveform"])
) as Record<EcgWaveName, EventName>),
};

/**
* Provides the API for connecting to the Vitals Monitor WebSocket and emitting
Expand Down Expand Up @@ -74,8 +94,10 @@ export interface HL7VitalsValueData extends VitalsDataBase, VitalsValueBase {
| "body-temperature2";
}

type EcgWaveName = (typeof ECG_WAVENAME_KEYS)[number];

export interface HL7VitalsWaveformData extends VitalsWaveformBase {
"wave-name": "II" | "Pleth" | "Respiration";
"wave-name": EcgWaveName | "Pleth" | "Respiration";
}

export interface HL7VitalsBloodPressureData extends VitalsDataBase {
Expand Down
2 changes: 1 addition & 1 deletion src/Components/VitalsMonitor/HL7PatientVitalsMonitor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export default function HL7PatientVitalsMonitor(props: IVitalsComponentProps) {
{/* Pulse Rate */}
<NonWaveformData
label="ECG"
attr={data.pulseRate ?? data.heartRate}
attr={data.pulseRate?.value ? data.pulseRate : data.heartRate}
className="text-green-400"
suffix={
<span className="animate-pulse font-sans text-red-500">❤️</span>
Expand Down

0 comments on commit c898f67

Please sign in to comment.