Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions api/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ type ApplicationParams struct {
//
// example: 5
DefaultPriority int `form:"defaultPriority" query:"defaultPriority" json:"defaultPriority"`
// The order in which this application should appear in the UI. Defaults to 0.
//
// example: 7
SortOrder int `form:"sortOrder" query:"sortOrder" json:"sortOrder"`
}

// CreateApplication creates an application and returns the access token.
Expand Down Expand Up @@ -90,6 +94,7 @@ func (a *ApplicationAPI) CreateApplication(ctx *gin.Context) {
Name: applicationParams.Name,
Description: applicationParams.Description,
DefaultPriority: applicationParams.DefaultPriority,
SortOrder: applicationParams.SortOrder,
Token: auth.GenerateNotExistingToken(generateApplicationToken, a.applicationExists),
UserID: auth.GetUserID(ctx),
Internal: false,
Expand Down Expand Up @@ -251,6 +256,7 @@ func (a *ApplicationAPI) UpdateApplication(ctx *gin.Context) {
app.Description = applicationParams.Description
app.Name = applicationParams.Name
app.DefaultPriority = applicationParams.DefaultPriority
app.SortOrder = applicationParams.SortOrder

if success := successOrAbort(ctx, 500, a.DB.UpdateApplication(app)); !success {
return
Expand Down
3 changes: 2 additions & 1 deletion api/application_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,9 @@ func (s *ApplicationSuite) Test_ensureApplicationHasCorrectJsonRepresentation()
Image: "asd",
Internal: true,
LastUsed: nil,
SortOrder: 7,
}
test.JSONEquals(s.T(), actual, `{"id":1,"token":"Aasdasfgeeg","name":"myapp","description":"mydesc", "image": "asd", "internal":true, "defaultPriority":0, "lastUsed":null}`)
test.JSONEquals(s.T(), actual, `{"id":1,"token":"Aasdasfgeeg","name":"myapp","description":"mydesc", "image": "asd", "internal":true, "defaultPriority":0, "lastUsed":null, "sortOrder":7}`)
}

func (s *ApplicationSuite) Test_CreateApplication_expectBadRequestOnEmptyName() {
Expand Down
2 changes: 1 addition & 1 deletion database/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func (d *GormDatabase) DeleteApplicationByID(id uint) error {
// GetApplicationsByUser returns all applications from a user.
func (d *GormDatabase) GetApplicationsByUser(userID uint) ([]*model.Application, error) {
var apps []*model.Application
err := d.DB.Where("user_id = ?", userID).Order("id ASC").Find(&apps).Error
err := d.DB.Where("user_id = ?", userID).Order("sort_order ASC").Find(&apps).Error
if err == gorm.ErrRecordNotFound {
err = nil
}
Expand Down
4 changes: 4 additions & 0 deletions model/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,8 @@ type Application struct {
// read only: true
// example: 2019-01-01T00:00:00Z
LastUsed *time.Time `json:"lastUsed"`
// The order in which the application should appear in the UI.
//
// example: 7
SortOrder int `json:"sortOrder" query:"sortOrder" form: "sortOrder"`
}
24 changes: 19 additions & 5 deletions ui/src/application/AddApplicationDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,30 @@ import React, {Component} from 'react';

interface IProps {
fClose: VoidFunction;
fOnSubmit: (name: string, description: string, defaultPriority: number) => void;
fOnSubmit: (
name: string,
description: string,
defaultPriority: number,
sortOrder: number
) => void;
}

interface IState {
name: string;
description: string;
defaultPriority: number;
sortOrder: number;
}

export default class AddDialog extends Component<IProps, IState> {
public state = {name: '', description: '', defaultPriority: 0};
public state = {name: '', description: '', defaultPriority: 0, sortOrder: 0};

public render() {
const {fClose, fOnSubmit} = this.props;
const {name, description, defaultPriority} = this.state;
const {name, description, defaultPriority, sortOrder} = this.state;
const submitEnabled = this.state.name.length !== 0;
const submitAndClose = () => {
fOnSubmit(name, description, defaultPriority);
fOnSubmit(name, description, defaultPriority, sortOrder);
fClose();
};
return (
Expand Down Expand Up @@ -69,6 +75,14 @@ export default class AddDialog extends Component<IProps, IState> {
onChange={(value) => this.setState({defaultPriority: value})}
fullWidth
/>
<NumberField
margin="dense"
className="sortOrder"
label="Sort Order"
value={sortOrder}
onChange={(value) => this.setState({sortOrder: value})}
fullWidth
/>
</DialogContent>
<DialogActions>
<Button onClick={fClose}>Cancel</Button>
Expand All @@ -90,7 +104,7 @@ export default class AddDialog extends Component<IProps, IState> {
}

private handleChange(propertyName: string, event: React.ChangeEvent<HTMLInputElement>) {
const state = this.state;
const state: any = this.state;
state[propertyName] = event.target.value;
this.setState(state);
}
Expand Down
8 changes: 6 additions & 2 deletions ui/src/application/AppStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,14 @@ export class AppStore extends BaseStore<IApplication> {
id: number,
name: string,
description: string,
defaultPriority: number
defaultPriority: number,
sortOrder: number
): Promise<void> => {
await axios.put(`${config.get('url')}application/${id}`, {
name,
description,
defaultPriority,
sortOrder,
});
await this.refresh();
this.snack('Application updated');
Expand All @@ -54,12 +56,14 @@ export class AppStore extends BaseStore<IApplication> {
public create = async (
name: string,
description: string,
defaultPriority: number
defaultPriority: number,
sortOrder: number
): Promise<void> => {
await axios.post(`${config.get('url')}application`, {
name,
description,
defaultPriority,
sortOrder,
});
await this.refresh();
this.snack('Application created');
Expand Down
10 changes: 8 additions & 2 deletions ui/src/application/Applications.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class Applications extends Component<Stores<'appStore'>> {
<TableCell>Token</TableCell>
<TableCell>Description</TableCell>
<TableCell>Priority</TableCell>
<TableCell>Sort Order</TableCell>
<TableCell>Last Used</TableCell>
<TableCell />
<TableCell />
Expand All @@ -79,6 +80,7 @@ class Applications extends Component<Stores<'appStore'>> {
key={app.id}
description={app.description}
defaultPriority={app.defaultPriority}
sortOrder={app.sortOrder}
image={app.image}
name={app.name}
value={app.token}
Expand Down Expand Up @@ -108,12 +110,13 @@ class Applications extends Component<Stores<'appStore'>> {
{updateId !== false && (
<UpdateDialog
fClose={() => (this.updateId = false)}
fOnSubmit={(name, description, defaultPriority) =>
appStore.update(updateId, name, description, defaultPriority)
fOnSubmit={(name, description, defaultPriority, sortOrder) =>
appStore.update(updateId, name, description, defaultPriority, sortOrder)
}
initialDescription={appStore.getByID(updateId).description}
initialName={appStore.getByID(updateId).name}
initialDefaultPriority={appStore.getByID(updateId).defaultPriority}
initialSortOrder={appStore.getByID(updateId).sortOrder}
/>
)}
{deleteId !== false && (
Expand Down Expand Up @@ -155,6 +158,7 @@ interface IRowProps {
description: string;
defaultPriority: number;
lastUsed: string | null;
sortOrder: number;
fUpload: VoidFunction;
image: string;
fDelete: VoidFunction;
Expand All @@ -169,6 +173,7 @@ const Row: SFC<IRowProps> = observer(
description,
defaultPriority,
lastUsed,
sortOrder,
fDelete,
fUpload,
image,
Expand All @@ -189,6 +194,7 @@ const Row: SFC<IRowProps> = observer(
</TableCell>
<TableCell>{description}</TableCell>
<TableCell>{defaultPriority}</TableCell>
<TableCell>{sortOrder}</TableCell>
<TableCell>
<LastUsedCell lastUsed={lastUsed} />
</TableCell>
Expand Down
26 changes: 21 additions & 5 deletions ui/src/application/UpdateApplicationDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,36 +11,44 @@ import React, {Component} from 'react';

interface IProps {
fClose: VoidFunction;
fOnSubmit: (name: string, description: string, defaultPriority: number) => void;
fOnSubmit: (
name: string,
description: string,
defaultPriority: number,
sortOrder: number
) => void;
initialName: string;
initialDescription: string;
initialDefaultPriority: number;
initialSortOrder: number;
}

interface IState {
name: string;
description: string;
defaultPriority: number;
sortOrder: number;
}

export default class UpdateDialog extends Component<IProps, IState> {
public state = {name: '', description: '', defaultPriority: 0};
public state = {name: '', description: '', defaultPriority: 0, sortOrder: 0};

constructor(props: IProps) {
super(props);
this.state = {
name: props.initialName,
description: props.initialDescription,
defaultPriority: props.initialDefaultPriority,
sortOrder: props.initialSortOrder,
};
}

public render() {
const {fClose, fOnSubmit} = this.props;
const {name, description, defaultPriority} = this.state;
const {name, description, defaultPriority, sortOrder} = this.state;
const submitEnabled = this.state.name.length !== 0;
const submitAndClose = () => {
fOnSubmit(name, description, defaultPriority);
fOnSubmit(name, description, defaultPriority, sortOrder);
fClose();
};
return (
Expand Down Expand Up @@ -81,6 +89,14 @@ export default class UpdateDialog extends Component<IProps, IState> {
onChange={(value) => this.setState({defaultPriority: value})}
fullWidth
/>
<NumberField
margin="dense"
className="sortOrder"
label="Sort Order"
value={sortOrder}
onChange={(value) => this.setState({sortOrder: value})}
fullWidth
/>
</DialogContent>
<DialogActions>
<Button onClick={fClose}>Cancel</Button>
Expand All @@ -102,7 +118,7 @@ export default class UpdateDialog extends Component<IProps, IState> {
}

private handleChange(propertyName: string, event: React.ChangeEvent<HTMLInputElement>) {
const state = this.state;
const state: any = this.state;
state[propertyName] = event.target.value;
this.setState(state);
}
Expand Down
1 change: 1 addition & 0 deletions ui/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface IApplication {
internal: boolean;
defaultPriority: number;
lastUsed: string | null;
sortOrder: number;
}

export interface IClient {
Expand Down