parent
							
								
									b01ed166be
								
							
						
					
					
						commit
						5c25f23082
					
				@ -1,7 +1,6 @@
 | 
			
		||||
import React, { createContext, useContext } from 'react';
 | 
			
		||||
 | 
			
		||||
import { useRequest } from '../api-client';
 | 
			
		||||
import { useAppSpin } from '../application/hooks/useAppSpin';
 | 
			
		||||
 | 
			
		||||
export const CurrentAppInfoContext = createContext(null);
 | 
			
		||||
CurrentAppInfoContext.displayName = 'CurrentAppInfoContext';
 | 
			
		||||
@ -18,12 +17,11 @@ export const useCurrentAppInfo = () => {
 | 
			
		||||
  }>(CurrentAppInfoContext);
 | 
			
		||||
};
 | 
			
		||||
export const CurrentAppInfoProvider = (props) => {
 | 
			
		||||
  const { render } = useAppSpin();
 | 
			
		||||
  const result = useRequest({
 | 
			
		||||
    url: 'app:getInfo',
 | 
			
		||||
  });
 | 
			
		||||
  if (result.loading) {
 | 
			
		||||
    return render();
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  return <CurrentAppInfoContext.Provider value={result.data}>{props.children}</CurrentAppInfoContext.Provider>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,11 @@
 | 
			
		||||
import { render, sleep, screen, waitFor } from '@tachybase/test/client';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { render, screen, sleep, waitFor } from '@tachybase/test/client';
 | 
			
		||||
 | 
			
		||||
import { describe } from 'vitest';
 | 
			
		||||
 | 
			
		||||
import { Application } from '../Application';
 | 
			
		||||
import { useApp, usePlugin, useRouter } from '../hooks';
 | 
			
		||||
import { Plugin } from '../Plugin';
 | 
			
		||||
import { useApp, usePlugin, useRouter, useAppSpin } from '../hooks';
 | 
			
		||||
 | 
			
		||||
describe('Application Hooks', () => {
 | 
			
		||||
  describe('useApp()', () => {
 | 
			
		||||
@ -59,37 +61,4 @@ describe('Application Hooks', () => {
 | 
			
		||||
      await sleep(10);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('useAppSpin()', () => {
 | 
			
		||||
    test('no app, should render ant-design Spin', async () => {
 | 
			
		||||
      const Demo = () => {
 | 
			
		||||
        const spin = useAppSpin();
 | 
			
		||||
        return spin.render();
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      render(<Demo />);
 | 
			
		||||
 | 
			
		||||
      await waitFor(() => {
 | 
			
		||||
        expect(document.querySelector('.ant-spin')).toBeTruthy();
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    test('has app, should render AppSpin Component', () => {
 | 
			
		||||
      const Demo = () => {
 | 
			
		||||
        const spin = useAppSpin();
 | 
			
		||||
        return spin.render();
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      const app = new Application({
 | 
			
		||||
        providers: [Demo],
 | 
			
		||||
        components: {
 | 
			
		||||
          AppSpin: () => <div data-testid="content">test</div>,
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
      const Root = app.getRootComponent();
 | 
			
		||||
      render(<Root></Root>);
 | 
			
		||||
      expect(document.querySelector('.ant-spin')).toBeFalsy();
 | 
			
		||||
      expect(screen.getByTestId('content')).toBeTruthy();
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
import React, { FC } from 'react';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
import { MainComponent } from './MainComponent';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
export * from './useApp';
 | 
			
		||||
export * from './usePlugin';
 | 
			
		||||
export * from './useRouter';
 | 
			
		||||
export * from './useAppSpin';
 | 
			
		||||
 | 
			
		||||
@ -1,12 +0,0 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
import { Spin } from 'antd';
 | 
			
		||||
 | 
			
		||||
import { useApp } from './useApp';
 | 
			
		||||
 | 
			
		||||
export const useAppSpin = () => {
 | 
			
		||||
  const app = useApp();
 | 
			
		||||
  return {
 | 
			
		||||
    render: () => (app?.renderComponent ? app?.renderComponent?.('AppSpin') : React.createElement(Spin)),
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
@ -6,7 +6,6 @@ import { Navigate } from 'react-router-dom';
 | 
			
		||||
 | 
			
		||||
import { useAPIClient, useRequest } from '../../api-client';
 | 
			
		||||
import { useApp } from '../../application';
 | 
			
		||||
import { useAppSpin } from '../../application/hooks/useAppSpin';
 | 
			
		||||
import { useBlockRequestContext } from '../../block-provider/BlockProvider';
 | 
			
		||||
import { useCollection_deprecated, useCollectionManager_deprecated } from '../../collection-manager';
 | 
			
		||||
import { useResourceActionContext } from '../../collection-manager/ResourceActionProvider';
 | 
			
		||||
@ -38,7 +37,6 @@ const getRouteUrl = (props) => {
 | 
			
		||||
export const ACLRolesCheckProvider = (props) => {
 | 
			
		||||
  const route = getRouteUrl(props.children.props);
 | 
			
		||||
  const { setDesignable } = useDesignable();
 | 
			
		||||
  const { render } = useAppSpin();
 | 
			
		||||
  const api = useAPIClient();
 | 
			
		||||
  const app = useApp();
 | 
			
		||||
  const result = useRequest<{
 | 
			
		||||
@ -68,7 +66,7 @@ export const ACLRolesCheckProvider = (props) => {
 | 
			
		||||
    },
 | 
			
		||||
  );
 | 
			
		||||
  if (result.loading) {
 | 
			
		||||
    return render();
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  if (result.error) {
 | 
			
		||||
    return <Navigate replace to={'/signin'} />;
 | 
			
		||||
 | 
			
		||||
@ -22,7 +22,6 @@ import {
 | 
			
		||||
  useRequest,
 | 
			
		||||
  useSystemSettings,
 | 
			
		||||
} from '../..';
 | 
			
		||||
import { useAppSpin } from '../../application/hooks/useAppSpin';
 | 
			
		||||
import { Plugin } from '../../application/Plugin';
 | 
			
		||||
import { VariablesProvider } from '../../variables';
 | 
			
		||||
 | 
			
		||||
@ -202,7 +201,6 @@ const MenuEditor = (props) => {
 | 
			
		||||
    setCurrent(schema);
 | 
			
		||||
    navigate(`/admin/${schema['x-uid']}`);
 | 
			
		||||
  };
 | 
			
		||||
  const { render } = useAppSpin();
 | 
			
		||||
  const adminSchemaUid = useAdminSchemaUid();
 | 
			
		||||
  const { data, loading } = useRequest<{
 | 
			
		||||
    data: any;
 | 
			
		||||
@ -320,7 +318,7 @@ const MenuEditor = (props) => {
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  if (loading) {
 | 
			
		||||
    return render();
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaIdContext.Provider value={defaultSelectedUid}>
 | 
			
		||||
 | 
			
		||||
@ -36,8 +36,18 @@ interface AppStatusProps {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const AppSpin = () => {
 | 
			
		||||
  // TODO: better loading and mobile loading fix
 | 
			
		||||
  return (
 | 
			
		||||
    <Spin style={{ position: 'fixed', top: '50%', left: '50%', fontSize: 72, transform: 'translate(-50%, -50%)' }} />
 | 
			
		||||
    <Spin
 | 
			
		||||
      size="large"
 | 
			
		||||
      style={{
 | 
			
		||||
        position: 'fixed',
 | 
			
		||||
        top: '50%',
 | 
			
		||||
        left: '50%',
 | 
			
		||||
        fontSize: 72 * (window.devicePixelRatio || 1),
 | 
			
		||||
        transform: 'translate(-50%, -50%)',
 | 
			
		||||
      }}
 | 
			
		||||
    />
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,6 @@ import React, { createContext, ReactNode, useContext } from 'react';
 | 
			
		||||
import { Result } from 'ahooks/es/useRequest/src/types';
 | 
			
		||||
 | 
			
		||||
import { useRequest } from '../../api-client';
 | 
			
		||||
import { useAppSpin } from '../../application/hooks/useAppSpin';
 | 
			
		||||
 | 
			
		||||
export const SystemSettingsContext = createContext<Result<any, any>>(null);
 | 
			
		||||
SystemSettingsContext.displayName = 'SystemSettingsContext';
 | 
			
		||||
@ -13,12 +12,11 @@ export const useSystemSettings = () => {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const SystemSettingsProvider: React.FC<{ children?: ReactNode }> = (props) => {
 | 
			
		||||
  const { render } = useAppSpin();
 | 
			
		||||
  const result = useRequest({
 | 
			
		||||
    url: 'systemSettings:get/1?appends=logo',
 | 
			
		||||
  });
 | 
			
		||||
  if (result.loading) {
 | 
			
		||||
    return render();
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return <SystemSettingsContext.Provider value={result}>{props.children}</SystemSettingsContext.Provider>;
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,6 @@ import React, { createContext, useContext, useEffect } from 'react';
 | 
			
		||||
import { useLocation } from 'react-router-dom';
 | 
			
		||||
 | 
			
		||||
import { useAPIClient, useRequest } from '../api-client';
 | 
			
		||||
import { useAppSpin } from '../application/hooks/useAppSpin';
 | 
			
		||||
 | 
			
		||||
export interface CollectionHistoryContextValue {
 | 
			
		||||
  historyCollections: any[];
 | 
			
		||||
@ -42,7 +41,6 @@ export const CollectionHistoryProvider = (props) => {
 | 
			
		||||
 | 
			
		||||
  const isAdminPage = location.pathname.startsWith('/admin');
 | 
			
		||||
  const token = api.auth.getToken() || '';
 | 
			
		||||
  const { render } = useAppSpin();
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    if (isAdminPage && token) {
 | 
			
		||||
@ -58,7 +56,7 @@ export const CollectionHistoryProvider = (props) => {
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  if (service.loading) {
 | 
			
		||||
    return render();
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,12 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
import { useAPIClient, useRequest } from '../api-client';
 | 
			
		||||
import { CollectionManagerSchemaComponentProvider } from './CollectionManagerSchemaComponentProvider';
 | 
			
		||||
import { CollectionCategroriesContext } from './context';
 | 
			
		||||
import { CollectionManagerOptions } from './types';
 | 
			
		||||
import { CollectionManagerProvider } from '../data-source/collection/CollectionManagerProvider';
 | 
			
		||||
import { useDataSourceManager } from '../data-source/data-source/DataSourceManagerProvider';
 | 
			
		||||
import { useCollectionHistory } from './CollectionHistoryProvider';
 | 
			
		||||
import { useAppSpin } from '../application/hooks/useAppSpin';
 | 
			
		||||
import { CollectionManagerSchemaComponentProvider } from './CollectionManagerSchemaComponentProvider';
 | 
			
		||||
import { CollectionCategroriesContext } from './context';
 | 
			
		||||
import { CollectionManagerOptions } from './types';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @deprecated use `CollectionManagerProvider` instead
 | 
			
		||||
@ -40,9 +40,8 @@ export const RemoteCollectionManagerProvider = (props: any) => {
 | 
			
		||||
    data: any;
 | 
			
		||||
  }>(coptions);
 | 
			
		||||
 | 
			
		||||
  const { render } = useAppSpin();
 | 
			
		||||
  if (service.loading) {
 | 
			
		||||
    return render();
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const refreshCategory = async () => {
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,6 @@ import { useSearchParams } from 'react-router-dom';
 | 
			
		||||
 | 
			
		||||
import { FormDialog } from '..';
 | 
			
		||||
import { useToken } from '../__builtins__';
 | 
			
		||||
import { useAppSpin } from '../../../application/hooks/useAppSpin';
 | 
			
		||||
import { useStyles as useAClStyles } from '../../../built-in/acl/style';
 | 
			
		||||
import { useDocumentTitle } from '../../../built-in/document-title';
 | 
			
		||||
import { FilterBlockProvider } from '../../../filter-provider/FilterProvider';
 | 
			
		||||
@ -202,10 +201,9 @@ function PageContent(
 | 
			
		||||
  props: any,
 | 
			
		||||
): React.ReactNode {
 | 
			
		||||
  const { token } = useToken();
 | 
			
		||||
  const { render } = useAppSpin();
 | 
			
		||||
 | 
			
		||||
  if (loading) {
 | 
			
		||||
    return render();
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return !disablePageHeader && enablePageTabs ? (
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,6 @@ import React, { createContext, useContext, useMemo } from 'react';
 | 
			
		||||
import { Navigate, useLocation } from 'react-router-dom';
 | 
			
		||||
 | 
			
		||||
import { ReturnTypeOfUseRequest, useRequest } from '../api-client';
 | 
			
		||||
import { useAppSpin } from '../application/hooks/useAppSpin';
 | 
			
		||||
import { useACLRoleContext } from '../built-in/acl';
 | 
			
		||||
import { useCompile } from '../schema-component';
 | 
			
		||||
 | 
			
		||||
@ -33,13 +32,12 @@ export const useCurrentRoles = () => {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const CurrentUserProvider = (props) => {
 | 
			
		||||
  const { render } = useAppSpin();
 | 
			
		||||
  const result = useRequest<any>({
 | 
			
		||||
    url: 'auth:check',
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  if (result.loading) {
 | 
			
		||||
    return render();
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return <CurrentUserContext.Provider value={result}>{props.children}</CurrentUserContext.Provider>;
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { useAppSpin, useRequest } from '@tachybase/client';
 | 
			
		||||
import { useRequest } from '@tachybase/client';
 | 
			
		||||
 | 
			
		||||
import { Carousel, Image } from 'antd';
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,6 @@ import { useStyles } from './style';
 | 
			
		||||
 | 
			
		||||
export const HomePage: React.FC<{}> = () => {
 | 
			
		||||
  const { styles } = useStyles();
 | 
			
		||||
  const { render } = useAppSpin();
 | 
			
		||||
  const { data, loading } = useRequest<{ data: any }>({
 | 
			
		||||
    url: 'home_page_presentations:list',
 | 
			
		||||
    params: {
 | 
			
		||||
@ -16,7 +15,7 @@ export const HomePage: React.FC<{}> = () => {
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  if (loading) {
 | 
			
		||||
    return render();
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  const date = new Date();
 | 
			
		||||
  const year = date.getFullYear();
 | 
			
		||||
 | 
			
		||||
@ -2,11 +2,7 @@ import React from 'react';
 | 
			
		||||
import { CurrentAppInfoProvider, SchemaComponentOptions } from '@tachybase/client';
 | 
			
		||||
 | 
			
		||||
export const DuplicatorProvider = function (props) {
 | 
			
		||||
  return (
 | 
			
		||||
    <CurrentAppInfoProvider>
 | 
			
		||||
      <SchemaComponentOptions>{props.children}</SchemaComponentOptions>
 | 
			
		||||
    </CurrentAppInfoProvider>
 | 
			
		||||
  );
 | 
			
		||||
  return <SchemaComponentOptions>{props.children}</SchemaComponentOptions>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
DuplicatorProvider.displayName = 'DuplicatorProvider';
 | 
			
		||||
 | 
			
		||||
@ -16,16 +16,14 @@ Gantt.Designer = GanttDesigner;
 | 
			
		||||
Gantt.Event = Event;
 | 
			
		||||
export { Gantt };
 | 
			
		||||
 | 
			
		||||
const GanttProvider = React.memo((props) => {
 | 
			
		||||
const GanttProvider = React.memo((props: { children: React.ReactNode }) => {
 | 
			
		||||
  return (
 | 
			
		||||
    <CurrentAppInfoProvider>
 | 
			
		||||
      <SchemaComponentOptions
 | 
			
		||||
        components={{ Gantt, GanttBlockInitializer, GanttBlockProvider }}
 | 
			
		||||
        scope={{ useGanttBlockProps }}
 | 
			
		||||
      >
 | 
			
		||||
        {props.children}
 | 
			
		||||
      </SchemaComponentOptions>
 | 
			
		||||
    </CurrentAppInfoProvider>
 | 
			
		||||
    <SchemaComponentOptions
 | 
			
		||||
      components={{ Gantt, GanttBlockInitializer, GanttBlockProvider }}
 | 
			
		||||
      scope={{ useGanttBlockProps }}
 | 
			
		||||
    >
 | 
			
		||||
      {props.children}
 | 
			
		||||
    </SchemaComponentOptions>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -19,16 +19,14 @@ Kanban.Designer = KanbanDesigner;
 | 
			
		||||
 | 
			
		||||
const KanbanV2 = Kanban;
 | 
			
		||||
 | 
			
		||||
const KanbanPluginProvider = React.memo((props) => {
 | 
			
		||||
const KanbanPluginProvider = React.memo((props: { children: React.ReactNode }) => {
 | 
			
		||||
  return (
 | 
			
		||||
    <CurrentAppInfoProvider>
 | 
			
		||||
      <SchemaComponentOptions
 | 
			
		||||
        components={{ Kanban, KanbanBlockProvider, KanbanV2, KanbanBlockInitializer }}
 | 
			
		||||
        scope={{ useKanbanBlockProps }}
 | 
			
		||||
      >
 | 
			
		||||
        {props.children}
 | 
			
		||||
      </SchemaComponentOptions>
 | 
			
		||||
    </CurrentAppInfoProvider>
 | 
			
		||||
    <SchemaComponentOptions
 | 
			
		||||
      components={{ Kanban, KanbanBlockProvider, KanbanV2, KanbanBlockInitializer }}
 | 
			
		||||
      scope={{ useKanbanBlockProps }}
 | 
			
		||||
    >
 | 
			
		||||
      {props.children}
 | 
			
		||||
    </SchemaComponentOptions>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
KanbanPluginProvider.displayName = 'KanbanPluginProvider';
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,7 @@ import { MapBlockDesigner } from './MapBlockDesigner';
 | 
			
		||||
import { MapBlockInitializer } from './MapBlockInitializer';
 | 
			
		||||
import { MapBlockProvider, useMapBlockProps } from './MapBlockProvider';
 | 
			
		||||
 | 
			
		||||
export const MapBlockOptions: React.FC = (props) => {
 | 
			
		||||
export const MapBlockOptions = (props) => {
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaComponentOptions
 | 
			
		||||
      scope={{ useMapBlockProps }}
 | 
			
		||||
 | 
			
		||||
@ -9,13 +9,11 @@ import { Configuration, Map } from './components';
 | 
			
		||||
import { fields } from './fields';
 | 
			
		||||
import { generateNTemplate, NAMESPACE } from './locale';
 | 
			
		||||
 | 
			
		||||
const MapProvider = React.memo((props) => {
 | 
			
		||||
const MapProvider = React.memo((props: { children: React.ReactNode }) => {
 | 
			
		||||
  return (
 | 
			
		||||
    <CurrentAppInfoProvider>
 | 
			
		||||
      <SchemaComponentOptions components={{ Map }}>
 | 
			
		||||
        <MapBlockOptions>{props.children}</MapBlockOptions>
 | 
			
		||||
      </SchemaComponentOptions>
 | 
			
		||||
    </CurrentAppInfoProvider>
 | 
			
		||||
    <SchemaComponentOptions components={{ Map }}>
 | 
			
		||||
      <MapBlockOptions>{props.children}</MapBlockOptions>
 | 
			
		||||
    </SchemaComponentOptions>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
MapProvider.displayName = 'MapProvider';
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,10 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { css } from '@tachybase/client';
 | 
			
		||||
import { connect, mapProps, mapReadPretty } from '@tachybase/schema';
 | 
			
		||||
 | 
			
		||||
import { Input, InputProps, TextArea, TextAreaProps } from 'antd-mobile';
 | 
			
		||||
 | 
			
		||||
type ComposedInput = React.FC<InputProps> & {
 | 
			
		||||
  TextArea?: React.FC<TextAreaProps>;
 | 
			
		||||
type ComposedInput = ((props: InputProps) => React.ReactNode) & {
 | 
			
		||||
  TextArea?: (props: TextAreaProps) => React.ReactNode;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const MInput: ComposedInput = connect(
 | 
			
		||||
@ -14,7 +13,7 @@ export const MInput: ComposedInput = connect(
 | 
			
		||||
    return { placeholder: '请输入内容', clearable: true, ...props, style: { '--font-size': '12px' } };
 | 
			
		||||
  }),
 | 
			
		||||
  mapReadPretty((props) => {
 | 
			
		||||
    return <text style={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>{props.value}</text>;
 | 
			
		||||
    return <span style={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>{props.value}</span>;
 | 
			
		||||
  }),
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user