Finilize VPC View support

This commit is contained in:
Borys_Levytskyi
2021-04-24 13:10:41 +03:00
parent 4e1b35a55b
commit 18272c712e
12 changed files with 157 additions and 99 deletions

View File

@@ -25,8 +25,8 @@ code { font-size: 1.2em; font-weight: bold; }
.result .content { padding-left: 10px}
.result .cur { margin-right: 5px; }
.hashLink { text-decoration: none; margin-left: 5px; visibility: hidden }
.hashLink:hover { text-decoration: underline; margin-left: 5px; }
.hashLink { text-decoration: none; margin-left: 5px; visibility: hidden; margin-right: 0; padding: 0; text-decoration: none; }
.hashLink:hover { text-decoration: underline; margin-left: 5px; background: none; }
.result:hover .hashLink { visibility: visible }
.expression .label { font-weight: bold; padding-right: 5px; text-align: right; }
@@ -48,7 +48,7 @@ code { font-size: 1.2em; font-weight: bold; }
.help ul { list-style-type: none; margin: 0; padding: 0; }
.help p { margin-top: 0 }
.indicator { padding: 2px 5px; font-family: monospace; font-size: 1.3em; background: transparent; border: none; cursor: pointer }
.indicator { padding: 0px 5px; background: transparent; border: none; cursor: pointer; vertical-align: middle; }
.error { color: maroon; }
.soft { opacity: 0.7 }
@@ -68,13 +68,13 @@ code { font-size: 1.2em; font-weight: bold; }
.light .on { color: #121212; }
.light .prefix { color: #888}
.light .other { color: #bbb }
.light .hashLink, .light .hashLink:visited { color: #ddd }
.light .hashLink, .light .hashLink:visited { color: #ddd; }
.light .hashLink:hover { color: #888 }
.light ul.top-links li:hover { background: #ddd }
.light .error { color: #da586d }
.light button { color: black}
.light button:hover { background: #ddd}
.light button:disabled { color: #888; background-color: inherit; }
.light button.btn { color: black}
.light button.btn:hover { background: #ddd}
.light button.btn:disabled { color: #888; background-color: inherit; }
/* Dark */
.dark { background: #121212; color: white;}
@@ -90,9 +90,9 @@ code { font-size: 1.2em; font-weight: bold; }
.dark .hashLink:hover { color: #999 }
.dark ul.top-links li:hover { background: #333 }
.dark .error { color: #da586d}
.dark button { color: white}
.dark button:hover { background: #333}
.dark button:disabled { color: #999; background-color: inherit; }
.dark button.btn { color: white}
.dark button.btn:hover { background: #333}
.dark button.btn:disabled { color: #999; background-color: inherit; }
/*
Midnight Theme
@@ -113,9 +113,9 @@ code { font-size: 1.2em; font-weight: bold; }
.midnight ul.top-links li:hover { background: #132537 }
.midnight .error { color:#da586d}
.midnight .changelog .item-new .date { font-weight: bold }
.midnight button { color: white}
.midnight button:hover { background: #132537}
.midnight button:disabled { color: #85a0ad; background-color: inherit; }
.midnight button.btn { color: white}
.midnight button.btn:hover { background: #132537}
.midnight button.btn:disabled { color: #85a0ad; background-color: inherit; }
button {
border: none;

View File

@@ -41,9 +41,9 @@ function SubnetView(props : {subnet : SubnetCommand}) {
</td>
<td data-test-name="decimal">
<button onClick={decrementMask} disabled={subnet.cidr.maskBits === 0} title="Decrease mask size">-</button>
<button className="btn" onClick={decrementMask} disabled={subnet.cidr.maskBits === 0} title="Decrease mask size">-</button>
<span>{subnet.cidr.maskBits}</span>
<button onClick={incrementMask} disabled={subnet.cidr.maskBits === 32} title="Increase mask size">+</button>
<button className="btn"onClick={incrementMask} disabled={subnet.cidr.maskBits === 32} title="Increase mask size">+</button>
</td>
</tr>
</tbody>

View File

@@ -32,7 +32,7 @@
}
.vpc-view .address-space {
font-size: 1.5em;
font-size: 1.2em;
vertical-align: middle;
}

View File

@@ -1,11 +1,13 @@
import React, { useState } from 'react';
import BinaryStringView from '../../core/components/BinaryString';
import './VpcView.css';
import { getNetworkAddress, getBroadCastAddress, createSubnetMaskIp, getAddressSpaceSize } from '../subnet-utils';
import { chunkifyString } from '../../core/utils';
import { getNetworkAddress, getAddressSpaceSize } from '../subnet-utils';
import IpAddressBinaryString from './IpAddressBinaryString';
import { IpAddress, IpAddressWithSubnetMask, SubnetCommand, VpcCommand } from '../models';
import formatter, { padLeft } from '../../core/formatter';
import { IpAddress, IpAddressWithSubnetMask, VpcCommand } from '../models';
import formatter from '../../core/formatter';
import Toggle from '../../shell/components/Toggle';
import { faQuestionCircle } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
const MAX_NON_HOSTS_BITS = 30; // leave two bits for hosts min
@@ -24,7 +26,6 @@ function SubnetView(props : {vpc : VpcCommand}) {
const incrVpc = () => setVpc(vpc.changeVpcCidr(new IpAddressWithSubnetMask(vpc.cidr.ipAddress, vpc.cidr.maskBits + 1)));
const decrVpc = () => setVpc(vpc.changeVpcCidr(new IpAddressWithSubnetMask(vpc.cidr.ipAddress, vpc.cidr.maskBits - 1)));
const split = formatter.splitByMasks(networkAddress.toBinaryString(), vpc.cidr.maskBits, subnetMaskSize);
return <React.Fragment>
@@ -35,21 +36,35 @@ function SubnetView(props : {vpc : VpcCommand}) {
<div>
<span>VPC Network Address</span>
</div>
<div>
<BinaryStringView binaryString={split.vpc} disableHighlight={true} className="address-space soft" />
<BinaryStringView binaryString={split.subnet} disableHighlight={true} className="address-space subnet-part" />
<BinaryStringView binaryString={split.hosts} disableHighlight={true} className="address-space host-part" />
<span className="address-space decimal-part">{networkAddress.toString()}</span>
<Toggle text="[i]" isOn={vpc.showLegend} onClick={() => setVpc(vpc.toggleLegend())} title="Show/Hide Color Legend">
<FontAwesomeIcon className="icon" icon={faQuestionCircle} size="sm" />
</Toggle>
</div>
<div style={{"display" : vpc.showLegend ? '' : 'none'}}>
<p>
Color Legend
</p>
<span className="address-space soft">000</span> - VPC address bits <br/>
<span className="address-space subnet-part">000</span> - Bits dedicated for subnets address<br/>
<span className="address-space host-part">000</span> - Bits dedicated to host addresses inside each subnet
</div>
</div>
<table className="vpc-details">
<tbody>
<tr>
<td className="soft">
VPC CIDR Mask:
</td>
<td>
<button onClick={decrVpc} disabled={vpc.cidr.maskBits <= 1} title="Decrease vpc address bits">-</button>
<button className="btn" onClick={decrVpc} disabled={vpc.cidr.maskBits <= 1} title="Decrease vpc address bits">-</button>
/{vpc.cidr.maskBits}
<button onClick={incrVpc} disabled={subnetMaskSize >= MAX_NON_HOSTS_BITS} title="Increse vpc address bits">+</button>
<button className="btn" onClick={incrVpc} disabled={subnetMaskSize >= MAX_NON_HOSTS_BITS} title="Increse vpc address bits">+</button>
</td>
</tr>
<tr>
@@ -57,9 +72,9 @@ function SubnetView(props : {vpc : VpcCommand}) {
Subnet CIDR Mask:
</td>
<td>
<button onClick={decrSubnet} disabled={vpc.subnetBits <= 1} title="Increase subnet bits">-</button>
<button className="btn" onClick={decrSubnet} disabled={vpc.subnetBits <= 1} title="Increase subnet bits">-</button>
/{subnetMaskSize}
<button onClick={incrSubnet} disabled={vpc.cidr.maskBits + vpc.subnetBits >= MAX_NON_HOSTS_BITS} title="Increase subnet bits">+</button>
<button className="btn" onClick={incrSubnet} disabled={vpc.cidr.maskBits + vpc.subnetBits >= MAX_NON_HOSTS_BITS} title="Increase subnet bits">+</button>
</td>
</tr>
<tr>
@@ -67,9 +82,9 @@ function SubnetView(props : {vpc : VpcCommand}) {
Max Subnets in VPC:
</td>
<td>
<button onClick={decrSubnet} disabled={vpc.subnetBits <= 1} title="Decrease subnet bits">-</button>
<button className="btn" onClick={decrSubnet} disabled={vpc.subnetBits <= 1} title="Decrease subnet bits">-</button>
{maxSubnets}
<button onClick={incrSubnet} disabled={vpc.cidr.maskBits + vpc.subnetBits >= MAX_NON_HOSTS_BITS} title="Increase subnet bits">+</button>
<button className="btn" onClick={incrSubnet} disabled={vpc.cidr.maskBits + vpc.subnetBits >= MAX_NON_HOSTS_BITS} title="Increase subnet bits">+</button>
</td>
</tr>
<tr>
@@ -88,6 +103,7 @@ function SubnetView(props : {vpc : VpcCommand}) {
{hostsPerSubnet}
</td>
</tr>
</tbody>
</table>
</div>
</React.Fragment>;
@@ -114,17 +130,23 @@ class VpcModel {
cidr: IpAddressWithSubnetMask;
subnetBits: number;
subnetNum: number;
showLegend: boolean;
constructor(cidr: IpAddressWithSubnetMask, subnetBits: number) {
this.cidr = cidr;
this.subnetBits = subnetBits;
this.subnetNum = 0;
this.showLegend = false;
}
static create(vpc: VpcCommand) {
return new VpcModel(vpc.cidr, vpc.subnetBits);
}
clone() : VpcModel {
return Object.assign(new VpcModel(this.cidr, this.subnetBits), this);
}
changeSubnetBits(n: number) {
return new VpcModel(this.cidr, n);
}
@@ -132,4 +154,10 @@ class VpcModel {
changeVpcCidr(newCidr: IpAddressWithSubnetMask) {
return new VpcModel(newCidr, this.subnetBits);
}
toggleLegend() {
var n = new VpcModel(this.cidr, this.subnetBits);
n.showLegend = !this.showLegend;
return n;
}
}

View File

@@ -14,8 +14,7 @@ export class IpAddressWithSubnetMask {
}
getAdressSpaceSize(): number {
const spaceLengthInBits = 32 - this.maskBits;
return getAddressSpaceSize(spaceLengthInBits);
return getAddressSpaceSize(this.maskBits);
}
toString() {

View File

@@ -1,6 +1,6 @@
import log from 'loglevel';
const APP_VERSION = 6;
const APP_VERSION = 7;
export type PersistedAppData = {
emphasizeBytes: boolean;
@@ -59,6 +59,14 @@ export default class AppState {
this.triggerChanged();
}
removeResult(index: number) {
if(index < 0 || index >= this.commandResults.length)
return;
this.commandResults.splice(index, 1);
this.triggerChanged();
}
toggleEmphasizeBytes() {
this.emphasizeBytes = !this.emphasizeBytes;
this.triggerChanged();

View File

@@ -38,7 +38,7 @@ export default class AppRoot extends React.Component<AppRootProps, AppRootState>
getResultViews() : JSX.Element[] {
var results = this.state.commandResults.map((r, i) =>
<DisplayResultView key={r.key} input={r.input} inputHash={hash.encodeHash(r.input)} appState={this.props.appState}>
<DisplayResultView resultIndex={i} resultKey={r.key} key={r.key} input={r.input} inputHash={hash.encodeHash(r.input)} appState={this.props.appState}>
{r.view}
</DisplayResultView>);
return results;

View File

@@ -23,7 +23,7 @@ function DebugIndicators(props: {appState: AppState}) {
return null;
return <div className="debug-indicators">
{list.map(i => <span title={i}>[{i.substring(0,1)}]&nbsp;</span>)}
{list.map(i => <span title={i} key={i}>[{i.substring(0,1)}]&nbsp;</span>)}
</div>
}

View File

@@ -1,3 +1,5 @@
import { faTrashAlt, faHashtag } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import React from 'react';
import AppState from '../AppState';
@@ -6,23 +8,32 @@ type DisplayResultProps = {
appState: AppState,
inputHash: string,
input: string,
key: number,
resultKey: number,
resultIndex: number,
onRemove?: (i: number) => void;
}
export default class DisplayResultView extends React.Component<DisplayResultProps> {
render() {
const DisplayResultView: React.FunctionComponent<DisplayResultProps> = (props) => {
const resultKey : number = props.resultKey;
const appState = props.appState;
return <div className="result">
<div className="input mono">
<span className="cur">
&gt;</span>{this.props.input}
<a className="hashLink" title="Link for this expression" href={window.location.pathname + '#' + this.props.inputHash}>#</a>
&gt;</span>{props.input}
<a className="hashLink" title="Link for this expression" href={window.location.pathname + '#' + props.inputHash}>
<FontAwesomeIcon className="icon" icon={faHashtag} size="xs" />
</a>
<button className="hashLink" title="Remove this result" onClick={() => appState.removeResult(props.resultIndex)}>
<FontAwesomeIcon className="icon" icon={faTrashAlt} size="xs" />
</button>
</div>
<div className="content">
{this.props.children}
{props.children}
</div>
</div>;
}
}
export default DisplayResultView;

View File

@@ -20,6 +20,7 @@ function HelpResultView() {
<li><code><CommandLink text="127.0.0.1" /></code> enter single or multiple ip addresses (separated by space) to see their binary represenation</li>
<li><code><CommandLink text="192.168.0.1/8" /></code> subnet mask notiations are support as well</li>
<li><code><CommandLink text="subnet 192.168.24.1/14" /></code> display information about subnet (network address, broadcast address, etc.)</li>
<li><code><CommandLink text="vpc 192.168.24.1/24" /></code> see how VPC network address bits are divided between VPC address, Subnets and Hosts</li>
</ul>
</div>
<div className="section">

View File

@@ -2,18 +2,21 @@
import React from "react";
export type ToggleProps = {
text: string,
text?: string,
isOn: boolean,
title: string,
elementId?: string
onClick: () => void
};
function Toggle(props: ToggleProps) {
const Toggle: React.FunctionComponent<ToggleProps> = (props) => {
return <span id={props.elementId}
className={"indicator " + getIndicator(props.isOn)}
title={props.title}
onClick={() => props.onClick()}>{props.text}</span>
onClick={() => props.onClick()}>
{ !props.children ? props.text : props.children }
</span>
}
function getIndicator(value : boolean) {

View File

@@ -7,6 +7,14 @@ function WhatsnewResultView() {
return <div className="changelog">
<h3>Changelog</h3>
<div className="item item-new">
<p><span className="soft date">Jul 24th, 2021</span> <br/>
<ul>
<li>Added support of <code>vpc</code> command to see hpw VPC network address is divided bettwen VPC, Subnets and Hosts. Try it out: <CommandLink text="vpc 192.168.24.1/24" /></li>
<li>Added ability to remove individual results</li>
</ul>
</p>
</div>
<div className="item">
<p><span className="soft date">Jun 16th, 2021</span> <br/>
Added support of <code>subnet</code> command to display information about subnet ip adress such. Try it out: <CommandLink text="subnet 192.168.24.1/14" />
</p>