mirror of
https://github.com/20kaushik02/spotify-manager-web.git
synced 2025-12-06 07:54:07 +00:00
chain populating, type corrections, disable buttons when loading
This commit is contained in:
parent
1e46c087d6
commit
3a2c23e2e3
@ -1,6 +1,7 @@
|
||||
import type { AxiosResponse } from "axios";
|
||||
import { type apiRespBaseType, axiosInstance } from "./axiosInstance.ts";
|
||||
import {
|
||||
opBackfillChainURL,
|
||||
opBackfillLinkURL,
|
||||
opCreateLinkURL,
|
||||
opDeleteLinkURL,
|
||||
@ -43,6 +44,16 @@ interface backfillLinkDataType extends apiRespBaseType {
|
||||
localNum: number;
|
||||
}
|
||||
|
||||
type backfillChainBodyType = {
|
||||
root: string; // playlistID
|
||||
};
|
||||
|
||||
interface backfillChainDataType extends apiRespBaseType {
|
||||
toAddNum: number;
|
||||
addedNum: number;
|
||||
localNum: number;
|
||||
}
|
||||
|
||||
type pruneLinkBodyType = createLinkBodyType;
|
||||
|
||||
interface pruneLinkDataType extends apiRespBaseType {
|
||||
@ -105,6 +116,17 @@ export const apiBackfillLink = async (
|
||||
}
|
||||
};
|
||||
|
||||
export const apiBackfillChain = async (
|
||||
data: backfillChainBodyType
|
||||
): Promise<AxiosResponse<backfillChainDataType, any>> => {
|
||||
try {
|
||||
const response = await axiosInstance.put(opBackfillChainURL, data);
|
||||
return response;
|
||||
} catch (error: any) {
|
||||
return error.response;
|
||||
}
|
||||
};
|
||||
|
||||
export const apiPruneLink = async (
|
||||
data: pruneLinkBodyType
|
||||
): Promise<AxiosResponse<pruneLinkDataType, any>> => {
|
||||
|
||||
@ -15,4 +15,5 @@ export const opUpdateUserDataURL = "api/operations/update";
|
||||
export const opCreateLinkURL = "api/operations/link";
|
||||
export const opDeleteLinkURL: "api/operations/link" = opCreateLinkURL;
|
||||
export const opBackfillLinkURL = "api/operations/populate/link";
|
||||
export const opBackfillChainURL = "api/operations/populate/chain";
|
||||
export const opPruneLinkURL = "api/operations/prune/link";
|
||||
|
||||
@ -14,22 +14,19 @@ const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
// because hooks (namely, useContext) can't be used outside functional components
|
||||
// so find a better way to pass refreshAuth
|
||||
|
||||
type APIWrapperProps<T extends apiRespBaseType> = {
|
||||
apiFn(
|
||||
data?: any,
|
||||
config?: AxiosRequestConfig
|
||||
): Promise<AxiosResponse<T, any>>;
|
||||
type APIWrapperProps<B, T extends apiRespBaseType> = {
|
||||
apiFn(data?: B, config?: AxiosRequestConfig): Promise<AxiosResponse<T, any>>;
|
||||
refreshAuth: () => Promise<boolean>;
|
||||
data?: any;
|
||||
data?: B;
|
||||
config?: AxiosRequestConfig;
|
||||
};
|
||||
|
||||
const APIWrapper = async <T extends apiRespBaseType>({
|
||||
const APIWrapper = async <B, T extends apiRespBaseType>({
|
||||
apiFn,
|
||||
refreshAuth,
|
||||
data,
|
||||
config,
|
||||
}: APIWrapperProps<T>): Promise<AxiosResponse<T, any> | null> => {
|
||||
}: APIWrapperProps<B, T>): Promise<AxiosResponse<T, any> | null> => {
|
||||
let apiResp;
|
||||
for (let i = 1; i <= maxRetries + 1; i++) {
|
||||
apiResp = await apiFn(data, config);
|
||||
|
||||
@ -3,11 +3,13 @@ import styles from "./Button.module.css";
|
||||
|
||||
type ButtonProps = {
|
||||
children: React.ReactNode;
|
||||
disabled?: boolean;
|
||||
onClickMethod?: () => void;
|
||||
};
|
||||
|
||||
const Button = ({
|
||||
children,
|
||||
disabled = false,
|
||||
onClickMethod = () => {},
|
||||
}: ButtonProps): React.ReactNode => {
|
||||
const clickHandler = (e: React.MouseEvent) => {
|
||||
@ -15,7 +17,12 @@ const Button = ({
|
||||
onClickMethod();
|
||||
};
|
||||
return (
|
||||
<button type="button" className={styles.btn_wrapper} onClick={clickHandler}>
|
||||
<button
|
||||
type="button"
|
||||
disabled={disabled}
|
||||
className={styles.btn_wrapper}
|
||||
onClick={clickHandler}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
|
||||
@ -43,6 +43,7 @@ import {
|
||||
|
||||
import { spotifyPlaylistLinkPrefix } from "../../api/paths.ts";
|
||||
import {
|
||||
apiBackfillChain,
|
||||
apiBackfillLink,
|
||||
apiCreateLink,
|
||||
apiDeleteLink,
|
||||
@ -154,7 +155,6 @@ const Graph = (): React.ReactNode => {
|
||||
|
||||
const onFlowInit: OnInit = (_instance) => {
|
||||
console.debug("flow loaded");
|
||||
console.log(selectedNodeID);
|
||||
};
|
||||
|
||||
// base event handling
|
||||
@ -252,14 +252,13 @@ const Graph = (): React.ReactNode => {
|
||||
[refreshAuth]
|
||||
);
|
||||
|
||||
// backfill link
|
||||
const backfillLink = async () => {
|
||||
if (selectedEdgeID === "") {
|
||||
showWarnToastNotification("Select an edge!");
|
||||
showWarnToastNotification("Select a link!");
|
||||
return;
|
||||
}
|
||||
const selectedEdge = linkEdges.filter((ed) => ed.id === selectedEdgeID)[0];
|
||||
if (!selectedEdge) throw new ReferenceError("no edge selected");
|
||||
if (!selectedEdge) throw new ReferenceError("no link selected");
|
||||
setLoading(true);
|
||||
const resp = await APIWrapper({
|
||||
apiFn: apiBackfillLink,
|
||||
@ -280,7 +279,34 @@ const Graph = (): React.ReactNode => {
|
||||
return;
|
||||
};
|
||||
|
||||
// prune link
|
||||
const backfillChain = async () => {
|
||||
if (selectedNodeID === "") {
|
||||
showWarnToastNotification("Select a playlist!");
|
||||
return;
|
||||
}
|
||||
const selectedNode = playlistNodes.filter(
|
||||
(nd) => nd.id === selectedNodeID
|
||||
)[0];
|
||||
if (!selectedNode) throw new ReferenceError("no playlist selected");
|
||||
setLoading(true);
|
||||
const resp = await APIWrapper({
|
||||
apiFn: apiBackfillChain,
|
||||
data: {
|
||||
root: spotifyPlaylistLinkPrefix + selectedNodeID,
|
||||
},
|
||||
refreshAuth,
|
||||
});
|
||||
setLoading(false);
|
||||
|
||||
if (resp?.status === 200) {
|
||||
if (resp?.data.addedNum < resp?.data.toAddNum)
|
||||
showWarnToastNotification(resp?.data.message);
|
||||
else showSuccessToastNotification(resp?.data.message);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
const pruneLink = async () => {
|
||||
if (selectedEdgeID === "") {
|
||||
showWarnToastNotification("Select an edge!");
|
||||
@ -531,29 +557,29 @@ const Graph = (): React.ReactNode => {
|
||||
<Panel position="top-right">{loading && <SimpleLoader />}</Panel>
|
||||
</ReactFlow>
|
||||
<div className={`${styles.operations_wrapper} custom_scrollbar`}>
|
||||
<Button onClickMethod={backfillLink}>
|
||||
<Button disabled={loading} onClickMethod={backfillLink}>
|
||||
<PiSupersetOf size={36} />
|
||||
Backfill Link
|
||||
</Button>
|
||||
<Button>
|
||||
<Button disabled={loading} onClickMethod={backfillChain}>
|
||||
<PiSupersetOf size={36} />
|
||||
Backfill Chain
|
||||
</Button>
|
||||
<hr className={styles.divider} />
|
||||
<Button onClickMethod={pruneLink}>
|
||||
<Button disabled={loading} onClickMethod={pruneLink}>
|
||||
<PiSubsetOf size={36} />
|
||||
Prune Link
|
||||
</Button>
|
||||
<Button>
|
||||
<Button disabled={loading}>
|
||||
<PiSubsetOf size={36} />
|
||||
Prune Link
|
||||
</Button>
|
||||
<hr className={styles.divider} />
|
||||
<Button onClickMethod={() => arrangeLayout("TB")}>
|
||||
<Button disabled={loading} onClickMethod={() => arrangeLayout("TB")}>
|
||||
<IoIosGitNetwork size={36} />
|
||||
Arrange
|
||||
</Button>
|
||||
<Button onClickMethod={toggleInteractive}>
|
||||
<Button disabled={loading} onClickMethod={toggleInteractive}>
|
||||
{isInteractive() ? (
|
||||
<MdOutlineLock size={36} />
|
||||
) : (
|
||||
@ -562,14 +588,14 @@ const Graph = (): React.ReactNode => {
|
||||
{isInteractive() ? "Lock" : "Unlock"}
|
||||
</Button>
|
||||
<hr className={styles.divider} />
|
||||
<Button onClickMethod={updateUserData}>
|
||||
<Button disabled={loading} onClickMethod={updateUserData}>
|
||||
<span className={styles.icons}>
|
||||
<WiCloudRefresh size={36} />
|
||||
<AiFillSpotify size={36} />
|
||||
</span>
|
||||
Sync Spotify
|
||||
</Button>
|
||||
<Button onClickMethod={refreshGraph}>
|
||||
<Button disabled={loading} onClickMethod={refreshGraph}>
|
||||
<WiCloudRefresh size={36} />
|
||||
Refresh Graph
|
||||
</Button>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user