Source: data-manager/pipeline-workers/server-side/load_server_side_pipeline_worker.js

//@ts-check
/**
 * For the server side data loading
 */
/**
 * @typedef { import("./load_server_side_pipeline_worker.d.ts.js").LoadServerSideDataPipelineStates } LoadServerSideDataPipelineStates
 * @typedef { import("./load_server_side_pipeline_worker.d.ts.js").LoadServerSidePipelineDFAGroups } LoadServerSidePipelineDFAGroups //With retry option for fail 
 */

//NORMAL IMPORT
//AVOID THE CONST - SO NORMAL CLASS DEFINITION
//NO TEMPLATES IN CONST
//USE JsDocs @extends
//PROVIDE THE TEMPLATES IN OTHER CLASS DEFINITION
import GenericBuildPipelineWorker from "../../../utils/generic-pipeline-worker/generic_build_pipeline_worker.js";
import ListReverser from "../../../utils/lists/list_reverser.js";
import DataManager from "../../data_manager.js";

/**
 * @template M
 * @typedef { import("./load_server_side_pipeline_worker.d.ts.js").LoadServerSideBuildArgs<M> } LoadServerSideBuildArgs
 */

/**
 * @deprecated - New Server side hydration technique in use
 * @extends {GenericBuildPipelineWorker<LoadServerSideDataPipelineStates, LoadServerSideBuildArgs<M>, LoadServerSidePipelineDFAGroups, null>}
 * @template M
 */
class LoadServerSidePipelineWorker extends GenericBuildPipelineWorker{

