mobx-react#inject TypeScript Examples

The following examples show how to use mobx-react#inject. 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: index.tsx    From config-generator with MIT License 6 votes vote down vote up
@inject('sourcesListStore', 'destinationsListStore')
@observer
class Destinations extends Component<IDestinationsProps> {
  public render() {
    return (
      <Container className="Destinations">
        <DestinationsCatalogue />
        <ConfiguredDestinations />
      </Container>
    );
  }
}
Example #2
Source File: banner.tsx    From config-generator with MIT License 6 votes vote down vote up
@inject(
  'messagesStore'
)

@observer
class Banner extends Component<{messagesStore?:IMessageStore}> {
  

  public render() { 
    const { messagesStore } = this.props;
    return (
    <Container move={messagesStore!.isAnimating} onAnimationEnd={() => { messagesStore!.setIsAnimating(false) }}>
              <Label color="#FF0000">
                We highly recommend signing up for RudderStack Cloud to get access to features such as Transformations, Live Events, Warehouse Syncs, and more.
            </Label>
              <Flex style={{ paddingTop: '20px' }}>
                <Button type="primary" shape="round" href="https://app.rudderstack.com"> Try Now </Button>
              </Flex>
            </Container>

    );
}
}
Example #3
Source File: MainStore.ts    From jmix-frontend with Apache License 2.0 5 votes vote down vote up
export function injectMainStore<T extends IReactComponent>(target: T): T & IWrappedComponent<T> {
  return inject(MainStore.NAME)(target);
}
Example #4
Source File: index.tsx    From config-generator with MIT License 5 votes vote down vote up
@inject('destinationDefsListStore')
@observer
export default class DestinationsCatalogue extends React.Component<
  IDestinationsCatalogueProps,
  IDestinationsCatalogueState
> {
  constructor(props: IDestinationsCatalogueProps) {
    super(props);
    this.state = {
      modalVisible: false,
      filteredDestinationDefs: [],
    };
  }
  handleCancel = () => {
    this.setState({ modalVisible: false });
  };
  onClick = (destinationDef: any) => {
    // Add a modal and open it on click.
    this.setState({ modalVisible: true, selected: destinationDef });
  };

  componentDidMount() {
    const { destinationDefsListStore } = this.props;

    if (destinationDefsListStore) {
      const destinationDefs = destinationDefsListStore!.destinationDefs;
      const destinationSettingsArr = Object.keys(formTemplatesMap);
      const filteredArr = [] as Array<object>;
      destinationDefs.map(def => {
        if (destinationSettingsArr.includes(def.name)) {
          filteredArr.push(def);
        }
      });
      this.setState({ filteredDestinationDefs: filteredArr });
    }
  }

  public render() {
    const { destinationDefsListStore } = this.props;
    const { selected, filteredDestinationDefs } = this.state;
    if (destinationDefsListStore && filteredDestinationDefs) {
      return (
        <div>
          <Drawer
            visible={this.state.modalVisible}
            onClose={this.handleCancel}
            width={'40%'}
          >
            <DestinationConfigure destinationDef={selected} />
          </Drawer>
          <Heading>
            <HeaderDiv color={theme.color.primary}>Destinations</HeaderDiv>
            <LabelMedium color={theme.color.grey300}>
              {destinationDefsListStore!.destinationDefs.filter(dest => !dest.config.preview).length}
              &nbsp;Available
            </LabelMedium>
          </Heading>
          <IconCardList
            type="destination"
            selectionMode="none"
            icons={filteredDestinationDefs.map((destinationDef: any) => ({
              id: destinationDef.id,
              type: destinationDef.name,
              title: destinationDef.displayName,
              onClick: () => this.onClick(destinationDef),
            }))}
            onSelectionChange={() => {}}
          />
        </div>
      );
    }
  }
}
Example #5
Source File: index.tsx    From config-generator with MIT License 5 votes vote down vote up
@inject(
  'messagesStore',
) 

@observer
class Sidebar extends React.Component<ISidebarProps> {

  public render() {
    const {messagesStore} = this.props;
    return (
      <Sider trigger={null} collapsible={true} collapsed={false}>
        <AvatarContainer>
          <SidebarAvatar icon="user" />
          <UserName>RUDDERSTACK</UserName>
        </AvatarContainer>
        <SidebarLinksContainer>
          <SidebarLink to="/home" exact>
            <Svg name="connection" />
            <span>Connections</span>
          </SidebarLink>
          <SidebarLink to="/sources">
            <Svg name="source" />
            <span>Sources</span>
          </SidebarLink>
          <SidebarLink to="/destinations">
            <Svg name="destination" />
            <span>Destinations</span>
          </SidebarLink>
          <Tooltip placement="right" title="Please try Ruderstack Control Plane for this feature">
            <div onClick = {()=> {if(messagesStore) { 
              messagesStore.setIsAnimating(true)}}} >
          <SidebarLink dim to="/transformation">            
            <Svg name="transformation" />
            <span>Transformations</span>
          </SidebarLink>
          </div>
          </Tooltip>
          <Tooltip placement="bottom" title="Please try Ruderstack Control Plane for this feature">
          <div onClick = {()=> {if(messagesStore) { 
              messagesStore.setIsAnimating(true)}}} >
          <SidebarLink dim to="/syncs">
            <Svg name="sync" />
            <span> Syncs </span>
          </SidebarLink>
          </div>
          </Tooltip>         
        </SidebarLinksContainer>
      </Sider>
    );
  }
}
Example #6
Source File: index.tsx    From config-generator with MIT License 5 votes vote down vote up
@inject('sourceDefinitionsListStore')
@observer
export default class SourcesCatalogue extends React.Component<
  ISourcesCatalogueProps,
  ISourcesCatalogueState
> {
  constructor(props: ISourcesCatalogueProps) {
    super(props);
    this.state = {
      modalVisible: false,
    };
  }
  handleCancel = () => {
    this.setState({ modalVisible: false });
  };
  onClick = (sourceDef: any) => {
    // Add a modal and open it on click.
    this.setState({ modalVisible: true, selected: sourceDef });
  };

  public render() {
    const { sourceDefinitionsListStore } = this.props;
    const { selected } = this.state;
    if (sourceDefinitionsListStore)
      return (
        <div>
          <Drawer
            visible={this.state.modalVisible}
            onClose={this.handleCancel}
            width={'40%'}
          >
            <SourceConfigure sourceDef={selected} />
          </Drawer>
          <Heading>
            <HeaderDiv color={theme.color.primary}>Sources</HeaderDiv>
            <LabelMedium color={theme.color.grey300}>
              {sourceDefinitionsListStore!.sourceDefinitions.length}
              &nbsp;Available
            </LabelMedium>
          </Heading>
          <IconCardList
            type="source"
            selectionMode="none"
            icons={sourceDefinitionsListStore.sourceDefinitions.map(
              sourceDef => ({
                id: sourceDef.id,
                type: sourceDef.name,
                title: sourceDef.name,
                onClick: () => this.onClick(sourceDef),
              }),
            )}
            onSelectionChange={() => {}}
          />
        </div>
      );
  }
}
Example #7
Source File: index.tsx    From generator-earth with MIT License 5 votes vote down vote up
@inject('detailsStore','commonTableStore')
@observer
class Home extends React.Component<IProps> {
    render() {
        const { setParamsStr, paramsStr, setRequestStr, requestStr, setLoading, getPage2Data } = this.props.detailsStore;
        return (
            <div>
                <CommonTableList
                    FT={FT}
                    type="get"
                    url={URL}
                    isShowLoading={true}
                    sourceId={SOURCE_ID}
                    pagination={{
                        pageNo: 1,
                        pageSize: 3
                    }}
                    commonTableStore={this.props.commonTableStore}
                />
                <h1>下面按钮展示了,进行对表格的其他自定义操作</h1>
                <ul>
                    <li>
                        <Button onClick={setParamsStr}>获取当前所有的参数列表</Button>
                        <p>{paramsStr}</p>
                    </li>
                    <li>
                        <Button onClick={setRequestStr}>获取当前请求的url和type</Button>
                        <p>{requestStr}</p>
                    </li>
                    <li>
                        <Button onClick={setLoading}>手动展示加载loading</Button>
                    </li>
                    <li>
                        <Button style={{ marginTop: 20 }} onClick={getPage2Data}>根据当前已有的参数请求第二页的数据</Button>
                    </li>
                </ul>
            </div>
        )
    }
}
Example #8
Source File: helpers.ts    From companion-kit with MIT License 5 votes vote down vote up
export function injectViewModelsMulti(inner: ViewModelInjectorMulti) {
    return inject(getViewModelMulti(inner));
}
Example #9
Source File: helpers.ts    From companion-kit with MIT License 5 votes vote down vote up
export function injectViewModel(inner: ViewModelInjector) {
    return inject(getViewModel(inner));
}
Example #10
Source File: Instance.tsx    From jmix-frontend with Apache License 2.0 5 votes vote down vote up
withDataInstance = (entityName: string, opts: DataInstanceOptions = {loadImmediately: true}) => <T extends IReactComponent>(target: T) => {
  return inject(() => {
    const dataInstance = new DataInstanceStore(entityName, opts.view, opts.stringIdName);
    return {dataInstance}
  })(target);
}
Example #11
Source File: Collection.tsx    From jmix-frontend with Apache License 2.0 5 votes vote down vote up
withDataCollection = (entityName: string, opts: DataCollectionOptions = defaultOpts) => <T extends IReactComponent>(target: T) => {
  return inject(() => {
    const dataCollection = createStore(entityName, opts);
    return {dataCollection}
  })(target);
}
Example #12
Source File: index.tsx    From config-generator with MIT License 4 votes vote down vote up
@inject('sourcesListStore', 'destinationsListStore', 'messagesStore')
@observer
class SourceDetails extends Component<IConfiguredSourcesProps, any> {
  constructor(props: IConfiguredSourcesProps) {
    super(props);
    this.state = {
      sourceId: props.match && props.match.params.id,
      stats: [],
      overview: true,
    };
  }

