Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge UI fixes and metadata standardizer #365

Merged
merged 49 commits into from
Sep 5, 2024
Merged

Merge UI fixes and metadata standardizer #365

merged 49 commits into from
Sep 5, 2024

Conversation

sanghoonio
Copy link
Member

Aside from some UI updates, I found that the patch update project API endpoint doesn't seem to let you remove schemas from projects. I disabled clearing from the schema dropdown for now so that you can't choose no schema when updating. What should be the proper formatting for pep_schema in the request body when the user is trying to remove current schema? It was set to empty string (""), which didn't work

@nleroy917
Copy link
Member

nleroy917 commented Aug 6, 2024

Could we try null (client-side) or None (server-side)? Maybe undefined?

if (e.target.value === "") {
  setSchema(null) // or undefined
}

@nleroy917
Copy link
Member

Another idea is to check (server-side) if the pep_schema has been assigned to an empty string ("") and then appropriately set it to null or None

@sanghoonio
Copy link
Member Author

I think it might have to be server side; I can set the onChange in schemas-databio-dropdown.tsx from

onChange={(newValue: SingleValue<{ label: string; value: string }>) => {
  onChange(newValue?.value || '');
}}

to

onChange={(newValue: SingleValue<{ label: string; value: string }>) => {
  onChange(newValue?.value || null ***or undefined***);
}}

and it still doesn't work. It doesn't error out, but the schema itself doesn't get dropped from the pep

@nleroy917
Copy link
Member

Yeah, I think somewhere it ignores undefined values. It's an all-encompassing function that updates whatever you give it...and doesn't try to update what you don't. So if you give it schema: undefined it will just be like, "oh cool you don't want to update the schema right now".

That's why I think that passing null or even the empty string is a good idea such that we can detect that on the server and handle it appropriately.

I might ask @khoroshevskyi what the best approach is here from a database perspective, but

@sanghoonio sanghoonio changed the title Merge UI fixes for schemas, views Merge UI fixes and metadata standardizer Aug 16, 2024
Copy link
Member

@nleroy917 nleroy917 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is AWESOME! Great job. I havnt pulled it locally so I haven't checked types... (it wont build unless types are correct), but yeah this is so great.

The endpoint could be a little more robust and I think my suggestions will get us 90% of the way there
Lets see what @saanikat says about AttrStandardizer
And make sure the types are all good

But this is awesome! Thanks for getting this done well

pephub/routers/api/v1/project.py Outdated Show resolved Hide resolved
pephub/routers/api/v1/project.py Show resolved Hide resolved

model = AttrStandardizer(schema)

results = model.standardize(pep=path)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems a little inefficient, no? We are already on PEPhub, but it seems like the attribute standardized is getting it... from PEPhub? But we are already there so its making a request to itself.

This is probably an implementation detail in AttrStandardizer... so we should raise an issue there, but I really feel like we should be able to just pass a peppy.Project object to it directly

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch

pephub/routers/api/v1/project.py Outdated Show resolved Hide resolved
web/src/components/modals/standardize-metadata.tsx Outdated Show resolved Hide resolved
if (data?.results) {
const defaultSelections = getDefaultSelections(data.results);
setWhereDuplicates(checkForDuplicates(defaultSelections));
console.log('Setting default selections:', defaultSelections);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove?

return [[selectedValue], ...topValues, ...emptyRows];
}, [selectedValues, tabData]);