    /**
     * 
     * @param {import("./load_server_side_pipeline_worker.d.ts.js").LoadServerSidePipelineWorkerConstructorArgs} args 
     */
    constructor(args){

        /**
         * @type {GenericBuildPipelineWorkerConstructorArgs<LoadServerSideBuildArgs<M>, LoadServerSideDataPipelineStates, LoadServerSidePipelineDFAGroups, null>}
         */
        const superArgs = {

            asynchronousBuildDefinition: {

                defaultPipelineState: "onBuildEnd",
                runAsynchronous: false
            },
            pseudoStates: null,
            stateTransitionDefinition: {

                loadServerSideDFA: {

                    autoTriggerState: null,
                    root: "setUpServerSide",

                    setUpServerSide: {

                        prev: "onBuildEnd",
                        next: "buildServerSide",
                        cb: (cbArgs) => {

                            const myBuildArgs = cbArgs.buildArgs.myBuildArgs;
                            if(myBuildArgs.apiOptions.serverSide && myBuildArgs.apiOptions.serverSide.buildFromServerSide){

                                //Move to next and work on the array                                

                                cbArgs.failNextCb({

                                    goToNext: true,
                                    buildArgs: cbArgs.buildArgs
                                });
                            } else {

                                cbArgs.failNextCb({

                                    goToNext: false,
                                    buildArgs: cbArgs.buildArgs
                                });
                            }
                        },
                        fail: "jumpServerSideLoad"
                    },
                    buildServerSide: {

                        prev: "setUpServerSide",
                        next: "onBuildEnd",
                        cb: async (cbArgs) => {

                            const myBuildArgs = cbArgs.buildArgs.myBuildArgs;
                            
                            //Now invoke calls
                            //Developer can tell that server side load is starting through a toast maybe?
                            cbArgs.buildArgs.myBuildArgs.apiOptions.serverSide.onServerSideBuildStart();

                            const finalModelArray = await extractViewAndBuildData(cbArgs.buildArgs.myBuildArgs.apiOptions.serverSide.options);
                            /**
                             * 
                             * @param {import("DataManager").ServerSideBuildOptions<M>[]} buildOptions
                             * @param {*[]} finalModelArray
                             * @returns {Promise<void>} 
                             */
                            async function extractViewAndBuildData(buildOptions, finalModelArray = []){

                                //Get the server-side rendered view classes
                                const option = buildOptions.at(0);
                                
                                //If not using a list, just add a unique class name to one server-sider rendered html element 
                                //and will get what we need (specifically pagination status) - Can avoid specifying and still ok
                                /**
                                 * @type {HTMLCollectionOf<Element>}
                                 */
                                let viewClasses = null;
                                if(option.targetView.parentID){
                    
                                    viewClasses = document.getElementById(option.targetView.parentID).getElementsByClassName(option.targetView.rootViewClass);
                                } else {
                    
                                    viewClasses = document.getElementsByClassName(option.targetView.rootViewClass);
                                }
                    
                                //Set your attributes in the LAST view
                                let targetAttrsView = viewClasses[viewClasses.length - 1];
                    
                                if(option.paginationEnabled){
                    
                                    //Get the pagination attributes from the appropriate element 
                                    const paginationEnd = targetAttrsView.getAttribute(DataManager._SERVER_SIDE_DATA_ATTRS.pagination.attrPaginationEnd);
                                    const paginationEndValue = paginationEnd === DataManager._SERVER_SIDE_DATA_ATTRS.values.true ? true : false;
                        
                                    const nextPageMarker = targetAttrsView.getAttribute(DataManager._SERVER_SIDE_DATA_ATTRS.pagination.attrNextPageMarker);

                                    myBuildArgs.setScopedAPIOption(option.scope, {

                                        enabled: true,
                                        paginationEnd: paginationEndValue,
                                        nextPageMarker: nextPageMarker
                                     });
                                }
                    
                                //Use the append order to know how to order the data (thus loop direct or in reverse)
                                let viewClassesArray = Array.from(viewClasses);
                                if(option.viewManagerOptions &&  option.viewManagerOptions.viewAppendOrder === "stack"){
                    
                                    viewClassesArray = ListReverser.reverseList(Array.from(viewClasses));
                                }

                                //Now load
                                const serverSideLoadedModels = await loadFromServerSideData(viewClassesArray, myBuildArgs.apiOptions.reqUtils, option.buildCbs.onServerSideLoad);

                                //Create them in data manager
                                myBuildArgs.createModelsCb(serverSideLoadedModels);

                                cbArgs.failNextCb({

                                    goToNext: true,
                                    buildArgs: cbArgs.buildArgs
                                });

                                /**
                                 * 
                                 * @param {Array<Element>} elementsArray 
                                 * @param {LifeCycleRemoteRequestUtils} reqUtils
                                 * @param {onServerSideLoadCb<M>} loadCallback
                                 * @param {*[]} modelsArray
                                 * 
                                 * @returns {Promise<Array<M>>}
                                 */
                                async function loadFromServerSideData(elementsArray, reqUtils, loadCallback, modelsArray = []){

                                    if(elementsArray.length > 0){

                                        const element = elementsArray.at(0);
                                        modelsArray.push(await loadCallback(element, reqUtils, modelsArray));
                                        elementsArray.splice(0, 1);

                                        return await loadFromServerSideData(elementsArray, reqUtils, loadCallback, modelsArray);
                                    } else {

                                        return modelsArray;
                                    }
                                }
                            }

                            cbArgs.failNextCb({

                                goToNext: true,
                                buildArgs: cbArgs.buildArgs
                            });
                        },
                        fail: null,
                    },
                    onBuildEnd: {

                        prev: "buildServerSide",
                        next: null,
                        cb: (cbArgs) => {

                            //Tell its complete
                            cbArgs.buildArgs.myBuildArgs.apiOptions.serverSide.onServerSideBuildEnd();

                            cbArgs.failNextCb({

                                goToNext: true,
                                buildArgs: cbArgs.buildArgs
                            });
                        },
                        fail: null,
                    }
                },
                jumpServerSideLoad: {

                    autoTriggerState: null,
                    root: "onBuildEnd",

                    onBuildEnd: {

                        prev: "setUpServerSide",
                        next: null,
                        cb: (cbArgs) => {

                            cbArgs.failNextCb({

                                goToNext: true,
                                buildArgs: cbArgs.buildArgs
                            });
                        },
                        fail: null
                    }
                },
                cancelServerSideDFA: {

                    autoTriggerState: null,
                    root: "onBuildEnd",

                    onBuildEnd: {

                        prev: "loadServerSideDFA", //Any point within this DFA. Doesn't matter
                        next: null,
                        cb: (cbArgs) => {

                            cbArgs.buildArgs.myBuildArgs.apiOptions.reqUtils.abortRunningRequests();
                            cbArgs.failNextCb({

                                goToNext: true,
                                buildArgs: cbArgs.buildArgs
                            });
                        },
                        fail: null
                    }
                }
            }
        }

        super(superArgs);
    }

    /**
     * @param {import("./load_server_side_pipeline_worker.d.ts.js").InitServerSideLoadArgs<M>} args 
     */
    initServerSideLoad(args){

        this.startPipelineBuild({

            myBuildArgs: args,
            buildDefinitionParams: {

                buildID: null,
            },
            targetDFAInfo: {

                dfaGroupKey: "loadServerSideDFA"
            },
            failStartCb: () => {

                console.error("Data manager failed to retrieve server-side data");
                args.mainCb();
            },
            completeCb: () => {

                args.mainCb();
            }
        });
    }

    /**
     * @param {import("./load_server_side_pipeline_worker.d.ts.js").InitServerSideLoadArgs<M>} args
     */
    cancelServerSideLoad(args){

        this.startPipelineBuild({

            myBuildArgs: args,
            buildDefinitionParams: {

                buildID: null,
            },
            targetDFAInfo: {

                dfaGroupKey: "cancelServerSideDFA"
            }
        });
    }
}

if(false){

    /**
     * @template M
     * @type {import("./load_server_side_pipeline_worker.d.ts.js").LoadServerSidePipelineWorkerConstructor<LoadServerSideDataPipelineStates, LoadServerSideBuildArgs<M>, LoadServerSidePipelineDFAGroups, null>}
     */
    const LoadServerSidePipelineWorkerCheck = LoadServerSidePipelineWorker;
}

export default LoadServerSidePipelineWorker;