summaryrefslogtreecommitdiffstats
path: root/sdnr/wt/odlux/apps/demoApp/src
diff options
context:
space:
mode:
Diffstat (limited to 'sdnr/wt/odlux/apps/demoApp/src')
-rw-r--r--sdnr/wt/odlux/apps/demoApp/src/actions/authorActions.ts34
-rw-r--r--sdnr/wt/odlux/apps/demoApp/src/components/counter.tsx17
-rw-r--r--sdnr/wt/odlux/apps/demoApp/src/handlers/demoAppRootHandler.ts26
-rw-r--r--sdnr/wt/odlux/apps/demoApp/src/handlers/editAuthorHandler.ts16
-rw-r--r--sdnr/wt/odlux/apps/demoApp/src/handlers/listAuthorsHandler.ts40
-rw-r--r--sdnr/wt/odlux/apps/demoApp/src/index.html25
-rw-r--r--sdnr/wt/odlux/apps/demoApp/src/models/author.ts19
-rw-r--r--sdnr/wt/odlux/apps/demoApp/src/plugin.tsx37
-rw-r--r--sdnr/wt/odlux/apps/demoApp/src/services/authorService.ts55
-rw-r--r--sdnr/wt/odlux/apps/demoApp/src/views/authorsList.tsx70
-rw-r--r--sdnr/wt/odlux/apps/demoApp/src/views/editAuthor.tsx17
11 files changed, 356 insertions, 0 deletions
diff --git a/sdnr/wt/odlux/apps/demoApp/src/actions/authorActions.ts b/sdnr/wt/odlux/apps/demoApp/src/actions/authorActions.ts
new file mode 100644
index 000000000..9ce1d59ba
--- /dev/null
+++ b/sdnr/wt/odlux/apps/demoApp/src/actions/authorActions.ts
@@ -0,0 +1,34 @@
+import { Action } from '../../../../framework/src/flux/action';
+import { Dispatch } from '../../../../framework/src/flux/store';
+import { AddErrorInfoAction } from '../../../../framework/src/actions/errorActions';
+
+import { IAuthor } from '../models/author';
+import { authorService } from '../services/authorService';
+
+export class ApplicationBaseAction extends Action { }
+
+
+export class LoadAllAuthorsAction extends ApplicationBaseAction {
+ constructor() {
+ super();
+ }
+}
+
+// in React Action is most times a Message
+export class AllAuthorsLoadedAction extends ApplicationBaseAction {
+ constructor(public authors: IAuthor[] | null, public error?: string) {
+ super();
+
+ }
+}
+
+export const loadAllAuthorsAsync = (dispatch: Dispatch) => {
+ dispatch(new LoadAllAuthorsAction());
+ authorService.getAllAuthors().then(authors => {
+ dispatch(new AllAuthorsLoadedAction(authors));
+ }, error => {
+ dispatch(new AllAuthorsLoadedAction(null, error));
+ dispatch(new AddErrorInfoAction(error));
+ });
+}
+
diff --git a/sdnr/wt/odlux/apps/demoApp/src/components/counter.tsx b/sdnr/wt/odlux/apps/demoApp/src/components/counter.tsx
new file mode 100644
index 000000000..30f7281bb
--- /dev/null
+++ b/sdnr/wt/odlux/apps/demoApp/src/components/counter.tsx
@@ -0,0 +1,17 @@
+import * as React from 'react';
+
+export class Counter extends React.Component<{}, { counter: number }> {
+ constructor(props: {}) {
+ super(props);
+
+ this.state = {
+ counter: 0
+ };
+ }
+
+ render() {
+ return (
+ <button onClick={ () => this.setState({ counter: this.state.counter + 1 }) }>{ this.state.counter }</button>
+ )
+ }
+} \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/demoApp/src/handlers/demoAppRootHandler.ts b/sdnr/wt/odlux/apps/demoApp/src/handlers/demoAppRootHandler.ts
new file mode 100644
index 000000000..ee21a9c90
--- /dev/null
+++ b/sdnr/wt/odlux/apps/demoApp/src/handlers/demoAppRootHandler.ts
@@ -0,0 +1,26 @@
+
+import { combineActionHandler } from '../../../../framework/src/flux/middleware';
+
+import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
+
+import { listAuthorsHandler, IListAuthors } from './listAuthorsHandler';
+import { editAuthorHandler, IEditAuthor } from './editAuthorHandler';
+
+export interface IDemoAppStoreState {
+ listAuthors: IListAuthors;
+ editAuthor: IEditAuthor;
+}
+
+declare module '../../../../framework/src/store/applicationStore' {
+ interface IApplicationStoreState {
+ demoApp: IDemoAppStoreState
+ }
+}
+
+const actionHandlers = {
+ listAuthors: listAuthorsHandler,
+ editAuthor: editAuthorHandler,
+};
+
+export const demoAppRootHandler = combineActionHandler <IDemoAppStoreState>(actionHandlers);
+export default demoAppRootHandler;
diff --git a/sdnr/wt/odlux/apps/demoApp/src/handlers/editAuthorHandler.ts b/sdnr/wt/odlux/apps/demoApp/src/handlers/editAuthorHandler.ts
new file mode 100644
index 000000000..2f00b0d20
--- /dev/null
+++ b/sdnr/wt/odlux/apps/demoApp/src/handlers/editAuthorHandler.ts
@@ -0,0 +1,16 @@
+import { IActionHandler } from '../../../../framework/src/flux/action';
+
+import { IAuthor } from '../models/author';
+export interface IEditAuthor {
+ author: IAuthor | null;
+ isDirty: boolean;
+}
+
+const editAuthorInit: IEditAuthor = {
+ author: null,
+ isDirty: false
+};
+
+export const editAuthorHandler: IActionHandler<IEditAuthor> = (state = editAuthorInit, action) => {
+ return state;
+};
diff --git a/sdnr/wt/odlux/apps/demoApp/src/handlers/listAuthorsHandler.ts b/sdnr/wt/odlux/apps/demoApp/src/handlers/listAuthorsHandler.ts
new file mode 100644
index 000000000..74228ddb8
--- /dev/null
+++ b/sdnr/wt/odlux/apps/demoApp/src/handlers/listAuthorsHandler.ts
@@ -0,0 +1,40 @@
+import { IActionHandler } from '../../../../framework/src/flux/action';
+
+import { IAuthor } from '../models/author';
+import { LoadAllAuthorsAction, AllAuthorsLoadedAction } from '../actions/authorActions';
+
+export interface IListAuthors {
+ authors: IAuthor[];
+ busy: boolean;
+}
+
+const listAuthorsInit: IListAuthors = {
+ authors: [],
+ busy: false
+};
+
+export const listAuthorsHandler: IActionHandler<IListAuthors> = (state = listAuthorsInit, action) => {
+ if (action instanceof LoadAllAuthorsAction) {
+
+ state = {
+ ...state,
+ busy: true
+ };
+
+ } else if (action instanceof AllAuthorsLoadedAction) {
+ if (!action.error && action.authors) {
+ state = {
+ ...state,
+ authors: action.authors,
+ busy: false
+ };
+ } else {
+ state = {
+ ...state,
+ busy: false
+ };
+ }
+ }
+
+ return state;
+}; \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/demoApp/src/index.html b/sdnr/wt/odlux/apps/demoApp/src/index.html
new file mode 100644
index 000000000..e85bcbb03
--- /dev/null
+++ b/sdnr/wt/odlux/apps/demoApp/src/index.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta http-equiv="X-UA-Compatible" content="ie=edge">
+ <!-- <link rel="stylesheet" href="./vendor.css" > -->
+ <title>Demo App</title>
+</head>
+
+<body>
+ <div id="app"></div>
+ <script type="text/javascript" src="./require.js"></script>
+ <script type="text/javascript" src="./config.js"></script>
+ <script>
+ // run the application
+ require(["app","demoApp"], function (app, demoApp) {
+ demoApp.register();
+ app("./app.tsx");
+ });
+ </script>
+</body>
+
+</html> \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/demoApp/src/models/author.ts b/sdnr/wt/odlux/apps/demoApp/src/models/author.ts
new file mode 100644
index 000000000..7e28ae8aa
--- /dev/null
+++ b/sdnr/wt/odlux/apps/demoApp/src/models/author.ts
@@ -0,0 +1,19 @@
+/**
+ * Represents an author.
+ */
+export interface IAuthor {
+ /**
+ * Defines the unique id of the autor.
+ */
+ id: number;
+
+ /**
+ * Defines the first name of this author.
+ */
+ firstName: string;
+
+ /**
+ * Defines the last name of this author.
+ */
+ lastName: string;
+}
diff --git a/sdnr/wt/odlux/apps/demoApp/src/plugin.tsx b/sdnr/wt/odlux/apps/demoApp/src/plugin.tsx
new file mode 100644
index 000000000..f450275c2
--- /dev/null
+++ b/sdnr/wt/odlux/apps/demoApp/src/plugin.tsx
@@ -0,0 +1,37 @@
+import * as React from "react";
+import { withRouter, RouteComponentProps, Route, Switch, Redirect } from 'react-router-dom';
+
+import { faAddressBook, faRegistered } from '@fortawesome/free-solid-svg-icons';
+
+import applicationManager from '../../../framework/src/services/applicationManager';
+import connect, { Connect } from '../../../framework/src/flux/connect';
+
+import { demoAppRootHandler } from './handlers/demoAppRootHandler';
+
+import AuthorsList from './views/authorsList';
+import EditAuthor from './views/editAuthor';
+
+import { Counter } from './components/counter';
+
+type AppProps = RouteComponentProps & Connect;
+
+const App = (props: AppProps) => (
+ <Switch>
+ <Route exact path={ `${ props.match.path }/authors` } component={AuthorsList} />
+ <Route path={ `${ props.match.path }/authors/:authorId` } component={EditAuthor } />
+ <Redirect to={ `${ props.match.path }/authors` } />
+ </Switch>
+);
+
+const FinalApp = withRouter(connect()(App));
+
+export function register() {
+ const applicationApi = applicationManager.registerApplication({
+ name: "demoApp",
+ icon: faAddressBook,
+ rootComponent: FinalApp,
+ rootActionHandler: demoAppRootHandler,
+ exportedComponents: { counter: Counter },
+ menuEntry: "Demo App"
+ });
+}
diff --git a/sdnr/wt/odlux/apps/demoApp/src/services/authorService.ts b/sdnr/wt/odlux/apps/demoApp/src/services/authorService.ts
new file mode 100644
index 000000000..d266f6b3e
--- /dev/null
+++ b/sdnr/wt/odlux/apps/demoApp/src/services/authorService.ts
@@ -0,0 +1,55 @@
+import { IAuthor } from '../models/author';
+
+import * as $ from 'jquery';
+
+const base_url = 'https://api.mfico.de/v1/authors';
+
+/**
+ * Represents a web api accessor service for all author related actions.
+ */
+class AuthorService {
+
+ /**
+ * Gets all known authors from the backend.
+ * @returns A promise of the type array of @see {@link IAuthor} containing all known authors.
+ */
+ public getAllAuthors(): Promise<IAuthor[]> {
+ return new Promise((resolve: (value: IAuthor[]) => void, reject: (err: any) => void) => {
+ $.ajax({ method: "GET", url: base_url })
+ .then((data) => { resolve(data); }, (err) => { reject(err) });
+ });
+ }
+
+ /**
+ * Gets an author by its id from the backend.
+ * @returns A promise of the type @see {@link IAuthor} containing the author to get.
+ */
+ public getAuthorById(id: string | number): Promise<IAuthor> {
+ return new Promise((resolve: (value: IAuthor) => void, reject: (err: any) => void) => {
+ $.ajax({ method: "GET", url: base_url + "/" + id })
+ .then((data) => { resolve(data); }, (err) => { reject(err) });
+ });
+ }
+
+
+/**
+ * Saves the given author to the backend api.
+ * @returns A promise of the type @see {@link IAuthor} containing the autor returned by the backend api.
+ */
+ public saveAuthor(author: IAuthor): Promise<IAuthor> {
+ return new Promise((resolve: (value: IAuthor) => void, reject: (err: any) => void) => {
+ // simulate server save
+ window.setTimeout(() => {
+ if (Math.random() > 0.8) {
+ reject("Could not save author.");
+ } else {
+ resolve(author);
+ }
+ }, 800); // simulate a short network delay
+ });
+ }
+}
+
+// return as a singleton
+export const authorService = new AuthorService();
+export default authorService;
diff --git a/sdnr/wt/odlux/apps/demoApp/src/views/authorsList.tsx b/sdnr/wt/odlux/apps/demoApp/src/views/authorsList.tsx
new file mode 100644
index 000000000..b192fccf8
--- /dev/null
+++ b/sdnr/wt/odlux/apps/demoApp/src/views/authorsList.tsx
@@ -0,0 +1,70 @@
+import * as React from 'react';
+import { withRouter, RouteComponentProps } from 'react-router-dom';
+
+import Table from '@material-ui/core/Table';
+import TableBody from '@material-ui/core/TableBody';
+import TableCell from '@material-ui/core/TableCell';
+import TableHead from '@material-ui/core/TableHead';
+import TableRow from '@material-ui/core/TableRow';
+import Paper from '@material-ui/core/Paper'; // means border
+
+import connect from '../../../../framework/src/flux/connect';
+
+import { loadAllAuthorsAsync } from '../actions/authorActions';
+import { IAuthor } from '../models/author';
+
+interface IAuthorsListProps {
+ authors: IAuthor[],
+ busy: boolean,
+ onLoadAllAuthors: () => void
+}
+
+class AuthorsListComponent extends React.Component<RouteComponentProps & IAuthorsListProps> {
+
+ render(): JSX.Element {
+ const { authors, busy } = this.props;
+ return (
+ <Paper>
+ <Table >
+ <TableHead>
+ <TableRow>
+ <TableCell numeric>Id</TableCell>
+ <TableCell >First Name</TableCell>
+ <TableCell >Last Name</TableCell>
+ </TableRow>
+ </TableHead>
+ <TableBody>
+ { authors.map(author => (
+ <TableRow key={ author.id } onClick={ (e) => this.editAuthor(author) }>
+ <TableCell>{ author.id }</TableCell>
+ <TableCell>{ author.firstName }</TableCell>
+ <TableCell>{ author.lastName }</TableCell>
+ </TableRow>
+ )) }
+ </TableBody>
+ </Table>
+ </Paper>
+ );
+ };
+
+ public componentDidMount() {
+ this.props.onLoadAllAuthors();
+ }
+
+ private editAuthor = (author: IAuthor) => {
+ author && this.props.history.push(this.props.match.path + '/' + author.id);
+ };
+}
+
+export const AuthorsList = withRouter(
+ connect(
+ ({ demoApp: state }) => ({
+ authors: state.listAuthors.authors,
+ busy: state.listAuthors.busy
+ }),
+ (dispatcher) => ({
+ onLoadAllAuthors: () => {
+ dispatcher.dispatch(loadAllAuthorsAsync)
+ }
+ }))(AuthorsListComponent));
+export default AuthorsList;
diff --git a/sdnr/wt/odlux/apps/demoApp/src/views/editAuthor.tsx b/sdnr/wt/odlux/apps/demoApp/src/views/editAuthor.tsx
new file mode 100644
index 000000000..31bfafc75
--- /dev/null
+++ b/sdnr/wt/odlux/apps/demoApp/src/views/editAuthor.tsx
@@ -0,0 +1,17 @@
+import * as React from 'react';
+import { withRouter, RouteComponentProps } from 'react-router-dom';
+
+type EditAuthorProps = RouteComponentProps<{ authorId: string}>;
+
+class EditAuthorComponent extends React.Component<EditAuthorProps> {
+ render(): JSX.Element {
+ return (
+ <div>
+ <h2>Edit Author { this.props.match.params.authorId }</h2>
+ </div>
+ )
+ }
+}
+
+export const EditAuthor = withRouter(EditAuthorComponent);
+export default EditAuthor; \ No newline at end of file