GithubHelp home page GithubHelp logo

openshift / angular-key-value-editor Goto Github PK

View Code? Open in Web Editor NEW
14.0 11.0 13.0 404 KB

A simple UI for editing key-value pairs

License: Other

JavaScript 56.19% HTML 42.71% CSS 0.92% Shell 0.18%

angular-key-value-editor's Introduction

angular-key-value-editor

A simple UI for editing key-value pairs

key-value-editor screenshot

Dependencies

This key-value-editor is based on the bootstrap based framework Patternfly. Patternfly or a similar boostrap based framework should be present for proper layout rendering. Icons are from font awesome. Alternative layouts with a different framework could be achieved by replacing the key-value-editor.html template which is pre-compiled into compiled-templates.js for convenience.

Tests

See the Test Readme.md file for details about running tests.

Basic usage:

Add the key-value-editor in html and provide it some data via the entries attribute:

<!-- hard coded -->
<key-value-editor entries="[{key: 'foo', value: 'bar'}]"></key-value-editor>
<!-- via scope -->
<key-value-editor entries="entries"></key-value-editor>

Note that entries is required or <key-value-editor> will log an error!

Attributes

For configuring the directive as a whole, use the following attributes.

Automatic vs manual rows:

key-value-editor screenshot

Automatic row creation is the default, however this may not be the most accessible solution depending on the placement of your other form inputs and buttons. For this reason, the attribute add-row-link is provided. If present, a link will appear that allows the user to manually create new pairs. The link text is set by passing a value to the attribute.

<key-value-editor
  entries="entries"
  add-row-link="Add another key,value pair"></key-value-editor>

If the automatic row creation feature is used, a user cannot tab past the last input in the <key-value-editor>. If a mouse or track pad is unavailable, this is not ideal as inputs after the <key-value-editor> will be unreachable, perhaps including the form submit itself.

Readonly:

<key-value-editor
  entries="entries"
  is-readonly></key-value-editor>

(is-readonly can also be an array of string names is-readonly="['foo']" for selectively making individual entries readonly. In addition, each entry.isReadonly can be set to true||false.)

Readonly keys:

<key-value-editor
  entries="entries"
  is-readonly-keys></key-value-editor>

Makes the keys of the inital set of entries readonly. Does not affect added entries. (In implementation, this just sets isReadonlyKey: true on each of the entries in the initial set of entries for you. isReadonlyKey can be directly controlled if preferred)

Disable adding new entries:

<key-value-editor
  entries="entries"
  cannot-add></key-value-editor>

Disable sorting entries:

<key-value-editor
  entries="entries"
  cannot-sort></key-value-editor>

(Sort handle will only appear if there is more than one entry in the list.)

Disable deleting entries:

<key-value-editor
  entries="entries"
  cannot-delete></key-value-editor>

(cannot-delete can also be an array of string names cannot-delete="['foo']" for selectively making individual entries readonly. In addition, each entry.cannotDelete can be set to true||false.)

Use the attributes together:

<key-value-editor
  entries="entries"
  is-readonly
  cannot-add    
  cannot-sort
  cannot-delete></key-value-editor>

Some of the above attributes can also be applied to individual entries to control them uniquely within the set:

$scope.entries = [{
  key: 'foo',
  value: 'bar',
  isReadonly: true,      // key & value are readonly
  isReadonlyKey: true,   // only key (name) is readonly
  cannotDelete: true
}];

Validator attributes and error messages:

<key-value-editor
  entries="entries"
  key-validator="[a-zA-Z0-9_]*"
  key-validator-error="Invalid name"  
  value-validator="[a-zA-Z0-9_]*"
  value-validator-error="Invalid value"></key-value-editor>

To pass a regex directly (or an object with a .test() method, simulating a regex), you can do something like the following:

