mirror of
https://github.com/Qortal/qapp-core.git
synced 2025-06-14 17:41:20 +00:00
added index manager
This commit is contained in:
parent
86689af488
commit
28fd2fd2d1
118
src/components/IndexManager/IndexManager.tsx
Normal file
118
src/components/IndexManager/IndexManager.tsx
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
import {
|
||||||
|
Box,
|
||||||
|
ButtonBase,
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogTitle,
|
||||||
|
IconButton,
|
||||||
|
Typography,
|
||||||
|
} from "@mui/material";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { useIndexStore } from "../../state/indexes";
|
||||||
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
|
import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos';
|
||||||
|
export const IndexManager = () => {
|
||||||
|
const open = useIndexStore((state) => state.open);
|
||||||
|
const setOpen = useIndexStore((state) => state.setOpen);
|
||||||
|
const [mode, setMode] = useState(1);
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
setOpen(null);
|
||||||
|
setMode(1);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
open={!!open}
|
||||||
|
fullWidth={true}
|
||||||
|
maxWidth={"md"}
|
||||||
|
sx={{
|
||||||
|
zIndex: 999990,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DialogTitle>Index manager</DialogTitle>
|
||||||
|
<IconButton
|
||||||
|
aria-label="close"
|
||||||
|
onClick={handleClose}
|
||||||
|
sx={(theme) => ({
|
||||||
|
position: "absolute",
|
||||||
|
right: 8,
|
||||||
|
top: 8,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<CloseIcon />
|
||||||
|
</IconButton>
|
||||||
|
<DialogContent>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
gap: "20px",
|
||||||
|
width: "100%",
|
||||||
|
alignItems: 'flex-start'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IconButton disabled={mode === 1} onClick={()=> setMode(1)}><ArrowBackIosIcon /></IconButton>
|
||||||
|
{mode === 1 && (
|
||||||
|
<>
|
||||||
|
<ButtonBase
|
||||||
|
sx={{
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
p: 2,
|
||||||
|
border: "2px solid",
|
||||||
|
borderRadius: 2,
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography>Create new index</Typography>
|
||||||
|
</Box>
|
||||||
|
</ButtonBase>
|
||||||
|
<ButtonBase
|
||||||
|
sx={{
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
p: 2,
|
||||||
|
border: "2px solid",
|
||||||
|
borderRadius: 2,
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography>Your indices</Typography>
|
||||||
|
</Box>
|
||||||
|
</ButtonBase>
|
||||||
|
<ButtonBase
|
||||||
|
sx={{
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
onClick={()=> setMode(4)}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
p: 2,
|
||||||
|
border: "2px solid",
|
||||||
|
borderRadius: 2,
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography>Add metadata</Typography>
|
||||||
|
</Box>
|
||||||
|
</ButtonBase>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{mode === 4 && <AddMetadata />}
|
||||||
|
</Box>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const AddMetadata = () => {
|
||||||
|
return <Box>hello</Box>;
|
||||||
|
};
|
@ -5,6 +5,8 @@ import { useAppInfo } from "../hooks/useAppInfo";
|
|||||||
import { useIdentifiers } from "../hooks/useIdentifiers";
|
import { useIdentifiers } from "../hooks/useIdentifiers";
|
||||||
import { Toaster } from "react-hot-toast";
|
import { Toaster } from "react-hot-toast";
|
||||||
import { useLocalStorage } from "../hooks/useLocalStorage";
|
import { useLocalStorage } from "../hooks/useLocalStorage";
|
||||||
|
import { IndexManager } from "../components/IndexManager/IndexManager";
|
||||||
|
import { useIndexes } from "../hooks/useIndexes";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -17,6 +19,7 @@ lists: ReturnType<typeof useResources>;
|
|||||||
appInfo: ReturnType<typeof useAppInfo>;
|
appInfo: ReturnType<typeof useAppInfo>;
|
||||||
identifierOperations: ReturnType<typeof useIdentifiers>
|
identifierOperations: ReturnType<typeof useIdentifiers>
|
||||||
localStorageOperations: ReturnType<typeof useLocalStorage>
|
localStorageOperations: ReturnType<typeof useLocalStorage>
|
||||||
|
indexOperations: ReturnType<typeof useIndexes>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -45,8 +48,9 @@ export const GlobalProvider = ({ children, config, toastStyle = {} }: GlobalProv
|
|||||||
const lists = useResources()
|
const lists = useResources()
|
||||||
const identifierOperations = useIdentifiers(config.publicSalt, config.appName)
|
const identifierOperations = useIdentifiers(config.publicSalt, config.appName)
|
||||||
const localStorageOperations = useLocalStorage(config.publicSalt, config.appName)
|
const localStorageOperations = useLocalStorage(config.publicSalt, config.appName)
|
||||||
|
const indexOperations = useIndexes()
|
||||||
// ✅ Merge all hooks into a single `contextValue`
|
// ✅ Merge all hooks into a single `contextValue`
|
||||||
const contextValue = useMemo(() => ({ auth, lists, appInfo, identifierOperations, localStorageOperations }), [auth, lists, appInfo, identifierOperations, localStorageOperations]);
|
const contextValue = useMemo(() => ({ auth, lists, appInfo, identifierOperations, localStorageOperations, indexOperations }), [auth, lists, appInfo, identifierOperations, localStorageOperations]);
|
||||||
return (
|
return (
|
||||||
<GlobalContext.Provider value={contextValue}>
|
<GlobalContext.Provider value={contextValue}>
|
||||||
<Toaster
|
<Toaster
|
||||||
@ -57,6 +61,7 @@ export const GlobalProvider = ({ children, config, toastStyle = {} }: GlobalProv
|
|||||||
}}
|
}}
|
||||||
containerStyle={{zIndex: 999999}}
|
containerStyle={{zIndex: 999999}}
|
||||||
/>
|
/>
|
||||||
|
<IndexManager />
|
||||||
{children}
|
{children}
|
||||||
</GlobalContext.Provider>
|
</GlobalContext.Provider>
|
||||||
);
|
);
|
||||||
|
20
src/hooks/useIndexes.tsx
Normal file
20
src/hooks/useIndexes.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import React, { useCallback } from "react";
|
||||||
|
import { OpenIndex, useIndexStore } from "../state/indexes";
|
||||||
|
|
||||||
|
export const useIndexes = () => {
|
||||||
|
const setOpen = useIndexStore((state) => state.setOpen);
|
||||||
|
const openPageIndexManager = useCallback(
|
||||||
|
({ link, name }: OpenIndex) => {
|
||||||
|
if(!link || !name) return
|
||||||
|
setOpen({
|
||||||
|
name,
|
||||||
|
link,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[setOpen]
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
openPageIndexManager,
|
||||||
|
};
|
||||||
|
};
|
@ -1,5 +1,8 @@
|
|||||||
export { useResourceStatus } from './hooks/useResourceStatus';
|
export { useResourceStatus } from './hooks/useResourceStatus';
|
||||||
|
export { Spacer } from './common/Spacer';
|
||||||
import './index.css'
|
import './index.css'
|
||||||
|
export { hashWordWithoutPublicSalt } from './utils/encryption';
|
||||||
|
export { createAvatarLink } from './utils/qortal';
|
||||||
export { objectToBase64 } from './utils/base64';
|
export { objectToBase64 } from './utils/base64';
|
||||||
export { generateBloomFilterBase64, isInsideBloom } from './utils/bloomFilter';
|
export { generateBloomFilterBase64, isInsideBloom } from './utils/bloomFilter';
|
||||||
export { addAndEncryptSymmetricKeys, decryptWithSymmetricKeys, encryptWithSymmetricKeys } from './utils/encryption';
|
export { addAndEncryptSymmetricKeys, decryptWithSymmetricKeys, encryptWithSymmetricKeys } from './utils/encryption';
|
||||||
@ -20,4 +23,3 @@ export {Service} from './types/interfaces/resources'
|
|||||||
export {ListItem} from './state/cache'
|
export {ListItem} from './state/cache'
|
||||||
export {SymmetricKeys} from './utils/encryption'
|
export {SymmetricKeys} from './utils/encryption'
|
||||||
|
|
||||||
|
|
||||||
|
18
src/state/indexes.ts
Normal file
18
src/state/indexes.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { create } from "zustand";
|
||||||
|
|
||||||
|
export interface OpenIndex {
|
||||||
|
link: string
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IndexState {
|
||||||
|
open: OpenIndex | null;
|
||||||
|
setOpen: (openIndex: OpenIndex | null ) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ Typed Zustand Store
|
||||||
|
export const useIndexStore = create<IndexState>((set) => ({
|
||||||
|
open: null,
|
||||||
|
setOpen: (openIndex) =>
|
||||||
|
set({ open: openIndex }),
|
||||||
|
}));
|
@ -48,6 +48,35 @@ export async function hashWord(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function hashWordWithoutPublicSalt(
|
||||||
|
word: string,
|
||||||
|
collisionStrength: number
|
||||||
|
): Promise<string> {
|
||||||
|
try {
|
||||||
|
if (!crypto?.subtle?.digest) throw new Error("Web Crypto not available");
|
||||||
|
|
||||||
|
const encoded = new TextEncoder().encode(word);
|
||||||
|
const hashBuffer = await crypto.subtle.digest("SHA-256", encoded);
|
||||||
|
|
||||||
|
return Buffer.from(hashBuffer)
|
||||||
|
.toString("base64")
|
||||||
|
.replace(/\+/g, "-")
|
||||||
|
.replace(/\//g, "_")
|
||||||
|
.replace(/=+$/, "")
|
||||||
|
.slice(0, collisionStrength);
|
||||||
|
} catch (err) {
|
||||||
|
const hash = SHA256(word);
|
||||||
|
const base64 = EncBase64.stringify(hash);
|
||||||
|
|
||||||
|
return base64
|
||||||
|
.replace(/\+/g, "-")
|
||||||
|
.replace(/\//g, "_")
|
||||||
|
.replace(/=+$/, "")
|
||||||
|
.slice(0, collisionStrength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const uid = new ShortUniqueId({ length: 10, dictionary: "alphanum" });
|
const uid = new ShortUniqueId({ length: 10, dictionary: "alphanum" });
|
||||||
|
|
||||||
interface EntityConfig {
|
interface EntityConfig {
|
||||||
|
3
src/utils/qortal.ts
Normal file
3
src/utils/qortal.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export const createAvatarLink = (qortalName: string)=> {
|
||||||
|
return `/arbitrary/THUMBNAIL/${encodeURIComponent(qortalName)}/qortal_avatar?async=true`
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user