Closed Charence closed 4 years ago
The new fields on the UI map to the following data fields:
element
risk_factor
scope
location_desc
Treatment will consist of 2 text fields, as follows:
mitigation_desc
(existing field, restricted to 220 chars)mitigation_detail
(new field, unrestricted)mitigation_stage
mitigation_type
Annotations have also been added the the wireframe:
@m1chalkubiak
Hi @Charence Thanks for describing new fields and adding comments in wireframes, they were really helpful. Most of the things from Milestone 1 are done. But I came back with a couple of things, that need your decisions.
I found one issue regarding the attachments tab. Until we create/ save risk we are unable to add any attachments. From what I understand we need to know the id of risk (which we get after creating the risk) to be able to add attachments. The best solution that I can see is disabling attachments tab for new risk (during creating) we can add tooltip saying that user needs to create (save) risk before trying to add an attachment.
From previous risk form there is one field that completely disappeared - safetibase_id
. Should we remove it completely from the application?
I have also doubts regarding displaying risk levels by
Icons. In the new layout, we have 3 places where icons are rendered
1) On risk tab the color and text part goes from level_of_risk
field
2) On treatment tab color and text part are going from residual_level_of_risk
field
3) The third icon is below the risk title and it acts exactly like the one on the treatment tab.
In all places, the type of icon is rendered depending on mitigation_status
field value.
Please, let me know if this is exactly the way how those icons should be rendered or there is different logic/depending witch was unclear for me.
If I understand You wireframes correctly You would also like to redesign the header part of the form. By moving the user name with icon and the date to common container wit title of risk and role indicator. This part of code is used in both risk and issue forms, so if You don’t anything against that it would be easier to change this in both forms.
Also, I will need to ask for help regarding mitigation_detail
field. I really don't understand what is it on the wireframes.
Is it about splitting this treatment description into two separate text areas?
Hi @m1chalkubiak, please see my responses below:
Until we create/ save risk we are unable to add any attachments. From what I understand we need to know the id of risk (which we get after creating the risk) to be able to add attachments. The best solution that I can see is disabling attachments tab for new risk (during creating) we can add tooltip saying that user needs to create (save) risk before trying to add an attachment.
Yes, let's do that!
From previous risk form there is one field that completely disappeared -
safetibase_id
. Should we remove it completely from the application?
safetibase_id
hidden in the UI. It does not need to be completely removed from the application.I have also doubts regarding displaying risk levels by Icons. In the new layout, we have 3 places where icons are rendered
- On risk tab the color and text part goes from
level_of_risk
field- On treatment tab color and text part are going from
residual_level_of_risk
field- The third icon is below the risk title and it acts exactly like the one on the treatment tab.
In all places, the type of icon is rendered depending on
mitigation_status
field value. Please, let me know if this is exactly the way how those icons should be rendered or there is different logic/depending witch was unclear for me.
Sorry this was not clearer. You are right for 1 and 2.
level_of_risk
residual_level_of_risk
overall_level_of_risk
I have added annotations to the wireframe here: https://marvelapp.com/4b107ge/screen/65518406
Yes, please change this part for both forms. We would like the Risk or Issue header to remain visible if the user scrolls.
mitigation_detail
field. I really don't understand what is it on the wireframes.
Is it about splitting this treatment description into two separate text areas?
Yes, the user wants to have a short treatment title/description (which will be the existing mitigation_desc
) and also a longer field for treatment details (which is the new field mitigation_detail
). Both of these fields describe the treatment.
Instead of having a label for both of them (e.g. Treatment Title and Treatment Details), I think it would be nicer if they are grouped together under Treatment. Perhaps this can be achieved by not displaying the label for the Treatment Details when the field contains text?
@Charence
Instead of having a label for both of them (e.g. Treatment Title and Treatment Details), I think it would be nicer if they are grouped together under Treatment. Perhaps this can be achieved by not displaying the label for the Treatment Details when the field contains text?
Not sure if I get You correctly, we can have second field without label for sure but is this will be clear for the user what is the purpose of this additional field?
On risk tab, color/text/icon is from level_of_risk On treatment tab, color/text/icon is from residual_level_of_risk On third small icon on header, color/icon is from overall_level_of_risk
So, now is even less clear. Currently, for types of icons we are using this mapping:
export const RISK_LEVELS = {
UNMITIGATED: '',
PROPOSED: 'proposed',
AGREED_PARTIAL: 'agreed_partial',
AGREED_FULLY: 'agreed_fully',
REJECTED: 'rejected'
};
export const RISK_LEVELS_ICONS = {
[RISK_LEVELS.UNMITIGATED]: NewReleases,
[RISK_LEVELS.PROPOSED]: ErrorOutline,
[RISK_LEVELS.AGREED_PARTIAL]: ErrorSolid,
[RISK_LEVELS.AGREED_FULLY]: CheckCircle,
[RISK_LEVELS.REJECTED]: SyncProblem
};
So, we have only 5 options directly related to mitigation_status
field values, I believe we need new mapping for this. Sure, nothing hard to do (one additional icon needed), but I just want to be clear about that.
It is in the frontend/constants/risks.ts
path if You would like to check it.
Instead of having a label for both of them (e.g. Treatment Title and Treatment Details)...
Not sure if I get You correctly, we can have second field without label for sure but is this will be clear for the user what is the purpose of this additional field?
@carmenfan says that we should have labels for both fields as it will be clearer for the user.
Wireframe: https://marvelapp.com/4b107ge/screen/65758806
On risk tab, color/text/icon is from level_of_risk On treatment tab, color/text/icon is from residual_level_of_risk On third small icon on header, color/icon is from overall_level_of_risk
So, now is even less clear. Currently, for types of icons we are using this mapping:
export const RISK_LEVELS = { UNMITIGATED: '', PROPOSED: 'proposed', AGREED_PARTIAL: 'agreed_partial', AGREED_FULLY: 'agreed_fully', REJECTED: 'rejected' }; export const RISK_LEVELS_ICONS = { [RISK_LEVELS.UNMITIGATED]: NewReleases, [RISK_LEVELS.PROPOSED]: ErrorOutline, [RISK_LEVELS.AGREED_PARTIAL]: ErrorSolid, [RISK_LEVELS.AGREED_FULLY]: CheckCircle, [RISK_LEVELS.REJECTED]: SyncProblem };
So, we have only 5 options directly related to
mitigation_status
field values, I believe we need new mapping for this. Sure, nothing hard to do (one additional icon needed), but I just want to be clear about that.It is in the
frontend/constants/risks.ts
path if You would like to check it.
level_of_risk
. We would like the icon to always be the warning
icon (same as the one used for SafetiBase card). Updated wireframe: https://marvelapp.com/4b107ge/screen/65758885On treatment tab, color and text is from residual_level_of_risk
. The icon should be from mitigation_status
, so it should have the same icon as the small icon in the header.
The third small icon on header should remain unchanged. Its color is from overall_level_of_risk
and icon is from mitigation_status
.
Hey @Charence , I am at the end of finishing the first milestone, still fighting with mitigation detail
field and making it collapsible.
Describing the logic behind rendering risk icons was very helpful, thank You so much for this.
But I have an organization question, as this feature is divided into milestones, would You like me to create separate PR's with them directed to the main ISSUE_1847 branch? Or should I just push all commits into ISSUE_1847
branch? I'm not sure how this was done in the past.
But I have an organization question, as this feature is divided into milestones, would You like me to create separate PR's with them directed to the main ISSUE_1847 branch? Or should I just push all commits into
ISSUE_1847
branch? I'm not sure how this was done in the past.
Hi @m1chalkubiak , just push all commits into the current ISSUE_1847
branch. I believe it will be more straightforward this way.
@m1chalkubiak For Teamspace Settings, we have the following new endpoints:
GET /:teamspace/settings
for retrieving all teamspace settingsExample Response:
HTTP/1.1 200 OK
{
"topicTypes":[
{
"value":"constructibility",
"label":"Constructibility"
},
{
"value":"gis",
"label":"GIS"
}
],
"riskCategories":[
{
"value":"other",
"label":"Other Issue"
},
{
"value":"unknown",
"label":"UNKNOWN"
}
],
"teamspace":"acme"
}
PUT /:teamspace/settings
for updating all teamspace settingsExample Request:
PUT /acme/settings HTTP/1.1
{
"topicTypes":[
"New Topic 1",
"New Topic 2"
],
"riskCategories":[
"New Category 1",
"NEW CATEGORY 2"
]
}
Response will be the updated teamspace settings in the same format as the GET request.
GET /:teamspace/topicTypes
for retrieving all teamspace topic types (you probably don't need to use this)Example Response:
HTTP/1.1 200 OK
[
{
"value":"for_information",
"label":"For information"
},
{
"value":"vr",
"label":"VR"
}
]
GET /:teamspace/riskCategories
for retrieving all teamspace risk categories (you probably don't need to use this)Example Response:
HTTP/1.1 200 OK
[
{
"value":"commercial",
"label":"Commercial Issue"
},
{
"value":"environmental",
"label":"Environmental Issue"
}
]
GET /:teamspace/treatments.csv
for downloading a treatments CSV file/CSV template with headersAt the moment, this will always return a 1 row CSV file with the headers. The backend code for storing and retrieving the file is not done yet.
POST /:teamspace/treatments.csv
for uploading a treatments CSV fileExample Response:
{ "status": "ok" }
At the moment, this will always return status: ok
as the backend code for processing the given file is not done yet.
Please note that the endpoint PUT /:teamspace/:model/settings
for update model settings will no longer process topicTypes.
@Charence,
I'm unable to force new endpoints to work. Until now, I've always used the ./run/run_app
command to run the backend, nothing else was needed. Do I need to do any additional actions this time to launch new endpoints?
I keep getting 404 with additional information that "Teamspace settings not found"
I'm unable to force new endpoints to work. Until now, I've always used the
./run/run_app
command to run the backend, nothing else was needed. Do I need to do any additional actions this time to launch new endpoints?I keep getting 404 with additional information that "Teamspace settings not found"
@m1chalkubiak I've run a migration script on the database you are using. Teamspace settings should exist now.
@Charence You are right, I see it works right now. Thanks for the help.
@Charence
One thing regarding GET /:teamspace/settings
endpoint
Instead of
HTTP/1.1 200 OK
{
"topicTypes":[
{
"value":"constructibility",
"label":"Constructibility"
},
{
"value":"gis",
"label":"GIS"
}
],
"riskCategories":[
{
"value":"other",
"label":"Other Issue"
},
{
"value":"unknown",
"label":"UNKNOWN"
}
],
"teamspace":"acme"
}
I'm getting labels at 'name' property for riskCategories
Can You take a look on this ?
@Charence Additional question: From what I understand from wireframes, at the bottom of form on teamspace settings page we should show the info regarding uploaded treatments:
Is calling the GET /:teamspace/treatments.csv
endpoint is the only way, to check if we have an uploaded treatments? maybe we could add this metadata to GET /:teamspace/settings
endpoint, then additional call on this page wouldn't be necessary.
One thing regarding
GET /:teamspace/settings
endpointI'm getting labels at 'name' property for
riskCategories
There was an error in the migration script. I have corrected and re-run it.
Regarding the uploaded treatments, I agree that this information can be added to the settings endpoint. Let me think about how to change this.
Also, I'm going to be removing the following as they seem to be redundant:
GET /:teamspace/topicTypes
GET /:teamspace/riskCategories
@Charence
There was an error in the migration script. I have corrected and re-run it.
Thanks, I see changes, now it looks fine.
Also, I'm going to be removing the following as they seem to be redundant:
GET /:teamspace/topicTypes
GET /:teamspace/riskCategories
Totally agree on that.
I re-read the description of GET /:teamspace/treatments.csv
endpoint
GET /:teamspace/treatments.csv for downloading a treatments CSV file/CSV template with headers At the moment, this will always return a 1 row CSV file with the headers. The backend code for storing and retrieving the file is not done yet.
And now I'm confused, Is the place I ment in https://github.com/3drepo/3drepo.io/issues/1847#issuecomment-580723841 is about downloading the template for treatments, or the already uploaded treatments? If it's about templates then message on wireframes 'No suggestions uploaded' doesn't feel to make sense.
GET /:teamspace/treatments.csv for downloading a treatments CSV file/CSV template with headers At the moment, this will always return a 1 row CSV file with the headers. The backend code for storing and retrieving the file is not done yet.
And now I'm confused, Is the place I ment in #1847 (comment) is about downloading the template for treatments, or the already uploaded treatments? If it's about templates then message on wireframes 'No suggestions uploaded' doesn't feel to make sense.
The initial idea was the button would download both, depending on if treatments is already uploaded. However, I can see that this can be confusing.
I think there are 2 options:
Download
if there is an uploaded file
b. Button text is Get Template
if there is no uploaded file and the same endpoint will return the templateI think perhaps option 1 is clearer. Would you agree? This will require an additional endpoint to retrieve a template file.
PLEASE NOTE: after discussing with Carmen, the following 2 endpoints have changed path:
GET /:teamspace/treatments.csv
--> GET /:teamspace/settings/treatments.csv
PUT /:teamspace/treatments.csv
--> PUT /:teamspace/settings/treatments.csv
Is calling the
GET /:teamspace/treatments.csv
endpoint is the only way, to check if we have an uploaded treatments? maybe we could add this metadata toGET /:teamspace/settings
endpoint, then additional call on this page wouldn't be necessary.
These endpoints will also include a timestamp in the field treatmentsUpdatedAt
if an uploaded treatments file exists.
Example response:
{
"riskCategories": [ ... ],
"topicTypes": [ ... ],
"treatmentsUpdatedAt": 1567156228976,
"teamspace": "acme"
}
Hi @Charence Now I get this idea and agree with option 1. But maybe the business perspective is different. Altho, I did go with this option and added additional button, the problem with this approach is that we only have one endpoint returning the template / current file, we would have to separate them.
Hi @m1chalkubiak
Instead of having an endpoint for the template, the CSV template file has been placed at templates/treatments-template.csv
. This is similar to how the ie6.html
and image files are accessed.
@m1chalkubiak
I have pulled the latest changes from this branch and I'm experiencing some problems loading the frontend.
@Charence But after pulling latest commit 973de28? I did have this or similar-looking problem today but restarting the backend server helped me.
@m1chalkubiak
No. I've just seen and pulled 973de28 and it works fine now! Thanks!
Good to hear that. If I can ask what are the estimations for the next backend tasks? I had started working on Milestone 3, but most of the features depend on backend endpoints, which I believe hasn't been done.
On the other hand, I didn't get any kind of feedback regarding current state of this feature, maybe there is something to fix from frontend side. Did You had time to check it?
Teamspace settings
@m1chalkubiak Just had a look. Can we rework the look and feel of the teamspace settings please (sorry, our fault on the design, but it kind of looks horrendous and takes much way too much space. )
Please see here: https://marvelapp.com/4b107ge/screen/66017347
Diff Notes:
Risk Panel
@m1chalkubiak somethings I noticed:
[x] These settings are wrong: Staging is showing: The data is there, so it should be set..
[x] Error when I'm trying to change risk likelihood/consequence. it is also sending a lot of junk along with it even though I've only changed 1 field: Same action, staging version only sends this:
[x] Now that it's in it's own tab, can we change the layout of the resources a bit please:
[x] When you create a new risk the default focus goes to construction scope. Can we change it to the title please:
[ ] The footer is massive on create new risk:
[x] Can we add a line on description, treatment and treatment description so it looks less like a header and more like a input box when it's empty?
[ ] Footer is also massive on the treatment/attachment tabs:
@carmenfan
Risk Panel
- [x] These settings are wrong:
- [x] Error when I'm trying to change risk likelihood/consequence. it is also sending a lot of junk along with it even though I've only changed 1 field:
- [x] Now that it's in it's own tab, can we change the layout of the resources a bit please:
- [x] When you create a new risk the default focus goes to construction scope. Can we change it to the title please:
All above should be done.
About the remaining task, those two about footer "size". I forced the layout to push footer to the end of the container. But please check if this was the intention you wanted to achieve in this form.
- [ ] The footer is massive on create new risk:
- [ ] Footer is also massive on the treatment/attachment tabs:
Regarding the one below, I would like to be 100% sure what We would like to achieve. Most of the forms witch having a text area fields are using the same component, I believe that in some of them the display wasn't so problematic, as they did have some default "placeholder" (No Description). So, should we add the underline to all of them, or are we missing the placeholder in some of them?
- [ ] Can we add a line on description, treatment and treatment description so it looks less like a header and more like a input box when it's empty?
@m1chalkubiak
I forced the layout to push footer to the end of the container. But please check if this was the intention you wanted to achieve in this form.
will check and let you know!
So, should we add the underline to all of them, or are we missing the placeholder in some of them?
Please add a line for all of them. My worry is that it looks more like a label than a "disabled input field"(I know it technically isn't), so the user doesn't know it's a field that is editable.
not sure if you saw the post above, as I double posted, there's also some change requests for the teamspace settings :)
not sure if you saw the post above, as I double posted, there's also some change requests for the teamspace settings :)
Don't worry I saw it, I just didn't start to work on it at all, for now. I would like to do the whole risk panel feedback and then move to Teamspace settings.
Hi @m1chalkubiak
Please note that in commit 3b2cca0 I renamed the treatments
endpoints to mitigations
. I realised that the fields in risk are currently named mitigations_*
and I think it will be clearer if the naming on the backend is kept consistent. References to treatment
will only be on the frontend UI (similar to how Risks
are called SafetiBase
on the UI).
The following endpoints have changed:
GET /:teamspace/settings/treatments.csv
--> GET /:teamspace/settings/mitigations.csv
POST /:teamspace/settings/treatments.csv
--> POST /:teamspace/settings/mitigations.csv
Please also note that the field treatmentsUpdatedAt
has been changed to mitigationsUpdatedAt
for Teamspace Settings.
The following endpoints are now available (currently with sample responses)
POST /:teamspace/mitigations
Find mitigation suggestionsAn example request:
POST /acme/mitigations HTTP/1.1
{
"associated_activity":"Activity 1",
"category":"safety_fall",
"element":"Doors",
"location_desc":"Tower 3 - Level 2",
"risk_factor":"Factor 9",
"scope":"Tower 3"
}
The request body includes the defined fields from the risk (e.g. associated_activity
, category
, etc.) to filter the results returned for the mitigation (treatment) suggestions. All of these fields are optional, so for example, if only element
is defined in the risk, the request body will be:
{
"element":"Doors",
}
and the response will only filter by element
.
The response will be a list of objects with fields mitigation_desc
, mitigation_detail
, mitigation_stage
and mitigation_type
, which correspond to the same fields for risk. A sample response:
[
{
"mitigation_desc":"Replace all openings required in floor slabs with precast service openings.",
"mitigation_detail":"Replace openings larger than a standard anvil required in floor slabs with precast service openings from A/W 2020 catalogue.",
"mitigation_stage":"Preliminary Design",
"mitigation_type":"Eliminate"
},
{
"mitigation_desc":"Provide safe walking surface joint covers. Any covering should be: strong enough to support any loads likely to be placed on it ; and fixed in position to prevent accidental dislodgement.",
"mitigation_detail":"Safe walking surface joint covers for all joins and gaps. Covers should be strong enough to support any loads likely to be placed on it and fixed in position with bolts to prevent accidental dislodgement.",
"mitigation_stage":"Detail Design",
"mitigation_type":"Reduce"
},
{
"mitigation_desc":"Provide warning markings and/or colour change.",
"mitigation_detail":"Provide warning markings from approved list of markings and/or colour change using chart from Document XYZ.",
"mitigation_stage":"Preconstruction",
"mitigation_type":"Control"
}
]
GET /:teamspace/mitigations/criteria
Get mitigation criteria (autocomplete for risk fields)This will return lists of strings for the autocomplete. A sample response:
{
"associated_activity":[
"All construction",
"Site tests",
"Logistics"
],
"category":[
"safety_electricity"
],
"element":[
"Doors",
"Floors",
"Pipes",
"Vents",
"Walls"
],
"location_desc":[
"Tower 1 - Level 0",
"Tower 1 - Level 1",
"Tower 1 - Level 2",
"Tower 2 - Level 0",
"Tower 2 - Level 1",
"Tower 3 - Level 0",
"Tower 3 - Level 1",
"Tower 3 - Level 2"
],
"mitigation_stage":[
"Preliminary Design",
"Detail Design",
"Preconstruction",
"Site work and Change Control"
],
"mitigation_type":[
"Eliminate",
"Reduce",
"Control",
"Inform"
],
"risk_factor":[
"Factor 2",
"Factor 5",
"Factor 8"
],
"scope":[
"General concrete",
"In situ concrete"
]
}
Where autocomplete values are available for a field, a list with a matching field name will be returned. e.g. scope
in the response corresponds to scope
in risks and it has General concrete
and In situ concrete
as 2 autocomplete candidates.
Similar to the text input in Smart Groups and User Management filters, the user can input text that does not match the list of autocomplete values.
If autocomplete values are not available, the field will not be returned in the response or it will be an empty list.
category
is a drop-down list. I'm not sure if the values for it should be a list of Strings or should it be in the format:
[
{
"label":"Category 1",
"value":"category_1"
},
{
"label":"Category 2",
"value":"category_2"
}
]
What is your opinion on this?
What is your opinion on this?
category
will be returned as a list of Strings when using the GET /:teamspace/mitigations/criteria
endpoint.
e.g.: [ "Category 1", "Category 2" ]
@m1chalkubiak
@Charence No problem, list of strings will be enough for showing drop-down list. I think for now everything seems clear to me.
@carmenfan Teamspace settings feedbacks are done. Changing display of chips took me longer then I expected. I end on using the external library, which covers most of the edge cases but has some additional features. I didn't try for now to customize them, just did a basic styling. However, I believe You could have some additional requests regarding its current behavior. Please check it and let me know.
@Charence
I think I've done all the features for the milestone 3.
Since yesterday I've been doing the tests trying to find all edge cases that I could miss, so now I believe everything works fine.
Regarding the backend part, I spotted two things.
In POST /:teamspace/mitigations
respons have mitigation_details
property while in others its called mitigation_detail
so its probably a typo.
Regarding category
field, I have doubt that it should stay a select field.
Maybe input with autosuggestion like in other new fields in this form would be a better idea in reference to backward compatibility.
Now, UI is unable to render old values of categories, but maybe You have some different plans assuming data migration.
In
POST /:teamspace/mitigations
respons havemitigation_details
property while in others its calledmitigation_detail
so its probably a typo.
Yes, you are right. I made a typo. It should be mitigation_detail
.
Regarding
category
field, I have doubt that it should stay a select field. Maybe input with autosuggestion like in other new fields in this form would be a better idea in reference to backward compatibility. Now, UI is unable to render old values of categories, but maybe You have some different plans assuming data migration.
For the category field, we would like to keep it as a drop down menu as the user shouldn't be able to add additional categories through the risk UI. For the old categories, I will write a db migration script.
@m1chalkubiak
I've noticed there's a slight problem when the mitigation_detail
is collapsed. It is fine when expanded.
@Charence Thanks for noticing this. I just pushed a fix.
Hey @Charence Is this branch ready for the final corrections on my side? I saw your last commit, but I don't know if your work is done. Also, I see some lint issues in backend code.
Is this branch ready for the final corrections on my side? I saw your last commit, but I don't know if your work is done. Also, I see some lint issues in backend code.
Sorry @m1chalkubiak it is not ready for final corrections yet. Backend changes are still incomplete. I will let you know when done and give you a list of corrections.
Hi @m1chalkubiak it is now possible to upload/download csv files, which was the last part missing.
There are some small things we would like to change on Teamspace Settings:
[x] Save button stays active even after it is pressed and teamspace settings updated. It should be disabled when there are no changes.
[x] The styling of the text should be more consistent with other pages such as Model Settings
.
There are also some conflicts on the frontend with staging. I will let you know if we have more comments. Thanks!
@Charence
There are some small things we would like to change on Teamspace Settings:
Both of them are done, unfortunately, I see some errors from backend during fetching of mitigations/criteria.
Thanks @m1chalkubiak, backend error has been fixed.
I have found the following problems:
[x] The scrolling goes too far down (I think Issue has the same problem because it is the same component)
[x] Two scrollbars appear - only the outer scrollbar should be needed to scroll everything in the card
[x] When saving a new risk the whole page goes blank
[x] Selecting a treatment suggestion also populates fields on the Risk tab, which should not happen. Fields on the risk tab should be used in the request for Suggestions, but the suggestion should not be able to populate category, associated activity, element type, risk factor, construction scope or location. It should only populate the fields in the treatment tab (mitigation_desc
, mitigation_detail
, mitigation_stage
, mitigation_type`)
Hi @Charence I think I had fixed all the issues you mentioned. However, I would be grateful if you could provide me a working example CSV file with suggestions treatments. Just to be able to make a final test regarding the last point.
Description
Ability to suggest risk mitigations and additional fields
Goals
Wireframe: https://marvelapp.com/4b107ge
Tasks
Milestone 1: Update Safetibase card layout
front end
backend
Milestone 2: Teamspace settings
frontend
backend
Milestone 3: Mitigation Suggestions
frontend
backend