// controller code:
$scope.validation = {
  key: new RegExp('^[0-9]+$'), // numbers only
  val: {
    test: function(val) {
      // some complicated test w/multiple regex or other insanity
    }
  }
}
<!-- view code -->
<key-value-editor
  entries="entries"
  key-validator-regex="validation.key"
  key-validator-error="Invalid name, numbers only plz"  
  value-validator-regex="validation.val"
  value-validator-error="Invalid value, cuz *complicated* things"></key-value-editor>

All attributes for convenient reference.

<key-value-editor
  entries="[
    {name: 'foo', value: 'stuff'},
    {name: 'bar', value: 'things'},
    {
      name: 'baz',
      value: '3',
      isReadonly: true,
      cannotDelete: true,
      isReadonlyKey: true
    }
  ]"
  key-placeholder="name"
  key-min-length="3"
  key-max-length="25"
  key-validator="[a-zA-Z0-9_]*"
  key-validator-error="Invalid name"
  key-validator-error-tooltip="Name must be alphanumeric including - and _"
  key-validator-error-tooltip-icon="fa fa-exclamation-circle"
  value-placeholder="value"
  value-min-length="3"
  value-max-length="25"
  value-validator="[a-zA-Z0-9_]*"
  value-validator-error="Invalid value"
  is-readonly="['can','be','a','list']"
  is-readonly-keys
  cannot-delete="['can','be','a','list']"
  cannot-add    
  cannot-sort
  grab-focus></key-value-editor>

Non-standard Values

key-value-editor screenshot

Some entry lists may include non-standard key-value pairs. If the value is not a string, or is a different object entirely, such as this:

$scope.entries = [{
                    name: 'entry_value',
                    value: 'value'
                  },{
                    name: 'valueFrom-valueAlt',
                    isReadonly: true,
                    // non-standard
                    valueFrom: {
                      "configMapKeyRef": {
                        "name": "test-configmap",
                        "key": "data-1"
                      }
                    },
                    // valueAlt to the rescue!
                    valueAlt: 'valueFrom is a non-standard value',
                  }];

The valueAlt attribute can provide the user with some alt text for understanding that this key-value pair will not display properly. It is not necessary to set isReadonly:true as an input receiving valueAlt will auto to readonly. The valueValidator property, minLength and maxLength properties are all ignored as valueAlt is help text and it is assumed that it will break typical validation rules for the rest of the values.

Tooltip

NOTE: the default template provided with <key-value-editor> uses bootstrap tooltips via Patternfly/Bootstrap. Be sure to initialize the tooltips somewhere with code such as:

// opt in to the bootstrap tooltips
$('[data-toggle="tooltip"]').tooltip();

Validation

General validation rules can be put on the directive as attributes and will run against each of the entries:

<key-value-editor
  key-validator="{{regex}}"
  value-validator="{{regex2}}"
  key-validator-error="The error message if you break it"
  value-validator-error="The other error message if you break it"></key-value-editor>

For a more granular approach, each entry provided can have its own custom validation rules that will override the generic set on the directive:

return [{
  key: 'foo',
  value: 'bar',
  keyValidator: '[a-zA-Z0-9]+' // alphanumeric
  keyValidatorError: 'Thats not alphanumeric!!',
  valueValidator: '[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,4}', // email address
  valueValidatorError: 'Hey, this has to be an email.'
}]

For convenience, here are a few useful regex. Note that the <key-value-editor> internally uses ng-pattern which expects string regex that angular will internally new RegExp('^' + regex + '$');. Therefore be sure to leave off the leading /^ and trailing $/ or your regex will not work.

// <key-value-editor key-validator="regex.digitsOnly"></key-value-editor>
$scope.regex = {
  noWhiteSpace: '\S*',
  digitsOnly: '[0-9]+',
  alphaOnly: '[a-zA-Z]+',
  alphaNumeric: '[a-zA-Z0-9]+',
  alphaNumericUnderscore: '[a-zA-Z0-9_]*',
  alphaNumericDashes: '[a-zA-Z0-9-_]+',
  email: '[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,4}',
}

