Skip to content

Commit

Permalink
- improved UI around adding new vars
Browse files Browse the repository at this point in the history
- updated documentation
  • Loading branch information
ChuckJonas committed Jul 9, 2019
1 parent cf9a692 commit 162d61d
Show file tree
Hide file tree
Showing 7 changed files with 330 additions and 293 deletions.
19 changes: 10 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Salesforce Environment Variables

A simple library for using Custom Metadata to manage simple Key/Value Environment variables + Admin UI.
A simple library which uses Custom Metadata to manage simple Key/Value Environment variables. Includes a custom UI to make configuration as easy & error free as possible.

![UI](https://user-images.githubusercontent.com/5217568/58003863-f841e400-7a9e-11e9-8e7a-27b710606086.png)

***WARNING:*** This project has been updated to a [namespaced unlocked package](https://github.com/ChuckJonas/Salesforce-Environment-Vars/issues/3). If you have already installed and want to stay up-to-sync with the latest improvements, then please follow the manual [migration process](https://github.com/ChuckJonas/Salesforce-Environment-Vars/blob/master/docs/upgrade-from-unpackaged.md)!
***NOTE:*** This project has been updated to a [namespaced unlocked package](https://github.com/ChuckJonas/Salesforce-Environment-Vars/issues/3). If you have already installed and want to stay up-to-sync with the latest improvements, then please follow the [manual migration process](https://github.com/ChuckJonas/Salesforce-Environment-Vars/blob/master/docs/UPGRADE-FROM-UNPACKAGED.md)!

## Install

Expand All @@ -18,7 +18,7 @@ login and navigate to [`/packaging/installPackage.apexp?p0=04t1C000000tfH0QAI`](
## Usage

1. Open Environment Variables from the app switcher (or "tabs" in classic)
2. Setup vars
2. Add and Save some env-vars
3. Use in Apex or Formulas<sup>1</sup>

Apex:
Expand All @@ -43,23 +43,24 @@ $CustomMetadata.VARS__ENV__mdt.FIELD_MAP.Val__c
- `String[]`: Format: `["a","b","c"]`
- `Map<String,String>`: Format: `{"456":"xyz","123":"abc"}`

### copy as apex/formula code to clipboard
### copy apex/formula code to clipboard
![copy code](https://user-images.githubusercontent.com/5217568/58001336-6636dd00-7a98-11e9-875b-a468d42633cc.png)

### "type-checking" to prevent user input errors
![copy code](https://user-images.githubusercontent.com/5217568/58004297-2ecc2e80-7aa0-11e9-9ca9-c0e2e5d4a0da.png)

### Optional "secret" values Support
### "secret" Values Support (Optional)

<img width="1342" alt="Salesforce_-_Unlimited_Edition" src="https://user-images.githubusercontent.com/5217568/60910786-f4c90e80-a23e-11e9-9806-6bf47a2a8f07.png">

In order to enable, [follow these instructions](https://github.com/ChuckJonas/Salesforce-Environment-Vars/blob/master/docs/ENABLE-SECRETS.md).

<img width="1342" alt="Salesforce_-_Unlimited_Edition" src="https://user-images.githubusercontent.com/5217568/60910786-f4c90e80-a23e-11e9-9806-6bf47a2a8f07.png">

### Quick Find on KEY or VALUE

### auto-formatting of JSON types

### ability to group "VARS"
### ability to group like "VARS" together

### ability to add Notes
![notes](
Expand All @@ -68,7 +69,7 @@ https://user-images.githubusercontent.com/5217568/58004459-7d79c880-7aa0-11e9-96
### Table of Contents / Glossary Index


### Contributing/Modifying
## Contributing/Modifying

Project Overview:

Expand All @@ -78,4 +79,4 @@ Project Overview:
- `sf-env-vars-npm`: npm package to make using env-vars easy in js applications


** Powered by [Callaway Cloud Consulting](http://www.callawaycloud.com/) **
** Powered by ** [Callaway Cloud Consulting](https://www.callawaycloud.com/)
67 changes: 42 additions & 25 deletions app/app.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Button, Card, Divider, Input, message, Spin, Switch } from 'antd';
import { Button, Card, Divider, Input, message, Spin, Switch, Affix } from 'antd';
import { hot } from 'react-hot-loader'; // needs to be before react!
import * as React from 'react';
import { EnvGroup } from './components/EnvGroup';
Expand All @@ -18,6 +18,7 @@ interface AppState {
}

class App extends React.Component<{}, AppState> {
private newRef = React.createRef<EnvVarItem>();
private mdapi: MetadataService;
private draggedItem: EnvVar;
constructor(props: any) {
Expand Down Expand Up @@ -104,9 +105,9 @@ class App extends React.Component<{}, AppState> {
const groups = this.state.groups.filter((g) => g !== undefined);
const vars: EnvVar[] = [...this.state.vars].filter(v => v.group !== undefined);
let groupVars = this.state.vars.filter(v => v.group === undefined)
groupVars.forEach(v => {
vars.push({ ...v, ...{ group: '' } });
});
groupVars.forEach(v => {
vars.push({ ...v, ...{ group: '' } });
});
this.setState({ groups, vars });
}

Expand All @@ -129,7 +130,12 @@ class App extends React.Component<{}, AppState> {
notes: '',
value: '',
});
this.setState({ vars });

this.setState({ vars }, ()=>{
if (this.newRef && this.newRef.current) {
this.newRef.current.focus();
}
});
}

// === DML HANDLERS ===
Expand Down Expand Up @@ -204,7 +210,9 @@ class App extends React.Component<{}, AppState> {

groupVars[group] = gVars.map((v, i) => {
return (

<EnvVarItem
ref={v.key ? null : this.newRef}
key={i}
item={v}
onRemove={this.removeVar}
Expand Down Expand Up @@ -244,26 +252,35 @@ class App extends React.Component<{}, AppState> {
);

return (

<Card
title='Environment Variables'
extra={toc}
>
<Spin spinning={this.state.loading} >
<Input.Search
placeholder='Search Keys or Values'
value={this.state.filter}
onChange={(e) => this.setState({ filter: e.target.value })}
allowClear={true}
style={{ width: '35%' }}
/>
<Button style={{ marginLeft: 10 }} icon='folder' onClick={() => this.newGroup()}>Add Group</Button>
<SecretsEnabled style={{float:'right'}} enabled={this.state.secretsEnabled} />
<Divider dashed={true} />
{groupElements}
<Button style={{ marginTop: 15 }} type='primary' icon='plus' onClick={this.addNew}>Add</Button>
</Spin>
</Card>
<div>
<Card
title='Environment Variables'
extra={toc}

>
<Spin spinning={this.state.loading} >
<Input.Search
placeholder='Search Keys or Values'
value={this.state.filter}
onChange={(e) => this.setState({ filter: e.target.value })}
allowClear={true}
style={{ width: '35%' }}
/>
<SecretsEnabled style={{ float: 'right' }} enabled={this.state.secretsEnabled} />

<Divider dashed={true} />
{groupElements}

</Spin>

</Card>
<Affix offsetBottom={10}>
<Card>
<Button style={{ marginTop: 15 }} type='primary' icon='plus' onClick={this.addNew}>Add</Button>
<Button style={{ marginLeft: 10 }} icon='folder' onClick={() => this.newGroup()}>Add Group</Button>
</Card>
</Affix>
</div>
);
}

Expand Down
22 changes: 16 additions & 6 deletions app/components/EnvItem/EnvItem.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as React from 'react';
import { Input, Button, Icon, Tooltip, Popover, message, Switch, Divider } from 'antd';
import TextArea from 'antd/lib/input/TextArea';
import { EnvVar, DataType } from '@src/types';
import { Input, Button, Icon, Tooltip, message, Switch, Divider } from 'antd';
import { EnvVar } from '@src/types';
import { NotesModal } from './NotesModal';
import { DataTypeSelect } from '../DataTypeSelect';
import { DeleteButton } from './DeleteButton';
Expand All @@ -13,7 +12,7 @@ const InputGroup = Input.Group;
export interface EnvVarItemProps {
item: EnvVar;
onRemove: (item: EnvVar) => void;
onUpdate: (item: EnvVar, field: keyof EnvVar, value: string|boolean) => void;
onUpdate: (item: EnvVar, field: keyof EnvVar, value: string | boolean) => void;
onSave: (item: EnvVar) => void;
onDragStart: (e: any, item: EnvVar) => void;
onDragOver: (draggedOver: EnvVar) => void;
Expand All @@ -26,15 +25,25 @@ export interface EnvVarItemState {
}

export class EnvVarItem extends React.Component<EnvVarItemProps, EnvVarItemState> {

private keyInput: React.RefObject<Input>;
constructor(props: EnvVarItemProps) {
super(props);
this.keyInput = React.createRef();
this.state = {
editing: false,
actionsVisible: false,
};
}

public focus = () => {
this.keyInput.current.input.focus();
this.keyInput.current.input.scrollIntoView({
behavior: 'smooth',
block: 'center',
inline: 'center'
});
}

private copySuccess = () => {
message.success('copied to clipboard');
this.setState({ actionsVisible: false })
Expand Down Expand Up @@ -81,7 +90,7 @@ export class EnvVarItem extends React.Component<EnvVarItemProps, EnvVarItemState
unCheckedChildren={<Icon type="eye" />}
/>
</Tooltip>
<Divider style={{margin:'15px 0px'}} />
<Divider style={{ margin: '15px 0px' }} />
<NotesModal
item={item}
onSaveNotes={this.onNotesSave}
Expand Down Expand Up @@ -120,6 +129,7 @@ export class EnvVarItem extends React.Component<EnvVarItemProps, EnvVarItemState
</Tooltip>

<Input
ref={this.keyInput}
style={keyStyle}
onChange={(e) => { this.props.onUpdate(item, 'key', e.target.value); }}
placeholder='KEY used to access this var. Once set, cannot be changed'
Expand Down
11 changes: 7 additions & 4 deletions docs/ENABLE-SECRETS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Enabling "Secret" Value support

*WARNING: While these values are stored encrypted, anyone with the ability to execute APEX will be able to retrieve and view them. Be careful not to leak them in logs!*
*WARNING: While these values are stored encrypted, anyone with the ability to execute APEX will be able to retrieve and view them. Be careful not to leak them in logs! It is recommended that you use "Named Credentials" or a self-contained, "namespaced managed package" with protected settings for anything that is highly sensitive*

## Install

Expand All @@ -14,7 +14,7 @@ Once installed, you'll notice that the UI now shows "Secrets Enabled"

## Usage

When creating a new env-var, you can mark it as secret BEFORE you save.
When creating a new "env var", you can mark it as "secret" BEFORE you save.

<img width="1342" alt="Salesforce_-_Unlimited_Edition" src="https://user-images.githubusercontent.com/5217568/60910786-f4c90e80-a23e-11e9-9806-6bf47a2a8f07.png">

Expand All @@ -24,9 +24,12 @@ When creating a new env-var, you can mark it as secret BEFORE you save.
- A Var cannot be made secret after it is created
- Secret vars can only be read by Apex. They will not work in formulas, or via the API.


## How it works

This package works by creating private AES key and storing it in a "Managed Protected Custom Settings" (as outlined by [salesforce best practices](https://trailhead.salesforce.com/content/learn/modules/secure-secret-storage/learn-about-platform-secret-protection)). When a "env-var" is saved as "secreted", we encrypt it using this key before we store it. It will then be decrypted automatically to `VARS.Env.get()`.
This package works by creating private AES key and storing it in a "Managed Protected Custom Settings" (as outlined by [salesforce best practices](https://trailhead.salesforce.com/content/learn/modules/secure-secret-storage/learn-about-platform-secret-protection)).

When a "env-var" is saved as "secret", we encrypt it using this key before we store it. It will then be decrypted automatically in calls to `VARS.Env.get()`.

Thus anyone who can execute `VARS.Env.get()` will essentially have the ability to read the secret.


2 changes: 1 addition & 1 deletion docs/UPGRADE-FROM-UNPACKAGED.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ If you installed this package prior to the "namespaced unlocked package release"

1. Install the packaged version
1. Use the script below to migrate your `ENV_Var__mdt` to `VARS__ENV__mdt`
1. Update any refrenences to `Env.get` to `VARS.Env.get`
1. Update any references to `Env.get` to `VARS.Env.get`
1. Update any other references to `ENV_Var__mdt` to `VARS__ENV__mdt` (formula, direct queries, rest api, etc)


Expand Down
Loading

0 comments on commit 162d61d

Please sign in to comment.