mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
[WIP] Add ExtensionsSearch to NewBehaviorDialog
This commit is contained in:
@@ -43,3 +43,23 @@ export const enumerateBehaviorsMetadata = (
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
export const filterEnumeratedBehaviorMetadata = (
|
||||
list: Array<EnumeratedBehaviorMetadata>,
|
||||
searchText: string
|
||||
): Array<EnumeratedBehaviorMetadata> => {
|
||||
if (!searchText) return list;
|
||||
|
||||
const lowercaseSearchText = searchText.toLowerCase();
|
||||
|
||||
return list.filter(enumerateBehaviorsMetadata => {
|
||||
return (
|
||||
enumerateBehaviorsMetadata.fullName
|
||||
.toLowerCase()
|
||||
.indexOf(lowercaseSearchText) !== -1 ||
|
||||
enumerateBehaviorsMetadata.description
|
||||
.toLowerCase()
|
||||
.indexOf(lowercaseSearchText) !== -1
|
||||
);
|
||||
});
|
||||
};
|
||||
|
@@ -9,6 +9,7 @@ import HelpButton from '../UI/HelpButton';
|
||||
import FlatButton from 'material-ui/FlatButton';
|
||||
import Subheader from 'material-ui/Subheader';
|
||||
import Avatar from 'material-ui/Avatar';
|
||||
import { Tabs, Tab } from 'material-ui/Tabs';
|
||||
import { List, ListItem } from 'material-ui/List';
|
||||
import Visibility from 'material-ui/svg-icons/action/visibility';
|
||||
import VisibilityOff from 'material-ui/svg-icons/action/visibility-off';
|
||||
@@ -18,7 +19,11 @@ import { getDeprecatedBehaviorsInformation } from '../Hints';
|
||||
import {
|
||||
type EnumeratedBehaviorMetadata,
|
||||
enumerateBehaviorsMetadata,
|
||||
filterEnumeratedBehaviorMetadata,
|
||||
} from './EnumerateBehaviorsMetadata';
|
||||
import SearchBar from 'material-ui-search-bar';
|
||||
import EmptyMessage from '../UI/EmptyMessage';
|
||||
import ExtensionsSearch from '../ExtensionsSearch';
|
||||
|
||||
const styles = {
|
||||
icon: { borderRadius: 0 },
|
||||
@@ -58,10 +63,22 @@ type Props = {|
|
||||
type State = {|
|
||||
behaviorMetadata: Array<EnumeratedBehaviorMetadata>,
|
||||
showDeprecated: boolean,
|
||||
searchText: string,
|
||||
|};
|
||||
|
||||
export default class NewBehaviorDialog extends Component<Props, State> {
|
||||
state = { ...this._loadFrom(this.props.project), showDeprecated: false };
|
||||
state = {
|
||||
...this._loadFrom(this.props.project),
|
||||
showDeprecated: false,
|
||||
searchText: '',
|
||||
};
|
||||
_searchBar = React.createRef<SearchBar>();
|
||||
|
||||
componentDidMount() {
|
||||
setTimeout(() => {
|
||||
if (this._searchBar.current) this._searchBar.current.focus();
|
||||
}, 20 /* Be sure that the search bar is shown */);
|
||||
}
|
||||
|
||||
_loadFrom(
|
||||
project: gdProject
|
||||
@@ -90,26 +107,29 @@ export default class NewBehaviorDialog extends Component<Props, State> {
|
||||
});
|
||||
};
|
||||
|
||||
_onNewExtensionInstalled = () => {
|
||||
// Reload behaviors
|
||||
this.setState(this._loadFrom(this.props.project));
|
||||
|
||||
// TODO: Go back to the first tab.
|
||||
// TODO: Display snackbar?
|
||||
};
|
||||
|
||||
render() {
|
||||
const { project, open, onClose, objectType } = this.props;
|
||||
const { showDeprecated, behaviorMetadata } = this.state;
|
||||
const { showDeprecated, behaviorMetadata, searchText } = this.state;
|
||||
if (!open || !project) return null;
|
||||
|
||||
const actions = [
|
||||
<FlatButton
|
||||
key="close"
|
||||
label={<Trans>Close</Trans>}
|
||||
primary={false}
|
||||
onClick={onClose}
|
||||
/>,
|
||||
];
|
||||
|
||||
const deprecatedBehaviorsInformation = getDeprecatedBehaviorsInformation();
|
||||
|
||||
const behaviors = behaviorMetadata.filter(
|
||||
const filteredBehaviorMetadata = filterEnumeratedBehaviorMetadata(
|
||||
behaviorMetadata,
|
||||
searchText
|
||||
);
|
||||
const behaviors = filteredBehaviorMetadata.filter(
|
||||
({ type }) => !deprecatedBehaviorsInformation[type]
|
||||
);
|
||||
const deprecatedBehaviors = behaviorMetadata.filter(
|
||||
const deprecatedBehaviors = filteredBehaviorMetadata.filter(
|
||||
({ type }) => !!deprecatedBehaviorsInformation[type]
|
||||
);
|
||||
|
||||
@@ -134,60 +154,106 @@ export default class NewBehaviorDialog extends Component<Props, State> {
|
||||
);
|
||||
};
|
||||
|
||||
const hasSearchNoResult =
|
||||
!!searchText && !behaviors.length && !deprecatedBehaviors.length;
|
||||
|
||||
return (
|
||||
<I18n>
|
||||
{({ i18n }) => (
|
||||
<Dialog
|
||||
title={<Trans>Add a new behavior to the object</Trans>}
|
||||
actions={actions}
|
||||
actions={[
|
||||
<FlatButton
|
||||
key="close"
|
||||
label={<Trans>Close</Trans>}
|
||||
primary={false}
|
||||
onClick={onClose}
|
||||
/>,
|
||||
]}
|
||||
secondaryActions={<HelpButton helpPagePath="/behaviors" />}
|
||||
open={open}
|
||||
noMargin
|
||||
autoScrollBodyContent
|
||||
>
|
||||
<List>
|
||||
{behaviors.map((behaviorMetadata, index) => (
|
||||
<BehaviorListItem
|
||||
key={index}
|
||||
behaviorMetadata={behaviorMetadata}
|
||||
onClick={() => chooseBehavior(i18n, behaviorMetadata)}
|
||||
disabled={!canBehaviorBeUsed(behaviorMetadata)}
|
||||
<Tabs>
|
||||
<Tab label={<Trans>Installed Behaviors</Trans>} value="installed">
|
||||
<SearchBar
|
||||
value={searchText}
|
||||
onRequestSearch={() => {
|
||||
if (behaviors.length) {
|
||||
chooseBehavior(i18n, behaviors[0]);
|
||||
} else if (showDeprecated && deprecatedBehaviors.length) {
|
||||
chooseBehavior(i18n, deprecatedBehaviors[0]);
|
||||
}
|
||||
}}
|
||||
onChange={text =>
|
||||
this.setState({
|
||||
searchText: text,
|
||||
})
|
||||
}
|
||||
ref={this._searchBar}
|
||||
/>
|
||||
))}
|
||||
{showDeprecated && (
|
||||
<Subheader>
|
||||
Deprecated (old, prefer not to use anymore)
|
||||
</Subheader>
|
||||
)}
|
||||
{showDeprecated &&
|
||||
deprecatedBehaviors.map((behaviorMetadata, index) => (
|
||||
<BehaviorListItem
|
||||
key={index}
|
||||
behaviorMetadata={behaviorMetadata}
|
||||
onClick={() => chooseBehavior(i18n, behaviorMetadata)}
|
||||
disabled={!canBehaviorBeUsed(behaviorMetadata)}
|
||||
/>
|
||||
))}
|
||||
</List>
|
||||
<Line justifyContent="center" alignItems="center">
|
||||
{!showDeprecated ? (
|
||||
<FlatButton
|
||||
key="toggle-experimental"
|
||||
icon={<Visibility />}
|
||||
primary={false}
|
||||
onClick={() => this._showDeprecated(true)}
|
||||
label={<Trans>Show deprecated (old) behaviors</Trans>}
|
||||
{hasSearchNoResult && (
|
||||
<EmptyMessage>
|
||||
<Trans>
|
||||
No behavior found for your search. Try another search, or
|
||||
search for new behaviors to install.
|
||||
</Trans>
|
||||
</EmptyMessage>
|
||||
)
|
||||
// TODO: Button to search behaviors
|
||||
}
|
||||
<List>
|
||||
{behaviors.map((behaviorMetadata, index) => (
|
||||
<BehaviorListItem
|
||||
key={index}
|
||||
behaviorMetadata={behaviorMetadata}
|
||||
onClick={() => chooseBehavior(i18n, behaviorMetadata)}
|
||||
disabled={!canBehaviorBeUsed(behaviorMetadata)}
|
||||
/>
|
||||
))}
|
||||
{showDeprecated && !!deprecatedBehaviors.length && (
|
||||
<Subheader>
|
||||
Deprecated (old, prefer not to use anymore)
|
||||
</Subheader>
|
||||
)}
|
||||
{showDeprecated &&
|
||||
deprecatedBehaviors.map((behaviorMetadata, index) => (
|
||||
<BehaviorListItem
|
||||
key={index}
|
||||
behaviorMetadata={behaviorMetadata}
|
||||
onClick={() => chooseBehavior(i18n, behaviorMetadata)}
|
||||
disabled={!canBehaviorBeUsed(behaviorMetadata)}
|
||||
/>
|
||||
))}
|
||||
</List>
|
||||
<Line justifyContent="center" alignItems="center">
|
||||
{!showDeprecated ? (
|
||||
<FlatButton
|
||||
key="toggle-experimental"
|
||||
icon={<Visibility />}
|
||||
primary={false}
|
||||
onClick={() => this._showDeprecated(true)}
|
||||
label={<Trans>Show deprecated (old) behaviors</Trans>}
|
||||
/>
|
||||
) : (
|
||||
<FlatButton
|
||||
key="toggle-experimental"
|
||||
icon={<VisibilityOff />}
|
||||
primary={false}
|
||||
onClick={() => this._showDeprecated(false)}
|
||||
label={<Trans>Show deprecated (old) behaviors</Trans>}
|
||||
/>
|
||||
)}
|
||||
</Line>
|
||||
</Tab>
|
||||
<Tab label={<Trans>Search New Behaviors</Trans>} value="search">
|
||||
<ExtensionsSearch
|
||||
project={project}
|
||||
onNewExtensionInstalled={this._onNewExtensionInstalled}
|
||||
/>
|
||||
) : (
|
||||
<FlatButton
|
||||
key="toggle-experimental"
|
||||
icon={<VisibilityOff />}
|
||||
primary={false}
|
||||
onClick={() => this._showDeprecated(false)}
|
||||
label={<Trans>Show deprecated (old) behaviors</Trans>}
|
||||
/>
|
||||
)}
|
||||
</Line>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</Dialog>
|
||||
)}
|
||||
</I18n>
|
||||
|
57
newIDE/app/src/ExtensionsSearch/ExtensionInstallDialog.js
Normal file
57
newIDE/app/src/ExtensionsSearch/ExtensionInstallDialog.js
Normal file
@@ -0,0 +1,57 @@
|
||||
// @flow
|
||||
import { Trans } from '@lingui/macro';
|
||||
import React, { Component } from 'react';
|
||||
import Dialog from '../UI/Dialog';
|
||||
import FlatButton from 'material-ui/FlatButton';
|
||||
import { type ExtensionShortHeader } from '../Utils/GDevelopServices/Extension';
|
||||
import LeftLoader from '../UI/LeftLoader';
|
||||
|
||||
type Props = {|
|
||||
extensionShortHeader: ExtensionShortHeader,
|
||||
isInstalling: boolean,
|
||||
onClose: () => void,
|
||||
onInstall: (type: string, defaultName: string) => void,
|
||||
|};
|
||||
type State = {||};
|
||||
|
||||
export default class ExtensionInstallDialog extends Component<Props, State> {
|
||||
// TODO: Load extension full header
|
||||
render() {
|
||||
const {
|
||||
isInstalling,
|
||||
extensionShortHeader,
|
||||
onClose,
|
||||
onInstall,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
title={extensionShortHeader.fullName}
|
||||
actions={[
|
||||
<FlatButton
|
||||
key="close"
|
||||
label={<Trans>Back</Trans>}
|
||||
primary={false}
|
||||
onClick={onClose}
|
||||
disabled={isInstalling}
|
||||
/>,
|
||||
<LeftLoader isLoading={isInstalling}>
|
||||
<FlatButton
|
||||
key="install"
|
||||
label={<Trans>Install in project</Trans>}
|
||||
primary
|
||||
onClick={onInstall}
|
||||
disabled={isInstalling}
|
||||
/>
|
||||
</LeftLoader>,
|
||||
]}
|
||||
open
|
||||
autoScrollBodyContent
|
||||
onRequestClose={onClose}
|
||||
>
|
||||
{extensionShortHeader.shortDescription}
|
||||
TODO: Display full description
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
}
|
201
newIDE/app/src/ExtensionsSearch/index.js
Normal file
201
newIDE/app/src/ExtensionsSearch/index.js
Normal file
@@ -0,0 +1,201 @@
|
||||
// @flow
|
||||
import { t } from '@lingui/macro';
|
||||
import { Trans } from '@lingui/macro';
|
||||
import { I18n } from '@lingui/react';
|
||||
import { type I18n as I18nType } from '@lingui/core';
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import SearchBar from 'material-ui-search-bar';
|
||||
import {
|
||||
getExtensionsRegistry,
|
||||
type ExtensionsRegistry,
|
||||
type ExtensionShortHeader,
|
||||
type SerializedExtension,
|
||||
getExtension,
|
||||
} from '../Utils/GDevelopServices/Extension';
|
||||
import { List, ListItem } from 'material-ui/List';
|
||||
import PlaceholderLoader from '../UI/PlaceholderLoader';
|
||||
import ExtensionInstallDialog from './ExtensionInstallDialog';
|
||||
import { unserializeFromJSObject } from '../Utils/Serializer';
|
||||
import { showErrorBox } from '../UI/Messages/MessageBox';
|
||||
|
||||
type Props = {|
|
||||
project: gdProject,
|
||||
onNewExtensionInstalled: () => void,
|
||||
|};
|
||||
type State = {|
|
||||
isInstalling: boolean,
|
||||
selectedExtensionShortHeader: ?ExtensionShortHeader,
|
||||
searchText: string,
|
||||
extensionsRegistry: ?ExtensionsRegistry,
|
||||
|};
|
||||
|
||||
// TODO: Factor this?
|
||||
const styles = {
|
||||
icon: { width: 40, height: 40 },
|
||||
disabledItem: { opacity: 0.6 },
|
||||
};
|
||||
|
||||
const addSerializedExtensionToProject = (
|
||||
project: gdProject,
|
||||
serializedExtension: SerializedExtension
|
||||
) => {
|
||||
const newEventsFunctionsExtension = project.insertNewEventsFunctionsExtension(
|
||||
serializedExtension.name,
|
||||
0
|
||||
);
|
||||
|
||||
unserializeFromJSObject(
|
||||
newEventsFunctionsExtension,
|
||||
serializedExtension,
|
||||
'unserializeFrom',
|
||||
project
|
||||
);
|
||||
// TODO: Refresh project extensions
|
||||
};
|
||||
|
||||
export default class ExtensionsSearch extends Component<Props, State> {
|
||||
state = {
|
||||
isInstalling: false,
|
||||
extensionsRegistry: null,
|
||||
selectedExtensionShortHeader: null,
|
||||
searchText: '',
|
||||
};
|
||||
_searchBar = React.createRef<SearchBar>();
|
||||
|
||||
componentDidMount() {
|
||||
getExtensionsRegistry().then(
|
||||
extensionsRegistry => {
|
||||
this.setState({
|
||||
extensionsRegistry,
|
||||
});
|
||||
},
|
||||
error => {
|
||||
// handle error
|
||||
}
|
||||
);
|
||||
|
||||
// TODO: move this to componentDidUpdate
|
||||
setTimeout(() => {
|
||||
if (this._searchBar.current) this._searchBar.current.focus();
|
||||
}, 20 /* Be sure that the search bar is shown */);
|
||||
}
|
||||
|
||||
_install = (i18n: I18nType, extensionShortHeader: ExtensionShortHeader) => {
|
||||
const { project } = this.props;
|
||||
|
||||
this.setState({
|
||||
isInstalling: true,
|
||||
});
|
||||
getExtension(extensionShortHeader)
|
||||
.then(
|
||||
serializedExtension => {
|
||||
addSerializedExtensionToProject(project, serializedExtension);
|
||||
this.setState({
|
||||
selectedExtensionShortHeader: null,
|
||||
});
|
||||
// TODO: Display newly added behaviors
|
||||
// Use context to get functions to reload extensions.
|
||||
this.props.onNewExtensionInstalled();
|
||||
},
|
||||
err => {
|
||||
// handle error
|
||||
showErrorBox(
|
||||
i18n._(
|
||||
t`Unable to load the extension. Verify that your internet connection is up, and try again later.`
|
||||
),
|
||||
err
|
||||
);
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
this.setState({
|
||||
isInstalling: false,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { project } = this.props;
|
||||
const {
|
||||
selectedExtensionShortHeader,
|
||||
extensionsRegistry,
|
||||
searchText,
|
||||
isInstalling,
|
||||
} = this.state;
|
||||
|
||||
return (
|
||||
<I18n>
|
||||
{({ i18n }) => (
|
||||
<React.Fragment>
|
||||
<SearchBar
|
||||
value={searchText}
|
||||
onRequestSearch={() => {
|
||||
//TODO: filtering
|
||||
}}
|
||||
onChange={searchText =>
|
||||
this.setState({
|
||||
searchText,
|
||||
})
|
||||
}
|
||||
ref={this._searchBar}
|
||||
/>
|
||||
<List>
|
||||
{!extensionsRegistry && <PlaceholderLoader />}
|
||||
{!!extensionsRegistry &&
|
||||
extensionsRegistry.extensionShortHeaders.map(
|
||||
extensionShortHeader => {
|
||||
const alreadyInstalled = project.hasEventsFunctionsExtensionNamed(
|
||||
extensionShortHeader.name
|
||||
);
|
||||
const disabled = alreadyInstalled;
|
||||
|
||||
return (
|
||||
<ListItem
|
||||
key={extensionShortHeader.name}
|
||||
primaryText={
|
||||
<span>
|
||||
{extensionShortHeader.fullName}{' '}
|
||||
{alreadyInstalled && (
|
||||
<Trans> (already installed)</Trans>
|
||||
)}
|
||||
</span>
|
||||
}
|
||||
secondaryText={
|
||||
<p>{extensionShortHeader.shortDescription}</p>
|
||||
}
|
||||
secondaryTextLines={2}
|
||||
onClick={() =>
|
||||
this.setState({
|
||||
selectedExtensionShortHeader: extensionShortHeader,
|
||||
})
|
||||
}
|
||||
style={disabled ? styles.disabledItem : undefined}
|
||||
disabled={disabled}
|
||||
/>
|
||||
);
|
||||
}
|
||||
)
|
||||
//TODO: Button to create a new extension
|
||||
}
|
||||
</List>
|
||||
{!!selectedExtensionShortHeader && (
|
||||
<ExtensionInstallDialog
|
||||
isInstalling={isInstalling}
|
||||
extensionShortHeader={selectedExtensionShortHeader}
|
||||
onInstall={() =>
|
||||
this._install(i18n, selectedExtensionShortHeader)
|
||||
}
|
||||
onClose={() =>
|
||||
this.setState({
|
||||
selectedExtensionShortHeader: null,
|
||||
})
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</React.Fragment>
|
||||
)}
|
||||
</I18n>
|
||||
);
|
||||
}
|
||||
}
|
@@ -283,6 +283,7 @@ class MainFrame extends React.Component<Props, State> {
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: Move this to a provider, take currentProject as parameter
|
||||
_loadProjectEventsFunctionsExtensions = () => {
|
||||
const { i18n } = this.props;
|
||||
if (this.props.eventsFunctionWriter && this.state.currentProject) {
|
||||
|
@@ -501,6 +501,7 @@ export default class ProjectManager extends React.Component<Props, State> {
|
||||
newEventsFunctionsExtension.setName(newName);
|
||||
|
||||
this.forceUpdate();
|
||||
this.props.onReloadEventsFunctionsExtensions();
|
||||
};
|
||||
|
||||
_moveUpEventsFunctionsExtension = (index: number) => {
|
||||
|
@@ -2,6 +2,10 @@
|
||||
import * as React from 'react';
|
||||
import CircularProgress from 'material-ui/CircularProgress';
|
||||
|
||||
const styles = {
|
||||
progress: { marginRight: 8, verticalAlign: 'middle' },
|
||||
};
|
||||
|
||||
export default ({
|
||||
children,
|
||||
isLoading,
|
||||
@@ -9,8 +13,8 @@ export default ({
|
||||
children: React.Node,
|
||||
isLoading: ?boolean,
|
||||
}) => (
|
||||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||
{isLoading && <CircularProgress size={20} style={{ marginRight: 5 }} />}
|
||||
<span>
|
||||
{isLoading && <CircularProgress size={20} style={styles.progress} />}
|
||||
{children}
|
||||
</div>
|
||||
</span>
|
||||
);
|
||||
|
@@ -2,6 +2,10 @@
|
||||
import * as React from 'react';
|
||||
import CircularProgress from 'material-ui/CircularProgress';
|
||||
|
||||
const styles = {
|
||||
progress: { marginLeft: 8, verticalAlign: 'middle' },
|
||||
};
|
||||
|
||||
export default ({
|
||||
children,
|
||||
isLoading,
|
||||
@@ -9,8 +13,8 @@ export default ({
|
||||
children: React.Node,
|
||||
isLoading: ?boolean,
|
||||
}) => (
|
||||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<span>
|
||||
{children}
|
||||
{isLoading && <CircularProgress size={20} style={{ marginLeft: 5 }} />}
|
||||
</div>
|
||||
{isLoading && <CircularProgress size={20} style={styles.progress} />}
|
||||
</span>
|
||||
);
|
||||
|
@@ -75,3 +75,9 @@ export const GDevelopReleaseApi = {
|
||||
? 'https://c8cldf4iqh.execute-api.us-east-1.amazonaws.com/dev'
|
||||
: 'https://api.gdevelop-app.com/release',
|
||||
};
|
||||
|
||||
export const GDevelopExtensionApi = {
|
||||
baseUrl: isDev
|
||||
? 'https://raw.githubusercontent.com/4ian/GDevelop-extensions/master'
|
||||
: 'https://raw.githubusercontent.com/4ian/GDevelop-extensions/master',
|
||||
};
|
||||
|
47
newIDE/app/src/Utils/GDevelopServices/Extension.js
Normal file
47
newIDE/app/src/Utils/GDevelopServices/Extension.js
Normal file
@@ -0,0 +1,47 @@
|
||||
// @flow
|
||||
import axios from 'axios';
|
||||
import { GDevelopExtensionApi } from './ApiConfigs';
|
||||
|
||||
export type ExtensionShortHeader = {|
|
||||
shortDescription: string,
|
||||
extensionNamespace: string,
|
||||
fullName: string,
|
||||
name: string,
|
||||
version: string,
|
||||
url: string,
|
||||
headerUrl: string,
|
||||
|};
|
||||
export type ExtensionHeader = {|
|
||||
...ExtensionShortHeader,
|
||||
description: string,
|
||||
|};
|
||||
|
||||
export type SerializedExtension = {
|
||||
...ExtensionHeader,
|
||||
}
|
||||
|
||||
export type ExtensionsRegistry = {
|
||||
version: string,
|
||||
extensionShortHeaders: Array<ExtensionShortHeader>,
|
||||
};
|
||||
|
||||
export const getExtensionsRegistry = (): Promise<ExtensionsRegistry> => {
|
||||
// TODO: Caching for a few minutes/hours?
|
||||
return axios
|
||||
.get(`${GDevelopExtensionApi.baseUrl}/extensions-registry.json`)
|
||||
.then(response => response.data);
|
||||
};
|
||||
|
||||
export const getExtensionHeader = (extensionShortHeader: ExtensionShortHeader): Promise<ExtensionHeader> => {
|
||||
// TODO: Handle absolute urls?
|
||||
return axios
|
||||
.get(`${GDevelopExtensionApi.baseUrl}/${extensionShortHeader.headerUrl}`)
|
||||
.then(response => response.data);
|
||||
};
|
||||
|
||||
export const getExtension = (extensionHeader: ExtensionShortHeader | ExtensionHeader): Promise<SerializedExtension> => {
|
||||
// TODO: Handle absolute urls?
|
||||
return axios
|
||||
.get(`${GDevelopExtensionApi.baseUrl}/${extensionHeader.url}`)
|
||||
.then(response => response.data);
|
||||
};
|
@@ -124,6 +124,7 @@ import EventsBasedBehaviorEditor from '../EventsBasedBehaviorEditor';
|
||||
import EventsBasedBehaviorEditorDialog from '../EventsBasedBehaviorEditor/EventsBasedBehaviorEditorDialog';
|
||||
import BehaviorTypeSelector from '../BehaviorTypeSelector';
|
||||
import ObjectTypeSelector from '../ObjectTypeSelector';
|
||||
import NewBehaviorDialog from '../BehaviorsEditor/NewBehaviorDialog';
|
||||
|
||||
// No i18n in this file
|
||||
|
||||
@@ -2083,3 +2084,16 @@ storiesOf('ObjectTypeSelector', module)
|
||||
onChange={action('change')}
|
||||
/>
|
||||
));
|
||||
|
||||
storiesOf('NewBehaviorDialog', module)
|
||||
.addDecorator(muiDecorator)
|
||||
.addDecorator(i18nProviderDecorator)
|
||||
.add('default, for a Sprite object', () => (
|
||||
<NewBehaviorDialog
|
||||
open
|
||||
project={project}
|
||||
objectType={'Sprite'}
|
||||
onClose={action('on close')}
|
||||
onChoose={action('on choose')}
|
||||
/>
|
||||
));
|
||||
|
Reference in New Issue
Block a user