forked from community/device-mgt-core
commit
a79b600922
@ -0,0 +1,157 @@
|
||||
/* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
|
||||
*
|
||||
* Entgra (Pvt) Ltd. licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.wso2.carbon.device.application.mgt.core.lifecycle;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.wso2.carbon.device.application.mgt.common.exception.LifecycleManagementException;
|
||||
import org.wso2.carbon.device.application.mgt.core.internal.DataHolder;
|
||||
import org.wso2.carbon.device.application.mgt.core.lifecycle.config.LifecycleState;
|
||||
import org.wso2.carbon.device.mgt.common.permission.mgt.PermissionManagementException;
|
||||
import org.wso2.carbon.device.mgt.core.permission.mgt.PermissionUtils;
|
||||
import org.wso2.carbon.device.mgt.core.search.mgt.Constants;
|
||||
import org.wso2.carbon.user.api.UserRealm;
|
||||
import org.wso2.carbon.user.api.UserStoreException;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* This class represents the activities related to lifecycle management
|
||||
*/
|
||||
public class LifecycleStateManager {
|
||||
|
||||
private Map<String, State> lifecycleStates;
|
||||
private static Log log = LogFactory.getLog(LifecycleStateManager.class);
|
||||
|
||||
public void init(List<LifecycleState> states) throws LifecycleManagementException {
|
||||
lifecycleStates = new HashMap<>();
|
||||
for (LifecycleState s : states) {
|
||||
if (s.getProceedingStates() != null) {
|
||||
s.getProceedingStates().replaceAll(String::toUpperCase);
|
||||
}
|
||||
lifecycleStates.put(s.getName().toUpperCase(), new State(s.getName().toUpperCase(),
|
||||
s.getProceedingStates(), s.getPermission(), s.isAppUpdatable(), s.isAppInstallable(),
|
||||
s.isInitialState(), s.isEndState()));
|
||||
try {
|
||||
PermissionUtils.putPermission(s.getPermission());
|
||||
} catch (PermissionManagementException e) {
|
||||
String msg = "Error when adding permission " + s.getPermission() + " related to the state: "
|
||||
+ s.getName();
|
||||
log.error(msg, e);
|
||||
throw new LifecycleManagementException(msg, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Set<String> getNextLifecycleStates(String currentLifecycleState) {
|
||||
return lifecycleStates.get(currentLifecycleState.toUpperCase()).getProceedingStates();
|
||||
}
|
||||
|
||||
public boolean isValidStateChange(String currentState, String nextState, String username, int tenantId) throws
|
||||
LifecycleManagementException {
|
||||
|
||||
UserRealm userRealm;
|
||||
String permission = getPermissionForStateChange(nextState);
|
||||
if (permission != null) {
|
||||
try {
|
||||
userRealm = DataHolder.getInstance().getRealmService().getTenantUserRealm(tenantId);
|
||||
if (userRealm != null && userRealm.getAuthorizationManager() != null &&
|
||||
userRealm.getAuthorizationManager().isUserAuthorized(username,
|
||||
PermissionUtils.getAbsolutePermissionPath(permission),
|
||||
Constants.UI_EXECUTE)) {
|
||||
if (currentState.equalsIgnoreCase(nextState)) {
|
||||
return true;
|
||||
}
|
||||
State state = getMatchingState(currentState);
|
||||
if (state != null) {
|
||||
return getMatchingNextState(state.getProceedingStates(), nextState);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
} catch (UserStoreException e) {
|
||||
throw new LifecycleManagementException(
|
||||
"UserStoreException exception from changing the state from : " + currentState + " to: "
|
||||
+ nextState + " with username : " + username + " and tenant Id : " + tenantId, e);
|
||||
}
|
||||
} else {
|
||||
throw new LifecycleManagementException(
|
||||
"Required permissions cannot be found for the state : " + nextState);
|
||||
}
|
||||
}
|
||||
|
||||
private State getMatchingState(String currentState) {
|
||||
Iterator it = lifecycleStates.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry pair = (Map.Entry) it.next();
|
||||
if (pair.getKey().toString().equalsIgnoreCase(currentState)) {
|
||||
return lifecycleStates.get(pair.getKey().toString());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private boolean getMatchingNextState(Set<String> proceedingStates, String nextState) {
|
||||
for (String state : proceedingStates) {
|
||||
if (state.equalsIgnoreCase(nextState)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private String getPermissionForStateChange(String nextState) {
|
||||
Iterator it = lifecycleStates.entrySet().iterator();
|
||||
State nextLifecycleState;
|
||||
while (it.hasNext()) {
|
||||
Map.Entry pair = (Map.Entry) it.next();
|
||||
if (pair.getKey().toString().equalsIgnoreCase(nextState)) {
|
||||
nextLifecycleState = lifecycleStates.get(nextState);
|
||||
return nextLifecycleState.getPermission();
|
||||
}
|
||||
it.remove();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isUpdatable(String state) {
|
||||
State currentState = getMatchingState(state);
|
||||
if (currentState.getIsAppUpdatable()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isInstallable(String state) {
|
||||
State currentState = getMatchingState(state);
|
||||
if (currentState.getIsAppInstallable()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setLifecycleStates(Map<String, State> lifecycleStates) {
|
||||
this.lifecycleStates = lifecycleStates;
|
||||
}
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
package org.wso2.carbon.device.application.mgt.core.lifecycle;
|
||||
|
||||
import org.wso2.carbon.device.application.mgt.core.lifecycle.config.LifecycleState;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* This class represents the activities related to lifecycle management
|
||||
*/
|
||||
public class LifecycleStateManger {
|
||||
|
||||
private Map<String, State> lifecycleStates;
|
||||
|
||||
public void init(List<LifecycleState> states){
|
||||
lifecycleStates = new HashMap<>();
|
||||
for (LifecycleState s : states) {
|
||||
if (s.getProceedingStates() != null) {
|
||||
s.getProceedingStates().replaceAll(String::toUpperCase);
|
||||
}
|
||||
lifecycleStates.put(s.getName().toUpperCase(), new State(s.getName().toUpperCase(), s.getProceedingStates()));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public Set<String> getNextLifecycleStates(String currentLifecycleState) {
|
||||
return lifecycleStates.get(currentLifecycleState.toUpperCase()).getProceedingStates();
|
||||
}
|
||||
|
||||
public boolean isValidStateChange(String currentState, String nextState) {
|
||||
if (currentState.equalsIgnoreCase(nextState)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
State state = getMatchingState(currentState);
|
||||
if (state != null) {
|
||||
return getMatchingNextState(state.getProceedingStates(), nextState);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private State getMatchingState(String currentState) {
|
||||
Iterator it = lifecycleStates.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry pair = (Map.Entry)it.next();
|
||||
if(pair.getKey().toString().equalsIgnoreCase(currentState)) {
|
||||
return lifecycleStates.get(pair.getKey().toString());
|
||||
}
|
||||
it.remove();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean getMatchingNextState(Set<String> proceedingStates, String nextState) {
|
||||
|
||||
for (String state: proceedingStates) {
|
||||
if (state.equalsIgnoreCase(nextState)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package org.wso2.carbon.device.application.mgt.core;
|
||||
|
||||
import org.wso2.carbon.device.application.mgt.core.lifecycle.LifecycleStateManager;
|
||||
import org.wso2.carbon.device.application.mgt.core.lifecycle.State;
|
||||
import org.wso2.carbon.device.application.mgt.core.lifecycle.config.LifecycleState;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class LifeCycleStateManagerTest extends LifecycleStateManager {
|
||||
|
||||
public void initializeLifeCycleDetails(List<LifecycleState> states) {
|
||||
HashMap<String, State> lifecycleStates = new HashMap<>();
|
||||
for (LifecycleState s : states) {
|
||||
if (s.getProceedingStates() != null) {
|
||||
s.getProceedingStates().replaceAll(String::toUpperCase);
|
||||
}
|
||||
lifecycleStates.put(s.getName().toUpperCase(), new State(s.getName().toUpperCase(),
|
||||
s.getProceedingStates(), s.getPermission(), s.isAppUpdatable(), s.isAppInstallable(),
|
||||
s.isInitialState(), s.isEndState()));
|
||||
}
|
||||
setLifecycleStates(lifecycleStates);
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
import React from 'react';
|
||||
import {Route} from 'react-router-dom';
|
||||
class RouteWithSubRoutes extends React.Component{
|
||||
props;
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.props = props;
|
||||
}
|
||||
render() {
|
||||
return(
|
||||
<Route path={this.props.path} render={(props) => (
|
||||
<this.props.component {...props} routes={this.props.routes}/>
|
||||
)}/>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default RouteWithSubRoutes;
|
@ -1,3 +1,27 @@
|
||||
.App {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.ant-layout-header{
|
||||
padding: 0;
|
||||
height: auto;
|
||||
box-shadow: 0 2px 8px #f0f1f2;
|
||||
}
|
||||
|
||||
.steps-content {
|
||||
margin-top: 16px;
|
||||
border: 1px dashed #e9e9e9;
|
||||
border-radius: 6px;
|
||||
background-color: #fafafa;
|
||||
min-height: 200px;
|
||||
text-align: center;
|
||||
padding-top: 80px;
|
||||
}
|
||||
|
||||
.steps-action {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.ant-input-affix-wrapper .ant-input{
|
||||
min-height: 0;
|
||||
}
|
@ -1,7 +1,15 @@
|
||||
.logo {
|
||||
width: 120px;
|
||||
height: 31px;
|
||||
background: rgba(0,0,0,.2);
|
||||
margin: 16px 24px 16px 0;
|
||||
margin: 16px 0 16px 20px;
|
||||
float: left;
|
||||
|
||||
img{
|
||||
height: 35px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
input{
|
||||
min-height: 0;
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
import React from "react";
|
||||
import "antd/dist/antd.css";
|
||||
import {PageHeader, Typography, Card, Steps, Button, message, Row, Col} from "antd";
|
||||
import Step1 from "./Step1"
|
||||
import Step2 from "./Step2"
|
||||
import Step3 from "./Step3"
|
||||
|
||||
const Paragraph = Typography;
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: 'index',
|
||||
breadcrumbName: 'publisher',
|
||||
},
|
||||
{
|
||||
path: 'first',
|
||||
breadcrumbName: 'dashboard',
|
||||
},
|
||||
{
|
||||
path: 'second',
|
||||
breadcrumbName: 'add new app',
|
||||
},
|
||||
];
|
||||
|
||||
const Step = Steps.Step;
|
||||
|
||||
const steps = [{
|
||||
title: 'First',
|
||||
content: Step1
|
||||
}, {
|
||||
title: 'Second',
|
||||
content: Step2,
|
||||
}, {
|
||||
title: 'Last',
|
||||
content: Step3,
|
||||
}];
|
||||
|
||||
|
||||
class AddNewApp extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
current: 0,
|
||||
};
|
||||
}
|
||||
|
||||
next() {
|
||||
const current = this.state.current + 1;
|
||||
this.setState({current});
|
||||
}
|
||||
|
||||
prev() {
|
||||
const current = this.state.current - 1;
|
||||
this.setState({current});
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const {current} = this.state;
|
||||
const Content = steps[current].content;
|
||||
return (
|
||||
<div>
|
||||
<PageHeader
|
||||
title="Add New App"
|
||||
breadcrumb={{routes}}
|
||||
>
|
||||
<div className="wrap">
|
||||
<div className="content">
|
||||
<Paragraph>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempo.
|
||||
</Paragraph>
|
||||
</div>
|
||||
</div>
|
||||
</PageHeader>
|
||||
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
|
||||
<Row>
|
||||
<Col span={16} offset={4}>
|
||||
<Card>
|
||||
<div>
|
||||
<Steps current={current}>
|
||||
{steps.map(item => <Step key={item.title} title={item.title}/>)}
|
||||
</Steps>
|
||||
<Content/>
|
||||
<div className="steps-action">
|
||||
{
|
||||
current < steps.length - 1
|
||||
&& <Button type="primary" onClick={() => this.next()}>Next</Button>
|
||||
}
|
||||
{
|
||||
current === steps.length - 1
|
||||
&& <Button type="primary"
|
||||
onClick={() => message.success('Processing complete!')}>Done</Button>
|
||||
}
|
||||
{
|
||||
current > 0
|
||||
&& (
|
||||
<Button style={{marginLeft: 8}} onClick={() => this.prev()}>
|
||||
Previous
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default AddNewApp;
|
@ -0,0 +1,153 @@
|
||||
import React from "react";
|
||||
import {Form, Input, Button, Select, Divider, Tag, Tooltip, Icon, Checkbox, Row, Col} from "antd";
|
||||
import styles from './Style.less';
|
||||
|
||||
const { Option } = Select;
|
||||
const { TextArea } = Input;
|
||||
const InputGroup = Input.Group;
|
||||
|
||||
const formItemLayout = {
|
||||
labelCol: {
|
||||
span: 8,
|
||||
},
|
||||
wrapperCol: {
|
||||
span: 16,
|
||||
},
|
||||
};
|
||||
|
||||
class EditableTagGroup extends React.Component {
|
||||
state = {
|
||||
tags: [],
|
||||
inputVisible: false,
|
||||
inputValue: '',
|
||||
};
|
||||
|
||||
handleClose = (removedTag) => {
|
||||
const tags = this.state.tags.filter(tag => tag !== removedTag);
|
||||
console.log(tags);
|
||||
this.setState({ tags });
|
||||
}
|
||||
|
||||
showInput = () => {
|
||||
this.setState({ inputVisible: true }, () => this.input.focus());
|
||||
}
|
||||
|
||||
handleInputChange = (e) => {
|
||||
this.setState({ inputValue: e.target.value });
|
||||
}
|
||||
|
||||
handleInputConfirm = () => {
|
||||
const { inputValue } = this.state;
|
||||
let { tags } = this.state;
|
||||
if (inputValue && tags.indexOf(inputValue) === -1) {
|
||||
tags = [...tags, inputValue];
|
||||
}
|
||||
console.log(tags);
|
||||
this.setState({
|
||||
tags,
|
||||
inputVisible: false,
|
||||
inputValue: '',
|
||||
});
|
||||
}
|
||||
|
||||
saveInputRef = input => this.input = input
|
||||
|
||||
render() {
|
||||
const { tags, inputVisible, inputValue } = this.state;
|
||||
return (
|
||||
<div>
|
||||
{tags.map((tag, index) => {
|
||||
const isLongTag = tag.length > 20;
|
||||
const tagElem = (
|
||||
<Tag key={tag} closable={index !== 0} onClose={() => this.handleClose(tag)}>
|
||||
{isLongTag ? `${tag.slice(0, 20)}...` : tag}
|
||||
</Tag>
|
||||
);
|
||||
return isLongTag ? <Tooltip title={tag} key={tag}>{tagElem}</Tooltip> : tagElem;
|
||||
})}
|
||||
{inputVisible && (
|
||||
<Input
|
||||
ref={this.saveInputRef}
|
||||
type="text"
|
||||
size="small"
|
||||
style={{ width: 78 }}
|
||||
value={inputValue}
|
||||
onChange={this.handleInputChange}
|
||||
onBlur={this.handleInputConfirm}
|
||||
onPressEnter={this.handleInputConfirm}
|
||||
/>
|
||||
)}
|
||||
{!inputVisible && (
|
||||
<Tag
|
||||
onClick={this.showInput}
|
||||
style={{ background: '#fff', borderStyle: 'dashed' }}
|
||||
>
|
||||
<Icon type="plus" /> New Tag
|
||||
</Tag>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Step1 extends React.Component {
|
||||
render() {
|
||||
console.log("hhhoohh");
|
||||
return (
|
||||
<div>
|
||||
<Form layout="horizontal" className={styles.stepForm} hideRequiredMark>
|
||||
|
||||
<Form.Item {...formItemLayout} label="Platform">
|
||||
<Select placeholder="ex: android">
|
||||
<Option value="Android">Android</Option>
|
||||
<Option value="iOS">iOS</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item {...formItemLayout} label="Type">
|
||||
<Select value="Enterprise">
|
||||
<Option value="Enterprise" selected>Enterprise</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item {...formItemLayout} label="Name">
|
||||
<Input placeholder="App Name" />
|
||||
</Form.Item>
|
||||
<Form.Item {...formItemLayout} label="Description">
|
||||
<TextArea placeholder="Enter the description" rows={4} />
|
||||
</Form.Item>
|
||||
<Form.Item {...formItemLayout} label="Category">
|
||||
<Select placeholder="Select a category">
|
||||
<Option value="travel">Travel</Option>
|
||||
<Option value="entertainment">Entertainment</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item {...formItemLayout} label="Tags">
|
||||
<EditableTagGroup/>
|
||||
</Form.Item>
|
||||
<Form.Item {...formItemLayout} label="Price">
|
||||
<Input prefix="$" placeholder="00.00" />
|
||||
</Form.Item>
|
||||
<Form.Item {...formItemLayout} label="Share with all tenents?">
|
||||
<Checkbox > </Checkbox>
|
||||
</Form.Item>
|
||||
<Form.Item {...formItemLayout} label="Meta Daa">
|
||||
<InputGroup>
|
||||
<Row gutter={8}>
|
||||
<Col span={5}>
|
||||
<Input placeholder="Key" />
|
||||
</Col>
|
||||
<Col span={10}>
|
||||
<Input placeholder="value" />
|
||||
</Col>
|
||||
<Col span={4}>
|
||||
<Button type="dashed" shape="circle" icon="plus" />
|
||||
</Col>
|
||||
</Row>
|
||||
</InputGroup>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Step1;
|
@ -0,0 +1,12 @@
|
||||
import React from "react"
|
||||
|
||||
class Step2 extends React.Component {
|
||||
render() {
|
||||
console.log("hhhoohh");
|
||||
return (
|
||||
<p>tttoooeeee</p>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Step2;
|
@ -0,0 +1,12 @@
|
||||
import React from "react"
|
||||
|
||||
class Step3 extends React.Component {
|
||||
render() {
|
||||
console.log("hhhoohh");
|
||||
return (
|
||||
<p>tttoooeeee</p>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Step3;
|
@ -0,0 +1,4 @@
|
||||
.stepForm {
|
||||
max-width: 500px;
|
||||
margin: 40px auto 0;
|
||||
}
|
@ -0,0 +1,215 @@
|
||||
import React from "react";
|
||||
import "antd/dist/antd.css";
|
||||
import {Table, Divider, Tag, Card, PageHeader, Typography, Avatar,Input, Button, Icon, Row, Col} from "antd";
|
||||
import Highlighter from 'react-highlight-words';
|
||||
|
||||
const Paragraph = Typography;
|
||||
const Search = Input.Search;
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: 'index',
|
||||
breadcrumbName: 'Publisher',
|
||||
},
|
||||
{
|
||||
path: 'first',
|
||||
breadcrumbName: 'Dashboard',
|
||||
},
|
||||
{
|
||||
path: 'second',
|
||||
breadcrumbName: 'Apps',
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
|
||||
|
||||
const data = [{
|
||||
key: '1',
|
||||
icon: 'https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png',
|
||||
name: 'John Brown',
|
||||
platform: 'android',
|
||||
type: 'Enterprise',
|
||||
status: 'published',
|
||||
version: '13.0.0.1',
|
||||
updated_at: '27-03-2019 08:27'
|
||||
},{
|
||||
key: '2',
|
||||
icon: 'http://aztechbeat.com/wp-content/uploads/2014/04/confide-app-icon.png',
|
||||
name: 'Lorem Ipsum',
|
||||
platform: 'ios',
|
||||
type: 'Enterprise',
|
||||
status: 'published',
|
||||
version: '2.3.1.2',
|
||||
updated_at: '27-03-2019 09:45'
|
||||
},{
|
||||
key: '3',
|
||||
icon: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRx2Xx1-hnH16EGZHUlT06nOcfGODPoboA2TXKaBVtODto4lJtK',
|
||||
name: 'Lorem Ipsum',
|
||||
platform: 'ios',
|
||||
type: 'Enterprise',
|
||||
status: 'removed',
|
||||
version: '4.1.1.0',
|
||||
updated_at: '27-03-2019 09:46'
|
||||
}];
|
||||
|
||||
class Apps extends React.Component {
|
||||
routes;
|
||||
|
||||
|
||||
state = {
|
||||
searchText: '',
|
||||
};
|
||||
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.routes = props.routes;
|
||||
}
|
||||
|
||||
getColumnSearchProps = (dataIndex) => ({
|
||||
filterDropdown: ({
|
||||
setSelectedKeys, selectedKeys, confirm, clearFilters,
|
||||
}) => (
|
||||
<div style={{ padding: 8 }}>
|
||||
<Input
|
||||
ref={node => { this.searchInput = node; }}
|
||||
placeholder={`Search ${dataIndex}`}
|
||||
value={selectedKeys[0]}
|
||||
onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
|
||||
onPressEnter={() => this.handleSearch(selectedKeys, confirm)}
|
||||
style={{ width: 188, marginBottom: 8, display: 'block' }}
|
||||
/>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => this.handleSearch(selectedKeys, confirm)}
|
||||
icon="search"
|
||||
size="small"
|
||||
style={{ width: 90, marginRight: 8 }}
|
||||
>
|
||||
Search
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => this.handleReset(clearFilters)}
|
||||
size="small"
|
||||
style={{ width: 90 }}
|
||||
>
|
||||
Reset
|
||||
</Button>
|
||||
</div>
|
||||
),
|
||||
filterIcon: filtered => <Icon type="search" style={{ color: filtered ? '#1890ff' : undefined }} />,
|
||||
onFilter: (value, record) => record[dataIndex].toString().toLowerCase().includes(value.toLowerCase()),
|
||||
onFilterDropdownVisibleChange: (visible) => {
|
||||
if (visible) {
|
||||
setTimeout(() => this.searchInput.select());
|
||||
}
|
||||
},
|
||||
render: (text) => (
|
||||
<Highlighter
|
||||
highlightStyle={{ backgroundColor: '#ffc069', padding: 0 }}
|
||||
searchWords={[this.state.searchText]}
|
||||
autoEscape
|
||||
textToHighlight={text.toString()}
|
||||
/>
|
||||
),
|
||||
})
|
||||
|
||||
handleSearch = (selectedKeys, confirm) => {
|
||||
confirm();
|
||||
this.setState({ searchText: selectedKeys[0] });
|
||||
}
|
||||
|
||||
handleReset = (clearFilters) => {
|
||||
clearFilters();
|
||||
this.setState({ searchText: '' });
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const columns = [{
|
||||
title: '',
|
||||
dataIndex: 'icon',
|
||||
key: 'icon',
|
||||
render: text => <Avatar size="large" src={text}/>,
|
||||
}, {
|
||||
title: 'Name',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
render: text => <a href="javascript:;">{text}</a>,
|
||||
...this.getColumnSearchProps('name'),
|
||||
}, {
|
||||
title: 'Platform',
|
||||
dataIndex: 'platform',
|
||||
key: 'platform',
|
||||
}, {
|
||||
title: 'Type',
|
||||
dataIndex: 'type',
|
||||
key: 'type',
|
||||
}, {
|
||||
title: 'Status',
|
||||
key: 'status',
|
||||
dataIndex: 'status',
|
||||
render: tag => {
|
||||
let color;
|
||||
switch (tag) {
|
||||
case 'published':
|
||||
color = 'green';
|
||||
break;
|
||||
case 'removed':
|
||||
color = 'red'
|
||||
break;
|
||||
case 'default':
|
||||
color = 'blue'
|
||||
}
|
||||
return <Tag color={color} key={tag}>{tag.toUpperCase()}</Tag>;
|
||||
},
|
||||
}, {
|
||||
title: 'Published Version',
|
||||
dataIndex: 'version',
|
||||
key: 'version',
|
||||
}, {
|
||||
title: 'Last Updated',
|
||||
dataIndex: 'updated_at',
|
||||
key: 'updated_at',
|
||||
},{
|
||||
title: 'Action',
|
||||
key: 'action',
|
||||
render: () => (
|
||||
<span>
|
||||
<a href="javascript:;">Edit</a>
|
||||
<Divider type="vertical" />
|
||||
<a href="javascript:;">Manage</a>
|
||||
</span>
|
||||
),
|
||||
}];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PageHeader
|
||||
breadcrumb={{routes}}
|
||||
/>
|
||||
<div style={{background: '#f0f2f5', padding: 24, minHeight: 780}}>
|
||||
|
||||
<Card>
|
||||
<Row style={{padding:10}}>
|
||||
<Col span={6} offset={18}>
|
||||
<Search
|
||||
placeholder="search"
|
||||
onSearch={value => console.log(value)}
|
||||
style={{ width: 200}}
|
||||
/>
|
||||
<Button style={{margin:5}}>Advanced Search</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
<Table columns={columns} dataSource={data}/>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Apps;
|
Loading…
Reference in new issue