  public async componentDidMount() {
    await this.getStats();
  }

  public getStats = async () => {
    const { sourceId } = this.state;
  };

  public toggle = async (val: any) => {
    this.setState(val);
  };

  deleteConnection = async (
    source: ISourceStore,
    destination: IDestinationStore,
  ) => {
    const { destinationsListStore, messagesStore } = this.props;
    try {
      await destinationsListStore.rootStore.connectionsStore.removeConnections(
        source,
        destination,
      );
      messagesStore.showSuccessMessage('Connection deletion successful');
    } catch (error) {
      messagesStore.showErrorMessage('Failed to delete connection');
    }
  };

  deleteSource = async (source: ISourceStore) => {
    const { sourcesListStore, messagesStore } = this.props;
    try {
      const isSuccess = await sourcesListStore.deleteSource(source);
      if (!isSuccess) {
        throw Error('error deleting source');
      }
      messagesStore.showSuccessMessage('Source deletion successful');
      this.props.history.push(`/home`);
    } catch (error) {
      messagesStore.showErrorMessage('Failed to delete source');
    }
  };

  public renderOverView = () => {
    const { sourceId, stats, overview } = this.state;
    const { sourcesListStore } = this.props;
    const { sources } = sourcesListStore;
    const source = sources.find(source => source.id === sourceId);
    if (source) {
      return (
        <>
          <div className={'m-b-lg'}>
            <SourceView source={source} deleteSource={this.deleteSource} />
          </div>
          <div className={'m-b-lg'}>
            <DestinationView
              destinations={source!.destinations}
              sourceId={source!.id}
              source={source}
              deleteConnection={this.deleteConnection}
            />
          </div>
        </>
      );
    }
    return null;
  };

  handleExportSourceConfig = () => {
    const { sourceId } = this.state;
    const { sourcesListStore } = this.props;
    const { sources } = sourcesListStore;
    const source = sources.find(source => source.id === sourceId);
    if (source) {
      const sourceConfig = {
        source: {
          config: source.config,
          id: source.id,
          name: source.name,
          writeKey: source.writeKey,
          enabled: source.enabled,
          sourceDefinitionId: source.sourceDefinitionId,
          deleted: false,
          createdAt: Date(),
          updatedAt: Date(),
          sourceDefinition: source.sourceDef,
          // Filter only useNativeSDK enabled destinations and
          // includes only includeKeys (from definition) in the config
          destinations: source.destinations
            .filter(dest => {
              return dest.config ? dest.config.useNativeSDK : false;
            })
            .map(dest => {
              return {
                id: dest.id,
                name: dest.name,
                enabled: dest.enabled,
                config: dest.filteredConfig(), // Very Very Important to use filterConfig instead of config
                destinationDefinition: dest.destinationDefinition,
              };
            }),
        },
        metadata: {
          version: version,
        },
      };
      fileDownload(
        JSON.stringify(sourceConfig, null, 2),
        `${source.name}_Source_Config.json`,
      );
    }
  };

  public render() {
    const { sourceId, stats, overview } = this.state;
    const { sourcesListStore } = this.props;
    const { sources } = sourcesListStore;
    const source = sources.find(source => source.id === sourceId);
    return (
      <Container>
        <Flex flexDirection="row" spaceBetween={true}>
          <PageTitle>Source {overview ? 'Details' : 'Debugger'}</PageTitle>
          <div style={{ width: '260px' }}>
            <ButtonSmall pink onClick={this.handleExportSourceConfig}>
              Export Source config
            </ButtonSmall>
          </div>
        </Flex>
        <Flex flexDirection="column">{this.renderOverView()}</Flex>
      </Container>
    );
  }
}
Example #13
Source File: index.tsx    From config-generator with MIT License 4 votes vote down vote up
@inject('sourceDefinitionsListStore')
@observer
export default class SourceCard extends React.Component<
  ISourceCardProps,
  ISourceCardState
> {
  constructor(props: ISourceCardProps) {
    super(props);

    this.state = {
      copied: false,
    };
  }

  onMouseEnter = () => {
    this.props.onMouseEnter!(this.props.source);
  };

  onMouseLeave = () => {
    this.props.onMouseLeave!(this.props.source);
  };

  copyText = (event: any) => {
    const { source } = this.props;
    event.preventDefault();
    navigator.clipboard.writeText(source!.writeKey);
    this.setState({ copied: true });
    setTimeout(() => {
      this.setState({ copied: false });
    }, 1000);
  };

  deleteSource = (e: any) => {
    e.preventDefault();
    this.props.onDelete!(this.props.source);
  };

  public render() {
    const { source } = this.props;
    const { copied } = this.state;
    if (source === null) {
      return <EmptySourceCard />;
    } else {
      return (
        <Link to={`/sources/${source.id}`}>
          <StyledCard
            id={`source-${source.id}`}
            onMouseEnter={this.onMouseEnter}
            onMouseLeave={this.onMouseLeave}
          >
            <div style={{ flexShrink: 0 }}>
              <SourceIcon
                source={source.sourceDef.name}
                height={theme.iconSize.large}
                width={theme.iconSize.large}
              />
            </div>
            <Content>
              <Flex flexDirection="row" spaceBetween>
                <LabelDiv>{source.name}</LabelDiv>
              </Flex>
              {source.enabled && (
                <Flex flexDirection="row" spaceBetween>
                  <div>
                    <Check />
                    <EnabledText color={theme.color.green}>Enabled</EnabledText>
                  </div>
                  {copied ? (
                    <Text color={theme.color.grey300}>Write key copied</Text>
                  ) : null}
                </Flex>
              )}
              {!source.enabled && (
                <>
                  <Text color={theme.color.grey300}>Disabled</Text>
                </>
              )}
              <Flex
                spaceBetween
                className="m-h-sm"
                onClick={this.copyText}
                title="click to copy"
                style={{ minWidth: '300px' }}
              >
                <Text color={theme.color.grey300}>
                  Write key {source.writeKey}
                </Text>
                <div className="p-l-xs">
                  <Icon type="copy" style={{ color: theme.color.grey300 }} />
                </div>
              </Flex>
            </Content>
            <Flex
              flexDirection="row"
              alignItems="flex-end"
              style={{
                width: '1px',
                paddingRight: '35px',
                backgroundColor: 'red',
              }}
              id={`fake-source-${source!.id}`}
            />
          </StyledCard>
        </Link>
      );
    }
  }
}
Example #14
Source File: addSource.tsx    From config-generator with MIT License 4 votes vote down vote up
@inject(
  'sourceDefinitionsListStore',
  'sourcesListStore',
  'destinationsListStore',
  'messagesStore',
)
@observer
class AddSource extends React.Component<IAddSourceProps, any> {
  constructor(props: IAddSourceProps) {
    super(props);
    const parsed = queryString.parse(this.props.location.search);
    this.state = {
      ref: (props.match && props.match.params.id) || null,
      currentStep: parsed.sourceDefId ? 1 : 0,
      enableNextButton: false,
      sourceName: '',
      selectedSourceDefintionId: parsed.sourceDefId || null,
      showNextLoader: false,
      filteredSources: [],
    };
  }

  public handleCancel = (event: React.MouseEvent<HTMLElement>) => {
    if (this.props.history.length > 2) {
      this.props.history.goBack();
    } else {
      this.props.history.push('/');
    }
  };

