Search filtering works
parent
142611deaa
commit
4e87effeba
|
@ -1,11 +1,9 @@
|
|||
import {
|
||||
RootFolderNode as Tree,
|
||||
FolderUnion,
|
||||
FolderNodeMedial,
|
||||
FolderNodeTerminal,
|
||||
RootFolderNode
|
||||
} from "./constants";
|
||||
import { cloneAndClimb, climb } from "./climb";
|
||||
import { cloneAndClimb } from "./climb";
|
||||
import { Color, TaggedResource, TaggedSequence } from "farmbot";
|
||||
import { store } from "../redux/store";
|
||||
import { initSave, destroy, edit, save } from "../api/crud";
|
||||
|
@ -92,10 +90,10 @@ export const updateSearchTerm = (payload: string | undefined) => {
|
|||
interface FolderSearchProps {
|
||||
references: Record<string, TaggedResource | undefined>;
|
||||
input: string;
|
||||
folders: RootFolderNode;
|
||||
root: RootFolderNode;
|
||||
}
|
||||
|
||||
const isSearchMatch =
|
||||
const isSearchMatchSeq =
|
||||
(searchTerm: string, s?: TaggedResource): s is TaggedSequence => {
|
||||
if (s && s.kind == "Sequence") {
|
||||
const name = s.body.name.toLowerCase();
|
||||
|
@ -105,42 +103,95 @@ const isSearchMatch =
|
|||
}
|
||||
};
|
||||
|
||||
const isSearchMatchFolder = (searchTerm: string, f: FolderUnion) => {
|
||||
if (f.name.toLowerCase().includes(searchTerm)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/** Given an input search term, returns folder IDs (number) and Sequence UUIDs
|
||||
* that match */
|
||||
export const searchFoldersAndSequencesForTerm = (props: FolderSearchProps) => {
|
||||
type MappableFolder = FolderNodeMedial | FolderNodeTerminal;
|
||||
// A sequence is included if:
|
||||
// * CASE 1: The name is a search match
|
||||
// * CASE 2: The containing folder is a search match.
|
||||
|
||||
// A folder is included if:
|
||||
// * CASE 3: The name is a search match
|
||||
// * CASE 4: It contains a sequence that is a match.
|
||||
// * CASE 5: It has a child that has a search match.
|
||||
|
||||
const searchTerm = props.input.toLowerCase();
|
||||
const sequenceSet = new Set<string>();
|
||||
const folderSet = new Set<FolderUnion>();
|
||||
|
||||
const sequenceMaper = (node: FolderUnion) => (x: string) => {
|
||||
const s = props.references[x];
|
||||
if (isSearchMatch(searchTerm, s)) {
|
||||
sequenceSet.add(s.uuid);
|
||||
folderSet.add(node);
|
||||
props.root.folders.map(level1 => {
|
||||
level1.content.map(level1Sequence => { // ========= Level 1
|
||||
if (isSearchMatchSeq(searchTerm, props.references[level1Sequence])) {
|
||||
// CASE 1:
|
||||
sequenceSet.add(level1Sequence);
|
||||
// CASE 4:
|
||||
folderSet.add(level1);
|
||||
}
|
||||
});
|
||||
|
||||
if (isSearchMatchFolder(searchTerm, level1)) {
|
||||
// CASE 2
|
||||
level1.content.map(uuid => sequenceSet.add(uuid));
|
||||
// CASE 3
|
||||
folderSet.add(level1);
|
||||
}
|
||||
};
|
||||
|
||||
const nodeMapper = (node: FolderUnion) => {
|
||||
if (node.name.toLowerCase().includes(searchTerm)) {
|
||||
folderSet.add(node);
|
||||
}
|
||||
};
|
||||
level1.children.map(level2 => { // ================ LEVEL 2
|
||||
if (isSearchMatchFolder(searchTerm, level2)) {
|
||||
// CASE 2
|
||||
level2.content.map(uuid => sequenceSet.add(uuid));
|
||||
// CASE 3
|
||||
folderSet.add(level2);
|
||||
// CASE 5
|
||||
folderSet.add(level1);
|
||||
}
|
||||
|
||||
const filter = (finalNode: FolderUnion): FolderUnion => {
|
||||
return {
|
||||
...finalNode,
|
||||
content: finalNode.content.filter(seqUUID => sequenceSet.has(seqUUID))
|
||||
};
|
||||
};
|
||||
|
||||
climb(props.folders, (node: FolderUnion) => {
|
||||
node.content.map(sequenceMaper(node));
|
||||
const nodes: MappableFolder[] = node.children || [];
|
||||
nodes.map(nodeMapper);
|
||||
level2.content.map(level2Sequence => {
|
||||
if (isSearchMatchSeq(searchTerm, props.references[level2Sequence])) {
|
||||
// CASE 1:
|
||||
sequenceSet.add(level2Sequence);
|
||||
// CASE 4:
|
||||
folderSet.add(level2);
|
||||
// CASE 5
|
||||
folderSet.add(level1);
|
||||
}
|
||||
});
|
||||
level2.children.map(level3 => { // ============== LEVEL 3
|
||||
if (isSearchMatchFolder(searchTerm, level3)) {
|
||||
// CASE 2
|
||||
level3.content.map(uuid => sequenceSet.add(uuid));
|
||||
// CASE 3
|
||||
folderSet.add(level3);
|
||||
// CASE 5
|
||||
folderSet.add(level2);
|
||||
// CASE 5
|
||||
folderSet.add(level1);
|
||||
}
|
||||
level3.content.map(level3Sequence => {
|
||||
if (isSearchMatchSeq(searchTerm, props.references[level3Sequence])) {
|
||||
// CASE 1:
|
||||
sequenceSet.add(level3Sequence);
|
||||
// CASE 3
|
||||
folderSet.add(level3);
|
||||
// CASE 5
|
||||
folderSet.add(level2);
|
||||
// CASE 5
|
||||
folderSet.add(level1);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return Array.from(folderSet).map(filter);
|
||||
return Array.from(folderSet);
|
||||
};
|
||||
|
||||
export const toggleFolderOpenState = (id: number) => Promise
|
||||
|
|
|
@ -187,11 +187,11 @@ export let resourceReducer =
|
|||
})
|
||||
.add<string | undefined>(Actions.FOLDER_SEARCH, (s, { payload }) => {
|
||||
s.index.sequenceFolders.searchTerm = payload;
|
||||
if (payload) {
|
||||
if (payload && payload.length > 2) {
|
||||
const folders = searchFoldersAndSequencesForTerm({
|
||||
references: s.index.references,
|
||||
input: payload,
|
||||
folders: s.index.sequenceFolders.folders
|
||||
root: s.index.sequenceFolders.folders
|
||||
});
|
||||
const nextFolder = ingest({
|
||||
localMetaAttributes: s.index.sequenceFolders.localMetaAttributes,
|
||||
|
|
Loading…
Reference in New Issue