diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/CustomAnalyzer.js | 75 | ||||
-rw-r--r-- | src/PatternTable.js | 1 | ||||
-rw-r--r-- | src/Settings.js | 212 | ||||
-rw-r--r-- | src/background.js | 24 |
4 files changed, 242 insertions, 70 deletions
diff --git a/src/CustomAnalyzer.js b/src/CustomAnalyzer.js index f76fa5e..f140151 100644 --- a/src/CustomAnalyzer.js +++ b/src/CustomAnalyzer.js @@ -38,20 +38,23 @@ const styles = theme => ({ class CustomAnalyzer extends React.Component { state = { patterns: [], - calendars: [], - timeRange: null, + calendars: {}, + startDate: null, + endDate: null, patternGraphData: default_chart_data, calendarGraphData: default_chart_data, - activePattern: null }; constructor(props) { super(props); this.msgClient = new MsgClient('main'); - this.msgClient.sendMsg({ type: msgType.getPatterns }).then(msg => { + this.msgClient.sendMsg({ + type: msgType.getPatterns, + data: { id: 'analyze' } + }).then(msg => { this.setState({ patterns: msg.data.map(p => PatternEntry.revive(p)) }); }); - this.msgClient.sendMsg({ type: msgType.getCalendars }).then(msg => { + this.msgClient.sendMsg({ type: msgType.getCalendars, data: { enabledOnly: true }}).then(msg => { this.setState({ calendars: msg.data }); }); } @@ -59,8 +62,10 @@ class CustomAnalyzer extends React.Component { updatePattern = (field, idx, value) => { let patterns = this.state.patterns; patterns[idx][field] = value; - this.setState({ patterns }); - this.msgClient.sendMsg({ type: msgType.updatePatterns, data: patterns }); + this.msgClient.sendMsg({ + type: msgType.updatePatterns, + data: { id: 'analyze', patterns } + }).then(() => this.setState({ patterns })); }; removePattern = idx => { @@ -68,26 +73,27 @@ class CustomAnalyzer extends React.Component { patterns.splice(idx, 1); for (let i = 0; i < patterns.length; i++) patterns[i].idx = i; - this.setState({ patterns }); - this.msgClient.sendMsg({ type: msgType.updatePatterns, data: patterns }); + this.msgClient.sendMsg({ + type: msgType.updatePatterns, + data: { id: 'analyze', patterns } + }).then(() => this.setState({ patterns })); }; newPattern = () => { let patterns = [PatternEntry.defaultPatternEntry(0), ...this.state.patterns]; for (let i = 1; i < patterns.length; i++) patterns[i].idx = i; - this.setState({ patterns }); - this.msgClient.sendMsg({ type: msgType.updatePatterns, data: patterns }); + this.msgClient.sendMsg({ + type: msgType.updatePatterns, + data: { id: 'analyze', patterns } + }).then(() => this.setState({ patterns })); }; loadPatterns = patterns => { - this.setState({ patterns }); - this.msgClient.sendMsg({ type: msgType.updatePatterns, data: patterns }); - }; - - loadCalendars = calendars => { - this.setState({ calendars }); - this.msgClient.sendMsg({ type: msgType.updateCalendars, data: calendars }); + this.msgClient.sendMsg({ + type: msgType.updatePatterns, + data: { id: 'analyze', patterns } + }).then(() => this.setState({ patterns })); }; getCalEvents = (id, start, end) => { @@ -160,27 +166,10 @@ class CustomAnalyzer extends React.Component { }); }; - load = () => { - let colors = gapi.getAuthToken().then(gapi.getColors).then(color => { - return color.calendar; - }); - let cals = gapi.getAuthToken().then(gapi.getCalendars); - Promise.all([colors, cals]).then(([colors, items]) => { - var cals = {}; - items.forEach(item => { - cals[item.id] = { - name: item.summary, - color: colors[item.colorId], - //cal: new gapi.GCalendar(item.id, item.summary) - }}); - this.loadCalendars(cals); - this.loadPatterns(items.map((item, idx) => { - return new PatternEntry(item.summary, idx, - new Pattern(item.id, false, item.summary, item.summary), - Pattern.anyPattern()); - })); - }); - }; + reset = () => { + this.loadPatterns([]); + this.setState({ startDate: null, endDate: null }); + } render() { const { classes } = this.props; @@ -191,7 +180,7 @@ class CustomAnalyzer extends React.Component { <FormControl fullWidth={true}> <FormGroup> <Typography variant="h6" component="h1" gutterBottom> - Event Patterns + Analyzed Events <IconButton style={{marginBottom: '0.12em', marginLeft: '0.5em'}} onClick={() => this.newPattern()}><AddCircleIcon /></IconButton> @@ -224,12 +213,12 @@ class CustomAnalyzer extends React.Component { <Grid container spacing={16}> <Grid item md={6} xs={12}> <FormGroup> - <Button variant="contained" color="primary" onClick={this.load}>Load</Button> + <Button variant="contained" color="primary" onClick={this.analyze}>Analyze</Button> </FormGroup> </Grid> <Grid item md={6} xs={12}> <FormGroup> - <Button variant="contained" color="primary" onClick={this.analyze}>Analyze</Button> + <Button variant="contained" color="primary" onClick={this.reset}>Reset</Button> </FormGroup> </Grid> </Grid> @@ -237,7 +226,7 @@ class CustomAnalyzer extends React.Component { </Grid> <Grid item md={6} xs={12}> <Typography variant="h6" component="h1" gutterBottom> - Graph + Results </Typography> <PieChart patternGraphData={this.state.patternGraphData} diff --git a/src/PatternTable.js b/src/PatternTable.js index e579921..3e16bbf 100644 --- a/src/PatternTable.js +++ b/src/PatternTable.js @@ -43,6 +43,7 @@ class PatternTable extends React.Component { state = { page: 0, rowsPerPage: 5, + activePattern: null }; handleChangePage = (event, page) => { diff --git a/src/Settings.js b/src/Settings.js index 11167a0..e071f9e 100644 --- a/src/Settings.js +++ b/src/Settings.js @@ -7,6 +7,7 @@ import Button from '@material-ui/core/Button'; import FormControl from '@material-ui/core/FormControl'; import FormGroup from '@material-ui/core/FormGroup'; import Grid from '@material-ui/core/Grid'; +import RefreshIcon from '@material-ui/icons/Refresh'; import AddCircleIcon from '@material-ui/icons/AddCircle'; import IconButton from '@material-ui/core/IconButton'; import Table from '@material-ui/core/Table'; @@ -14,11 +15,28 @@ import TableBody from '@material-ui/core/TableBody'; import TableRow from '@material-ui/core/TableRow'; import TableCell from '@material-ui/core/TableCell'; import TableHead from '@material-ui/core/TableHead'; +import List from '@material-ui/core/List'; +import ListItem from '@material-ui/core/ListItem'; +import ListItemText from '@material-ui/core/ListItemText'; +import Checkbox from '@material-ui/core/Checkbox'; import * as gapi from './gapi'; import { msgType, MsgClient } from './msg'; import { Pattern, PatternEntry } from './pattern'; +import PatternTable from './PatternTable'; const styles = theme => ({ + tableHead: { + verticalAlign: 'top', + textAlign: 'right', + lineHeight: '3em', + }, + tableContent: { + textAlign: 'left', + }, + calendarList: { + maxHeight: 400, + overflowY: 'auto' + } }); const STableCell = withStyles(theme => ({ @@ -27,48 +45,194 @@ const STableCell = withStyles(theme => ({ }, }))(TableCell); +const CompactListItem = withStyles(theme => ({ + dense: { + paddingTop: 0, + paddingBottom: 0 + }, +}))(ListItem); + class Settings extends React.Component { state = { - isLoggedIn: false + isLoggedIn: false, + patterns: [], + calendars: {}, }; constructor(props) { super(props); + this.msgClient = new MsgClient('main'); gapi.getLoggedIn().then(b => this.setState({ isLoggedIn: b })); + this.msgClient.sendMsg({ + type: msgType.getPatterns, + data: { id: 'main' } + }).then(msg => { + this.setState({ patterns: msg.data.map(p => PatternEntry.revive(p)) }); + }); + this.msgClient.sendMsg({ type: msgType.getCalendars, data: { enabledOnly: false } }).then(msg => { + this.setState({ calendars: msg.data }); + }); } handleLogin = () => { - gapi.login().then(() => this.setState({ isLoggedIn: true })); + gapi.login().then(() => { + this.setState({ isLoggedIn: true }); + this.loadAll(true); + }); } handleLogout = () => { - gapi.logout().then(() => this.setState({ isLoggedIn: false })); + gapi.logout().then(() => { + this.setState({ isLoggedIn: false }); + this.loadPatterns([], 'analyze'); + }); } + handleToggleCalendar = id => { + var calendars = {...this.state.calendars}; + calendars[id].enabled = !calendars[id].enabled; + this.msgClient.sendMsg({ type: msgType.updateCalendars, data: calendars }).then(() => + this.setState({ calendars })); + } + + loadAll = loadDefaultPatterns => { + let colors = gapi.getAuthToken().then(gapi.getColors).then(color => { + return color.calendar; + }); + let cals = gapi.getAuthToken().then(gapi.getCalendars); + Promise.all([colors, cals]).then(([colors, items]) => { + var cals = {}; + items.forEach(item => { + cals[item.id] = { + name: item.summary, + color: colors[item.colorId], + enabled: true + //cal: new gapi.GCalendar(item.id, item.summary) + }}); + this.loadCalendars(cals); + if (loadDefaultPatterns) + { + this.loadPatterns(items.map((item, idx) => { + return new PatternEntry(item.summary, idx, + new Pattern(item.id, false, item.summary, item.summary), + Pattern.anyPattern()); + }), 'main'); + } + }); + }; + + loadCalendars = calendars => { + for (let id in this.state.calendars) { + if (calendars.hasOwnProperty(id)) + calendars[id].enabled = this.state.calendars[id].enabled; + } + this.msgClient.sendMsg({ type: msgType.updateCalendars, data: calendars }).then(() => + this.setState({ calendars })); + }; + + loadPatterns = (patterns, id) => { + this.msgClient.sendMsg({ + type: msgType.updatePatterns, + data: { id, patterns } + }).then(() => this.setState({ patterns })); + }; + + updatePattern = (field, idx, value) => { + let patterns = this.state.patterns; + patterns[idx][field] = value; + this.msgClient.sendMsg({ + type: msgType.updatePatterns, + data: { id: 'main', patterns } + }).then(() => this.setState({ patterns })); + }; + + removePattern = idx => { + let patterns = this.state.patterns; + patterns.splice(idx, 1); + for (let i = 0; i < patterns.length; i++) + patterns[i].idx = i; + this.msgClient.sendMsg({ + type: msgType.updatePatterns, + data: { id: 'main', patterns } + }).then(() => this.setState({ patterns })); + }; + + newPattern = () => { + let patterns = [PatternEntry.defaultPatternEntry(0), ...this.state.patterns]; + for (let i = 1; i < patterns.length; i++) + patterns[i].idx = i; + this.msgClient.sendMsg({ + type: msgType.updatePatterns, + data: { id: 'main', patterns } + }).then(() => this.setState({ patterns })); + }; + render() { const { classes } = this.props; return ( - <Grid container spacing={16}> - <Grid item md={6} xs={12}> - <Typography variant="h6" component="h1" gutterBottom> - General - </Typography> - <Table> - <TableBody> - <TableRow> - <STableCell align='right'>Account</STableCell> - <STableCell align='left'> - { - (this.state.isLoggedIn && - <Button variant="contained" color="primary" onClick={this.handleLogout}>Logout</Button>) || - <Button variant="contained" color="primary" onClick={this.handleLogin}>Login</Button> - } - </STableCell> - </TableRow> - </TableBody> - </Table> - </Grid> - </Grid> + <div> + <Typography variant="h6" component="h1" gutterBottom> + General + </Typography> + <Table> + <TableBody> + <TableRow> + <STableCell className={classes.tableHead}>Account</STableCell> + <STableCell align='left'> + { + (this.state.isLoggedIn && + <Button variant="contained" color="primary" onClick={this.handleLogout}>Logout</Button>) || + <Button variant="contained" color="primary" onClick={this.handleLogin}>Login</Button> + } + </STableCell> + </TableRow> + <TableRow> + <STableCell className={classes.tableHead}> + <IconButton + style={{marginBottom: '0.12em', marginRight: '0.5em'}} + onClick={() => this.loadAll(false)} + disabled={!this.state.isLoggedIn}><RefreshIcon /></IconButton> + Calendars + </STableCell> + <STableCell className={classes.tableContent}> + {(this.state.isLoggedIn && + <List className={classes.calendarList}> + {Object.keys(this.state.calendars).map(id => + <CompactListItem + key={id} + onClick={() => this.handleToggleCalendar(id)} + disableGutters + dense button > + <Checkbox + checked={this.state.calendars[id].enabled} + disableRipple /> + <ListItemText primary={this.state.calendars[id].name} /> + </CompactListItem>)} + </List>) || 'Please Login.'} + </STableCell> + </TableRow> + <TableRow> + <STableCell className={classes.tableHead}> + <IconButton + style={{marginBottom: '0.12em', marginRight: '0.5em'}} + onClick={() => this.newPattern()} + disabled={!this.state.isLoggedIn}><AddCircleIcon /></IconButton> + Tracked Events + </STableCell> + <STableCell className={classes.tableContent}> + {(this.state.isLoggedIn && + <FormControl fullWidth={true}> + <PatternTable + patterns={this.state.patterns} + calendars={this.state.calendars} + onRemovePattern={this.removePattern} + onUpdatePattern={this.updatePattern} /> + </FormControl>) || 'Please Login.'} + </STableCell> + </TableRow> + </TableBody> + </Table> + </div> ); } } diff --git a/src/background.js b/src/background.js index 177ec68..e9b0f60 100644 --- a/src/background.js +++ b/src/background.js @@ -1,7 +1,8 @@ import * as gapi from './gapi'; import { msgType, Msg } from './msg'; -let patterns = []; +let mainPatterns = []; +let analyzePatterns = []; let calendars = {}; let calData = {}; @@ -11,9 +12,18 @@ chrome.runtime.onConnect.addListener(function(port) { let msg = Msg.inflate(_msg); console.log(msg); if (msg.type == msgType.updatePatterns) { - patterns = msg.data; + if (msg.data.id == 'analyze') + analyzePatterns = msg.data.patterns; + else + mainPatterns = msg.data.patterns; + port.postMessage(msg.genResp(null)); } else if (msg.type == msgType.getPatterns) { + let patterns; + if (msg.data.id == 'analyze') + patterns = analyzePatterns; + else + patterns = mainPatterns; port.postMessage(msg.genResp(patterns)); } else if (msg.type == msgType.updateCalendars) { @@ -22,9 +32,17 @@ chrome.runtime.onConnect.addListener(function(port) { if (!calData.hasOwnProperty(id)) calData[id] = new gapi.GCalendar(id, calendars[id].summary); } + port.postMessage(msg.genResp(null)); } else if (msg.type == msgType.getCalendars) { - port.postMessage(msg.genResp(calendars)); + let cals = calendars; + if (msg.data.enabledOnly) + { + cals = Object.keys(calendars) + .filter(id => calendars[id].enabled) + .reduce((res, id) => (res[id] = calendars[id], res), {}); + } + port.postMessage(msg.genResp(cals)); } else if (msg.type == msgType.getCalEvents) { calData[msg.data.id].getEvents(new Date(msg.data.start), new Date(msg.data.end)) |