  async componentDidMount() {
    const filteredSources = await this.props.sourceDefinitionsListStore.getFilteredSourceDefinitions();
    this.setState({ filteredSources });
  }

  createConnection = async (source: any) => {
    const { ref } = this.state;
    const { destinationsListStore } = this.props;

    if (ref != null) {
      const destination = destinationsListStore.destinations.find(
        dest => dest.id === ref,
      );
      await destinationsListStore.createDestinationConnections(destination, [
        source.id,
      ]);
    }
  };

  public handleNext = async (event?: React.MouseEvent<HTMLElement>) => {
    try {
      if (this.state.currentStep === 1) {
        this.setState({ showNextLoader: true });
        const source = await this.props.sourcesListStore.createSource({
          name: this.state.sourceName,
          sourceDefinitionId: this.state.selectedSourceDefintionId,
        });
        this.props.messagesStore.showSuccessMessage('Added source');
        if (this.state.ref != null) {
          this.createConnection(source);
          this.props.history.push(`/destinations/${this.state.ref}`);
        } else {
          this.props.history.push(`/sources/${source.id}`);
        }
      } else {
        this.setState({
          currentStep: this.state.currentStep + 1,
          enableNextButton: false,
        });
      }
    } catch (error) {
      this.setState({ showNextLoader: false });
      this.props.messagesStore.showErrorMessage(
        'Failed to add source. Try again after sometime',
      );
      //throw Error(error); // ToDo how will bugsnag error-boundry know of this?
    }
  };

  public handleSelection = (selectedMap: any) => {
    const sourceDefId = Object.keys(selectedMap)[0];
    if (selectedMap[sourceDefId]) {
      this.setState({
        enableNextButton: true,
        selectedSourceDefintionId: sourceDefId,
      });
    } else {
      this.setState({
        enableNextButton: false,
        selectedSourceDefintionId: null,
      });
    }
  };

  public handleNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    let enableNextButton = event.target.value.length > 0;
    this.setState({ sourceName: event.target.value, enableNextButton });
  };

  public handleKeyDown = (e: any) => {
    if (e.key === 'Enter' && this.state.enableNextButton) {
      this.handleNext();
    }
  };

  public render() {
    const { filteredSources } = this.state;
    if (filteredSources.length > 0) {
      return (
        <StyledContainer>
          <HeaderDiv className="p-b-lg">Add Source</HeaderDiv>
          <Steps
            onCancel={this.handleCancel}
            onNext={this.handleNext}
            current={this.state.currentStep}
            enableNext={this.state.enableNextButton}
            showNextLoader={this.state.showNextLoader}
          >
            <Step>
              <HeaderDiv className="text-center p-t-lg">
                Choose a source
              </HeaderDiv>
              <IconCardListContainer>
                <IconCardList
                  type="source"
                  selectionMode="single"
                  icons={filteredSources.map((s: any) => ({
                    id: s.id,
                    type: s.name,
                    title: s.name,
                  }))}
                  onSelectionChange={this.handleSelection}
                />
              </IconCardListContainer>
            </Step>
            <Step>
              <HeaderDiv className="text-center p-t-lg">
                Name your source
              </HeaderDiv>
              <SourceNameInputContainer>
                <Input
                  placeholder="eg. Android Dev"
                  onChange={this.handleNameChange}
                  autoFocus
                  onKeyDown={this.handleKeyDown}
                />
                <TextDiv
                  color={this.props.theme.color.grey300}
                  className="p-t-sm"
                >
                  Identifies this source within your workspace, and typically
                  includes the product area and environment.
                </TextDiv>
              </SourceNameInputContainer>
            </Step>
          </Steps>
        </StyledContainer>
      );
    } else {
      return <div></div>;
    }
  }
}
Example #15
Source File: home.tsx    From config-generator with MIT License 4 votes vote down vote up
@inject(
  'sourcesListStore',
  'destinationsListStore',
  'connectionsStore',
  'sourceDefinitionsListStore',
  'destinationDefsListStore',
  'messagesStore',
)
@observer
class Home extends Component<IHomeProps> {
  public async componentDidMount() {
    const {
      sourcesListStore,
      destinationsListStore,
      connectionsStore,
      sourceDefinitionsListStore,
      destinationDefsListStore,
    } = this.props;
    sourcesListStore.loadAndSave();
    destinationsListStore.loadAndSave();
    connectionsStore.loadAndSave();
    await Promise.all([
      sourceDefinitionsListStore.getSourceDefinitions(),
      destinationDefsListStore.getDestinationDefs(),
    ]);
  }

  public isReadyToRender() {
    return (
      this.props.sourceDefinitionsListStore.sourceDefinitions.length > 0 &&
      this.props.destinationDefsListStore.destinationDefs.length > 0
    );
  }

  handleClose(type: string) {
    const { messagesStore } = this.props;
    if (type == 'error') {
      messagesStore.setError(false);
    }
    if (type === 'success') {
      messagesStore.setSuccess(false);
    }
  }

  getAlertContainer(messagesStore: MessagesStore) {
    if (messagesStore.isError) {
      return (
        <StyledNotification>
          <Alert
            message={messagesStore.infoString}
            type="error"
            showIcon
            closable
            afterClose={() => this.handleClose('error')}
          />
        </StyledNotification>
      );
    }
    if (messagesStore.isSuccess) {
      return (
        <StyledNotification>
          <Alert
            message={messagesStore.infoString}
            type="success"
            showIcon
            closable
            afterClose={() => this.handleClose('success')}
          />
        </StyledNotification>
      );
    }
    return null;
  }

  public renderError(messagesStore: IMessageStore) {
    if (messagesStore.isError) {
      message.error(messagesStore.infoString);
    }
    if (messagesStore.isSuccess) {
      message.success(messagesStore.infoString);
    }
  }
  public renderLayout() {
    if (this.isReadyToRender()) {
      return <RenderLayout></RenderLayout>;
    } else {
      return (
        <Layout>
          <Skeleton active />
        </Layout>
      );
    }
  }

  public render() {
    const { messagesStore } = this.props;
    return (
      <Router>
        <Layout style={{ minHeight: '100vh' }}>
          <Sidebar />
          <Layout>
            <Banner/>
            {this.getAlertContainer(messagesStore)}
            {this.renderLayout()}
          </Layout>
        </Layout>
      </Router>
    );
  }
}
Example #16
Source File: index.tsx    From config-generator with MIT License 4 votes vote down vote up
@inject('destinationsListStore', 'messagesStore')
@observer
class DestinationsList extends React.Component<
  IDestinationsListProps,
  IDestinationsListState
> {
  linesMap: any;

  constructor(props: IDestinationsListProps) {
    super(props);

    this.state = {};
    this.linesMap = props.linesMap;
  }

  onMouseEnter = (destination: any) => {
    Object.keys(this.linesMap).forEach(key => {
      let destId = key.split('-')[1];
      if (destId == destination.id) {
        this.linesMap[key].setOptions({
          color: this.props.theme.color.primary,
        });
      } else {
        this.linesMap[key].setOptions({
          size: 0.01,
        });
      }
    });
  };

  onMouseLeave = (destination: any) => {
    Object.values(this.linesMap).forEach((line: any) => {
      line.setOptions({
        color: this.props.theme.color.grey100,
        size: 4,
      });
    });
  };

  deleteDestination = (destination: IDestinationStore) => {
    const { destinationsListStore, messagesStore } = this.props;
    try {
      destinationsListStore!.deleteDestination(destination);
      messagesStore!.showSuccessMessage('Delete destination successful');
    } catch (error) {
      messagesStore!.showErrorMessage('Destination deletion failed');
    }
  };

  public render() {
    const { destinationsListStore } = this.props;
    const destinations =
      destinationsListStore && destinationsListStore.destinations;
    return (
      <Container style={{ zIndex: 1 }}>
        <Header color={theme.color.grey300} className="m-b-md">
          Destinations
        </Header>
        {!destinations || destinations.length === 0 ? (
          <div className="p-t-md">
            <DestinationCard destination={null} key={undefined} />
          </div>
        ) : (
          <div className="p-t-md">
            {destinations.map(destination => (
              <DestinationCard
                destination={destination}
                key={destination.name}
                onMouseEnter={this.onMouseEnter}
                onMouseLeave={this.onMouseLeave}
                onDelete={this.deleteDestination}
              />
            ))}
            <Link to="/destinations/setup" className="d-block p-t-sm">
              <Plus />
              <ButtonText>ADD DESTINATION</ButtonText>
            </Link>
          </div>
        )}
      </Container>
    );
  }
}
Example #17
Source File: index.tsx    From config-generator with MIT License 4 votes vote down vote up
@inject('sourcesListStore')
@observer
class SourcesList extends React.Component<ISourcesListProps> {
  linesMap: any;

