Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
def run_query(id, query_type):
# TODO: this will have to be extended to handle a list of ids as params
try:
# Validate query_type - it must be provided and not None or 'undefined'
if query_type is None or query_type == 'undefined' or query_type == '':
raise ValueError("query_type parameter is required and must be a valid query type. Use get_term_info endpoint to retrieve available queries.")

# Create a unique cache key for the query
cache_key = f"query_{id}_{query_type}"
cached_data = queries_cache.get(cache_key)
Expand Down Expand Up @@ -35,10 +39,7 @@ def run_query(id, query_type):

return data_queries
else:
# For queries list, we can also cache this
result = dict({'queries': queries, 'name': data['Name']})
queries_cache.set(cache_key, result)
return result
raise ValueError(f"Query type '{query_type}' not found for instance '{id}'")

except Exception as e:
return str(e)
6 changes: 5 additions & 1 deletion applications/virtual-fly-brain/frontend/src/network/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ export const get_queries = async (queryId) => {
return response.json()
})
.then((data) => {
return data;
// Extract only the queries array and name to minimize response
return {
queries: data.query?.Queries || data.Queries || [],
name: data.Name || data.query?.Name
};
});
return response;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,27 @@ const QueriesReducer = (state = initialStateQueriesReducer, response) => {
let updatedQueries = [...state.queries];
response.payload.query.active = true;
if (Array.isArray(response.payload.query.queries)) {
response.payload?.query.queries.forEach((query) => {
query.active = true;
let findQuery = updatedQueries?.find(
(i) => i.short_form === response.payload.short_form
);
if (findQuery === undefined) {
const newQuery = {
short_form: response.payload.short_form,
name: response.payload.query.name,
queries: { [query["query"]]: query },
};
updatedQueries.push(newQuery);
} else {
if (findQuery.queries?.[response.payload.type]) {
findQuery.queries[response.payload.type] = Object.assign(
findQuery.queries[response.payload.type],
response.payload.query
);
}
}
});
let findQuery = updatedQueries?.find(
(i) => i.short_form === response.payload.short_form
);
if (findQuery === undefined) {
const queriesObject = {};
response.payload.query.queries.forEach((query) => {
query.active = true;
queriesObject[query["query"]] = query;
});
const newQuery = {
short_form: response.payload.short_form,
name: response.payload.query.name,
queries: queriesObject,
};
updatedQueries.push(newQuery);
} else {
response.payload.query.queries.forEach((query) => {
query.active = true;
findQuery.queries[query["query"]] = query;
});
}
} else {
let findQuery = updatedQueries?.find(
(i) => i.short_form === response.payload.short_form
Expand All @@ -56,7 +56,6 @@ const QueriesReducer = (state = initialStateQueriesReducer, response) => {
findQuery.queries[response.payload.type] = response.payload.query;
}
}

return Object.assign({}, state, {
queries: updatedQueries,
isLoading: false,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import store from '../../store';
import { get_query_results } from "../../network/query"
import { get_query_results, get_queries } from "../../network/query"
import { getQueriesTypes } from './types/getQueriesTypes';

const getQueriesSuccess = (query, short_form, type) => ({
type: getQueriesTypes.GET_QUERIES_SUCCESS,
payload: {
query : query,
short_form : short_form,
type : type
query: query,
short_form: short_form,
type: type
}
});

Expand All @@ -31,25 +31,58 @@ const _getQueriesStarted = () => ({
});


export const getQueriesFailure = ( error, id) => ({
export const getQueriesFailure = (error, id) => ({
type: getQueriesTypes.GET_QUERIES_FAILURE,
payload: {
error : error,
id : id
error: error,
id: id
}
});

export const getQueries = async (short_form, type) => {

store.dispatch(_getQueriesStarted())

const state = store.getState();
const allLoadedInstances = state.instances.allLoadedInstances;

let response;
try {
response = await get_query_results(short_form, type);
// When type is provided - execute the specific query
if (type) {
response = await get_query_results(short_form, type);
store.dispatch(getQueriesSuccess(response, short_form, type))
}
// When type is not provided - load available queries list
else {
// Check if instance already loaded (CACHE CHECK)
const existingInstance = allLoadedInstances?.find(
i => i.metadata?.Id === short_form
);

let queriesData;
if (existingInstance?.metadata?.Queries) {
// Use cached instance data - no network call needed!
queriesData = {
queries: existingInstance.metadata.Queries,
name: existingInstance.metadata.Name
};
} else {
// Instance not loaded, fetch queries from backend using get_queries
queriesData = await get_queries(short_form);
}

// Format response to match what reducer expects
response = {
queries: queriesData.queries, // Array of all available queries
name: queriesData.name
};

store.dispatch(getQueriesSuccess(response, short_form, undefined))
}
} catch (error) {
store.dispatch(getQueriesFailure(error.message, short_form))
Comment on lines 83 to 84

Choose a reason for hiding this comment

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

P2 Badge Clear loading state on query fetch errors

In the new getQueries flow, the catch path only dispatches GET_QUERIES_FAILURE. The reducer’s failure handler doesn’t reset isLoading, so any thrown error (e.g., network outage or invalid JSON) leaves state.queries.isLoading stuck true, and the query UI spinner never clears. Consider dispatching a completion action here or updating the failure reducer to set isLoading: false so error paths unwind correctly.

Useful? React with 👍 / 👎.

}

store.dispatch(getQueriesSuccess(response, short_form, type))
}

export const deleteQuery = async (instance) => {
Expand Down
69 changes: 42 additions & 27 deletions applications/virtual-fly-brain/frontend/src/shared/header/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { getLayoutManagerInstance } from "@metacell/geppetto-meta-client/common/

const { primaryBg, headerBoxShadow } = vars;

const Header = ({setBottomNav}) => {
const Header = ({ setBottomNav }) => {
const classes = {
root: {
background: primaryBg,
Expand All @@ -38,6 +38,7 @@ const Header = ({setBottomNav}) => {
const recentSearches = useSelector(state => state.globalInfo.recentSearches)
const queries = useSelector(state => state.queries.queries)
const allLoadedInstances = useSelector(state => state.instances.allLoadedInstances)
const focusedInstance = useSelector(state => state.instances.focusedInstance)
const widgets = useSelector(state => state.widgets);
const firstIdLoaded = useSelector(state => state.globalInfo.firstIDLoaded);
let autoSaveLayout = useSelector(state => state.globalInfo.autoSaveLayout);
Expand All @@ -55,8 +56,20 @@ const Header = ({setBottomNav}) => {
}

const handleQueryStatsClick = () => {
// TODO: what to do here?
console.log('QueryStats Clicked!')
// Open queries for the focused instance
if (focusedInstance?.metadata?.Id) {
// Ensure queries are loaded if not already
const queriesForInstance = queries?.find(
q => q.short_form === focusedInstance.metadata.Id
);

if (!queriesForInstance) {
getQueries(focusedInstance.metadata.Id);
}

// Open the query component panel
setBottomNav(2);
}
}

const handleMenuClick = () => {
Expand All @@ -67,7 +80,7 @@ const Header = ({setBottomNav}) => {
* Handler function triggered when a Menu item is clicked.
*/
const menuHandler = (action, _component) => {
switch (action.handlerAction){
switch (action.handlerAction) {
case ACTIONS.SHOW_WIDGET: {
const newWidget = { ...widgets[action.parameters[0]] }
const layoutManager = getLayoutManagerInstance();
Expand Down Expand Up @@ -100,7 +113,7 @@ const Header = ({setBottomNav}) => {
case ACTIONS.SHOW_COMPONENT:
setBottomNav(action.parameters[0])
break;
case ACTIONS.SHOW_TERM_INFO:{
case ACTIONS.SHOW_TERM_INFO: {
dispatch(setTermInfoOpened(true))
break;
}
Expand All @@ -109,38 +122,38 @@ const Header = ({setBottomNav}) => {
window.open(item, '_blank');
})
break;
case ACTIONS.SELECT_INSTANCE:{
let matchInstance = allLoadedInstances?.find( q => q.metadata?.Id === action.parameters[0] );
if (matchInstance ) {
case ACTIONS.SELECT_INSTANCE: {
let matchInstance = allLoadedInstances?.find(q => q.metadata?.Id === action.parameters[0]);
if (matchInstance) {
focusInstance(action.parameters[0])
selectInstance(action.parameters[0])
} else {
getInstanceByID(action.parameters[0], true, true, true)
}
break;
}
case ACTIONS.RUN_QUERY:{
case ACTIONS.RUN_QUERY: {
let updatedQueries = [...queries];
let matchQuery = updatedQueries?.find( q => q.short_form === action.parameters[0] );
updatedQueries?.forEach( query => {
if( query.queries ){
Object.keys(query.queries)?.forEach( q => query.queries[q].active = false );
let matchQuery = updatedQueries?.find(q => q.short_form === action.parameters[0]);
updatedQueries?.forEach(query => {
if (query.queries) {
Object.keys(query.queries)?.forEach(q => query.queries[q].active = false);
}
});
if ( matchQuery?.queries?.[action?.parameters[1]] ) {
if (matchQuery?.queries?.[action?.parameters[1]]) {
matchQuery.queries[action.parameters[1]].active = true;
updateQueries(updatedQueries);
setBottomNav(2)
} else {
getQueries(action.parameters[0],action.parameters[1])
getQueries(action.parameters[0], action.parameters[1])
setBottomNav(2)
}
break;
}
case ACTIONS.HISTORY_MENU_INJECTOR:{
case ACTIONS.HISTORY_MENU_INJECTOR: {
var historyList = [];
// Add instances to history menu
recentSearches?.reverse()?.forEach( i => {
recentSearches?.reverse()?.forEach(i => {
historyList.push(
{
label: i?.label,
Expand All @@ -154,12 +167,12 @@ const Header = ({setBottomNav}) => {
})
return historyList;
}
case ACTIONS.LOAD_LAYOUT:{
case ACTIONS.LOAD_LAYOUT: {
if (!firstIdLoaded) {
dispatch(triggerInstanceFailure('No instance loaded, wait please ...'));
break;
}
switch (action.parameters[0]){
switch (action.parameters[0]) {
case 'layout1':
dispatch(loadCustomLayout(layout1));
break;
Expand Down Expand Up @@ -263,7 +276,7 @@ const Header = ({setBottomNav}) => {
</Box>

<Box
sx={ {
sx={{
'& span': {
display: {
xs: 'block',
Expand Down Expand Up @@ -295,13 +308,15 @@ const Header = ({setBottomNav}) => {
</Box>

<MediaQuery minWidth={1200}>
{/* <Button
onClick={() => setBottomNav((prev) => prev === 2 ? null : 2)}
variant="outlined"
>
<QueryStats size={16} />
Queries for V_ilpn (FlyEM-HB:2064165421)
</Button> */}
{focusedInstance?.metadata?.Id && (focusedInstance?.metadata?.Queries?.length > 0 || queries?.find(q => q.short_form === focusedInstance.metadata.Id)) && (
<Button
onClick={() => setBottomNav((prev) => prev === 2 ? null : 2)}
variant="outlined"
>
<QueryStats size={16} />
Queries for {focusedInstance.metadata?.Name || ''} ({focusedInstance.metadata?.Id || ''})
</Button>
)}
</MediaQuery>
</Box>
)
Expand Down
Loading