query-string#parse TypeScript Examples

The following examples show how to use query-string#parse. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: use-url-state.ts    From bext with MIT License 7 votes vote down vote up
useUrlState = <S extends UrlState = UrlState>(
  initialState?: S | (() => S),
  options?: Options,
) => {
  type State = Partial<{ [key in keyof S]: any }>;
  const { navigateMode = 'push' } = options || {};
  const history = useHistory();
  const update = useUpdate();

  const initialStateRef = useRef(
    typeof initialState === 'function'
      ? (initialState as () => S)()
      : initialState || {},
  );

  const queryFromUrl = useMemo(() => {
    return parse(location.search, parseConfig);
  }, [location.search]);

  const targetQuery: State = useMemo(
    () => ({
      ...initialStateRef.current,
      ...queryFromUrl,
    }),
    [queryFromUrl],
  );

  const setState = (s: React.SetStateAction<State>) => {
    const newQuery = typeof s === 'function' ? s(targetQuery) : s;
    update();
    history[navigateMode]({
      hash: location.hash,
      search: stringify({ ...queryFromUrl, ...newQuery }, parseConfig) || '?',
    });
  };

  return [targetQuery, useMemoizedFn(setState)] as const;
}
Example #2
Source File: LineItem.tsx    From yugong with MIT License 6 votes vote down vote up
LineItem: React.FC<Props> = ({ label, describe, children }) => {
  return (
    <Row className={s.row} gutter={10}>
      <Col span={4} className={s.label}>
        {describe ? <Tooltip
          placement="topRight"
          title={parse(describe || '')}
        >
          {label}
        </Tooltip> : label}
      </Col>
      <Col span={20}>
        {children}
      </Col>
    </Row>
  )
}
Example #3
Source File: BaiduSearchEngineAdapter.tsx    From joplin-utils with MIT License 6 votes vote down vote up
/**
   * 参考:https://www.jianshu.com/p/5ce9b98e4d81
   */
  parseKeyword(): string | null {
    const query = parse(location.search)
    const keyword = query.wd || query.word
    if (typeof keyword !== 'string') {
      return null
    }
    return keyword
  }
Example #4
Source File: utils.tsx    From erda-ui with GNU Affero General Public License v3.0 6 votes vote down vote up
keepRedirectUrlQuery = (url: string, redirectUrl?: string) => {
  const query = parse(window.location.search);
  const curRedirectUrl = redirectUrl || query?.redirectUrl;
  if (curRedirectUrl && !url.includes('redirectUrl=')) {
    return `${url}${url.includes('?') ? '&' : '?'}redirectUrl=${curRedirectUrl}`;
  }
  return url;
}
Example #5
Source File: inject.ts    From Mokku with MIT License 6 votes vote down vote up
getLog = (
  request: Omit<ILog["request"], "headers"> & {
    headers: Record<string, string>;
    mokku?: {
      id: number;
    };
  },
  response?: ILog["response"]
): IEventMessage["message"] => {
  const separator = request.url.indexOf("?");
  const url = separator !== -1 ? request.url.substr(0, separator) : request.url;
  const queryParams =
    separator !== -1
      ? JSON.stringify(parse(request.url.substr(separator)))
      : undefined;

  let body = request.body;

  try {
    if (typeof body === "object") {
      const stringifiedBody = JSON.stringify(body);
      body = stringifiedBody;
    }
  } catch (e) {
    body = "Unsupported body type!";
  }

  return {
    request: {
      url,
      body,
      queryParams,
      method: request.method,
      headers: getHeaders(request.headers),
    },
    response,
    id: request.mokku?.id,
  };
}
Example #6
Source File: LoginGovCallback.tsx    From crossfeed with Creative Commons Zero v1.0 Universal 6 votes vote down vote up
LoginGovCallback: React.FC = () => {
  const { apiPost, login } = useAuthContext();
  const { push: historyPush } = useHistory();

  const handleLoginGovCB = useCallback(async () => {
    const { state, code } = parse(window.location.search);
    const nonce = localStorage.getItem('nonce');
    const origState = localStorage.getItem('state');

    try {
      const { token } = await apiPost<cbResponse>('/auth/callback', {
        body: {
          state,
          code,
          nonce,
          origState
        }
      });
      await login(token);
      localStorage.removeItem('nonce');
      localStorage.removeItem('state');
    } catch (e) {
    } finally {
      // route guard on '/' will respond appropriately
      historyPush('/');
    }
  }, [apiPost, historyPush, login]);

  useEffect(() => {
    handleLoginGovCB();
  }, [handleLoginGovCB]);

  return <div></div>;
}
Example #7
Source File: GoogleSearchEngineAdapter.tsx    From joplin-utils with MIT License 5 votes vote down vote up
parseKeyword(): string | null {
    const keyword = parse(location.search).q
    if (typeof keyword !== 'string') {
      return null
    }
    return keyword
  }