  constructor(props: ISourcesListProps) {
    super(props);
    this.state = {};
  }

  componentDidMount() {
    this.linesMap = this.props.linesMap;
  }

  /* componentWillUnmount() {
    this.removeDestConnectionLines();
  } */

  componentDidUpdate() {
    this.linesMap = this.props.linesMap;
  }

  /* drawDestConnectionLines = () => {
    let existingCombos = Object.keys(this.linesMap);
    let combos: string[] = [];
    this.props.sourcesListStore!.sources.forEach(source => {
      source.destinations.forEach(dest => {
        if (dest.state != 'deleting') {
          combos.push(`${source.id}-${dest.id}`);
        }
      });
    });
    existingCombos.forEach(c => {
      if (!combos.includes(c)) {
        this.linesMap[c].remove();
        delete this.linesMap[c];
      }
    });
    combos.forEach(c => {
      if (!existingCombos.includes(c)) {
        let line = new LeaderLine(
          document.getElementById(`fake-source-${c.split('-')[0]}`),
          document.getElementById(`fake-destination-${c.split('-')[1]}`),
          { endPlug: 'behind', color: this.props.theme.color.grey100, size: 4 },
        );
        this.linesMap[c] = line;
      }
    });
  };

  removeDestConnectionLines = () => {
    Object.values(this.linesMap).forEach((l: any) => l.remove());
    this.linesMap = {};
  }; */

  onMouseEnter = (source: any) => {
    Object.keys(this.linesMap).forEach(key => {
      if (key.startsWith(source.id)) {
        this.linesMap[key].setOptions({
          color: this.props.theme.color.primary,
        });
      } else {
        this.linesMap[key].setOptions({
          size: 0.01,
        });
      }
    });
  };

  onMouseLeave = (source: any) => {
    Object.values(this.linesMap).forEach((line: any) => {
      line.setOptions({
        color: this.props.theme.color.grey100,
        size: 4,
      });
    });
  };

  deleteSource = (source: ISourceStore) => {
    // useful logs
    // console.log('source is to be deleted');
    // console.log(source.name);
    const { sourcesListStore } = this.props;
    sourcesListStore!.deleteSource(source);
  };

  public render() {
    const { sourcesListStore } = this.props;
    const sources = sourcesListStore && sourcesListStore.sources;
    return (
      <Container id="sources-list" style={{ zIndex: 1 }}>
        <Header color={theme.color.grey300} className="m-b-md">
          Sources
        </Header>
        {!sources || sources.length === 0 ? (
          <div className="p-t-md">
            <SourceCard source={null} key={undefined} />
          </div>
        ) : (
          <div className="p-t-md">
            {sources.map(source => (
              <SourceCard
                source={source}
                key={source.name}
                onDelete={this.deleteSource}
                onMouseEnter={this.onMouseEnter}
                onMouseLeave={this.onMouseLeave}
              />
            ))}
            <Link to="/sources/setup" className="d-block p-t-sm">
              <Plus />
              <ButtonText> ADD SOURCE</ButtonText>
            </Link>
          </div>
        )}
      </Container>
    );
  }
}
Example #18
Source File: index.tsx    From config-generator with MIT License 4 votes vote down vote up
@inject('sourcesListStore', 'destinationsListStore', 'messagesStore')
@observer
class DestinationDetails extends Component<IConfiguredDestinationsProps, any> {
  constructor(props: IConfiguredDestinationsProps) {
    super(props);
    this.state = {
      destinationId: props.match && props.match.params.id,
    };
  }

  deleteConnection = async (
    source: ISourceStore,
    destination: IDestinationStore,
  ) => {
    const { destinationsListStore, messagesStore } = this.props;
    try {
      await destinationsListStore.rootStore.connectionsStore.removeConnections(
        source,
        destination,
      );
      messagesStore.showSuccessMessage('Connection deletion successful');
    } catch (error) {
      messagesStore.showErrorMessage('Failed to delete connection');
    }
  };

  deleteDestination = async (destination: IDestinationStore) => {
    const { destinationsListStore, messagesStore } = this.props;
    try {
      const isSuccess = await destinationsListStore.deleteDestination(
        destination,
      );
      console.log('isSuccess', isSuccess);
      if (!isSuccess) {
        throw Error('not successful');
      }
      messagesStore.showSuccessMessage('Delete destination successful');
      this.props.history.push(`/home`);
    } catch (error) {
      messagesStore.showErrorMessage('Failed to delete destination');
    }
  };

  public render() {
    const { destinationId } = this.state;
    const { destinationsListStore, messagesStore } = this.props;
    const { destinations } = destinationsListStore;
    const destination = destinations.find(
      destination => destination.id === destinationId,
    );
    if (destination) {
      return (
        <Container>
          <Flex flexDirection="row" spaceBetween>
            <PageTitle>Destination Details</PageTitle>
            <div onClick={() => { messagesStore.setIsAnimating(true) }}>
              <Tooltip title={"Please try Rudderstack Control Plane for this feature"}>
                <Button disabled >
                  <PlayCircleOutlined />
                Live events
              </Button>
              </Tooltip>
            </div>
          </Flex>
          <CardsView>
            <Spacing>
              <DestinationView
                destination={destination}
                deleteDestination={this.deleteDestination}
              />
            </Spacing>
            <Spacing>
              <SourceView
                sources={destination!.sources}
                destination={destination}
                deleteConnection={this.deleteConnection}
              />
            </Spacing>
            <Spacing></Spacing>
          </CardsView>
        </Container>
      );
    }
    return null;
  }
}
Example #19
Source File: addDestination.tsx    From config-generator with MIT License 4 votes vote down vote up
@inject('destinationDefsListStore', 'destinationsListStore', 'sourcesListStore')
@observer
class AddDestination extends React.Component<IAddDestinationProps, any> {
  constructor(props: IAddDestinationProps) {
    super(props);
    const parsed = queryString.parse(this.props.location.search);

    let selectedSources: any = [];
    if (parsed.sourceId) {
      const selectedSource = props.sourcesListStore.sources.find(
        source => source.id === parsed.sourceId,
      );
      if (selectedSource) {
        selectedSources = [selectedSource];
      }
    }
    this.state = {
      currentStep: parsed.destinationDefId ? 1 : 0,
      enableNextButton: selectedSources ? true : false,
      destinationName: '',
      selectedDestDefintionId: parsed.destinationDefId || null,
      selectedDestDef:
        props.destinationDefsListStore.destinationDefs.filter(
          def => def.id === parsed.destinationDefId,
        )[0] || null,
      selectedSources,
      config: {},
      showNextLoader: false,
      filteredDestinationDefs: [],
    };
  }

  componentDidMount() {
    const { destinationDefsListStore } = this.props;

    if (destinationDefsListStore) {
      const destinationDefs = destinationDefsListStore!.destinationDefs;
      const destinationSettingsArr = Object.keys(formTemplatesMap);
      const filteredArr = [] as Array<object>;
      destinationDefs.map(def => {
        if (destinationSettingsArr.includes(def.name)) {
          filteredArr.push(def);
        }
      });
      this.setState({ filteredDestinationDefs: filteredArr });
    }
  }

  public enableConnection = async () => {
    const { destinationsListStore } = this.props;
    const {
      destinationName,
      config,
      selectedDestDef,
      selectedSources,
    } = this.state;
    const dest = await destinationsListStore.createDestination({
      name: destinationName,
      config: config,
      destinationDefinitionId: selectedDestDef.id,
    });
    await destinationsListStore.createDestinationConnections(
      dest,
      selectedSources.map((source: any) => source.id),
    );
    this.setState({ destinationId: dest.id });
  };

  public handleNext = async (event?: React.MouseEvent<HTMLElement>) => {
    const { currentStep } = this.state;
    if (currentStep === 3) {
      this.setState({ showNextLoader: true });
      await this.enableConnection();
      this.props.history.push(`/`);
    } else {
      this.setState({
        currentStep: currentStep + 1,
        enableNextButton: false,
      });
    }
  };

  public handleCancel = (event: React.MouseEvent<HTMLElement>) => {
    if (this.props.history.length > 2) {
      this.props.history.goBack();
    } else {
      this.props.history.push('/connections');
    }
  };

  public handleSelection = (selectedMap: any) => {
    const destDefId = Object.keys(selectedMap)[0];
    if (selectedMap[destDefId]) {
      this.setState({
        enableNextButton: true,
        selectedDestDefintionId: destDefId,
        selectedDestDef: this.state.filteredDestinationDefs.filter(
          (def: any) => def.id === destDefId,
        )[0],
      });
    } else {
      this.setState({
        enableNextButton: false,
        selectedDestDefintionId: null,
      });
    }
  };