useEffect(() => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm trying to think of ways to get rid of this useEffect... I might need to pull the code and look at it in detail

) => {
const session = useSession();
const query = useQuery({
queryKey: [namespace, project, tag],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
queryKey: [namespace, project, tag],
queryKey: ['standardize', schema, namespace, project, tag],

Can we change the key for this so it gets cached properly?

Comment on lines +1 to +11
import { create } from 'zustand';

type StandardizeModalStore = {
showStandardizeMetadataModal: boolean;
setShowStandardizeMetadataModal: (show: boolean) => void;
};

export const useStandardizeModalStore = create<StandardizeModalStore>((set) => ({
showStandardizeMetadataModal: false,
setShowStandardizeMetadataModal: (show) => set({ showStandardizeMetadataModal: show }),
}));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice love this

Copy link
Member

@khoroshevskyi khoroshevskyi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one big thing, that Nathan mentioned, don't call pephub from pephub api. Other things look good


model = AttrStandardizer(schema)

results = model.standardize(pep=path)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch

pephub/routers/api/v1/project.py Show resolved Hide resolved
pephub/routers/api/v1/project.py Outdated Show resolved Hide resolved
@sanghoonio
Copy link
Member Author

Can we merge this to dev today? I want to merge it all before adding the updated geofetch UI and forking from history features

@nleroy917
Copy link
Member

I can get a review by EOD

Copy link
Member

@nleroy917 nleroy917 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, nothing struck as particularly problematic. I can pull it locally and check it out too and my environment will probably identify things too..

Really the biggest comments are those made in the python code on the server.

)
from .helpers import verify_updated_project

from attribute_standardizer.attr_standardizer_class import AttrStandardizer
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this isnt pephub but I still wanna say I don't like the ergonomics of this import 🙃

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed a little bit bedbs, so now you can do: from attribute_standardizer import AttrStandardizer

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you push to bedms?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is already there, I added it with input changes

Comment on lines 1164 to 1169
if schema == "":
raise HTTPException(
code=400,
detail="Schema is required! Available schemas are ENCODE and Fairtracks",
)
return {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove the return {} here since it's unreachable.

Also, this could be just a tad more robust with this kind of setup:

# const.py
VALID_STANDARDIZE_SCHEMAS = ["ENCODE", "Fairtracks"]

# route.py
if schema not in VALID_STANDARDIZE_SCHEMAS:
    raise HTTPException(
            code=400,
            detail=f"Invalid schema provided: {schema}. Valid schemas are: {VALID_STANDARDIZE_SCHEMAS}"
         )

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this variable (VALID_STANDARDIZE_SCHEMAS) should be imported from bedms, as we will be adding new models there

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Saanika is adding a function to bedms that lists the existing schemas

Comment on lines +1176 to +1180
except Exception:
raise HTTPException(
code=400,
detail=f"Error standardizing PEP.",
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably fine for now, but we'd ideally want to capture specific Exceptions and dispatch accordingly. We might be sending a 400 back indicating a user error, when in fact it could be our fault and a 500 error (developer error)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated code to 500 for now

response_model=StandardizerResponse,
)
async def get_standardized_cols(
pep: project = Depends(get_project),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is project here?

pep: project = Depends(get_project),

Why is Project not capitalized? Should we by type annotating that as a peppy.Project object?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, it should be peppy.Project

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

) => {
const url = `${API_BASE}/projects/${namespace}/${name}/standardize?schema=${schema}&tag=${tag}`;
return axios
.post<StandardizeColsResponse>(url, { headers: { Authorization: `Bearer ${jwt}` } })
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.post<StandardizeColsResponse>(url, { headers: { Authorization: `Bearer ${jwt}` } })
.post<StandardizeColsResponse>(url, { headers: { Authorization: `Bearer ${jwt || 'NO_AUTHORIZATION'}` } })

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

Comment on lines +25 to +46
type CombinedErrorMessageProps = {
errors: FieldErrors<POPInputs>;
};

const CombinedErrorMessage = (props: CombinedErrorMessageProps) => {
const { errors } = props;
const nameError = errors.name?.message;
let msg = null;

if (nameError == 'empty') {
msg = 'Project Name must not be empty.';
} else if (nameError == 'invalid') {
msg = "Project Name must contain only alphanumeric characters, '-', or '_'.";
}

if (nameError) {
return <p className="text-danger text-xs pt-1 mb-0">{msg}</p>;
}

return null;
};

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Second time I have seen this.... should we abstract it into its own component that can be imported?

setNewSamples: (samples: any[][]) => void;
resetStandardizedData: boolean;
setResetStandardizedData: (boolean) => void;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove space? 😀

If you havnt yet... getting prettier setup is such a blessing. It auto-formats the markup for you and its a great great great life-enhancer

@@ -688,3 +697,176 @@ body {
.btn-dark.glow-button {
--box-shadow-color: #343a4080;
}

.btn-group-vertical .btn-check:checked + .btn-outline-secondary {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No comments on the CSS, but you strike me as someone who would love tailwind...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sanghoonio sanghoonio merged commit 015f4e0 into dev Sep 5, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants