Skip to content

Commit

Permalink
Merge branch 'master' into feat/types
Browse files Browse the repository at this point in the history
  • Loading branch information
allanhvam authored Aug 26, 2024
2 parents e0f62d5 + aca1aa9 commit 0d21446
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 10 deletions.
33 changes: 32 additions & 1 deletion app/src/app/analysis/analysis-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import { Judgement } from "./judgement/judgement";
import { Health } from "./health/health";
import { Debug } from "./debug";
import { AnalysisSelectionMenu } from "./analysis-selection-menu";
import { CellConfirmModal } from "./data-table/cell-confirm-modal";

// When the fields in this array are 'approved', a given sequence is rendered
// as 'approved' also.
Expand All @@ -59,6 +60,13 @@ export default function AnalysisPage() {
const dispatch = useDispatch();
const toast = useToast();

const [isModalOpen, setModalOpen] = useState(false);
const [modalInfo, setModalInfo] = useState({
rowId: "",
columnId: "",
value: "",
});

const [detailsIsolate, setDetailsIsolate] = useState<
React.ComponentProps<typeof AnalysisDetailsModal>["isolate"]
>();
Expand Down Expand Up @@ -393,9 +401,24 @@ export default function AnalysisPage() {
[submitChange]
);

const handleConfirm = () => {
submitChange({
[modalInfo.rowId]: { [modalInfo.columnId]: modalInfo.value },
});
setModalOpen(false);
};

const handleClose = () => {
setModalOpen(false);
};

const onFreeTextEdit = React.useCallback(
(rowId: string, field: string) => (val: string) => {
if (columnConfigs[field].editable_format === "date") {
// May need a more dynamic check if other fields should use same dialog.
if (field === "cluster_id") {
setModalInfo({ rowId, columnId: field, value: val });
setModalOpen(true);
} else if (columnConfigs[field].editable_format === "date") {
if (val.match(/\d{4}-\d{1,2}-\d{1,2}/) != null) {
submitChange({ [rowId]: { [field]: val } });
}
Expand Down Expand Up @@ -670,6 +693,14 @@ export default function AnalysisPage() {
`${t("Staging")} ${Object.keys(selection).length} ${t("records")}.`}
</Box>
</Box>
<CellConfirmModal
rowId={modalInfo.rowId}
field={modalInfo.columnId}
value={modalInfo.value}
isOpen={isModalOpen}
onClose={handleClose}
onConfirm={handleConfirm}
/>
<Debug>
<p>redux selection:</p>
<pre>{JSON.stringify(selection, undefined, " ")}</pre>
Expand Down
47 changes: 47 additions & 0 deletions app/src/app/analysis/data-table/cell-confirm-modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from "react";
import {
Button,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
} from "@chakra-ui/react";
import { useTranslation } from "react-i18next";

type Props = {
rowId: string;
field: string;
value: string;
isOpen: boolean;
onClose: () => void;
onConfirm: () => void;
};

export const CellConfirmModal = (props: Props) => {
const { rowId, field, value, isOpen, onClose, onConfirm } = props;
const { t } = useTranslation();

return (
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader>{`${t("Confirm editing")} ${field}?`}</ModalHeader>
<ModalCloseButton />
<ModalBody>{`${t(
"Are you sure you want to change the value on sequence"
)} ${rowId} ${t("to")} ${value}`}</ModalBody>
<ModalFooter>
<Button variant="ghost" mr={3} onClick={onClose}>
{t("Close")}
</Button>
<Button colorScheme="blue" onClick={onConfirm}>
{t("Confirm")}
</Button>
</ModalFooter>
</ModalContent>
</Modal>
);
};
2 changes: 1 addition & 1 deletion app/src/app/workspaces/create-workspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export function CreateWorkspace() {
const [
createWorkspaceQueryState,
createWorkspaceMutation,
] = useMutation((name: string) => createWorkspace({ name }));
] = useMutation((name: string) => createWorkspace({ name, samples: [] }));

const [needsNotify, setNeedsNotify] = useState(true);

Expand Down
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ services:
command: ["/bin/sh", "-c", "/app/start.sh"]
depends_on:
- "keycloak"
- "bio_api"
- "bioapi"
restart: on-failure

environment:
Expand Down Expand Up @@ -160,7 +160,7 @@ services:
- ./auth/pg/pg-init:/docker-entrypoint-initdb.d
- ${PG_DATA_DIR}:/var/lib/postgresql/data/

bio_api:
bioapi:
image: ghcr.io/ssi-dk/bio_api:latest
user: ${CURRENT_UID}
ports:
Expand Down
2 changes: 1 addition & 1 deletion web/src/SAP/src/controllers/MicroreactController.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def send_to_microreact(user, token_info, body: NewMicroreactProjectRequestData):
tree_calcs=[]
samples = list(map(lambda s: s["id"], workspace["samples"]))

with ApiClient(Configuration(host="http://bio_api:8000")) as api_client:
with ApiClient(Configuration(host="http://bioapi:8000")) as api_client:
# Distance
api_instance = DistancesApi(api_client)
request = DistanceMatrixRequest(seq_collection="samples",
Expand Down
5 changes: 2 additions & 3 deletions web/src/SAP/src/controllers/NearestNeighborsController.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@

def post(user, token, body: NearestNeighborsRequest):
assert_user_has("search", token)

if body.id is None:
return abort(400)

with ApiClient(Configuration(host="http://bio_api:8000")) as api_client:
with ApiClient(Configuration(host="http://bioapi:8000")) as api_client:
sample = get_single_sample(body.id)
detected_species = sample["categories"]["species_detection"]["summary"]["detected_species"]

Expand Down
6 changes: 5 additions & 1 deletion web/src/SAP/src/controllers/UserController.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@


def who_am_i(user, token_info):
groups=[]
if "security-groups" in token_info:
groups=[item.lstrip('/') for item in token_info["security-groups"]]

return jsonify(
UserInfo(
user_id=token_info["email"],
data_clearance=token_info["sofi-data-clearance"],
institution=token_info["institution"],
groups=[item.lstrip('/') for item in token_info["security-groups"]],
groups=groups,
permissions=list_permissions(token_info),
)
)
Expand Down
4 changes: 4 additions & 0 deletions web/src/SAP/src/repositories/workspaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ def delete_workspace_sample(user: str, workspace_id: str, sample_id: str):

def create_workspace(user: str, workspace: CreateWorkspace):
workspaces = get_collection(WORKSPACES_COL_NAME)

if workspace.samples is None:
workspace.samples = []

record = {**workspace.to_dict(), "created_by": user}
return workspaces.update_one({'created_by': user, 'name': workspace.name}, {"$set": record}, upsert=True)

Expand Down
10 changes: 9 additions & 1 deletion web/src/SAP/src/security/permission_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,21 @@ def list_permissions(token_info: Dict[str, str]) -> List[str]:
if PERMISSION_CONFIG is None:
return permissions

if not "security-groups" in token_info:
return permissions

for group in [item.lstrip('/') for item in token_info["security-groups"]]:
for perm in PERMISSION_CONFIG[group]:
permissions.append(perm)
return permissions


def user_has(permission: str, token_info: Dict[str, str]) -> bool:
if PERMISSION_CONFIG is None:
return False

if not "security-groups" in token_info:
return False

for group in [item.lstrip('/') for item in token_info["security-groups"]]:
for perm in PERMISSION_CONFIG[group]:
if perm == permission:
Expand All @@ -40,6 +45,9 @@ def authorized_to_edit(token_info: Dict[str, str], metadata: Dict[str, Any]):
# User must have the approve claim to do modifications
if not user_has("approve", token_info):
return False
# I no institution, allow
if not "institution" in metadata:
return True
# When user's not from the same institution as the sample, they can't modify it
if token_info["institution"] == metadata["institution"]:
return True
Expand Down

0 comments on commit 0d21446

Please sign in to comment.