  public handleNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    let enableNextButton = event.target.value.length > 0;
    this.setState({ destinationName: event.target.value, enableNextButton });
  };

  public handleSourceSelection = (selectedMap: any) => {
    let sourceIds = Object.keys(selectedMap).filter(k => selectedMap[k]);
    if (sourceIds.length < 1) {
      return this.setState({ enableNextButton: false, selectedSources: [] });
    }
    this.setState({
      enableNextButton: true,
      selectedSources: this.props.sourcesListStore.sources.filter(
        source => sourceIds.indexOf(source.id) > -1,
      ),
    });
  };

  public handleKeyDown = (e: any) => {
    if (e.key === 'Enter' && this.state.enableNextButton) {
      this.handleNext();
    }
  };

  public handleConfigChange = (config: any) => {
    this.setState({ config });
  };

  // public handleTransformationSelection = (
  //   transformation: ITransformationStore | null,
  // ) => {
  //   this.setState({ transformation });
  // };

  public render() {
    const {
      selectedSources,
      selectedDestDef,
      destinationId,
      filteredDestinationDefs,
    } = this.state;
    let icon;
    if (selectedSources.length > 0) {
      icon = selectedSources.map((source: any) => source.sourceDef.name);
    } else {
      icon = null;
    }
    return (
      <StyledContainer>
        <HeaderDiv className="p-b-lg">Add Destination</HeaderDiv>
        <Steps
          onCancel={this.handleCancel}
          onNext={this.handleNext}
          current={this.state.currentStep}
          enableNext={this.state.enableNextButton}
          showNextLoader={this.state.showNextLoader}
        >
          <Step>
            <AddDestDialogBody>
              <Flex justifyContentCenter className="p-t-lg" alignItems="center">
                {icon != null ? (
                  <DottedCircle iconName={icon} />
                ) : (
                  <DottedCircle />
                )}
                <div className="p-l-sm p-r-sm">
                  <Svg name="forward-thick" />
                </div>
                {selectedDestDef != null ? (
                  <DottedCircle iconName={selectedDestDef!.name} destination />
                ) : (
                  <DottedCircle solid />
                )}
              </Flex>
              <HeaderDiv className="text-center p-t-md">
                Choose a destination
              </HeaderDiv>
              <IconCardListContainer>
                <IconCardList
                  type="destination"
                  selectionMode="single"
                  icons={filteredDestinationDefs.map((def: any) => ({
                    id: def.id,
                    type: def.name,
                    title: def.displayName,
                  }))}
                  onSelectionChange={this.handleSelection}
                />
              </IconCardListContainer>
            </AddDestDialogBody>
          </Step>
          <Step>
            <AddDestDialogBody>
              <Flex justifyContentCenter className="p-t-lg" alignItems="center">
                {icon ? <DottedCircle iconName={icon} /> : <DottedCircle />}
                <div className="p-l-sm p-r-sm">
                  <Svg name="forward-thick" />
                </div>
                {selectedDestDef != null ? (
                  <DottedCircle iconName={selectedDestDef!.name} destination />
                ) : (
                  <DottedCircle solid />
                )}
              </Flex>
              <HeaderDiv className="text-center p-t-md">
                Name destination
              </HeaderDiv>
              <DestNameInputContainer>
                <Input
                  placeholder="eg. Google Analytics Dev"
                  onChange={this.handleNameChange}
                  autoFocus
                  onKeyDown={this.handleKeyDown}
                />
                <TextDiv
                  color={this.props.theme.color.grey300}
                  className="p-t-sm"
                >
                  Pick a name to help you identify this destination.
                </TextDiv>
              </DestNameInputContainer>
            </AddDestDialogBody>
          </Step>
          <Step>
            {this.state.selectedDestDef && (
              <AddDestDialogBody>
                <Flex
                  justifyContentCenter
                  className="p-t-lg"
                  alignItems="center"
                >
                  <DottedCircle solid />
                  <Flex className="selected-source-icons" alignItems="center">
                    {this.state.selectedSources.map(
                      (source: ISourceStore, index: number) => {
                        return (
                          <IconCircle
                            name={source.sourceDef.name}
                            listIndex={index}
                          />
                        );
                      },
                    )}
                  </Flex>
                  <div className="p-l-sm p-r-sm">
                    <Svg name="forward-thick" />
                  </div>
                  <IconCircle
                    name={this.state.selectedDestDef!.name}
                    destination
                  />
                </Flex>
                <HeaderDiv className="text-center p-t-md">
                  Connect Sources
                </HeaderDiv>
                <IconCardListContainer>
                  {this.props.sourcesListStore.sources.length === 0 ? (
                    <Flex justifyContentCenter>
                      <EmptySourceCard />
                    </Flex>
                  ) : (
                    <IconCardList
                      type="source"
                      selectionMode="multi"
                      destinationDefConfig={
                        this.state.selectedDestDef.config.sourceType
                      }
                      icons={this.props.sourcesListStore.sources.map(
                        source => ({
                          id: source.id,
                          type: source.sourceDef.name,
                          title: source.name,
                          selected:
                            selectedSources.length > 0
                              ? source.id === selectedSources[0].id
                                ? true
                                : false
                              : false,
                        }),
                      )}
                      onSelectionChange={this.handleSourceSelection}
                    />
                  )}
                </IconCardListContainer>
              </AddDestDialogBody>
            )}
          </Step>
          <Step>
            {this.state.selectedDestDef && (
              <FormBody>
                <Flex
                  justifyContentCenter
                  className="p-t-lg"
                  alignItems="center"
                >
                  <DottedCircle solid />
                  <Flex className="selected-source-icons" alignItems="center">
                    {this.state.selectedSources.map(
                      (source: ISourceStore, index: number) => {
                        return (
                          <IconCircle
                            name={source.sourceDef.name}
                            listIndex={index}
                          />
                        );
                      },
                    )}
                  </Flex>
                  <div className="p-l-sm p-r-sm">
                    <Svg name="forward-thick" />
                  </div>
                  <IconCircle
                    name={this.state.selectedDestDef!.name}
                    destination
                  />
                </Flex>
                <FormContainer>
                  <DestinationSettings
                    destName={this.state.selectedDestDef!.name}
                    onSettingsChange={this.handleConfigChange}
                    setRequirementsState={(reqsState: any) =>
                      this.setState({ enableNextButton: reqsState })
                    }
                  ></DestinationSettings>
                </FormContainer>
              </FormBody>
            )}
          </Step>
        </Steps>
      </StyledContainer>
    );
  }
}
Example #20
Source File: index.tsx    From config-generator with MIT License 4 votes vote down vote up
@inject(
  'sourcesListStore',
  'destinationsListStore',
  'sourceDefinitionsListStore',
  'destinationDefsListStore',
  'connectionsStore',
)
@observer
class Connections extends Component<IConnectionsProps, any> {
  linesMap: any;

  constructor(props: IConnectionsProps) {
    super(props);
    this.linesMap = {};
    this.state = {};
  }

  componentDidMount() {
    this.drawSourceConnectionLines();
  }

  componentWillUnmount() {
    this.removeSourceConnectionLines();
  }

  drawSourceConnectionLines = () => {
    let existingCombos = Object.keys(this.linesMap);
    let combos: string[] = [];
    this.props.sourcesListStore!.sources.forEach(source => {
      source.destinations.forEach(dest =>
        combos.push(`${source.id}-${dest.id}`),
      );
    });
    existingCombos.forEach(c => {
      if (!combos.includes(c)) {
        this.linesMap[c].remove();
      }
    });
    combos.forEach(c => {
      if (!existingCombos.includes(c)) {
        let line = new LeaderLine(
          document.getElementById(`fake-source-${c.split('-')[0]}`),
          document.getElementById(`fake-destination-${c.split('-')[1]}`),
          { endPlug: 'behind', color: theme.color.grey100, size: 4 },
        );
        this.linesMap[c] = line;
      }
    });
  };

  removeSourceConnectionLines = () => {
    Object.values(this.linesMap).forEach((l: any) => l.remove());
  };