Setting global validation via the provider

Global defaults can be set via the provider:

angular
  .module('demo')
  .config([
    'keyValueEditorConfigProvider',
    function(keyValueEditorConfigProvider) {
      // set a global value here:
      keyValueEditorConfigProvider.set('keyValidator', '[0-9]+');
      // or, pass an object to set multiple values at once:
      keyValueEditorConfigProvider.set({
        keyValidator: '[0-9]+',
        keyValidatorError: 'This is an invalid key'
      });
    }
  ]);

Globals are still overridden via attributes on the <key-value-editor> directive, or via the entries="entries" data objects passed to the directive.

Other utils

There are two useful utility functions provided to help process the entries. The first will eliminate entries missing the name or value, the second will convert the list of entries to a map (object) of name-values (duplicate keys override values).

angular
  .module('app')
  .controller([
    'keyValueEditorUtils'
    function(kveUtils) {
      angular.extend($scope, {
        entries: [{name: 'foo', value: 'bar'}],
        // a 'save'function
        onSubmit: function() {
          // eliminates entries missing a key or val.
          console.log('compact', kveUtils.compactEntries($scope.entries));
          // transforms the array into an object.
          console.log('map', kveUtils.mapEntries($scope.entries));
        }
      })
    }
  ]);

If other filtering/mapping abilities are needed user will have to write own utils or use a lib such as lodash.

angular-key-value-editor's People

Contributors

benjaminapetersen avatar dtaylor113 avatar rhamilto avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

angular-key-value-editor's Issues

Are the config & $attrs assignments backwards in the link fn?

in this code:

  // min/max lengths
            $scope.keyMinlength = keyValueEditorConfig.keyMinlength || $attrs.keyMinlength;
            $scope.keyMaxlength = keyValueEditorConfig.keyMaxlength || $attrs.keyMaxlength;
            $scope.valueMinlength = keyValueEditorConfig.valueMinlength || $attrs.valueMinlength;
            $scope.valueMaxlength = keyValueEditorConfig.valueMaxlength || $attrs.valueMaxlength;
            // validation regex
            $scope.keyValidator = keyValueEditorConfig.keyValidator || $attrs.keyValidator;
            $scope.valueValidator = keyValueEditorConfig.valueValidator || $attrs.valueValidator;
            $scope.keyValidatorError = keyValueEditorConfig.keyValidatorError || $attrs.keyValidatorError;
            $scope.valueValidatorError = keyValueEditorConfig.valueValidatorError || $attrs.valueValidatorError;
            // key value validator error tooltip
            $scope.keyValidatorErrorTooltip = keyValueEditorConfig.keyValidatorErrorTooltip || $attrs.keyValidatorErrorTooltip;
            $scope.keyValidatorErrorTooltipIcon = keyValueEditorConfig.keyValidatorErrorTooltipIcon || $attrs.keyValidatorErrorTooltipIcon;
            // secret values
            $scope.secretValueTooltip = keyValueEditorConfig.secretValueTooltip || $attrs.secretValueTooltip;
            $scope.secretValueIcon = keyValueEditorConfig.secretValueIcon || $attrs.secretValueIcon;
            // placeholders
            $scope.keyPlaceholder = keyValueEditorConfig.keyPlaceholder || $attrs.keyPlaceholder;
            $scope.valuePlaceholder = keyValueEditorConfig.valuePlaceholder || $attrs.valuePlaceholder;

Seems like the $attrs should come first. @rhamilto

Setup unit tests

We have enough dense complexity here that it really would be nice to run tests when we commit at this point & avoid regressions.

Support readonly secrets

This is a "key value pair"... but the value is something complicated that really can't be displayed. Therefore we probably need a displayName property on the entry.

Doc some corner case attrib mixes

Example:

<key-value-editor
    entries="entries"
    is-readonly
    add-row-link></key-value-editor>

