Skip to content

Commit

Permalink
Tasks edit: Merged parent selector feature into subtask list feature
Browse files Browse the repository at this point in the history
  • Loading branch information
MangoCubes committed Jul 23, 2023
1 parent 2a63b04 commit 2d4de66
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/Tasks/Main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ export default function TasksMain() {
>
<TaskEdit
directChildren={[]}
entries={flatEntries}
collections={cachedCollections}
onSave={onMultipleItemsSave}
onDelete={onItemDelete}
Expand Down Expand Up @@ -175,6 +176,7 @@ export default function TasksMain() {
>
<TaskEdit
directChildren={flatEntries.filter((t) => t.relatedTo === item.uid)}
entries={flatEntries}
key={itemUid}
initialCollection={item.collectionUid}
item={item}
Expand Down
62 changes: 62 additions & 0 deletions src/Tasks/TaskEdit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,10 @@ import ColoredRadio from "../widgets/ColoredRadio";
import RRule, { RRuleOptions } from "../widgets/RRule";
import { CachedCollection } from "../Pim/helpers";
import { Checkbox, IconButton, InputAdornment, List, ListItem, ListItemSecondaryAction, ListItemText, OutlinedInput } from "@material-ui/core";
import TaskSelector from "./TaskSelector";

interface PropsType {
entries: TaskType[];
collections: CachedCollection[];
directChildren: TaskType[];
initialCollection?: string;
Expand Down Expand Up @@ -95,6 +97,8 @@ export default class TaskEdit extends React.PureComponent<PropsType> {
* children are deleted in a recursive manner.
*/
recursiveDelete: boolean;
showSelectorDialog: boolean;
parentEntry: string | null;

error?: string;
showDeleteDialog: boolean;
Expand All @@ -103,6 +107,7 @@ export default class TaskEdit extends React.PureComponent<PropsType> {
constructor(props: PropsType) {
super(props);
this.state = {
parentEntry: props.item?.relatedTo ?? "",
uid: "",
title: "",
status: TaskStatusType.NeedsAction,
Expand All @@ -116,6 +121,7 @@ export default class TaskEdit extends React.PureComponent<PropsType> {
timezone: null,
creatingSubtasks: false,
recursiveDelete: false,
showSelectorDialog: false,

collectionUid: "",
showDeleteDialog: false,
Expand Down Expand Up @@ -184,6 +190,43 @@ export default class TaskEdit extends React.PureComponent<PropsType> {
tempSubtask: "",
});
}
public filterChildren() {
if (!this.props.item) {
return this.props.entries;
}
const idsToRemove: string[] = [this.props.item.uid];
const parentMap: {[itemId: string]: TaskType[]} = { "": [] };
for (const e of this.props.entries) {
if (e.uid === this.props.item.uid) {
continue;
}
if (!e.relatedTo) {
parentMap[""].push(e);
} else {
if (parentMap[e.relatedTo]) {
parentMap[e.relatedTo].push(e);
} else {
parentMap[e.relatedTo] = [e];
}
}
}
while (idsToRemove.length > 0) {
const current = idsToRemove.shift()!;
const children = parentMap[current];
if (!children) {
continue;
}
for (const c of children) {
idsToRemove.push(c.uid);
}
delete parentMap[current];
}
const ret: TaskType[] = [];
for (const k in parentMap) {
ret.push(...parentMap[k]);
}
return ret;
}

public handleInputChange(event: React.ChangeEvent<any>) {
const name = event.target.name;
Expand Down Expand Up @@ -261,6 +304,7 @@ export default class TaskEdit extends React.PureComponent<PropsType> {
task.status = this.state.status;
task.priority = this.state.priority;
task.tags = this.state.tags;
task.relatedTo = this.state.parentEntry ?? undefined;
if (startDate) {
task.startDate = startDate;
}
Expand Down Expand Up @@ -400,6 +444,17 @@ export default class TaskEdit extends React.PureComponent<PropsType> {
</Select>
</FormControl>

<Button onClick={() => this.setState({ showSelectorDialog: true })} style={styles.fullWidth}>
Select parent task
</Button>
<TextField
style={styles.fullWidth}
label="Parent task"
name="parent"
disabled
value={this.props.entries.find((e) => e.uid === this.state.parentEntry)?.title ?? "None"}
/>

<FormControl style={styles.fullWidth}>
<InputLabel>
Status
Expand Down Expand Up @@ -650,6 +705,13 @@ export default class TaskEdit extends React.PureComponent<PropsType> {
label="Delete recursively"
/>
</ConfirmationDialog>
<TaskSelector
entries={this.filterChildren()}
orig={this.state.parentEntry}
open={this.state.showSelectorDialog}
onConfirm={(entry) => this.setState({ showSelectorDialog: false, parentEntry: entry })}
onCancel={() => this.setState({ showSelectorDialog: false })}
/>
</React.Fragment>
);
}
Expand Down
69 changes: 69 additions & 0 deletions src/Tasks/TaskSelector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { TaskType } from "../pim-types";
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, FormControlLabel, FormGroup, List, Switch } from "@material-ui/core";
import React from "react";
import TaskSelectorListItem from "./TaskSelectorListItem";

interface PropsType {
entries: TaskType[];
orig: string | null;
open: boolean;
onConfirm: (entry: string | null) => void;
onCancel: () => void;
}

export default function TaskSelector(props: PropsType) {

const [showHidden, setShowHidden] = React.useState(false);
const [showCompleted, setShowCompleted] = React.useState(false);

const itemList = props.entries
.filter((e) => !e.relatedTo && (showHidden || !e.hidden) && (showCompleted || !e.finished))
.map((e) =>
<TaskSelectorListItem
showHidden={showHidden}
showCompleted={showCompleted}
key={e.uid}
entries={props.entries}
thisEntry={e}
onClick={props.onConfirm}
/>
);

return (
<Dialog open={props.open} onClose={props.onCancel} fullWidth>
<DialogTitle>
Select parent task
</DialogTitle>
<DialogContent>
<FormGroup>
<FormControlLabel
control={
<Switch
checked={showCompleted}
onChange={(e) => setShowCompleted(e.target.checked)}
/>
}
label="Show completed"
/>
<FormControlLabel
control={
<Switch
checked={showHidden}
onChange={(e) => setShowHidden(e.target.checked)}
/>
}
label="Show hidden"
/>
</FormGroup>
<List>
{itemList}
</List>
</DialogContent>
<DialogActions>
<Button color="primary" onClick={() => props.onConfirm(null)}>
Clear
</Button>
</DialogActions>
</Dialog>
);
}
34 changes: 34 additions & 0 deletions src/Tasks/TaskSelectorListItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { TaskType } from "../pim-types";
import { ListItem } from "../widgets/List";
import React from "react";

interface PropsType {
entries: TaskType[];
showHidden: boolean;
showCompleted: boolean;
onClick: (uid: string) => void;
thisEntry: TaskType;
}

export default function TaskSelectorListItem(props: PropsType) {
const tasks = props.entries
.filter((e) => e.relatedTo === props.thisEntry.uid && (props.showHidden || !e.hidden) && (props.showCompleted || !e.finished));

return (
<ListItem
primaryText={props.thisEntry.title}
key={props.thisEntry.uid}
onClick={() => props.onClick(props.thisEntry.uid)}
nestedItems={tasks.map((e) =>
<TaskSelectorListItem
showHidden={props.showHidden}
showCompleted={props.showCompleted}
key={e.uid}
entries={props.entries}
onClick={props.onClick}
thisEntry={e}
/>
)}
/>
);
}

0 comments on commit 2d4de66

Please sign in to comment.