  buildWorkspaceConfig = () => {
    const workspaceConfig = {
      sources: [] as any,
      metadata: {
        sourceListStore: this.props.sourcesListStore.returnWithoutRootStore(),
        destinationListStore: this.props.destinationsListStore.returnWithoutRootStore(),
        connectionsStore: this.props.connectionsStore.returnWithoutRootStore(),
        version,
      },
    };

    this.props.sourcesListStore!.sources.forEach(source => {
      let obj = {
        config: source.config,
        id: source.id,
        name: source.name,
        writeKey: source.writeKey,
        enabled: source.enabled,
        sourceDefinitionId: source.sourceDefinitionId,
        deleted: false,
        createdAt: Date(),
        updatedAt: Date(),
        sourceDefinition: source.sourceDef,
        destinations: source.destinations.map(dest => {
          return {
            ...dest,
            isProcessorEnabled:
              dest.enabled &&
              source.enabled &&
              !dest.config.useNativeSDK &&
              !dest.destinationDefinition.config.deviceModeOnly,
            rootStore: null,
          };
        }),
      };
      workspaceConfig.sources.push(obj);
    });
    return workspaceConfig;
  };

  handleExportWorkspaceConfig = () => {
    const workspaceConfig = this.buildWorkspaceConfig();
    fileDownload(
      JSON.stringify(workspaceConfig, null, 2),
      'workspaceConfig.json',
    );
  };

  handleSaveWorkspaceConfig = () => {
    const workspaceConfig = this.buildWorkspaceConfig();
    apiServerCaller().post('/saveToFile', { workspaceConfig });
  };

  handleFileChosen = (event: any) => {
    const file = event.target.files[0];
    let fileReader = new FileReader();
    fileReader.onloadend = e => {
      const content = fileReader.result;
      this.setupWorkspace(content);
    };
    fileReader.readAsText(file);
  };

  setupWorkspace = (jsonContent: any) => {
    const content = JSON.parse(jsonContent);
    this.props.sourcesListStore!.loadImportedFile(
      content.metadata.sourceListStore.sources,
    );
    this.props.destinationsListStore!.loadImportedFile(
      content.metadata.destinationListStore.destinations,
    );
    this.props.connectionsStore!.loadImportedFile(
      content.metadata.connectionsStore.connections,
    );
    this.props.connectionsStore!.setConnections(content.sources);
  };

  public render() {
    const isSaveToFileEnabled =
      (process.env.REACT_APP_IS_SAVE_TO_FILE_ENABLED || '').toLowerCase() ===
      'true';
    return (
      <Container>
        <Flex flexDirection="column">
          <Heading>
            <Flex flexDirection="row" spaceBetween>
              <HeaderDiv color={theme.color.primary}>Connections</HeaderDiv>
              <Flex
                flexDirection="row"
                style={{ justifyContent: 'space-around' }}
              >
                <ButtonPrimary
                  onClick={this.handleExportWorkspaceConfig}
                  style={{ height: '40px', fontSize: theme.fontSize.sm }}
                >
                  Export
                </ButtonPrimary>

                {isSaveToFileEnabled && (
                  <ButtonPrimary
                    className="m-l-sm"
                    onClick={this.handleSaveWorkspaceConfig}
                    style={{ height: '40px', fontSize: theme.fontSize.sm }}
                  >
                    Save
                  </ButtonPrimary>
                )}

                <ImportInputButton
                  type="file"
                  name="file"
                  onChange={this.handleFileChosen}
                  id="myuniqueid"
                />
                <ImportConfigContainer htmlFor="myuniqueid">
                  IMPORT
                </ImportConfigContainer>
              </Flex>
            </Flex>
          </Heading>
          <BodyContainer>
            <SourcesList linesMap={this.linesMap} />
            <DestinationsList linesMap={this.linesMap} />
          </BodyContainer>
        </Flex>
      </Container>
    );
  }
}
Example #21
Source File: index.tsx    From config-generator with MIT License 4 votes vote down vote up
@inject('destinationsListStore', 'sourcesListStore')
@observer
class ConnectSources extends React.Component<IConnectSourcesProps, any> {
  constructor(props: IConnectSourcesProps) {
    super(props);
    const propsDestinationId = props.match.params.id;

    let destination: any = undefined;
    if (propsDestinationId) {
      var selectedDestination = props.destinationsListStore.destinations.find(
        destination => destination.id === propsDestinationId,
      );
      if (selectedDestination) {
        destination = selectedDestination;
      }
    }
    this.state = {
      selectedSources: [],
      destination,
      refinedSourceList: [],
    };
  }

  public componentDidMount() {
    const { sourcesListStore } = this.props;
    const { refinedSourceList, destination } = this.state;
    const destinationId = destination.id;
    const sourcesList = sourcesListStore.sources;

    for (let sourceCount = 0; sourceCount < sourcesList.length; sourceCount++) {
      var check = true;
      for (let i = 0; i < sourcesList[sourceCount].destinations.length; i++) {
        if (sourcesList[sourceCount].destinations[i].id === destinationId) {
          check = false;
        }
      }
      if (check === true) {
        refinedSourceList.push(sourcesList[sourceCount]);
      }
    }
    this.setState({ refinedSourceList });
  }

  public handleSourceSelection = (selectedMap: any) => {
    let sourceIds = Object.keys(selectedMap).filter(k => selectedMap[k]);
    if (sourceIds.length < 1) {
      return this.setState({ enableNextButton: false, selectedSources: [] });
    }
    this.setState({
      selectedSources: this.props.sourcesListStore.sources.filter(
        source => sourceIds.indexOf(source.id) > -1,
      ),
    });
  };

  public handleCancel = () => {
    if (this.props.history.length > 2) {
      this.props.history.goBack();
    } else {
      this.props.history.push('/connections');
    }
  };

  public handleSubmit = async () => {
    const { destination, selectedSources } = this.state;
    let destinationId = destination.id;
    const { destinationsListStore } = this.props;
    if (selectedSources.length > 0) {
      let selectedDestination = destinationsListStore.destinations.find(
        destination => destination.id === destinationId,
      );
      if (selectedDestination) {
        selectedDestination.sources.push(selectedSources);
      }
      await this.props.destinationsListStore.createDestinationConnections(
        selectedDestination,
        selectedSources.map((source: any) => source.id),
      );
      this.props.history.push(`/`);
    }
  };


  renderIconCardListContainer = () => {
    const { selectedSources, destination, refinedSourceList } = this.state;
    if (refinedSourceList.length > 0) {
      return (
        <IconCardListContainer>
          {this.props.sourcesListStore.sources.length === 0 ? (
            <Flex justifyContentCenter>
              <EmptySourceCard destinationId={destination.id} />
            </Flex>
          ) : (
            <IconCardList
              type="source"
              selectionMode="multi"
              destinationDefConfig={
                destination.destinationDefinition.config.sourceType
              }
              icons={refinedSourceList.map((source: any) => ({
                  id: source.id,
                  type: source.sourceDef.name,
                  title: source.name,
                  selected:
                    selectedSources.length > 0
                      ? source.id === selectedSources[0].id
                        ? true
                        : false
                      : false,
                }))}
              onSelectionChange={this.handleSourceSelection}
            />
          )}
        </IconCardListContainer>
      );
    }
    return (
      <IconCardListContainer>
        <Flex justifyContentCenter>
          <EmptySourceCard destinationId={destination.id} />
        </Flex>
      </IconCardListContainer>
    );
  };

  renderModalFooter = () => {
    const { selectedSources, destination, refinedSourceList } = this.state;
    if (refinedSourceList.length > 0) {
      return (
        <>
          <BorderLine />
          <Flex flexDirection="row" spaceBetween className="p-h-md p-v-xs">
            <ButtonSecondary onClick={this.handleCancel}>
              Cancel
            </ButtonSecondary>
            <ButtonSecondary onClick={this.handleSubmit}>
              Submit
            </ButtonSecondary>
          </Flex>
        </>
      );
    }
  };

  public render() {
    const { selectedSources, destination, refinedSourceList } = this.state;
    return (
      <StyledContainer>
        <HeaderDiv className="p-b-lg"></HeaderDiv>
        <AddDestDialogBody>
          <Flex justifyContentCenter className="p-t-lg" alignItems="center">
            <DottedCircle solid />
            <Flex alignItems="center">
              {this.state.selectedSources.map(
                (source: ISourceStore, index: number) => {
                  return (
                    <IconCircle
                      name={source.sourceDef.name}
                      listIndex={index}
                    />
                  );
                },
              )}
            </Flex>
            <div className="p-l-sm p-r-sm">
              <Svg name="forward-thick" />
            </div>
            <IconCircle
              name={destination.destinationDefinition.name}
              destination
            />
          </Flex>
          <HeaderDiv className="text-center p-t-md">Connect Sources</HeaderDiv>
          {this.renderIconCardListContainer()}
          {this.renderModalFooter()}
        </AddDestDialogBody>
      </StyledContainer>
    );
  }
}
Example #22
Source File: index.tsx    From config-generator with MIT License 4 votes vote down vote up
@inject('sourcesListStore', 'destinationsListStore')
@observer
class ConfiguredSources extends Component<
  IConfiguredSourcesProps,
  IConfiguredSourcesState
