-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial implementation of a generic UI component (#61)
* Add generic component * Add validation. Rename to widgetRenderer * Remove test code from splash screen * Clean up infobox * Fix styling/layout * Move test code into unit test * Replace <input> and <labe> by <TextField> and <Text> respectively. Fix style. * Replace InfoBoxComponent with UI fabric MessageBar. Fix styling for TextField * Use MessageBar for error message * Rename WdigetRendererComponent to SmartUiComponent
- Loading branch information
Showing
8 changed files
with
790 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
16 changes: 16 additions & 0 deletions
16
src/Explorer/Controls/RadioSwitchComponent/RadioSwitchComponent.less
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
@import "../../../../less/Common/Constants.less"; | ||
|
||
.radioSwitchComponent { | ||
cursor: pointer; | ||
display: flex; | ||
|
||
&>span:nth-child(n+2) { | ||
margin-left: 10px; | ||
} | ||
|
||
.caption { | ||
color: @BaseDark; | ||
padding-left: @SmallSpace; | ||
vertical-align: top; | ||
} | ||
} |
51 changes: 51 additions & 0 deletions
51
src/Explorer/Controls/RadioSwitchComponent/RadioSwitchComponent.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/** | ||
* Horizontal switch component | ||
*/ | ||
|
||
import * as React from "react"; | ||
import "./RadioSwitchComponent.less"; | ||
import { Icon } from "office-ui-fabric-react/lib/Icon"; | ||
import { NormalizedEventKey } from "../../../Common/Constants"; | ||
|
||
export interface Choice { | ||
key: string; | ||
onSelect: () => void; | ||
label: string; | ||
} | ||
|
||
export interface RadioSwitchComponentProps { | ||
choices: Choice[]; | ||
selectedKey: string; | ||
onSelectionKeyChange?: (newValue: string) => void; | ||
} | ||
|
||
export class RadioSwitchComponent extends React.Component<RadioSwitchComponentProps> { | ||
public render(): JSX.Element { | ||
return ( | ||
<div className="radioSwitchComponent"> | ||
{this.props.choices.map((choice: Choice) => ( | ||
<span | ||
tabIndex={0} | ||
key={choice.key} | ||
onClick={() => this.onSelect(choice)} | ||
onKeyPress={event => this.onKeyPress(event, choice)} | ||
> | ||
<Icon iconName={this.props.selectedKey === choice.key ? "RadioBtnOn" : "RadioBtnOff"} /> | ||
<span className="caption">{choice.label}</span> | ||
</span> | ||
))} | ||
</div> | ||
); | ||
} | ||
|
||
private onSelect(choice: Choice): void { | ||
this.props.onSelectionKeyChange && this.props.onSelectionKeyChange(choice.key); | ||
choice.onSelect(); | ||
} | ||
|
||
private onKeyPress(event: React.KeyboardEvent<HTMLSpanElement>, choice: Choice): void { | ||
if (event.key === NormalizedEventKey.Enter || event.key === NormalizedEventKey.Space) { | ||
this.onSelect(choice); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
/* Utilities for validation */ | ||
|
||
export const onValidateValueChange = (newValue: string, minValue?: number, maxValue?: number): number => { | ||
let numericValue = parseInt(newValue); | ||
if (!isNaN(numericValue) && isFinite(numericValue)) { | ||
if (minValue !== undefined && numericValue < minValue) { | ||
numericValue = minValue; | ||
} | ||
if (maxValue !== undefined && numericValue > maxValue) { | ||
numericValue = maxValue; | ||
} | ||
|
||
return Math.floor(numericValue); | ||
} | ||
|
||
return undefined; | ||
}; | ||
|
||
export const onIncrementValue = (newValue: string, step: number, max?: number): number => { | ||
const numericValue = parseInt(newValue); | ||
if (!isNaN(numericValue) && isFinite(numericValue)) { | ||
const newValue = numericValue + step; | ||
return max !== undefined ? Math.min(max, newValue) : newValue; | ||
} | ||
return undefined; | ||
}; | ||
|
||
export const onDecrementValue = (newValue: string, step: number, min?: number): number => { | ||
const numericValue = parseInt(newValue); | ||
if (!isNaN(numericValue) && isFinite(numericValue)) { | ||
const newValue = numericValue - step; | ||
return min !== undefined ? Math.max(min, newValue) : newValue; | ||
} | ||
return undefined; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
@import "../../../../less/Common/Constants.less"; | ||
|
||
.widgetRendererContainer { | ||
text-align: left; | ||
|
||
.inputLabelContainer { | ||
margin-bottom: 4px; | ||
|
||
.inputLabel { | ||
color: #393939; | ||
font-weight: 600; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import React from "react"; | ||
import { shallow } from "enzyme"; | ||
import { SmartUiComponent, Descriptor, InputType } from "./SmartUiComponent"; | ||
|
||
describe("SmartUiComponent", () => { | ||
const exampleData: Descriptor = { | ||
root: { | ||
id: "root", | ||
info: { | ||
message: "Start at $24/mo per database", | ||
link: { | ||
href: "https://aka.ms/azure-cosmos-db-pricing", | ||
text: "More Details" | ||
} | ||
}, | ||
children: [ | ||
{ | ||
id: "throughput", | ||
input: { | ||
label: "Throughput (input)", | ||
dataFieldName: "throughput", | ||
type: "number", | ||
min: 400, | ||
max: 500, | ||
step: 10, | ||
defaultValue: 400, | ||
inputType: "spin" | ||
} | ||
}, | ||
{ | ||
id: "throughput2", | ||
input: { | ||
label: "Throughput (Slider)", | ||
dataFieldName: "throughput2", | ||
type: "number", | ||
min: 400, | ||
max: 500, | ||
step: 10, | ||
defaultValue: 400, | ||
inputType: "slider" | ||
} | ||
}, | ||
{ | ||
id: "containerId", | ||
input: { | ||
label: "Container id", | ||
dataFieldName: "containerId", | ||
type: "string" | ||
} | ||
}, | ||
{ | ||
id: "analyticalStore", | ||
input: { | ||
label: "Analytical Store", | ||
trueLabel: "Enabled", | ||
falseLabel: "Disabled", | ||
defaultValue: true, | ||
dataFieldName: "analyticalStore", | ||
type: "boolean" | ||
} | ||
}, | ||
{ | ||
id: "database", | ||
input: { | ||
label: "Database", | ||
dataFieldName: "database", | ||
type: "enum", | ||
choices: [ | ||
{ label: "Database 1", key: "db1", value: "database1" }, | ||
{ label: "Database 2", key: "db2", value: "database2" }, | ||
{ label: "Database 3", key: "db3", value: "database3" } | ||
], | ||
defaultKey: "db2" | ||
} | ||
} | ||
] | ||
} | ||
}; | ||
|
||
const exampleCallbacks = (newValues: Map<string, InputType>): void => { | ||
console.log("New values:", newValues); | ||
}; | ||
|
||
it("should render", () => { | ||
const wrapper = shallow(<SmartUiComponent descriptor={exampleData} onChange={exampleCallbacks} />); | ||
expect(wrapper).toMatchSnapshot(); | ||
}); | ||
}); |
Oops, something went wrong.