the add-row-link will exist, but is-readonly means no rows can be edited. Don't use add-row-link with is-readonly. This is simple enough, but could be problematic if some attribs are conditionally applied via ng-attr-* usage.

Setup e2e style tests

Prob some of the features cannot be easily tested via standard unit tests. Therefore setting up protractor would probably be handy.

Ensure no empty pairs in returned source

Right now we are tacking on an extra empty pair every time the last pair is clicked. This may need to be adjusted, perhaps by putting the "new" empty item in its own separate block until the user interacts with it. $dirty may be the route to take, however it may just end up being the responsibity of the object receiving the pairs to ensure final validation (ie, no lingering empty pairs anywhere, as the user could blank them all out).

Add labels for inputs

Need to ensure that screen readers can clearly communicate the purpose of each input.

'is-readonly' attribute should take boolean

'is-readonly' attribute should take boolean, since the there are cases we want to have the envVar editor readlony and cases we don't.
Eg: different users have different actions allowed, so when checking user's permissions we would pass the result into the attribute

Fix the validator error tooltip title attrib

Code snippet when bug found:

<span ng-if="entry.keyValidatorErrorTooltip || keyValidatorErrorTooltip" class="help action-inline">
            <a aria-hidden="true" data-toggle="tooltip" data-placement="top" title="{{entry.keyValidatorErrorTooltip || keyValidatorErrorTooltip}}">
              <i class="{{entry.keyValidatorErrorTooltipIcon || keyValidatorErrorTooltipIcon}}"></i>
            </a>
          </span>

did not render properly via bootstrap tooltip, hack around was to use data-original-title="" directly, but this isn't right.

@rhamilto

value as a textarea

Some values may be quite a bit larger and require a textbox instead of an input.

@rhamilto im adding as issues so we can work on them if we divvy out anything

validation

A general keyValidator and valueValidator property should be able to be set to provide regex validation for the key-value pairs.

Ideally these should be able to be provided on each entry as keyValidator: '<some-regex>' so individual entries can be uniquely validated if they serve different purposes

Fix main entry in bower.json

bower complains:

bower angular-key-value-editor#1.1.0     invalid-meta The "main" field has to contain only 1 file per filetype; found multiple .js files: ["dist/angular-key-value-editor.js","dist/compiled-templates.js"]

Fix is probably to create a third file & put the minified js + compiled templates together (but leaves option for someone to opt out of templates).

Finish demo by saving modifications

add a "save" button to the demo that will take the UI copy of the data and merge it back into the original data to conceptually send to server (or whatever is going to be done with it).

support object as well as array

Opening this mostly to illustrate why it won't be supported.

Illustration:

var list = [{
  name: 'foo',
  value: 'bar'
  isReadonly: true
}, {
  name: 'foo2',
  value: 'bar2'
  cannotDelete: true
}];

var list2 = {
  foo: 'bar',        // now, how to add additional props? mess. nope.
  foo2: 'bar2'
}

A plain object of key-value pairs can't be supported while also supporting the additional properties desired. For this reason, objects should be converted to a list to display with this control, then back to an object when user interaction is complete (save, etc).

@rhamilto just documenting why this wont work

update main in bower.json

@rhamilto just found this when added to web console :)

  "main": [
    "dist/angular-key-value-editor.css",
    "dist/angular-key-value-editor.js",
    "dist/compiled-templates.js"
  ],

Add cache to travis.yml?

Removed this block, but perhaps should put it back:

#cache:
#  directories:
#  - node_modules
#  - bower_components

Create a picker directive for complex key value pairs

In the web console of openshift we will have key value pars where the value is a complex object (something like choosing a value from a secret, or from a config map). This directive needs to be able to take an array of data to "choose" from, or perhaps take a url that would allow it to fetch data to then present as a picker.

I'm leaning towards no HTTP calls, that should be provided by calling code (controller).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.