> {
  constructor(props: IConfiguredSourcesProps) {
    super(props);
    this.state = {
      count: 1,
      active: 1,
      inactive: 0,
    };
  }
  dataSource: any = [];
  columns = [
    {
      title: '',
      dataIndex: 'icon',
      key: 'icon',
    },
    {
      title: 'Name',
      dataIndex: 'name',
      key: 'name',
    },
    {
      title: 'Status',
      dataIndex: 'status',
      key: 'status',
    },
    {
      title: 'Destination',
      dataIndex: 'destination',
      key: 'destination',
    },
  ];

  public async componentDidMount() {
    const { sourcesListStore } = this.props;
    await this.constructDataSource(sourcesListStore!.sources);
  }

  public constructDataSource = (sources: any) => {
    this.dataSource = [];
    let activeCount = 0;
    for (let i = 0; i < sources.length; i++) {
      const destinationList: any = [];
      const obj: any = {};

      obj.key = i;
      for (let dcount = 0; dcount < sources[i].destinations.length; dcount++) {
        const a = (
          <IconSpacing key={`${sources[i].destinations[dcount].id}`}>
            <DestinationIcon
              destination={
                sources[i].destinations[dcount].destinationDefinition.name
              }
            />
          </IconSpacing>
        );
        destinationList.push(a);
      }
      if (sources[i].enabled) {
        activeCount++;
      }
      obj.destination = destinationList;
      obj.icon = <SourceIcon source={sources[i].sourceDef.name} />;
      obj.id = sources[i].id;
      obj.name = sources[i].name;
      obj.status = sources[i].enabled ? 'Enabled' : 'Disabled';
      this.dataSource.push(obj);
    }
    this.setState({ count: sources.length });
    this.setState({ active: activeCount });
    this.setState({ inactive: this.state.count - this.state.active });
  };

  handleRowClick = (record: any, Index: Number) => {
    const { history } = this.props;
    history!.push(`/sources/${record.id}`);
  };

  public renderAddSource = () => {
    return (
      <Link to="/sources/setup">
        <Flex flexDirection={'row'}>
          <IconStyle>
            <Svg name="plus" />
          </IconStyle>
          <AddSource>Add source</AddSource>
        </Flex>
      </Link>
    );
  };

  public render() {
    const { count, active, inactive } = this.state;
    return (
      <Container>
        <Flex flexDirection="column">
          <MainHeading>Configured Sources</MainHeading>
          <HeadingTag className={'p-v-xs'}>
            {count} Added {active} Active {inactive} Inactive
          </HeadingTag>
        </Flex>
        <TableViewContainer>
          <Table
            dataSource={this.dataSource}
            columns={this.columns}
            pagination={false}
            footer={this.renderAddSource}
            onRow={(record, Index) => ({
              onClick: () => this.handleRowClick(record, Index),
            })}
          />
        </TableViewContainer>
      </Container>
    );
  }
}
Example #23
Source File: index.tsx    From config-generator with MIT License 4 votes vote down vote up
@inject('sourcesListStore', 'destinationsListStore')
@observer
class ConfiguredDestinations extends Component<
  IConfiguredDestinationsProps,
  IConfiguredDestinationsState
> {
  constructor(props: IConfiguredDestinationsProps) {
    super(props);
    this.state = {
      count: 1,
      active: 1,
      inactive: 0,
    };
  }

  public async componentDidMount() {
    const { sourcesListStore, destinationsListStore } = this.props;
    await this.constructDataSource(
      sourcesListStore!.sources,
      destinationsListStore!.destinations,
    );
  }

  dataSource: any = [];

  columns = [
    {
      title: '',
      dataIndex: 'icon',
      key: 'icon',
    },
    {
      title: 'Name',
      dataIndex: 'name',
      key: 'name',
    },
    {
      title: 'Status',
      dataIndex: 'status',
      key: 'status',
    },
    {
      title: 'Sources',
      dataIndex: 'sources',
      key: 'sources',
    },
  ];

  public constructDataSource = (sources: any, destinations: any) => {
    this.dataSource = [];
    let activeCount = 0;

    for (let i = 0; i < destinations.length; i++) {
      const sourceList: any = [];
      const obj: any = {};

      obj.key = destinations[i].id;
      for (let scount = 0; scount < destinations[i].sources.length; scount++) {
        const a = (
          <IconSpacing key={`${destinations[i].sources[scount].id}`}>
            <SourceIcon
              key={`${scount}`}
              source={destinations[i].sources[scount].sourceDef.name}
            />
          </IconSpacing>
        );
        sourceList.push(a);
      }

      if (destinations[i].enabled) {
        activeCount++;
      }
      obj.sources = sourceList;
      obj.icon = (
        <DestinationIcon
          destination={destinations[i].destinationDefinition.name}
        />
      );
      obj.id = destinations[i].id;
      obj.name = destinations[i].name;
      obj.status = destinations[i].enabled ? 'Enabled' : 'Disabled';
      this.dataSource.push(obj);
    }
    this.setState({ active: activeCount });
    this.setState({ count: sources.length });
    this.setState({ inactive: this.state.count - this.state.active });
  };

  handleRowClick = (record: any, Index: Number) => {
    const { history } = this.props;
    history!.push(`/destinations/${record.id}`);
  };

  public render() {
    const { count, active, inactive } = this.state;
    return (
      <Container className="Sources">
        <HeadingContainer>
          <MainHeading>Configured Destinations</MainHeading>
          <HeadingTag>
            {count} Added {active} Active {inactive} Inactive
          </HeadingTag>
        </HeadingContainer>
        <TableViewContainer>
          <Table
            dataSource={this.dataSource}
            columns={this.columns}
            pagination={false}
            onRow={(record, Index) => ({
              onClick: () => this.handleRowClick(record, Index),
            })}
          />
        </TableViewContainer>
      </Container>
    );
  }
}
Example #24
Source File: index.tsx    From react-amis-admin with Apache License 2.0 4 votes vote down vote up
@inject("store")
@observer
export default class Admin extends React.Component<AdminProps, any> {
    renderHeader() {
        const store = this.props.store;

        return (
            <div>
                <div className={`cxd-Layout-brandBar`}>
                    <button
                        onClick={store.toggleOffScreen}
                        className="pull-right visible-xs"
                    >
                        <i className="fa fa-bars text-white"></i>
                    </button>
                    <div className={`cxd-Layout-brand`}>
                        <i className="fa fa-paw"></i>
                        <span className="hidden-folded m-l-sm">react-amis-admin</span>
                    </div>
                </div>
                <div className={`cxd-Layout-headerBar`}>
                    <div className="nav navbar-nav hidden-xs pull-left">
                        <Button
                            level="link"
                            className="no-shadow navbar-btn"
                            onClick={store.toggleAsideFolded}
                            tooltip="展开或收起侧边栏"
                            placement="bottom"
                            iconOnly
                        >
                            <i className={store.asideFolded ? 'fa fa-indent' : 'fa fa-outdent'}/>
                        </Button>
                    </div>

                    <div className="m-l-auto hidden-xs pull-right">
                        <span>{store.user.name}</span><span className={'btn btn-link'} onClick={this.logout}>[退出]</span>
                    </div>
                </div>


            </div>
        );
    }

    state = {
        pathname: '',
        hasLoadMenu: false,
        navigations: []
    }

    logout = () => {
        const store = this.props.store;
        store.user.logout()
        const history = this.props.history;
        history.replace(`/login`)
    }

    componentDidMount() {
        const store = this.props.store;
        const history = this.props.history;
        console.log("componentDidMount, store.user:", store.user)
        if (!store.user.isAuthenticated) {
            toast['error']('用户未登陆,请先登陆!', '消息')
            history.replace(`/login`)
        }
        this.refreshMenu()
    }

    componentDidUpdate() {
        this.refreshMenu()
    }

    refreshMenu = () => {
        const store = this.props.store;
        let pathname = this.props.location.pathname;
        console.log("location:", pathname)
        console.log("store.user:", store.user)
        if (pathname != 'login' && pathname != '/' &&
            !this.state.hasLoadMenu &&
            store.user.isAuthenticated
        ) {
            request({
                method: "get",
                url: '/api/menus'
            }).then((res: any) => {
                console.log("res:", res);
                this.setState({
                        "navigations": res.data.data,
                        "hasLoadMenu": true
                    }
                )
            })
        }
    }