Example #8
Source File: BingSearchEngineAdapter.tsx    From joplin-utils with MIT License 5 votes vote down vote up
parseKeyword(): string | null {
    const keyword = parse(location.search).q
    if (typeof keyword !== 'string') {
      return null
    }
    return keyword
  }
Example #9
Source File: inject.ts    From Mokku with MIT License 5 votes vote down vote up
xhook.before(function (request, callback) {
  const separator = request.url.indexOf("?");
  const url = separator !== -1 ? request.url.substr(0, separator) : request.url;
  const queryParams =
    separator !== -1
      ? JSON.stringify(parse(request.url.substr(separator)))
      : undefined;

  request.mokku = {
    id: logIdFactory.getId(),
  };

  const data: IEventMessage["message"] = getLog(request);
  postMessage(data, "LOG", false);

  postMessage(data, "NOTIFICATION", true)
    .then((data: { mockResponse: IMockResponse }) => {
      if (data && data.mockResponse) {
        const mock = data.mockResponse;

        const headers = mock.headers
          ? mock.headers.reduce<Record<string, string>>((final, header) => {
              final[header.name] = header.value;
              return final;
            }, {})
          : {
              "content-type": "application/json; charset=UTF-8",
            };

        const finalResponse = {
          status: mock.status,
          text: mock.response ? mock.response : "",
          headers,
          type: "json",
        };

        if (mock.delay) {
          setTimeout(() => {
            callback(finalResponse);
          }, mock.delay);
        } else {
          callback(finalResponse);
        }
      } else {
        callback();
      }
    })
    .catch(() => {
      console.log("something went wrong!");
    });
});
Example #10
Source File: index.tsx    From erda-ui with GNU Affero General Public License v3.0 5 votes vote down vote up
Registration = () => {
  const [flow, setFlow] = React.useState<SelfServiceRegistrationFlow>();
  const query = parse(window.location.search);
  const { flow: flowId } = query;

  React.useEffect(() => {
    if (flow) {
      return;
    }

    // If ?flow=.. was in the URL, we fetch it
    if (flowId) {
      ory
        .getSelfServiceRegistrationFlow(String(flowId))
        .then(({ data }) => {
          // We received the flow - let's use its data and render the form!
          setFlow(data);
        })
        .catch(handleFlowError('registration', setFlow));
      return;
    }

    // Otherwise we initialize it
    ory
      .initializeSelfServiceRegistrationFlowForBrowsers()
      .then(({ data }) => {
        setFlow(data);
      })
      .catch(handleFlowError('registration', setFlow));
  }, [flowId, flow]);

  const onSubmit = (values: SubmitSelfServiceRegistrationFlowBody) => {
    history.push(`/uc/registration?flow=${flow?.id}`);
    return ory
      .submitSelfServiceRegistrationFlow(String(flow?.id), values)
      .then(({ data }) => {
        // If we ended up here, it means we are successfully signed up!
        //
        // You can do cool stuff here, like having access to the identity which just signed up:
        console.log('This is the user session: ', data, data.identity);

        // For now however we just want to redirect home!
        return history.push('/uc/login');
      })
      .catch(handleFlowError('registration', setFlow))
      .catch((err: AxiosError) => {
        // If the previous handler did not catch the error it's most likely a form validation error
        if (err.response?.status === 400) {
          // Yup, it is!
          setFlow(err.response?.data);
          return;
        }

        return Promise.reject(err);
      });
  };

  const goToLogin = () => {
    history.push('/uc/login');
  };

  return (
    <Container>
      <h2 className="text-center text-4xl text-indigo-800 font-display font-semibold lg:text-left xl:text-5xl xl:text-bold">
        {i18n.t('Sign up')}
      </h2>
      <div className="mt-12">
        <Flow flow={flow} onSubmit={onSubmit} hideNode={['avatar']} />

        <div className="my-8 text-sm font-display font-semibold text-gray-700 text-center">
          {i18n.t('Already have an account?')}{' '}
          <span className="cursor-pointer text-indigo-600 hover:text-indigo-800" onClick={goToLogin}>
            {i18n.t('Login')}
          </span>
        </div>
      </div>
    </Container>
  );
}
Example #11
Source File: index.ts    From imove with MIT License 5 votes vote down vote up
safeParse = (json: string): Record<string, any> => {
  try {
    return JSON.parse(json);
  } catch (error) {
    return {};
  }
}
Example #12
Source File: index.ts    From imove with MIT License 5 votes vote down vote up
parseQuery = (): { [key: string]: any } => {
  return parse(location.search, parseConfig);
}
Example #13
Source File: index.tsx    From erda-ui with GNU Affero General Public License v3.0 4 votes vote down vote up
Setting = () => {
  const [flow, setFlow] = React.useState<SelfServiceSettingsFlow>();
  const query = parse(window.location.search);
  const { flow: flowId } = query;
  const [messageMap, setMessageMap] = React.useState<Obj<undefined | Array<UiText>>>({
    profile: undefined,
    password: undefined,
    global: undefined,
  });

  const onLogout = CreateLogoutHandler();

  React.useEffect(() => {
    if (flow) {
      return;
    }

    // If ?flow=.. was in the URL, we fetch it
    if (flowId) {
      ory
        .getSelfServiceSettingsFlow(String(flowId))
        .then(({ data }) => {
          setFlow(data);
          setMessageMap((prev) => ({ ...prev, global: data?.ui?.messages }));
        })
        .catch(handleFlowError('settings', setFlow));
      return;
    }

    // Otherwise we initialize it
    ory
      .initializeSelfServiceSettingsFlowForBrowsers()
      .then(({ data }) => {
        setFlow(data);
      })
      .catch(handleFlowError('settings', setFlow));
  }, [flowId, flow]);

  const onSubmit = (type: string) => (values: SubmitSelfServiceSettingsFlowBody) => {
    history.push(`/uc/settings?flow=${flow?.id}`);
    return ory
      .submitSelfServiceSettingsFlow(String(flow?.id), undefined, values)
      .then(({ data }) => {
        // The settings have been saved and the flow was updated. Let's show it to the user!
        setFlow(data);
        setMessageMap((prev) => ({ ...prev, [type]: data?.ui?.messages }));
      })
      .catch(handleFlowError('settings', setFlow))
      .catch(async (err: AxiosError) => {
        // If the previous handler did not catch the error it's most likely a form validation error
        if (err.response?.status === 400) {
          // Yup, it is!
          setFlow(err.response?.data);

          setMessageMap((prev) => ({ ...prev, [type]: err.response?.data?.ui?.messages }));
          return;
        }

        return Promise.reject(err);
      });
  };
  const curUser = flow?.identity?.traits;
  return (
    <Container>
      <h2 className="text-center text-4xl text-indigo-800 font-display font-semibold lg:text-left xl:text-5xl xl:text-bold">
        {i18n.t('Hello {name}', { name: curUser?.nickname || curUser?.username || curUser?.email })}
      </h2>
      <div className="mt-12">
        <Alert messages={messageMap.global} />
        <div className="border-b border-gray-300 pb-12">
          <span className="text-indigo-800 font-bold">{i18n.t('Profile setting')}</span>
          <Alert messages={messageMap.profile} />
          <Flow only="profile" flow={flow} hideGlobalMessages onSubmit={onSubmit('profile')} />
        </div>

        <div className="pt-12">
          <span className="text-indigo-800 font-bold">{i18n.t('Password setting')}</span>
          <Alert messages={messageMap.password} />
          <Flow only="password" flow={flow} hideGlobalMessages onSubmit={onSubmit('password')} />
        </div>

        <div className="my-8 text-sm font-display font-semibold text-gray-700 text-center">
          <span className="cursor-pointer text-indigo-600 hover:text-indigo-800" onClick={onLogout}>
            {i18n.t('Logout')}
          </span>
        </div>
      </div>
    </Container>
  );
}
Example #14
Source File: header.tsx    From erda-ui with GNU Affero General Public License v3.0 4 votes vote down vote up
Header = ({ layout }: { layout?: RouteConfigItem_Layout }) => {
  const { hideSidebar } = layout || {};
  const [currentApp, topButtonsWidth] = layoutStore.useStore((s) => [s.currentApp, s.topButtonsWidth]);
  const [routes, markedRoutePreview] = routeInfoStore.useStore((s) => [s.routes, s.markedRoutePreview]);
  const [pageName, setPageName] = React.useState<string>();
  const [backToUp, setBackToUp] = React.useState(0);
  const infoMap = breadcrumbStore.useStore((s) => s.infoMap);
  const [query] = routeInfoStore.useStore((s) => [s.query]);
  const [backToUpKey, setBackToUpKey] = React.useState('');

  const [allRoutes, setAllRoutes] = React.useState<IRoute[]>([]);
  const [params, setParams] = React.useState<Obj<string>>({});
  const [pageNameInfo, setPageNameInfo] = React.useState<Function>();
  const checkHasTemplate = React.useCallback(
    (breadcrumbName: string) => {
      const replacePattern = /\{([\w.])+\}/g;
      let _breadcrumbName = breadcrumbName || '';
      const matches = _breadcrumbName.match(replacePattern);
      if (!matches) {
        return _breadcrumbName;
      }
      matches.forEach((match: string) => {
        const [type, key] = match.slice(1, -1).split('.'); // match: {params.id}
        let value;
        if (type === 'params') {
          value = params[key];
        } else if (type === 'query') {
          value = decodeURIComponent(query[key]);
        } else {
          value = infoMap[type];
        }
        _breadcrumbName = _breadcrumbName.replace(match, value);
      });
      if (_breadcrumbName === 'undefined') {
        _breadcrumbName = '';
      }
      return _breadcrumbName;
    },
    [infoMap, params, query],
  );

  const getBreadcrumbTitle = React.useCallback(
    (route: IRoute, isBreadcrumb = false) => {
      const { breadcrumbName, pageName } = route;
      let _title = '';
      if (!isBreadcrumb && pageName) {
        _title = isFunction(pageName)
          ? breadcrumbName({ infoMap, route, params, query })
          : checkHasTemplate(pageName as string);
      } else {
        _title = isFunction(breadcrumbName)
          ? breadcrumbName({ infoMap, route, params, query })
          : checkHasTemplate(breadcrumbName as string);
      }
      return _title;
    },
    [checkHasTemplate, infoMap, params, query],
  );

  React.useEffect(() => {
    if (allRoutes.length) {
      const lastRoute = allRoutes[allRoutes.length - 1];
      const _title = getBreadcrumbTitle(lastRoute);
      setPageNameInfo(() => lastRoute?.pageNameInfo);
      setPageName(_title);
    }
  }, [allRoutes, getBreadcrumbTitle]);

  React.useEffect(() => {
    document.title = pageName ? `${pageName} · Erda` : 'Erda';
  }, [pageName]);

  React.useEffect(() => {
    let _params: Obj<string> = {};
    // get params from path
    if (routes.length > 0) {
      const match = matchPath(window.location.pathname, {
        path: routes[0].path,
        exact: true,
        strict: false,
      });
      if (match) {
        _params = match.params;
        setParams(_params);
      }
      let backToUpLevel = 0;
      const currentRoute = routes[0];
      if (currentRoute.backToUp) {
        const targetRoute = routes.find((a) => a.mark === currentRoute.backToUp);
        if (targetRoute) {
          backToUpLevel = location.pathname.split('/').length - targetRoute.path.split('/').length;
        }
      }
      setBackToUpKey(currentRoute.backToUp);
      setBackToUp(backToUpLevel);
    }
    const filteredRoutes = routes.filter((route) => {
      return route.path && (route.breadcrumbName || route.pageName || typeof route.breadcrumbName === 'function');
    });
    if (!isEmpty(currentApp)) {
      const eternalApp = {
        key: currentApp.key,
        eternal: currentApp.href,
        breadcrumbName: currentApp.breadcrumbName,
        path: typeof currentApp.path === 'function' ? currentApp.path(_params || {}, routes) : currentApp.href,
      };
      filteredRoutes.reverse().splice(1, 0, eternalApp as IRoute);
      setAllRoutes(filteredRoutes);
    }
  }, [currentApp, routes]);

  const displayPageName = () => {
    if (typeof pageNameInfo === 'function') {
      const Comp = pageNameInfo;
      return <Comp />;
    }
    if (backToUp) {
      const search = markedRoutePreview[backToUpKey];
      const _query = search ? { ...parse(search, { arrayFormat: 'bracket' }) } : undefined;
      return (
        <div
          className="text-xl truncate inline-flex items-center cursor-pointer"
          onClick={() => goTo('../'.repeat(backToUp), { query: _query })}
        >
          <ErdaIcon type="arrow-left" className="mr-1" />
          {allWordsFirstLetterUpper(pageName as string)}
        </div>
      );
    }
    return <div className="text-xl truncate">{allWordsFirstLetterUpper(pageName as string)}</div>;
  };

  return (
    <div className="erda-header" style={{ marginRight: topButtonsWidth }}>
      <div className={`erda-header-title-con inline-flex ${hideSidebar ? 'ml-4' : ''}`}>
        {pageName && displayPageName()}
      </div>
      <Tab />
    </div>
  );
}
Example #15
Source File: index.tsx    From erda-ui with GNU Affero General Public License v3.0 4 votes vote down vote up
export default function Recovery() {
  const query = parse(window.location.search);

  // refres: means we want to refresh the session. This is needed, for example, when we want to update the password of a user.
  const { flow: flowId, refresh } = query;
  const [flow, setFlow] = React.useState<SelfServiceRecoveryFlow>();

  React.useEffect(() => {
    if (flow) {
      return;
    }

    // If ?flow=.. was in the URL, we fetch it
    if (flowId) {
      ory
        .getSelfServiceRecoveryFlow(String(flowId))
        .then(({ data }) => {
          setFlow(data);
        })
        .catch(handleFlowError('recovery', setFlow));
      return;
    }
    ory
      .initializeSelfServiceRecoveryFlowForBrowsers()
      .then(({ data }) => {
        setFlow(data);
      })
      .catch(handleFlowError('recovery', setFlow))
      .catch((err: AxiosError) => {
        // If the previous handler did not catch the error it's most likely a form validation error
        if (err.response?.status === 400) {
          // Yup, it is!
          setFlow(err.response?.data);
          return;
        }

        return Promise.reject(err);
      });
  }, [flowId, refresh, flow]);

  const onSubmit = (values: SubmitSelfServiceRecoveryFlowBody) => {
    history.push(`/uc/recovery?flow=${flow?.id}`);
    return ory
      .submitSelfServiceRecoveryFlow(String(flow?.id), undefined, values)
      .then(({ data }) => {
        // Form submission was successful, show the message to the user!
        setFlow(data);
      })
      .then(() => {})
      .catch(handleFlowError('recovery', setFlow))
      .catch((err: AxiosError) => {
        switch (err.response?.status) {
          case 400:
            // Status code 400 implies the form validation had an error
            setFlow(err.response?.data);
            return;
        }

        throw err;
      });
  };

  const goToRegistration = () => {
    history.push('/uc/registration');
  };

  const goToLogin = () => {
    history.push('/uc/login');
  };
  return (
    <Container>
      <h2 className="text-center text-4xl text-indigo-800 font-display font-semibold lg:text-left xl:text-5xl xl:text-bold">
        {i18n.t('Recovery account')}
      </h2>
      <div className="mt-12">
        <Flow flow={flow} onSubmit={onSubmit} />

        <div className="mt-8 mb-2 pb-2 text-sm font-display font-semibold text-gray-700 text-center">
          {i18n.t('Already have an account?')}{' '}
          <span className="cursor-pointer text-indigo-600 hover:text-indigo-800" onClick={goToLogin}>
            {i18n.t('Login')}
          </span>
        </div>
        <div className="mb-8 mt-2 text-sm font-display font-semibold text-gray-700 pb-2 text-center">
          {i18n.t('Do not have an account?')}{' '}
          <span className="cursor-pointer text-indigo-600 hover:text-indigo-800" onClick={goToRegistration}>
            {i18n.t('Sign up')}
          </span>
        </div>
      </div>
    </Container>
  );
}
Example #16
Source File: index.tsx    From erda-ui with GNU Affero General Public License v3.0 4 votes vote down vote up
export default function Login() {
  const query = parse(window.location.search);

  // refres: means we want to refresh the session. This is needed, for example, when we want to update the password of a user.
  const { flow: flowId, refresh } = query;
  const [flow, setFlow] = React.useState<SelfServiceLoginFlow>();

  React.useEffect(() => {
    if (flow) {
      return;
    }

    // If ?flow=.. was in the URL, we fetch it
    if (flowId) {
      ory
        .getSelfServiceLoginFlow(String(flowId))
        .then(({ data }) => {
          setFlow(data);
        })
        .catch(handleFlowError('login', setFlow));
      return;
    }
    // Otherwise we initialize it
    ory
      .initializeSelfServiceLoginFlowForBrowsers(Boolean(refresh), undefined)
      .then(({ data }) => {
        setFlow(data);
      })
      .catch(handleFlowError('login', setFlow));
  }, [flowId, refresh, flow]);

  const onSubmit = (values: SubmitSelfServiceLoginFlowBody) => {
    history.push(keepRedirectUrlQuery(`/uc/login?flow=${flow?.id}`));
    return (
      ory
        .submitSelfServiceLoginFlow(String(flow?.id), undefined, values)
        // We logged in successfully! Let's bring the user home.
        .then((res) => {
          const query = parse(window.location.search);
          if (query?.redirectUrl) {
            window.location.href = query.redirectUrl as string;
          } else {
            history.push('/uc/settings');
          }
        })
        .then(() => {})
        .catch(handleFlowError('login', setFlow))
        .catch((err: AxiosError) => {
          // If the previous handler did not catch the error it's most likely a form validation error
          if (err.response?.status === 400) {
            // Yup, it is!
            setFlow(err.response?.data);
            return;
          }

          return Promise.reject(err);
        })
    );
  };

  const goToRegistration = () => {
    history.push('/uc/registration');
  };

  const goToRecover = () => {
    history.push('/uc/recovery');
  };

  return (
    <Container>
      <h2 className="text-center text-4xl text-indigo-800 font-display font-semibold lg:text-left xl:text-5xl xl:text-bold">
        {i18n.t('Welcome to Erda')}
      </h2>
      <div className="mt-12">
        <Flow flow={flow} onSubmit={onSubmit} ignorRegKeys={['password']} />

        <div className="mt-8 mb-2 text-sm font-display font-semibold text-gray-700 pb-2 text-center">
          {i18n.t('Do not have an account?')}{' '}
          <span className="cursor-pointer text-indigo-600 hover:text-indigo-800" onClick={goToRegistration}>
            {i18n.t('Sign up')}
          </span>
        </div>
        <div className="mt-2 mb-6 text-sm font-display font-semibold text-gray-700 pb-2 text-center">
          {i18n.t('Forgot password?')}{' '}
          <span className="cursor-pointer text-indigo-600 hover:text-indigo-800" onClick={goToRecover}>
            {i18n.t('Recovery account')}
          </span>
        </div>
      </div>
    </Container>
  );
}
Example #17
Source File: route.ts    From erda-ui with GNU Affero General Public License v3.0 4 votes vote down vote up
routeInfoStore = createStore({
  name: 'routeInfo',
  state: initRouteInfo,
  reducers: {
    $_updateRouteInfo(
      state,
      location: { pathname: string; search: string; key: string },
      extraData?: any,
      extraPayload?: { force?: boolean },
    ) {
      const { pathname, search, key: urlKey } = location;
      const { force = false } = extraPayload || {};
      const prevRouteInfo = state;
      if (!force && prevPath === pathname && search === prevSearch) {
        return prevRouteInfo;
      }
      prevPath = pathname;
      prevSearch = search;
      const query = { ...parse(search, { arrayFormat: 'bracket' }) }; // parse出来的对象prototype为null,fast-deep-equal判断时报错
      let routes: IRouteInfo[] = [];
      const params: Obj = {};
      const { routePatterns, routeMap, parsed } = extraData || prevRouteInfo;
      let currentRoute = null;
      let routeMarks: string[] = [];
      const findParent = (item: any) => {
        const { _parent, mark } = item;
        if (mark) {
          routeMarks.push(mark);
        }
        if (_parent) {
          routes.push(_parent);
          findParent(_parent);
        }
      };

      for (let i = 0; i < routePatterns?.length; i++) {
        const pattern = routePatterns[i];

        const keys: Key[] = [];
        const match = pathToRegexp(pattern, keys).exec(pathname);

        if (match) {
          keys.forEach((k, j) => {
            if (k.name !== 0) {
              // 移除 * 号匹配时的0字段
              params[k.name] = match[j + 1];
            }
          });
          currentRoute = routeMap[pattern].route;
          const routeLevel = pattern.split('/').length;
          Object.keys(queryLevelMap).forEach((level) => {
            // 清除大于当前层级(更深)的路由的query
            if (routeLevel < level) {
              Object.values(queryLevelMap[level]).forEach((r) => {
                r.routeQuery = {};
              });
            }
          });

          // 如果需要保持路由query
          if (currentRoute.keepQuery) {
            currentRoute.routeQuery = { ...currentRoute.routeQuery, ...query };
            queryLevelMap[routeLevel] = queryLevelMap[routeLevel] || {};
            queryLevelMap[routeLevel][pattern] = currentRoute;
          }
          routes = [currentRoute];
          routeMarks = [];
          findParent(currentRoute);
          break;
        }
      }

      const curUrlPaths = [...state.urlPathRecord];
      const curUrlFull = new Set(state.urlFullRecord);

      let urlState = 'new';
      if (curUrlFull.has(urlKey) && curUrlPaths.length > 1) {
        if (curUrlPaths.includes(urlKey)) {
          urlState = 'back';
          curUrlPaths.pop();
        } else {
          urlState = 'forward';
          curUrlPaths.push(urlKey);
        }
      } else if (!(curUrlPaths.length === 1 && curUrlPaths.includes(urlKey))) {
        // forbidden first time execute $_updateRouteInfo more than once;
        curUrlPaths.push(urlKey);
      }

      curUrlFull.add(urlKey);

      const markedRoutePreview = {
        ...state.markedRoutePreview,
        ...(currentRoute?.searchMark ? { [currentRoute.searchMark]: search } : {}),
      };
      const routeInfo = {
        prevRouteInfo,
        params,
        query,
        routes,
        currentRoute,
        markedRoutePreview,
        urlFullRecord: curUrlFull,
        urlPathRecord: curUrlPaths,
        urlState,
        routePatterns,
        routeMap,
        parsed,
        routeMarks,
        isIn: (level: string) => routeMarks.includes(level),
        isMatch: (pattern: string) => !!pathToRegexp(pattern, []).exec(pathname),
        isEntering: (level: string) => routeMarks.includes(level) && !prevRouteInfo.routeMarks.includes(level),
        isLeaving: (level: string) => !routeMarks.includes(level) && prevRouteInfo.routeMarks.includes(level),
      };
      return routeInfo;
    },
  },
})
Example #18
Source File: BeforeOutput.tsx    From yugong with MIT License 4 votes vote down vote up
BeforeOutput: React.FC<Props> = () => {
  const { updateAppData } = useDispatch<Dispatch>().appData;
  const { updatePage } = useDispatch<Dispatch>().pageData;
  const { setCurrentEditorStylePath } = useDispatch<Dispatch>().controller;

  const pageData = useSelector((state: RootState) => state.pageData);

  // 页面准备状态
  const [isAppdataReady, setIsAppdataReady] = useState(false);
  const [isPagedataReady, setIsPagedataReady] = useState(false);

  // 获取缓存的页面数据与模块数据
  const [appDataLocalStoreData] = useLocalStorage('appData', null);
  const [pageDataLocalStoreData] = useLocalStorage('pageData', null);

  // 用于编辑模式下,观察编辑器通知,设置当前编辑路径
  const sendMessage = usePostMessage((data) => {
    const { tag, value } = data;
    if (tag === 'setCurrentEditorStylePath') {
      setCurrentEditorStylePath(value);
    }
  });

  // 同步App数据
  const asyncAppData = useCallback(
    (appData) => {
      if (appData) {
        updateAppData(appData);
        setIsAppdataReady(true);
        sendMessage(
          {
            tag: 'updateAppData',
            value: appData,
          },
          window.top,
        );
      }
    },
    [sendMessage, updateAppData],
  );

  // 同步page数据
  const asyncPageData = useCallback(
    (pageData) => {
      if (pageData) {
        updatePage(pageData);
        setIsPagedataReady(true);
        sendMessage(
          {
            tag: 'updatePage',
            value: pageData,
          },
          window.top,
        );
      }
    },
    [sendMessage, updatePage],
  );

  // 初始化App
  const setApp = useCallback(async () => {
    const { tpl } = parse(window.location.search);
    let appDataRes, pageDataRes;
    if (!tpl) {
      appDataRes = appDataLocalStoreData || [];
      pageDataRes = pageDataLocalStoreData || {};
    } else {
      const result = await queryTemplateById(tpl as string);
      if (!isType(result, 'Object')) return;
      const { appData = '"[]"', pageData = '"{}"' } = result;
      appDataRes = JSON.parse(appData);
      pageDataRes = JSON.parse(pageData);
    }
    asyncAppData(appDataRes);
    asyncPageData(pageDataRes);
  }, [
    appDataLocalStoreData,
    asyncAppData,
    asyncPageData,
    pageDataLocalStoreData,
  ]);

  useEffect(() => {
    setApp();
  }, [setApp]);

  // 底层数据将完全准备就绪,再放行App!
  if (!isAppdataReady || !isPagedataReady || !pageData) {
    return null;
  }
  return <Output pageData={pageData} />;
}
Example #19
Source File: Vulnerabilities.tsx    From crossfeed with Creative Commons Zero v1.0 Universal 4 votes vote down vote up
Vulnerabilities: React.FC<{ groupBy?: string }> = ({
  groupBy = undefined
}: {
  children?: React.ReactNode;
  groupBy?: string;
}) => {
  const {
    currentOrganization,
    apiPost,
    apiPut,
    showAllOrganizations
  } = useAuthContext();
  const [vulnerabilities, setVulnerabilities] = useState<Vulnerability[]>([]);
  const [totalResults, setTotalResults] = useState(0);
  const tableRef = useRef<TableInstance<Vulnerability>>(null);
  const listClasses = useStyles();
  const [noResults, setNoResults] = useState(false);

  const updateVulnerability = useCallback(
    async (index: number, body: { [key: string]: string }) => {
      try {
        const res = await apiPut<Vulnerability>(
          '/vulnerabilities/' + vulnerabilities[index].id,
          {
            body: body
          }
        );
        const vulnCopy = [...vulnerabilities];
        vulnCopy[index].state = res.state;
        vulnCopy[index].substate = res.substate;
        vulnCopy[index].actions = res.actions;
        setVulnerabilities(vulnCopy);
      } catch (e) {
        console.error(e);
      }
    },
    [setVulnerabilities, apiPut, vulnerabilities]
  );
  const columns = useMemo(() => createColumns(updateVulnerability), [
    updateVulnerability
  ]);
  const groupedColumns = useMemo(() => createGroupedColumns(), []);

  const vulnerabilitiesSearch = useCallback(
    async ({
      filters,
      sort,
      page,
      pageSize = PAGE_SIZE,
      doExport = false,
      groupBy = undefined
    }: {
      filters: Filters<Vulnerability>;
      sort: SortingRule<Vulnerability>[];
      page: number;
      pageSize?: number;
      doExport?: boolean;
      groupBy?: string;
    }): Promise<ApiResponse | undefined> => {
      try {
        const tableFilters: {
          [key: string]: string | boolean | undefined;
        } = filters
          .filter((f) => Boolean(f.value))
          .reduce(
            (accum, next) => ({
              ...accum,
              [next.id]: next.value
            }),
            {}
          );
        // If not open or closed, substitute for appropriate substate
        if (
          tableFilters['state'] &&
          !['open', 'closed'].includes(tableFilters['state'] as string)
        ) {
          const substate = (tableFilters['state'] as string)
            .match(/\((.*)\)/)
            ?.pop();
          if (substate)
            tableFilters['substate'] = substate.toLowerCase().replace(' ', '-');
          delete tableFilters['state'];
        }
        if (!showAllOrganizations && currentOrganization) {
          if ('rootDomains' in currentOrganization)
            tableFilters['organization'] = currentOrganization.id;
          else tableFilters['tag'] = currentOrganization.id;
        }
        if (tableFilters['isKev']) {
          // Convert string to boolean filter.
          tableFilters['isKev'] = tableFilters['isKev'] === 'true';
        }
        return await apiPost<ApiResponse>(
          doExport ? '/vulnerabilities/export' : '/vulnerabilities/search',
          {
            body: {
              page,
              sort: sort[0]?.id ?? 'createdAt',
              order: sort[0]?.desc ? 'DESC' : 'ASC',
              filters: tableFilters,
              pageSize,
              groupBy
            }
          }
        );
      } catch (e) {
        console.error(e);
        return;
      }
    },
    [apiPost, currentOrganization, showAllOrganizations]
  );

  const fetchVulnerabilities = useCallback(
    async (query: Query<Vulnerability>) => {
      const resp = await vulnerabilitiesSearch({
        filters: query.filters,
        sort: query.sort,
        page: query.page,
        groupBy
      });
      if (!resp) return;
      const { result, count } = resp;
      setVulnerabilities(result);
      setTotalResults(count);
      setNoResults(count === 0);
    },
    [vulnerabilitiesSearch, groupBy]
  );

  const fetchVulnerabilitiesExport = async (): Promise<string> => {
    const { sortBy, filters } = tableRef.current?.state ?? {};
    const { url } = (await vulnerabilitiesSearch({
      filters: filters!,
      sort: sortBy!,
      page: 1,
      pageSize: -1,
      doExport: true
    })) as ApiResponse;
    return url!;
  };

  const renderPagination = (table: TableInstance<Vulnerability>) => (
    <Paginator
      table={table}
      totalResults={totalResults}
      export={{
        name: 'vulnerabilities',
        getDataToExport: fetchVulnerabilitiesExport
      }}
    />
  );

  const initialFilterBy: Filters<Vulnerability> = [];
  let initialSortBy: SortingRule<Vulnerability>[] = [];
  const params = parse(window.location.search);
  if (!('state' in params)) params['state'] = 'open';
  for (const param of Object.keys(params)) {
    if (param === 'sort') {
      initialSortBy = [
        {
          id: params[param] as string,
          desc: 'desc' in params ? params['desc'] === 'true' : true
        }
      ];
    } else if (param !== 'desc') {
      initialFilterBy.push({
        id: param,
        value: params[param] as string
      });
    }
  }

  return (
    <div>
      <div className={listClasses.contentWrapper}>
        <Subnav
          items={[
            { title: 'Search Results', path: '/inventory', exact: true },
            { title: 'All Domains', path: '/inventory/domains' },
            { title: 'All Vulnerabilities', path: '/inventory/vulnerabilities' }
          ]}
        ></Subnav>
        <br></br>
        <div className={classes.root}>
          <Table<Vulnerability>
            renderPagination={renderPagination}
            columns={groupBy ? groupedColumns : columns}
            data={vulnerabilities}
            pageCount={Math.ceil(totalResults / PAGE_SIZE)}
            fetchData={fetchVulnerabilities}
            tableRef={tableRef}
            initialFilterBy={initialFilterBy}
            initialSortBy={initialSortBy}
            noResults={noResults}
            pageSize={PAGE_SIZE}
            noResultsMessage={
              "We don't see any vulnerabilities that match your criteria."
            }
          />
        </div>
      </div>
    </div>
  );
}