    renderAside() {
        const location = this.props.location;
        const store = this.props.store;

        return (
            <AsideNav
                key={store.asideFolded ? 'folded-aside' : 'aside'}
                navigations={this.state.navigations}
                renderLink={({link, toggleExpand, classnames: cx, depth}: any) => {
                    if (link.hidden) {
                        return null;
                    }
                    let children = [];

                    if (link.children) {
                        children.push(
                            <span
                                key="expand-toggle"
                                className={cx('AsideNav-itemArrow')}
                                onClick={(e) => toggleExpand(link, e)}
                            ></span>
                        );
                    }

                    link.badge && children.push(
                        <b key="badge"
                           className={cx(`AsideNav-itemBadge`, link.badgeClassName || 'bg-info')}>{link.badge}</b>
                    );

                    if (link.icon) {
                        children.push(
                            <i key="icon" className={cx(`AsideNav-itemIcon`, link.icon)}/>
                        )
                    } else if (store.asideFolded && depth === 1) {
                        children.push(
                            <i key="icon"
                               className={cx(`AsideNav-itemIcon`, link.children ? 'fa fa-folder' : 'fa fa-info')}/>
                        )
                    }
                    ;

                    children.push(
                        <span key="label" className={cx('AsideNav-itemLabel')}>{link.label}</span>
                    );

                    return link.path
                        ? (link.active ? <a>{children}</a> : <Link
                            to={link.path}>{children}</Link>)
                        : (
                            <a onClick={link.onClick ? link.onClick : link.children ? () => toggleExpand(link) : undefined}>{children}</a>);
                }}

                isActive={(link: any) => isActive(link.path, location)}
            />
        );
    }


    render() {
        const store = this.props.store;
        let pathname = this.props.location.pathname;
        console.log("location:", pathname)
        if (pathname == 'login' || pathname == '/') {
            return (
                <Switch>
                    <RouterGuard/>
                    <Redirect to={`/404`}/>
                </Switch>
            )
        } else {
            return (
                <Layout
                    aside={this.renderAside()}
                    header={this.renderHeader()}
                    folded={store.asideFolded}
                    offScreen={store.offScreen}
                >
                    <Switch>
                        <RouterGuard/>
                        <Redirect to={`/404`}/>
                    </Switch>
                </Layout>
            );
        }

    }
}
Example #25
Source File: Login.tsx    From react-amis-admin with Apache License 2.0 4 votes vote down vote up
@inject("store")
// @ts-ignore
@withRouter
@observer
export default class LoginRoute extends React.Component<LoginProps, any> {

  state = {
    inputUsername: 'admin',
    inputPassword: 'admin'
  }

  handleFormSaved = (value: any) => {
    const history = this.props.history;
    const store = this.props.store;
    console.log("inputUsername:", this.state.inputUsername)
    console.log("inputPassword:", this.state.inputPassword)
    // 这里可以进行登陆密码验证
    axios.request({
      method: "post",
      url: "/api/login"
    }).then(res => {
      console.log("login res", res);
      if (res.data != null && res.data.status === 0) {
        store.user.login(this.state.inputUsername);
        toast['info']('登陆成功', '消息')
        // 跳转到dashboard页面
        console.log("replace history to dashboard, value:", value)
        history.replace(`/dashboard`)
      } else {
        toast['error']('登陆失败', '消息')
      }
    })
  }

  handleChangeForPassword = (e: any) => {
    this.setState({
      inputPassword: e.target.value
    })
  }

  componentDidMount() {
    const store = this.props.store;
    console.log("store.user.name", store.user.name)
    console.log("store.user.isAuthenticated", store.user.isAuthenticated)
  }

  handleChangeForUsername = (e: any) => {
    this.setState({
      inputUsername: e.target.value
    })
  }

  render() {
    return (
        <div className="login-page-container" >

          <div className="container mt-5">
            <span className="block m-b-xl text-center text-2x">React-Amis-Admin系统</span>
            <span className="block m-b-xl text-center">一个开箱可用的Amis + React 低代码开发环境</span>

            <div className="row d-flex justify-content-center">
              <div className="col-md-6">
                <div className="card px-5 py-5 bg-glass">

                  <div className="card-body">
                    <div className="form-data">
                      <div className="forms-inputs mb-4"><span>用户名</span>
                        <input autoComplete="off"
                               className="form-control"
                               placeholder="用户名"
                               type="text"
                               onChange={this.handleChangeForUsername}
                               defaultValue={this.state.inputUsername}
                        />
                        <div className="invalid-feedback">A valid email is required!</div>
                      </div>
                      <div className="forms-inputs mb-4"><span>密码</span>
                        <input placeholder="密码"
                               type="password"
                               className="form-control"
                               onChange={this.handleChangeForPassword}
                               defaultValue={this.state.inputPassword}/>
                        <div className="invalid-feedback">Password must be 8 character!</div>
                      </div>
                      <div className="mb-3">
                        <button className="btn btn-dark w-100" onClick={this.handleFormSaved}>登陆</button>
                      </div>
                    </div>
                  </div>

                </div>
              </div>
            </div>
          </div>
        </div>
    )
        ;
  }
}
Example #26
Source File: AMisRenderer.tsx    From react-amis-admin with Apache License 2.0 4 votes vote down vote up
@inject("store")
// @ts-ignore
@withRouter
@observer
export default class AMisRenderer extends React.Component<RendererProps, any> {
    env:any = null;
    
    handleAction = (e:any, action:Action) => {
        this.env.alert(`没有识别的动作:${JSON.stringify(action)}`);
    }

    constructor(props:RendererProps) {
        super(props);
        const store = props.store as IMainStore;
        const fetcher = getEnv(store).fetcher;
        const notify = getEnv(store).notify;
        const alert = getEnv(store).alert;
        const confirm = getEnv(store).confirm;
        const copy = getEnv(store).copy;
        const apiHost = getEnv(store).apiHost;
        const getModalContainer = getEnv(store).getModalContainer;
        const history = props.history;
        
        const normalizeLink = (to:string) => {
            if (/^\/api\//.test(to)) {
                return to;
            }
            to = to || '';
            const location = history.location;
            if (to && to[0] === '#') {
                to = location.pathname + location.search + to;
            } else if (to && to[0] === '?') {
                to = location.pathname + to;
            }
            const idx = to.indexOf('?');
            const idx2 = to.indexOf('#');
            let pathname =  ~idx ? to.substring(0, idx) : ~idx2 ? to.substring(0, idx2) : to;
            let search = ~idx ? to.substring(idx, ~idx2 ? idx2 : undefined) : '';
            let hash = ~idx2 ? to.substring(idx2) : '';
            if (!pathname) {
                pathname = location.pathname;
            }else if (pathname[0] != '/' && !/^https?\:\/\//.test(pathname)) {
                let relativeBase = location.pathname;
                const paths = relativeBase.split('/');
                paths.pop();
                let m;
                while ((m = /^\.\.?\//.exec(pathname))) {
                    if (m[0] === '../') {
                        paths.pop();
                    }
                    pathname = pathname.substring(m[0].length);
                }
                pathname = paths.concat(pathname).join('/');
            }
            return pathname + search + hash;
        }

        // todo,这个过程可以 cache
        this.env = {
            session: 'global',
            updateLocation: props.updateLocation || ((location:string, replace:boolean) => {
                if (location === 'goBack') {
                    return history.goBack();
                }
                history[replace ? 'replace' : 'push'](normalizeLink(location));
            }),
            isCurrentUrl: (to:string) => {
                const link = normalizeLink(to);
                const location = history.location;
                let pathname = link;
                let search = '';
                const idx = link.indexOf('?');
                if (~idx) {
                    pathname = link.substring(0, idx);
                    search = link.substring(idx);
                }
                if (search) {
                    if (pathname !== location.pathname || !location.search) {
                        return false;
                    }
                    const query = qs.parse(search.substring(1));
                    const currentQuery = qs.parse(location.search.substring(1));
                    return Object.keys(query).every(key => query[key] === currentQuery[key]);
                } else if (pathname === location.pathname) {
                    return true;
                }
                return false;
            },
            jumpTo: props.jumpTo || ((to:string, action?:any) => {
                if (to === 'goBack') {
                    return history.goBack();
                }
                to = normalizeLink(to);
                if (action && action.actionType === 'url') {
                    action.blank === false ? (window.location.href = to) : window.open(to);
                    return;
                }
                if (/^https?:\/\//.test(to)) {
                    window.location.replace(to);
                } else {
                    history.push(to);
                }
            }),
            fetcher,
            notify,
            alert,
            confirm,
            copy,
            apiHost,
            getModalContainer
        };
    }
    
    render() {
        const {
            schema,
            store,
            onAction,
            ...rest
        } = this.props;
        return renderSchema(schema, {
            onAction: onAction || this.handleAction,
            theme: store && store.theme,
            ...rest
        }, this.env);
    }
}