From f3eb3e16baf9ddd6c1008d3950a677a4a0cea9b0 Mon Sep 17 00:00:00 2001 From: Tomek Moryl Date: Fri, 3 Aug 2018 13:24:28 +0200 Subject: [PATCH] New Example for Action with CSS styling --- .babelrc | 3 +- .eslintrc | 244 ++++++++++++++++++ .gitattributes | 1 + .gitignore | 77 +++++- EULA.md | 36 +-- README.md | 19 +- config/certs/localhost.cert.pem | 32 --- config/certs/localhost.key.pem | 52 ---- config/colors.js | 25 -- config/paths.js | 16 -- config/webpack.common.config.js | 97 ------- config/webpack.dev.config.js | 40 --- config/webpack.prod.config.js | 33 --- config/webpackDevServer.config.js | 106 -------- package.json | 90 +++++-- screenshots/action.png | Bin 15011 -> 9376 bytes screenshots/binding.png | Bin 15472 -> 6199 bytes screenshots/helloAction.png | Bin 3093 -> 2862 bytes scripts/start.js | 29 +-- src/app/action.js | 9 +- src/app/binding.js | 4 +- src/app/components/DialogBox.jsx | 80 ++++++ src/app/components/DialogBoxConsts.jsx | 8 + .../DialogBoxContent/ButtonsArea.jsx | 13 + .../DialogBoxContent/DialogBoxContent.jsx | 39 +++ .../DialogBoxContent/DialogBoxContent.scss | 73 ++++++ .../components/DialogBoxContent/ShadowBox.jsx | 9 + src/app/containers/MainPaneContainer.js | 40 +++ src/app/index.js | 16 -- src/app/index.jsx | 23 ++ src/app/redux/actions/actionTypes.js | 8 + src/app/redux/actions/makeAction.js | 6 + src/app/redux/reducers/exampleReducer.js | 27 ++ src/app/redux/reducers/index.js | 8 + src/app/redux/saga/exampleSaga.js | 21 ++ src/app/redux/saga/index.js | 8 + src/app/services/persist.js | 10 + src/app/services/request.js | 36 +++ src/app/services/validation.js | 22 ++ src/avid_api/view/ViewWrapper.js | 20 +- src/index.js | 3 + src/package.json | 8 +- src/project.act | 10 +- src/store.js | 12 + 44 files changed, 901 insertions(+), 512 deletions(-) create mode 100644 .eslintrc create mode 100644 .gitattributes delete mode 100644 config/certs/localhost.cert.pem delete mode 100644 config/certs/localhost.key.pem delete mode 100644 config/colors.js delete mode 100644 config/paths.js delete mode 100644 config/webpack.common.config.js delete mode 100644 config/webpack.dev.config.js delete mode 100644 config/webpack.prod.config.js delete mode 100644 config/webpackDevServer.config.js create mode 100644 src/app/components/DialogBox.jsx create mode 100644 src/app/components/DialogBoxConsts.jsx create mode 100644 src/app/components/DialogBoxContent/ButtonsArea.jsx create mode 100644 src/app/components/DialogBoxContent/DialogBoxContent.jsx create mode 100644 src/app/components/DialogBoxContent/DialogBoxContent.scss create mode 100644 src/app/components/DialogBoxContent/ShadowBox.jsx create mode 100644 src/app/containers/MainPaneContainer.js delete mode 100644 src/app/index.js create mode 100644 src/app/index.jsx create mode 100644 src/app/redux/actions/actionTypes.js create mode 100644 src/app/redux/actions/makeAction.js create mode 100644 src/app/redux/reducers/exampleReducer.js create mode 100644 src/app/redux/reducers/index.js create mode 100644 src/app/redux/saga/exampleSaga.js create mode 100644 src/app/redux/saga/index.js create mode 100644 src/app/services/persist.js create mode 100644 src/app/services/request.js create mode 100644 src/app/services/validation.js create mode 100644 src/store.js diff --git a/.babelrc b/.babelrc index 38510da..bb47155 100644 --- a/.babelrc +++ b/.babelrc @@ -1,6 +1,7 @@ { "presets": [ - "env" + "env", + "react" ], "plugins": [ "transform-class-properties", diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..aa1111b --- /dev/null +++ b/.eslintrc @@ -0,0 +1,244 @@ +{ + "parser": "babel-eslint", + "env": { + "browser": true, + "node": true, + "es6": true, + "mocha": true + }, + + "plugins": ["react"], + + "parserOptions": { + "ecmaFeatures": { + "arrowFunctions": true, + "binaryLiterals": true, + "blockBindings": true, + "classes": true, + "defaultParams": true, + "destructuring": true, + "forOf": true, + "generators": true, + "modules": true, + "objectLiteralComputedProperties": true, + "objectLiteralDuplicateProperties": true, + "objectLiteralShorthandMethods": true, + "objectLiteralShorthandProperties": true, + "octalLiterals": true, + "regexUFlag": true, + "regexYFlag": true, + "spread": true, + "superInFunctions": true, + "templateStrings": true, + "unicodeCodePointEscapes": true, + "globalReturn": true, + "jsx": true + } + }, + + "rules": { + + // + //Possible Errors + // + // The following rules point out areas where you might have made mistakes. + // + "comma-dangle": ["warn", "always-multiline"], // disallow or enforce trailing commas + "no-cond-assign": 2, // disallow assignment in conditional expressions + "no-console": [1, {"allow": ["error"] }], // disallow use of console (off by default in the node environment) + "no-control-regex": 2, // disallow control characters in regular expressions + "no-debugger": 2, // disallow use of debugger + "no-dupe-args": 2, // disallow duplicate arguments in functions + "no-dupe-keys": 2, // disallow duplicate keys when creating object literals + "no-duplicate-case": 2, // disallow a duplicate case label. + "no-empty": 2, // disallow empty statements + "no-empty-character-class": 2, // disallow the use of empty character classes in regular expressions + "no-ex-assign": 2, // disallow assigning to the exception in a catch block + "no-extra-boolean-cast": 2, // disallow double-negation boolean casts in a boolean context + "no-extra-parens": 0, // disallow unnecessary parentheses (off by default) + "no-extra-semi": 2, // disallow unnecessary semicolons + "no-func-assign": 2, // disallow overwriting functions written as function declarations + "no-inner-declarations": 2, // disallow function or variable declarations in nested blocks + "no-invalid-regexp": 2, // disallow invalid regular expression strings in the RegExp constructor + "no-irregular-whitespace": 2, // disallow irregular whitespace outside of strings and comments + "no-negated-in-lhs": 2, // disallow negation of the left operand of an in expression + "no-obj-calls": 2, // disallow the use of object properties of the global object (Math and JSON) as functions + "no-regex-spaces": 2, // disallow multiple spaces in a regular expression literal + "no-sparse-arrays": 2, // disallow sparse arrays + "no-unreachable": 2, // disallow unreachable statements after a return, throw, continue, or break statement + "use-isnan": 2, // disallow comparisons with the value NaN + "valid-jsdoc": 2, // Ensure JSDoc comments are valid (off by default) + "valid-typeof": 2, // Ensure that the results of typeof are compared against a valid string + + // + // Best Practices + // + // These are rules designed to prevent you from making mistakes. + // They either prescribe a better way of doing something or help you avoid footguns. + // + "no-duplicate-imports": 1, + "prefer-const": ["error", { "destructuring": "any", "ignoreReadBeforeAssign": false }], + "block-scoped-var": 0, // treat var statements as if they were block scoped (off by default). 0: deep destructuring is not compatible https://github.com/eslint/eslint/issues/1863 + "complexity": 0, // specify the maximum cyclomatic complexity allowed in a program (off by default) + "consistent-return": 2, // require return statements to either always or never specify values + "curly": 2, // specify curly brace conventions for all control statements + "default-case": 2, // require default case in switch statements (off by default) + "dot-notation": 2, // encourages use of dot notation whenever possible + "eqeqeq": 2, // require the use of === and !== + "guard-for-in": 2, // make sure for-in loops have an if statement (off by default) + "no-alert": 2, // disallow the use of alert, confirm, and prompt + "no-caller": 2, // disallow use of arguments.caller or arguments.callee + "no-div-regex": 2, // disallow division operators explicitly at beginning of regular expression (off by default) + //"no-else-return": 2, // disallow else after a return in an if (off by default) + //"no-empty-label": 2, // disallow use of labels for anything other then loops and switches + "no-eq-null": 2, // disallow comparisons to null without a type-checking operator (off by default) + "no-eval": 2, // disallow use of eval() + "no-extend-native": 2, // disallow adding to native types + "no-extra-bind": 2, // disallow unnecessary function binding + "no-fallthrough": 2, // disallow fallthrough of case statements + "no-floating-decimal": 2, // disallow the use of leading or trailing decimal points in numeric literals (off by default) + "no-implied-eval": 2, // disallow use of eval()-like methods + "no-iterator": 2, // disallow usage of __iterator__ property + "no-lone-blocks": 2, // disallow unnecessary nested blocks + "no-loop-func": 2, // disallow creation of functions within loops + "no-multi-spaces": 0, // disallow use of multiple spaces + "no-multi-str": 2, // disallow use of multiline strings + "no-native-reassign": 2, // disallow reassignments of native objects + "no-new": 2, // disallow use of new operator when not part of the assignment or comparison + "no-new-func": 2, // disallow use of new operator for Function object + "no-new-wrappers": 2, // disallows creating new instances of String,Number, and Boolean + "no-octal": 2, // disallow use of octal literals + "no-octal-escape": 2, // disallow use of octal escape sequences in string literals, such as var foo = "Copyright \251"; + "no-param-reassign": 2, // disallow reassignment of function parameters (off by default) + "no-proto": 2, // disallow usage of __proto__ property + "no-redeclare": 2, // disallow declaring the same variable more then once + "no-return-assign": 2, // disallow use of assignment in return statement + "no-script-url": 2, // disallow use of javascript: urls. + "no-self-compare": 2, // disallow comparisons where both sides are exactly the same (off by default) + "no-sequences": 2, // disallow use of comma operator + "no-throw-literal": 2, // restrict what can be thrown as an exception (off by default) + "no-unused-expressions": 2, // disallow usage of expressions in statement position + "no-void": 2, // disallow use of void operator (off by default) + "no-warning-comments": [0, {"terms": ["todo", "fixme"], "location": "start"}], // disallow usage of configurable warning terms in comments": 2, // + "no-with": 2, // disallow use of the with statement + "radix": 2, // require use of the second argument for parseInt() (off by default) + "vars-on-top": 2, // requires to declare all vars on top of their containing scope (off by default) + "wrap-iife": 2, // require immediate function invocation to be wrapped in parentheses (off by default) + "yoda": 2, // require or disallow Yoda conditions + + // + // Strict Mode + // + // These rules relate to using strict mode. + // + "strict": 0, // controls location of Use Strict Directives. 0: required by `babel-eslint` + + // + // Variables + // + // These rules have to do with variable declarations. + // + "no-catch-shadow": 2, // disallow the catch clause parameter name being the same as a variable in the outer scope (off by default in the node environment) + "no-delete-var": 2, // disallow deletion of variables + "no-label-var": 2, // disallow labels that share a name with a variable + "no-shadow": 2, // disallow declaration of variables already declared in the outer scope + "no-shadow-restricted-names": 2, // disallow shadowing of names such as arguments + "no-undef": 2, // disallow use of undeclared variables unless mentioned in a /*global */ block + "no-undef-init": 2, // disallow use of undefined when initializing variables + "no-undefined": 2, // disallow use of undefined variable (off by default) + "no-unused-vars": 1, // disallow declaration of variables that are not used in the code + "no-use-before-define": ["error", { "functions": false, "classes": true }], // disallow use of variables before they are defined + + // + //Stylistic Issues + // + // These rules are purely matters of style and are quite subjective. + // + //"indent": [1, 2], // this option sets a specific tab width for your code (off by default) + "brace-style": 1, // enforce one true brace style (off by default) + "comma-spacing": [1, {"before": false, "after": true}], // enforce spacing before and after comma + "comma-style": [1, "last"], // enforce one true comma style (off by default) + "consistent-this": [1, "_this"], // enforces consistent naming when capturing the current execution context (off by default) + "eol-last": 1, // enforce newline at the end of file, with no multiple empty lines + "func-names": 0, // require function expressions to have a name (off by default) + "func-style": 0, // enforces use of function declarations or expressions (off by default) + +// "max-nested-callbacks": [1, 4], // specify the maximum depth callbacks can be nested (off by default) THROWN OUT BECAUSE IT MADE ME ANGRY + "new-cap": [1, {"newIsCap": true, "capIsNew": false}], // require a capital letter for constructors + "new-parens": 1, // disallow the omission of parentheses when invoking a constructor with no arguments + "newline-after-var": 0, // allow/disallow an empty newline after var statement (off by default) + "no-array-constructor": 1, // disallow use of the Array constructor + "no-inline-comments": 0, // disallow comments inline after code (off by default) + "no-lonely-if": 1, // disallow if as the only statement in an else block (off by default) + "no-mixed-spaces-and-tabs": 1, // disallow mixed spaces and tabs for indentation + "no-multiple-empty-lines": [1, {"max": 2}], // disallow multiple empty lines (off by default) + "no-new-object": 1, // disallow use of the Object constructor + "no-spaced-func": 1, // disallow space between function identifier and application + "no-ternary": 0, // disallow the use of ternary operators (off by default) + //"no-trailing-spaces": 1, // disallow trailing whitespace at the end of lines + //"no-underscore-dangle": 1, // disallow dangling underscores in identifiers + "one-var": [1, "never"], // allow just one var statement per function (off by default) + "padded-blocks": [1, "never"], // enforce padding within blocks (off by default) + + "quotes": [1, "single"], // specify whether double or single quotes should be used + "semi": [1, "always"], // require or disallow use of semicolons instead of ASI + "semi-spacing": [1, {"before": false, "after": true}], // enforce spacing before and after semicolons + "sort-vars": 0, // sort variables within the same declaration block (off by default) + // "space-after-keywords": [1, "always"], // require a space after certain keywords (off by default) + "space-before-blocks": [1, "always"], // require or disallow space before blocks (off by default) + "space-before-function-paren": [1, {"anonymous": "always", "named": "never"}], // require or disallow space before function opening parenthesis (off by default) + //"space-in-brackets": [1, "never"], // require or disallow spaces inside brackets (off by default) + "space-in-parens": [1, "never"], // require or disallow spaces inside parentheses (off by default) + "space-unary-ops": [1, {"words": true, "nonwords": false}], // Require or disallow spaces before/after unary operators (words on by default, nonwords off by default) + "spaced-comment": [1, "always"], // require or disallow a space immediately following the // in a line comment (off by default) + "wrap-regex": 0, // require regex literals to be wrapped in parentheses (off by default) + "indent": [1, 4, { "SwitchCase": 1 }], + + // + // ECMAScript 6 + // + // These rules are only relevant to ES6 environments and are off by default. + // + "no-var": 2, // require let or const instead of var (off by default) + "generator-star-spacing": [2, "before"], // enforce the spacing around the * in generator functions (off by default) + + // + // Legacy + // + // The following rules are included for compatibility with JSHint and JSLint. + // While the names of the rules may not match up with the JSHint/JSLint counterpart, + // the functionality is the same. + // + "max-depth": [2, 4], // specify the maximum depth that blocks can be nested (off by default) + "max-len": [2, 300, 2], // specify the maximum length of a line in your program (off by default) + "max-params": [2, 666], // limits the number of parameters that can be used in the function declaration. (off by default) + "max-statements": 0, // specify the maximum number of statement allowed in a function (off by default) + "no-bitwise": 0, // disallow use of bitwise operators (off by default) + + // + // eslint-plugin-react + // + // React specific linting rules for ESLint + // + "react/display-name": 0, // Prevent missing displayName in a React component definition + //"react/jsx-quotes": [2, "double", "avoid-escape"], // Enforce quote style for JSX attributes + "jsx-quotes": [ + 2, "prefer-double" + ], + // "react/jsx-quotes": 0, + "react/jsx-sort-props": 0, // Enforce props alphabetical sorting + "react/jsx-uses-react": 2, // Prevent React to be incorrectly marked as unused + "react/jsx-uses-vars": 2, // Prevent variables used in JSX to be incorrectly marked as unused + "react/no-did-mount-set-state": 2, // Prevent usage of setState in componentDidMount + "react/no-did-update-set-state": 2, // Prevent usage of setState in componentDidUpdate + "react/no-multi-comp": 0, // Prevent multiple component definition per file + "react/no-unknown-property": 2, // Prevent usage of unknown DOM property + "react/prop-types": 1, // Prevent missing props validation in a React component definition + "react/self-closing-comp": 1, // Prevent extra closing tags for components without children + "react/jsx-wrap-multilines": 1, // Prevent missing parentheses around multilines JSX + "react/no-deprecated": 2, + "react/no-direct-mutation-state": 2, + "react/no-find-dom-node": 2, + "react/no-is-mounted": 2 + } +} diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..07764a7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text eol=lf \ No newline at end of file diff --git a/.gitignore b/.gitignore index 284fdc5..cdff5dd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,67 @@ -node_modules -package-lock.json -.DS_Store -dist -build -brass_build -npm-debug.log -yarn.lock -.vs -.vscode +# Created by .ignore support plugin (hsz.mobi) +### Node template +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +# next.js build output +.next .idea -coverage/ +package-lock.json +.npm +cssch diff --git a/EULA.md b/EULA.md index e288600..6eb93bc 100644 --- a/EULA.md +++ b/EULA.md @@ -2,7 +2,7 @@ This Avid Developer Toolkit Evaluation License Agreement (the "Agreement&qu By downloading and/or using the SDK (as defined below), you unconditionally consent and agree to be bound by and a party to this Agreement. -##**1. Definitions**. +## **1. Definitions**. - **1.1.**"Avid Product" means the Avid product or products for which the SDK is intended. @@ -16,40 +16,40 @@ By downloading and/or using the SDK (as defined below), you unconditionally cons - **1.6.**"SDK Software" shall mean Avid's API, header files, library files, DLLs, Sample Code and applications that make up the SDK. -##**2. Evaluation License Grant**. +## **2. Evaluation License Grant**. Subject to the terms and conditions of this Agreement, Avid grants to You a worldwide, cost-free, temporary, nontransferable, nonexclusive, revocable license, without the right to sublicense to use the SDK solely for the purpose of evaluating the SDK in order to determine whether You wish to enter into negotiations with Avid for a future agreement related to the SDK, without any obligation upon either party to engage in any such future negotiations or enter into any future agreement. No license to develop, distribute or sell any product using the SDK is granted hereunder. -##**3. Support**. +## **3. Support**. Avid is under no obligation to provide any support for or respond to any inquiries regarding the SDK Software. Nonetheless, Avid may, in its sole discretion, respond to inquiries regarding the SDK Software or provide to You additional information relating to the SDK Software, via whatever method that Avid deems acceptable ("Future Information"). All Future Information provided by Avid in whatever format (including but not limited to oral, written, electronic, or printed) shall also be deemed to be part of the SDK for the purposes of this Agreement. This Agreement also applies to any future version of the SDK provided to You in the absence of any agreement for that future version. -##**4. Protection of Avid Confidential Information**. +## **4. Protection of Avid Confidential Information**. You acknowledge that the SDK is proprietary and contains confidential information belonging to Avid or its suppliers ("Confidential Information"). You shall use the Confidential only for the purposes set forth in Section 2 and protect the confidentiality of the Confidential Information with at least the same degree of care as You use to protect the confidentiality of your own confidential information, but in no event less than reasonable care. You shall restrict access to the Confidential Information to your employees or consultants who are each directly engaged in the performance of this Agreement and who are each contractually bound to protect the Confidential Information in accordance with this Agreement. You shall promptly notify Avid in writing of any use or disclosure in violation of this Agreement. You acknowledge that the use or disclosure of the Confidential Information in any manner inconsistent with this Agreement will cause Avid irreparable harm. In addition to the injunctive relief provided in Section 12, Avid will have the right to recover from You the amount of all such damages or expenses (including attorneys' fees and expenses) incurred by Avid in connection with such use or disclosure. -##**5. Proprietary Rights.** +## **5. Proprietary Rights.** This Agreement is a license and is not a sale of the SDK Software, or any copy thereof. Avid (and/or its suppliers or licensors) retains all rights, title, interest and ownership of the SDK Software, including patents, copyrights, trademarks and proprietary rights applicable thereto, and all copies, regardless of the form or media on or in which the original or any copy may exist. You will include and will not alter or remove any copyright, patent, trade secret, proprietary and/or other legal notices contained on or in the SDK Software, and any copy of an item, or portion thereof, of the SDK Software made by You for any reason shall contain the same proprietary notice as currently appearing on that item. You shall not use any trademark of Avid without prior written consent. -##**6. No Reverse Engineering**. +## **6. No Reverse Engineering**. You shall not, directly or indirectly, reverse engineer, decompile, or disassemble the SDK Software. -##**7. U.S. Government End Users**. +## **7. U.S. Government End Users**. If any software or documentation is acquired by or on behalf of the United States Government, the U.S. Government agrees that such software or documentation is "commercial computer software" or "commercial computer software documentation" and that absent a written agreement to the contrary, the U.S. Government's rights with respect to such software or documentation are limited by the terms of this License Agreement, pursuant to FAR § 12.212(a) and/or DFARS § 227.7202-1(a), as applicable. -##**8. Disclaimer of Warranty by Avid**. +## **8. Disclaimer of Warranty by Avid**. YOU ACKNOWLEDGE BY ENTERING INTO THIS AGREEMENT THAT AVID HAS NOT PROVIDED AND EXPRESSLY DISCLAIMS ANY WARRANTIES, TERMS OR OTHER CONDITIONS AS TO THE PERFORMANCE, CORRECTNESS, FUNCTIONALITY OR SUITABILITY OF THE SDK OR ANY RESULTS OBTAINED FROM IT, ITS USE, TITLE, QUALITY, QUIET ENJOYMENT, MERCHANTABILITY, FITNESS FOR ANY PARTICULAR PURPOSE OR ITS NON-INFRINGEMENT OF THIRD PARTY'S RIGHTS. THE SDK IS PROVIDED "AS IS" AND AVID EXPRESSLY DISCLAIMS ANY WARRANTIES, TERMS OR OTHER CONDITIONS, WHETHER EXPRESS OR IMPLIED (BY LAW, CUSTOM OR OTHERWISE), INCLUDING, BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY OR FITNESS FOR A PARTICULAR PURPOSE, WITH RESPECT TO THE SDK. AVID DOES NOT WARRANT THAT THE USE OF THE SDK WILL BE UNINTERRUPTED OR ERROR-FREE. THE ENTIRE RISK AS TO THE USE, QUALITY AND PERFORMANCE OF THE SDK IS WITH YOU OR YOUR END USERS. THIS SECTION SHALL APPLY TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW. THIS DISCLAIMER IS AN ESSENTIAL PART OF THIS AGREEMENT. -##**9. EXCLUSION OF DAMAGES**. +## **9. EXCLUSION OF DAMAGES**. YOU AGREE THAT AVID SHALL NOT BE LIABLE FOR ANY LOSS OR DAMAGE THAT MAY ARISE IN CONNECTION WITH THE FURNISHING, PERFORMANCE OR USE BY YOU OF THE SDK, INCLUDING WITHOUT LIMITATION, ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL, ECONOMIC, PUNITIVE, OR CONSEQUENTIAL DAMAGES OR ANY LOSS OF PROFIT ARISING FROM OR RELATING TO THE SDK EVEN IF AVID HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. IF YOU ARE DISSATISFIED WITH THE SDK, OR WITH THIS AGREEMENT, YOUR SOLE AND EXCLUSIVE REMEDY IS TO DISCONTINUE USING THE SDK AND TERMINATE THIS AGREEMENT. THIS SECTION SHALL APPLY TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW. -##**10. Choice of Language / Choix de Langue**. +## **10. Choice of Language / Choix de Langue**. The parties confirm that they have each requested that this Agreement and any related documents be drawn up in the English language. _Les parties aux présentes confirment que chacune d'elles a exigé que cette convention et tous les documents s'y rattachant soient rédigés en anglais._ -##**11. Indemnification**. +## **11. Indemnification**. You shall indemnify, hold harmless, and defend Avid, its directors, officers, affiliates, employees and agents, from and against any claims or lawsuits (including reasonable attorneys' fees), that arise from or relate to (1) Your use of the SDK; or (2) Your breach of Your obligations in Section 4 (Protection of Avid Confidential Information). -##**12. Injunctive Relief**. +## **12. Injunctive Relief**. You acknowledge that Your breach of this Agreement would cause irreparable harm to Avid for which a remedy at law would be inadequate. Accordingly, You agree that, in the event of such a breach, Avid shall be entitled to injunctive relief, without being required to post a bond, in addition to all other remedies that may then be available. -##**13. Term**. +## **13. Term**. - **13.1. Evaluation License Term.** This Agreement shall remain in effect for a period of ninety (90) days following download of the SDK. Either party may terminate this Agreement at any time, for any reason, effective immediately upon notice to the other party. Avid may, at your request, extend the term by written notice in its sole discretion. @@ -59,17 +59,17 @@ You acknowledge that Your breach of this Agreement would cause irreparable harm - 13.2.2.destroy all copies of the SDK created by You; and - 13.2.3.cease copying and distributing the SDK Software or any modifications to the SDK Software. -##**14. Export.** +## **14. Export.** You acknowledge that the SDK is subject to U.S. export jurisdiction. You agree to comply with all applicable international and national laws that apply to the SDK, including the U.S. Export Administration Regulations, as well as end-user, end use, and destination restrictions issued by U.S. and other governments. -##**15. Choice Of Law.** +## **15. Choice Of Law.** This Agreement shall be construed and enforced in accordance with the laws of the Commonwealth of Massachusetts, U.S.A., without regard to conflict of laws rules that would cause the laws of any other jurisdiction to apply. The parties agree that the exclusive venue for disputes regarding any breach or for the enforcement of this Agreement shall be the state or federal courts in and of the Commonwealth of Massachusetts, and each of the parties submits to the exclusive jurisdiction of such courts. Notwithstanding the foregoing, Avid reserves the right to seek equitable relief, such as an injunction, for the infringement of any trademark or copyright in whatever jurisdiction as may be appropriate. This Agreement will not be governed by (1) the United Nations Convention on Contracts for the International Sale of Goods; (2) the 1974 Convention on the Limitation Period in the International Sale of Goods (the "1974 Convention"); and (3) the Protocol amending the 1974 Convention, done at Vienna April 11, 1980. -##**16. Identification of Licensee.** +## **16. Identification of Licensee.** You grant to Avid permission to use Your name and logo for marketing purposes, subject to Your prior consent, which shall not be withheld unreasonably. -##**17. Change of Control; Bankruptcy.** +## **17. Change of Control; Bankruptcy.** You shall notify Avid in the event of: (1) a change in the Control of Licensee; (2) the institution by or against Licensee of insolvency, receivership or bankruptcy proceedings or any other proceedings for the settlement of Licensee's debts; or (3) a general assignment for the benefit of creditors by Licensee. -##**18. General.** +## **18. General.** This Agreement shall constitute the complete and exclusive agreement between You and Avid with regard to the SDK. For avoidance of doubt, the parties acknowledge that nothing in this Agreement is intended to supersede or terminate any separate confidentiality agreement that may be between them and that information exchanged between the parties pursuant to that confidentiality agreement shall continue to be protected in accordance with its own terms. The terms and conditions of this Agreement shall not be modified unless both You and an authorized Avid representative execute a separate written instrument. If any provision of this Agreement is held to be unenforceable for any reason, such provision shall be reformed only to the extent necessary to make it enforceable and such decision shall not affect the enforceability of such provision under other circumstances and in other jurisdictions, or of the remaining provisions hereof under all circumstances. You acknowledge that You and Avid are independent entities, that You are not a representative, agent, employee, or partner of Avid, and that You have no authority to speak for or incur obligations on behalf of or bind Avid. Any delay or failure by Avid to exercise any of its rights hereunder shall not constitute or be deemed a waiver or forfeiture of such rights. Sections4 (Protection of Avid Confidential Information), 5 (Proprietary Rights), 6 (No Reverse Engineering), 8 (Disclaimer of Warranty by Avid), 9 (Exclusion of Damages), 10 (Choice of Language), 11 (Indemnification), 13.2 (Termination or Expiration), 15 (Choice of Law), and 18 (General), and all applicable definitions shall survive expiration or termination of this Agreement. \ No newline at end of file diff --git a/README.md b/README.md index 57b9886..1f57294 100644 --- a/README.md +++ b/README.md @@ -20,25 +20,18 @@ See action displayed: ![Alt text](screenshots/helloAction.png "Hello") -Action definition: +Action [definition](src/app/action.js "Action"): ![Alt text](screenshots/action.png "Hello") -Binding definition: +Binding [definition](src/app/binding.js "Action"): ![Alt text](screenshots/binding.png "Hello") ## Running the examples To run these examples you will need a running MediaCentral Cloud UX server running. -Connection settings can be changed in [src/project.act](src/project.act) -### Dependencies -* [cloudux-l10n ](https://www.npmjs.com/package/cloudux-l10n) - -### MediaCentral Cloud UX Toolkit -This example contains a basic action description and it's binding. - -Running: - - npm install - npm start +**Running:** +1. Change connections settings in [src/project.act](src/project.act) +2. In CLI type **npm install** +3. Then in CLI type **npm start** diff --git a/config/certs/localhost.cert.pem b/config/certs/localhost.cert.pem deleted file mode 100644 index 0179f7a..0000000 --- a/config/certs/localhost.cert.pem +++ /dev/null @@ -1,32 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFhTCCA22gAwIBAgIJAIfExcQ0I/AeMA0GCSqGSIb3DQEBCwUAMFkxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xNzAxMjQwMTIw -MzlaFw0yNzAxMjIwMTIwMzlaMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21l -LVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNV -BAMMCWxvY2FsaG9zdDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANqz -gpGo9kVJ6qRWoNKbRYy2FbcRfn5iCV+ZD+WW1XW0udOFe39820ggN31DfdOuFNb9 -BUn38MIeMFUFNxWpsAILTA6g0qSofmDXvn+2ON015LkwqcyN1RgCQj+zp/jbbfhv -JwbCfYW+eELmsgu9S/QUbA5OgV/UabJV76fA19MLoXGknS2Mt6TqM9eEhcJEaq1w -iEFJB0ZrqDf/9D5vgDa0hAp3UOMvSJbnH012qSvyatBu0ccudT+EYOV+REmXQwQ+ -Fm2N4StcRU2hyeMXcLNKmvZDzTJDIkmFRdqob/0LiJUqXnSAPF7lDf48Ghr+gsi8 -LhcctmdYN/jXJjKL1F/lh/fbYTh4hLZ7w55TCnS6Q+uZbckm3o4nsyNf+xoh6V6D -NczCm+UlJRCu/ePgBc2DlFb9rlLcyjeP6rlzt5Jxkp2WUOM4K99e9k32hERZg43x -XKydjgcFjrC2SdhVfvueZbu5ckwRQBm+RO9LwYgh+bQeKGQwwey3Mt2Z/VE7YSTp -RXuDYJD26krJmEYPTXGRKQKGd+oLuvREK7mzXJYuTe86Wp3i3stohZOElpQPVzNr -wS+c6ZxpltCTxNfDUpQ6yidKSpxxNhYGhI1YOY7l7WTYOgV4bmULLinFwse7HL/6 -D7XAdyypdKb/O2XVhJOYFtofYjsLA9eXcJkgDEZ3AgMBAAGjUDBOMB0GA1UdDgQW -BBQU8BKYGVXu+yAQ7Cn4A4Zp72WXgjAfBgNVHSMEGDAWgBQU8BKYGVXu+yAQ7Cn4 -A4Zp72WXgjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQCWMgb6voxJ -7Q5++C/xTIyfzto8ky46uxGAOJvINzYM1lmeom81u0PzXE4gfumKXRJZ7iQq79cL -1dWpfLzqam4xyRmnOljIW+b96X7jOqPc6ci3ak6chARUbO7wZ4olq6os7c37n2if -clRvjJ1Uauhp+fHuhPCls2eaxAW4JBMt8Kawa3PTNrKBvfe6COc1HqM/kOXdJaaD -M2+Sklya+OKrGg79j0cPnEga+9D7ib/LtVf9++JQkv2MQRMWz263hM9tPQJSzclV -S6q00NFR4ISRPq1PYdzDfb2gU+gNhnwvhGAtUC75kFTwAJQLxiEI9rQuX1JFIAbb -KUGxEJJnGwSS28r/x/NHbuHaZI9bAHC3hNycyW2pIe71J9Y9ECliktvnzrtLAkcM -C/p20irXiMT2M1qbEMT3Yk5D3l1JoDQK2E9f29DjrjMVetjy0lMiP2EPLxuFE+hE -puZo96E/XZYOi7P+GGVvfZLne8YkMaGZtJBY07wCAujF4AdQ6o10uKs4d2xONoMo -+uoLRqF9hrMMb2Ym2UrMYn8yfNF4AeJB9Y0sS9vSjoATnTrURyAT8hK0wmg/SA9K -ly4KWyyyc7ljK4C4qiRY/OpcuWJj6m6g+54DPcqQjkOHrtnOTR1eKBLQDbI6Gq5c -ai05a27pkjeoarhNiGdR4iCvenQEHoue1w== ------END CERTIFICATE----- diff --git a/config/certs/localhost.key.pem b/config/certs/localhost.key.pem deleted file mode 100644 index 94f0733..0000000 --- a/config/certs/localhost.key.pem +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN PRIVATE KEY----- -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 -RzfRj5kVtlXjjFfOStYPNXMzU7Rn ------END PRIVATE KEY----- diff --git a/config/colors.js b/config/colors.js deleted file mode 100644 index 066a09c..0000000 --- a/config/colors.js +++ /dev/null @@ -1,25 +0,0 @@ -module.exports.Reset = "\x1b[0m"; -module.exports.Bright = "\x1b[1m"; -module.exports.Dim = "\x1b[2m"; -module.exports.Underscore = "\x1b[4m"; -module.exports.Blink = "\x1b[5m"; -module.exports.Reverse = "\x1b[7m"; -module.exports.Hidden = "\x1b[8m"; - -module.exports.FgBlack = "\x1b[30m"; -module.exports.FgRed = "\x1b[31m"; -module.exports.FgGreen = "\x1b[32m"; -module.exports.FgYellow = "\x1b[33m"; -module.exports.FgBlue = "\x1b[34m"; -module.exports.FgMagenta = "\x1b[35m"; -module.exports.FgCyan = "\x1b[36m"; -module.exports.FgWhite = "\x1b[37m"; - -module.exports.BgBlack = "\x1b[40m"; -module.exports.BgRed = "\x1b[41m"; -module.exports.BgGreen = "\x1b[42m"; -module.exports.BgYellow = "\x1b[43m"; -module.exports.BgBlue = "\x1b[44m"; -module.exports.BgMagenta = "\x1b[45m"; -module.exports.BgCyan = "\x1b[46m"; -module.exports.BgWhite = "\x1b[47m"; \ No newline at end of file diff --git a/config/paths.js b/config/paths.js deleted file mode 100644 index 14df052..0000000 --- a/config/paths.js +++ /dev/null @@ -1,16 +0,0 @@ -const path = require('path'); -const fs = require('fs'); - -// Make sure any symlinks in the project folder are resolved: -// https://github.com/facebookincubator/create-react-app/issues/637 -const appDirectory = fs.realpathSync(process.cwd()); -const resolveApp = relativePath => path.resolve(appDirectory, relativePath); - -// we're in ./config/ -module.exports = { - appBuild: resolveApp('build'), - appNodeModules: resolveApp('node_modules'), - appIndexJs: resolveApp('src/index.js'), - appConfig: resolveApp('src/package.json'), - appSrc: resolveApp('src'), -}; diff --git a/config/webpack.common.config.js b/config/webpack.common.config.js deleted file mode 100644 index 268fca5..0000000 --- a/config/webpack.common.config.js +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Copyright 2018 by Avid Technology, Inc. - */ -const paths = require('./paths'); -const CopyWebpackPlugin = require('copy-webpack-plugin'); -const ExtractTextPlugin = require('extract-text-webpack-plugin'); -const LoaderOptionsPlugin = require('webpack').LoaderOptionsPlugin; - -module.exports = { - entry: paths.appIndexJs, - output: { - path: paths.appBuild, - filename: 'index.js', - libraryTarget: 'amd', - }, - - resolve: { - // This allows you to set a fallback for where Webpack should look for modules. - // We placed these paths second because we want `node_modules` to "win" - // if there are any conflicts. This matches Node resolution mechanism. - // https://github.com/facebookincubator/create-react-app/issues/253 - modules: [paths.appNodeModules], - extensions: ['.web.js', '.js', '.json', '.web.jsx', '.jsx'], - }, - - module: { - rules: [ - { - test: /\.(js|jsx)$/, - exclude: /(node_modules|build)/, - use: 'babel-loader', - }, - { - test: /\.css$/, - use: ['style-loader', 'css-loader'], - }, // https://github.com/webpack/webpack/issues/684 - { - test: /\.html$/, - use: 'html-loader', - }, - { - test: /\.scss$/, - use: ExtractTextPlugin.extract({ - fallback: 'style-loader', - use: [ - { - loader: 'css-loader', - options: { - modules: true, - localIdentName: '[path]___[name]__[local]___[hash:base64:5]', - }, - }, - { - loader: 'resolve-url-loader', - options: { sourceMap: true }, - }, - { - loader: 'postcss-loader', - options: { sourceMap: true }, - }, - { - loader: 'sass-loader', - options: { sourceMap: true }, - }], - }), - }, - { - test: /\.svg$/, - use: 'svg-url-loader', - }, - ], - }, - plugins: [ - new LoaderOptionsPlugin({ - minimize: true, - }), - new ExtractTextPlugin({ filename: 'style.css', allChunks: true }), - new CopyWebpackPlugin([ - { - from: 'src/l10n/lang.*.json', - to: 'resources/', - flatten: true, - }]), - new CopyWebpackPlugin([ - { - from: 'src/package.json', - to: '.', - flatten: true, - }]), - new CopyWebpackPlugin([ - { - from: 'src/images/icon.svg', - to: 'images/', - flatten: true, - }]) - ] -}; diff --git a/config/webpack.dev.config.js b/config/webpack.dev.config.js deleted file mode 100644 index a76a4ae..0000000 --- a/config/webpack.dev.config.js +++ /dev/null @@ -1,40 +0,0 @@ -const ProgressBarPlugin = require('progress-bar-webpack-plugin'); -const chalk = require('chalk'); -const fs = require('fs'); -const path = require('path'); - -const merge = require('webpack-merge'); -const common = require('./webpack.common.config'); - -const config = JSON.parse(fs.readFileSync(path.join(__dirname, '../src/project.act'), 'utf8')); - -let host = ''; - -if (config.connection.hostPort && config.connection.hostPort.length > 0) { - host = `${config.connection.hostIp}:${config.connection.hostPort}`; -} else { - host = config.connection.hostIp; -} - -module.exports = merge(common, { - devtool: 'cheap-eval-source-map', - - devServer: { - proxy: { - '/': { - target: `https://${host}`, - secure: false, - autoRewrite: true, - xfwd: true, - } - } - }, - - plugins: [ - new ProgressBarPlugin({ - format: ' build [:bar] ' + chalk.green.bold(':percent') + - ' (:elapsed seconds)', - clear: false, - }) - ] -}); diff --git a/config/webpack.prod.config.js b/config/webpack.prod.config.js deleted file mode 100644 index d4796dd..0000000 --- a/config/webpack.prod.config.js +++ /dev/null @@ -1,33 +0,0 @@ -const merge = require('webpack-merge'); -const webpack = require('webpack'); -const CompressionPlugin = require('compression-webpack-plugin'); -const UglifyJsPlugin = require('webpack').optimize.UglifyJsPlugin; -const common = require('./webpack.common.config'); - -module.exports = merge(common, { - devtool: false, - plugins: [ - new webpack.DefinePlugin({ - 'process.env': { - 'NODE_ENV': JSON.stringify('production') - } - }), - new UglifyJsPlugin({ - compress: { - sequences: false, - warnings: false - }, - output: { - semicolons: false - }, - sourceMap: false - }), - new CompressionPlugin({ - asset: '[path].gz[query]', - algorithm: 'gzip', - test: /\.js$|\.html$|\.css$/, - threshold: 10240, - minRatio: 0.8, - }) - ] -}); diff --git a/config/webpackDevServer.config.js b/config/webpackDevServer.config.js deleted file mode 100644 index 3eccb36..0000000 --- a/config/webpackDevServer.config.js +++ /dev/null @@ -1,106 +0,0 @@ -const fs = require('fs'); -const path = require('path'); -const request = require('request'); - -const config = JSON.parse(fs.readFileSync(path.join(__dirname, '../src/project.act'), 'utf8')); -config.identity.appName = require('../src/package.json').identity.appName; -config.main = require('../src/package.json').main; -config.avid = require('../src/package.json').avid; - -let host = ''; - -if (config.connection.hostPort && config.connection.hostPort.length > 0) { - host = `${config.connection.hostIp}:${config.connection.hostPort}`; -} else { - host = config.connection.hostIp; -} - -module.exports = { - // webpack-dev-server options - publicPath: "/build/", - - hot: true, - // Enable special support for Hot Module Replacement - // Page is no longer updated, but a "webpackHotUpdate" message is sent to the content - // Use "webpack/hot/dev-server" as additional module in your entry point - // Note: this does _not_ add the `HotModuleReplacementPlugin` like the CLI option does. - - historyApiFallback: false, - // Set this as true if you want to access dev server from arbitrary url. - // This is handy if you are using a html5 router. - - compress: true, - // Set this if you want to enable gzip compression for assets - - proxy: { - '/': { - target: `https://${host}`, - secure: false, - autoRewrite: true, - ws: true, - xfwd: true, - } - }, - // Set this if you want webpack-dev-server to delegate a single path to an arbitrary server. - // Use "**" to proxy all paths to the specified server. - // This is useful if you want to get rid of 'http://localhost:8080/' in script[src], - // and has many other use cases (see https://github.com/webpack/webpack-dev-server/pull/127 ). - - before: function(app) { - // Here you can access the Express app object and add your own custom middleware to it. - // For example, to define custom handlers for some paths: - - // serve local module from file system - app.use(`/plugins/${config.identity.appName}`, (req, res, next) => { - let url = req.originalUrl.replace(`/plugins/${config.identity.appName}`, ''); - res.redirect(`/build/${url}`) - }); - // add local module to the list of plugins - app.get(/\/apis\/avid\.plugins\.list;version=\d;realm=.+\/plugins/, (req, res, next) => { - if(req.query.mode === 'main'){ - request({ - url: `https://${host}${req.originalUrl}`, - strictSSL: false, - json: true, - method: 'GET', - credentials: 'include', - headers: req.headers - }, (err, noNeeded, body) => { - if(err){ - console.error(err); - next(); - } - else { - body.plugins.push({ - folderName: config.identity.appName, - main: config.main, - avid: config.avid - }); - res.setHeader('Content-Type', 'application/json'); - res.send(JSON.stringify(body)); - return; - } - }); - } - else { - next(); - } - }); - }, - - clientLogLevel: "info", - // Control the console log messages shown in the browser when using inline mode. Can be `error`, `warning`, `info` or `none`. - - // webpack-dev-middleware options - quiet: false, - noInfo: false, - watchOptions: { - aggregateTimeout: 300, - poll: 1000 - }, - - https: { - cert: fs.readFileSync(path.join(__dirname, '../config/certs/localhost.cert.pem')), - key: fs.readFileSync(path.join(__dirname, '../config/certs/localhost.key.pem')) - } -}; \ No newline at end of file diff --git a/package.json b/package.json index bb236ec..d51a8b3 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "cloudux-action-example", + "name": "cloudux-starter-kit-react", "version": "0.1.0", - "description": "Starter kit for UI developers in CloudUX", + "description": "Starter kit for UX developers in CloudUX - React", "main": "build/index.js", "scripts": { "start": "node --inspect scripts/start.js", @@ -12,36 +12,88 @@ "keywords": [ "CloudUX", "UI", - "Toolkit" + "Toolkit", + "React" ], "author": "Michał Oleszczuk ", - "license": "See EULA or LICENDE in README.", + "license": "SEE LICENSE IN EULA.md", "dependencies": { - "autoprefixer": "7.2.5", + "async": "2.6.0", + "autoprefixer": "8.2.0", + "axios": "0.18.0", + "babel-cli": "6.26.0", "babel-core": "6.26.0", - "babel-loader": "7.1.2", + "babel-eslint": "8.2.2", + "babel-generator": "6.26.1", + "babel-jest": "22.4.3", + "babel-loader": "7.1.4", "babel-plugin-transform-class-properties": "6.24.1", "babel-plugin-transform-decorators": "6.24.1", "babel-plugin-transform-object-rest-spread": "6.26.0", "babel-plugin-transform-runtime": "6.23.0", "babel-polyfill": "6.26.0", "babel-preset-env": "1.6.1", - "cloudux-l10n": "1.0.0", - "compression-webpack-plugin": "1.1.3", - "copy-webpack-plugin": "4.3.1", - "css-loader": "0.28.8", - "express": "4.16.2", + "babel-preset-react": "6.24.1", + "cloudux-bootstrap": "0.0.2", + "cloudux-l10n": "1.0.1", + "compression-webpack-plugin": "1.1.11", + "copy-webpack-plugin": "4.5.1", + "css-loader": "0.28.11", + "enzyme": "3.3.0", + "enzyme-adapter-react-16": "1.1.1", + "enzyme-to-json": "3.3.3", + "eslint": "4.19.1", + "eslint-config-airbnb": "16.1.0", + "eslint-config-react-app": "2.1.0", + "eslint-loader": "2.0.0", + "eslint-plugin-flowtype": "2.46.1", + "eslint-plugin-import": "2.10.0", + "eslint-plugin-jest": "21.15.0", + "eslint-plugin-jsx-a11y": "6.0.3", + "eslint-plugin-node": "6.0.1", + "eslint-plugin-promise": "3.7.0", + "eslint-plugin-react": "7.7.0", + "eslint-plugin-standard": "3.0.1", + "express": "4.16.3", "extract-text-webpack-plugin": "3.0.2", - "html-loader": "0.5.4", - "http-proxy-middleware": "0.17.4", + "file-loader": "1.1.11", + "fs-sync": "1.0.4", + "html-loader": "0.5.5", + "http-proxy-middleware": "0.18.0", "identity-obj-proxy": "3.0.0", - "postcss-loader": "2.0.10", - "progress-bar-webpack-plugin": "1.10.0", - "request": "2.83.0", - "resolve-url-loader": "2.2.1", - "sass-loader": "6.0.6", + "immutable": "3.8.2", + "invariant": "2.2.4", + "jest": "22.4.3", + "lodash": "4.17.5", + "moment": "2.22.0", + "node-sass": "4.9.2", + "postcss": "6.0.21", + "postcss-loader": "2.1.3", + "progress-bar-webpack-plugin": "1.11.0", + "prop-types": "15.6.1", + "react": "16.3.1", + "react-dom": "16.3.1", + "react-image": "1.3.1", + "react-menu-list": "5.0.0", + "react-redux": "5.0.7", + "react-tabs": "2.2.1", + "react-test-renderer": "16.3.1", + "redux": "3.7.2", + "redux-devtools-extension": "2.13.2", + "redux-form": "7.3.0", + "redux-immutable": "4.0.0", + "redux-mock-store": "1.5.1", + "redux-saga": "0.16.0", + "request": "2.85.0", + "require-dir": "1.0.0", + "reselect": "3.0.1", + "resolve-url-loader": "2.3.0", + "rimraf": "2.6.2", + "sass-loader": "6.0.7", "spdy": "3.4.7", - "style-loader": "0.19.1", + "style-loader": "0.20.3", + "ui-toolkit-common-example": "^0.1.0", + "url-loader": "1.0.1", "webpack": "3.10.0", "webpack-merge": "4.1.2" }, diff --git a/screenshots/action.png b/screenshots/action.png index 5762ac213d178968911a89632f4e9c37ece36a0d..57a3b6c3b33fe0017520e5eef7abe80c8da7ac4c 100644 GIT binary patch literal 9376 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ξAWe#k_^E^WHpNj*0GDDwQzz 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 literal 15472 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 literal 3093 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 Jkxe|~{t5LCAh7@d diff --git a/scripts/start.js b/scripts/start.js index 9780206..e98ef40 100644 --- a/scripts/start.js +++ b/scripts/start.js @@ -1,20 +1,15 @@ -const WebpackDevServer = require("webpack-dev-server"); -const webpack = require("webpack"); -const webpackDevConfig = require('../config/webpack.dev.config'); -const compiler = webpack(webpackDevConfig); -const webpackDevServerConfig = require('../config/webpackDevServer.config'); -const colors = require('../config/colors'); +const fs = require('fs'); +const path = require('path'); -const port = 8080; +const config = JSON.parse(fs.readFileSync(path.join(__dirname, '../src/project.act'), 'utf8')); +config.identity.appName = require('../src/package.json').identity.appName; +config.main = require('../src/package.json').main; +config.avid = require('../src/package.json').avid; -const server = new WebpackDevServer(compiler, webpackDevServerConfig); +const start = require('ui-toolkit-common-example'); +const indexPath = path.join(__dirname, '../src/index.js'); +const nodeModulesPath = path.join(__dirname, '../node_modules'); +const host = config.connection.hostIp; +const proxyPort = config.connection.proxyPort; -server.listen(port, "localhost", function() { - console.log('Listening on https://localhost:' + port); -}).on('error', (err) => { - console.error(`${colors.FgRed}ERROR: Couldn't start proxy on port ${port}. - Is it already running? - ${err} - ${colors.Reset}`); -}); -// server.close(); \ No newline at end of file +start(indexPath, nodeModulesPath, host, proxyPort, config); diff --git a/src/app/action.js b/src/app/action.js index a530150..ae7f474 100644 --- a/src/app/action.js +++ b/src/app/action.js @@ -1,3 +1,6 @@ +import actionTypes from './redux/actions/actionTypes'; +import {store} from '../store'; + const action = { id: 'user.action', @@ -9,9 +12,9 @@ const action = { return true; }, - handler({ selection, component }) { - alert('Hello from example Action') + handler({selection, component}) { + store.dispatch({type: actionTypes.EXAMPLE_ACTION, payload: true}); }, }; -export default action; \ No newline at end of file +export default action; diff --git a/src/app/binding.js b/src/app/binding.js index 605fd77..54d0d40 100644 --- a/src/app/binding.js +++ b/src/app/binding.js @@ -9,4 +9,6 @@ export default { menuModelProvider: () => [ { actionId: 'user.action' } ], -}; \ No newline at end of file +}; + + diff --git a/src/app/components/DialogBox.jsx b/src/app/components/DialogBox.jsx new file mode 100644 index 0000000..0a5a378 --- /dev/null +++ b/src/app/components/DialogBox.jsx @@ -0,0 +1,80 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import DialogBoxContent from './DialogBoxContent/DialogBoxContent'; +import PropTypes from 'prop-types'; +import {DIALOG_BOX_CLASS, DialogBoxConsts} from './DialogBoxConsts'; + +export default class DialogBox extends React.Component { + + componentDidMount() { + if (this.props.isShown) { + this.showDialogBox(); + } + } + + componentWillUnmount() { + this.hideDialogBox(); + } + + showDialogBox() { + const element = document.createElement('div'); + + element.className = DIALOG_BOX_CLASS; + element.style.height = '100%'; + + ReactDOM.render(, element); + document.body.appendChild(element); + } + + hideDialogBox() { + const container = document.getElementsByClassName(DIALOG_BOX_CLASS)[0]; + + if (container) { + ReactDOM.unmountComponentAtNode(container); + document.body.removeChild(container); + } + } + + componentDidUpdate() { + this.props.isShown ? this.showDialogBox() : this.hideDialogBox(); + } + + render() { + return null; + } + +} + +export const DialogBoxProps = { + message: PropTypes.string.isRequired, + title: PropTypes.string.isRequired, + + yesClickHandler: PropTypes.func, + noClickHandler: PropTypes.func, + okClickHandler: PropTypes.func, + type: PropTypes.oneOf(Object.values(DialogBoxConsts.TYPE)), + isShown: PropTypes.bool, + isErrorIconShown: PropTypes.bool, + height: PropTypes.oneOfType([ + PropTypes.number, + PropTypes.string + ]), + width: PropTypes.oneOfType([ + PropTypes.number, + PropTypes.string + ]) +}; + +DialogBox.propTypes = DialogBoxProps; + +DialogBox.defaultProps = { + isShown: true, + errorIcon: false, + height: 'auto', + width: 360, + yesClickHandler: () => { }, + noClickHandler: () => { }, + okClickHandler: () => { }, + type: DialogBoxConsts.TYPE.OK +}; + diff --git a/src/app/components/DialogBoxConsts.jsx b/src/app/components/DialogBoxConsts.jsx new file mode 100644 index 0000000..ba80177 --- /dev/null +++ b/src/app/components/DialogBoxConsts.jsx @@ -0,0 +1,8 @@ +export const DialogBoxConsts = { + TYPE: { + YES_NO: 'yesNo', + OK: 'ok' + } +}; + +export const DIALOG_BOX_CLASS = 'avid-nux-pulse-components-dialog-box'; diff --git a/src/app/components/DialogBoxContent/ButtonsArea.jsx b/src/app/components/DialogBoxContent/ButtonsArea.jsx new file mode 100644 index 0000000..af08782 --- /dev/null +++ b/src/app/components/DialogBoxContent/ButtonsArea.jsx @@ -0,0 +1,13 @@ +import React from 'react'; + +export default class ButtonsArea extends React.Component { + + render() { + return ( +
+ +
+ ) + } + +} diff --git a/src/app/components/DialogBoxContent/DialogBoxContent.jsx b/src/app/components/DialogBoxContent/DialogBoxContent.jsx new file mode 100644 index 0000000..85ba275 --- /dev/null +++ b/src/app/components/DialogBoxContent/DialogBoxContent.jsx @@ -0,0 +1,39 @@ +import React from 'react'; +import ShadowBox from './ShadowBox'; +import {DialogBoxProps} from '../DialogBox'; +import ButtonsArea from './ButtonsArea'; + + +export default class DialogBoxContent extends React.Component { + + render() { + + if (!this.props.isShown) + return null; + + return
+
+
+

{this.props.title}

+ +
+ +
+ {this.props.isErrorIconShown && } +

{this.props.message}

+
+ +
+ +
; + } +} + +DialogBoxContent.propTypes = DialogBoxProps; + + + diff --git a/src/app/components/DialogBoxContent/DialogBoxContent.scss b/src/app/components/DialogBoxContent/DialogBoxContent.scss new file mode 100644 index 0000000..566c37a --- /dev/null +++ b/src/app/components/DialogBoxContent/DialogBoxContent.scss @@ -0,0 +1,73 @@ +.dialogBox-wrapper { + display: flex; + justify-content: center; + height: 100%; +} + +.dialogBox { + width: 360px; + z-index: 8; + align-self: center; + -webkit-box-shadow: 0px 5px 20px 4px rgba(0,0,0,0.2); + -moz-box-shadow: 0px 5px 20px 4px rgba(0,0,0,0.2); + box-shadow: 0px 5px 20px 4px rgba(0,0,0,0.2); + + + &-header { + padding: 17px 20px; + background-color: #33353d; + text-align: center; + } + + &-content { + padding: 20px; + background: #292a31; + text-align: center; + } + + &-footer { + padding: 20px; + text-align: right; + background-color: #33353d; + } +} + +.dialogBox-title { + font-size: 14px; + font-weight: 400; + line-height: 19px; + color: #c7c7c7; +} + +.dialogBox-message { + text-align: left; + font-size: 11px; + line-height: 15px; + color: #808499; + word-wrap: break-word; +} + +.error-icon { + display: inline-block; + padding-bottom: 20px; + width: 20px; + height: 20px; + -webkit-mask-size: contain; + mask-size: contain; + vertical-align: middle; + background-color: #ad292f; + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; +} + +.shadow-box { + position: fixed; + top: 0; + left: 0; + z-index: 7; + background-color: #000; + opacity: .5; + width: 100%; + height: 100%; +} + diff --git a/src/app/components/DialogBoxContent/ShadowBox.jsx b/src/app/components/DialogBoxContent/ShadowBox.jsx new file mode 100644 index 0000000..b8bb41e --- /dev/null +++ b/src/app/components/DialogBoxContent/ShadowBox.jsx @@ -0,0 +1,9 @@ +import React from 'react'; +import styles from './DialogBoxContent.scss'; + +export default class ShadowBox extends React.Component { + + render() { + return
; + } +} diff --git a/src/app/containers/MainPaneContainer.js b/src/app/containers/MainPaneContainer.js new file mode 100644 index 0000000..dad712b --- /dev/null +++ b/src/app/containers/MainPaneContainer.js @@ -0,0 +1,40 @@ +import React from 'react'; +import {connect} from 'react-redux'; +import actionTypes from '../redux/actions/actionTypes'; +import {makeAction} from '../redux/actions/makeAction'; +import DialogBox from '../components/DialogBox'; + +class PaneContainer extends React.Component { + + render() { + return ( +
+ { + this.props.exampleAction(false); + }} + isErrorIconShown={false} + height={'auto'} + width={400} + /> +
+ ); + } +} + +const mapStateToProps = (state) => ({ + isShown: state.example.isShown, +}); + +const mapDispatchToProps = { + exampleAction: makeAction(actionTypes.EXAMPLE_ACTION), +}; + +export default connect( + mapStateToProps, + mapDispatchToProps +)(PaneContainer); diff --git a/src/app/index.js b/src/app/index.js deleted file mode 100644 index 69cc8a2..0000000 --- a/src/app/index.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Copyright 2017 by Avid Technology, Inc. - */ -import { getLocalization } from 'cloudux-l10n'; -import l10nData from '../l10n/lang.en.json'; - -export default class ApplicationContainer { - constructor() { - this.div = document.createElement('div'); - this.div.innerHTML = getLocalization(l10nData)('example-plugin-message'); - } - - returnElement() { - return this.div; - } -} \ No newline at end of file diff --git a/src/app/index.jsx b/src/app/index.jsx new file mode 100644 index 0000000..0db4d4e --- /dev/null +++ b/src/app/index.jsx @@ -0,0 +1,23 @@ +import ReactDOM from 'react-dom'; +import React from 'react'; +import {Provider} from 'react-redux'; + +import rootSaga from './redux/saga/index'; +import PaneContainer from './containers/MainPaneContainer'; +import {store, sagaMiddleware} from '../store'; +import 'cloudux-bootstrap/dist/css/cloudux.min.css'; + +export default class ApplicationContainer { + constructor() { + sagaMiddleware.run(rootSaga); + } + + render(element) { + ReactDOM.render( + + + , + element + ); + } +} diff --git a/src/app/redux/actions/actionTypes.js b/src/app/redux/actions/actionTypes.js new file mode 100644 index 0000000..f745ad0 --- /dev/null +++ b/src/app/redux/actions/actionTypes.js @@ -0,0 +1,8 @@ +const actionTypes = { + EXAMPLE_ACTION: 'EXAMPLE_ACTION', + EXAMPLE_ACTION_IN_PROGRESS: 'EXAMPLE_ACTION_IN_PROGRESS', + EXAMPLE_ACTION_SUCCESS: 'EXAMPLE_ACTION_SUCCESS', + EXAMPLE_ACTION_FAILED: 'EXAMPLE_ACTION_FAILED', +}; + +export default Object.freeze(actionTypes); diff --git a/src/app/redux/actions/makeAction.js b/src/app/redux/actions/makeAction.js new file mode 100644 index 0000000..7fb7481 --- /dev/null +++ b/src/app/redux/actions/makeAction.js @@ -0,0 +1,6 @@ +export const makeAction = (type) => { + return (payload) => ({ + type, + payload, + }); +}; diff --git a/src/app/redux/reducers/exampleReducer.js b/src/app/redux/reducers/exampleReducer.js new file mode 100644 index 0000000..299f2a1 --- /dev/null +++ b/src/app/redux/reducers/exampleReducer.js @@ -0,0 +1,27 @@ +import actionTypes from '../actions/actionTypes'; + +const DEFAULT_STATE = { + isShown: false, +}; + +const authReducer = (state = DEFAULT_STATE, action) => { + switch (action.type) { + case actionTypes.EXAMPLE_ACTION_SUCCESS: { + return { + ...state, + isShown: action.payload, + }; + } + case actionTypes.EXAMPLE_ACTION_FAILED: { + return { + ...state, + isShown: false, + }; + } + default: { + return state; + } + } +}; + +export default authReducer; diff --git a/src/app/redux/reducers/index.js b/src/app/redux/reducers/index.js new file mode 100644 index 0000000..66c750a --- /dev/null +++ b/src/app/redux/reducers/index.js @@ -0,0 +1,8 @@ +import {combineReducers} from 'redux'; +import example from './exampleReducer'; + +const root = combineReducers({ + example, +}); + +export default root; diff --git a/src/app/redux/saga/exampleSaga.js b/src/app/redux/saga/exampleSaga.js new file mode 100644 index 0000000..0b4ceb3 --- /dev/null +++ b/src/app/redux/saga/exampleSaga.js @@ -0,0 +1,21 @@ +import {take, put, all, fork} from 'redux-saga/effects'; +import actionTypes from '../actions/actionTypes'; + +export function* example() { + while (true) { + try { + const {payload} = yield take(actionTypes.EXAMPLE_ACTION); + yield put({type: actionTypes.EXAMPLE_ACTION_IN_PROGRESS}); + yield put({type: actionTypes.EXAMPLE_ACTION_SUCCESS, payload: payload}); + } catch (e) { + console.error(e); + yield put({type: actionTypes.EXAMPLE_ACTION_FAILED, error: e}); + } + } +} + +export default function* exampleSaga() { + yield all([ + fork(example), + ]); +} diff --git a/src/app/redux/saga/index.js b/src/app/redux/saga/index.js new file mode 100644 index 0000000..3f1713a --- /dev/null +++ b/src/app/redux/saga/index.js @@ -0,0 +1,8 @@ +import {all, fork} from 'redux-saga/effects'; +import exampleSaga from './exampleSaga'; + +export default function *rootSaga() { + yield all([ + fork(exampleSaga), + ]); +} diff --git a/src/app/services/persist.js b/src/app/services/persist.js new file mode 100644 index 0000000..655b0f1 --- /dev/null +++ b/src/app/services/persist.js @@ -0,0 +1,10 @@ +export function save(key, object) { + localStorage.setItem(key, object); + return object; +} +export function get(key) { + return localStorage.getItem(key); +} +export function remove(key) { + localStorage.removeItem(key); +} diff --git a/src/app/services/request.js b/src/app/services/request.js new file mode 100644 index 0000000..1428322 --- /dev/null +++ b/src/app/services/request.js @@ -0,0 +1,36 @@ +import request from 'axios'; +import {get} from './persist'; + +export const GET = 'GET'; +export const POST = 'POST'; +export const PUT = 'PUT'; +export const PATCH = 'PATCH'; +export const DELETE = 'DELETE'; + +const service = (requestType, url, data = {}, config = {}) => { + request.defaults.headers.common.Authorization = get('token') ? `Token ${get('token')}` : ''; + request.defaults.credentials = 'same-origin'; + + switch (requestType) { + case GET: { + return request.get(url, config); + } + case POST: { + return request.post(url, data, config); + } + case PUT: { + return request.put(url, data, config); + } + case PATCH: { + return request.patch(url, data, config); + } + case DELETE: { + return request.delete(url, config); + } + default: { + throw new TypeError('No valid request type provided'); + } + } +}; + +export default service; diff --git a/src/app/services/validation.js b/src/app/services/validation.js new file mode 100644 index 0000000..bf4f457 --- /dev/null +++ b/src/app/services/validation.js @@ -0,0 +1,22 @@ +const _apply_to_all = (arr, ...func_arr) => { + for (const obj of arr) { + for (const func of func_arr) { + if (!func(obj)) { + return false; + } + } + } + return true; +}; + +export const isNotEmpty = (...strings) => _apply_to_all(strings, str => !!str); + + +export const emailRegex = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i; +export const isValidEmail = (...strings) => isNotEmpty(strings) && _apply_to_all(strings, emailRegex.test.bind(emailRegex)); + +export const passRegex = /(((?=.*[a-z])(?=.*[0-9])(?=.*[A-Z]))|((?=.*[a-z])(?=.*[A-Z])(?=.*[!@#\\$%\\^&\\+=]))|((?=.*[a-z])(?=.*[0-9])(?=.*[!@#\\$%\\^&\\+=]))|((?=.*[0-9])(?=.*[A-Z])(?=.*[!@#\\$%\\^&\\+=]))).{8,30}/; +export const isValidPass = (...strings) => isNotEmpty(strings) && _apply_to_all(strings, isNotEmpty, passRegex.test.bind(passRegex)); + +export const zipCodeRegex = /[0-9]{5}/; +export const isValidZipCode = (...strings) => _apply_to_all(strings, zipCodeRegex.test.bind(zipCodeRegex)); diff --git a/src/avid_api/view/ViewWrapper.js b/src/avid_api/view/ViewWrapper.js index 97db198..c6f1828 100644 --- a/src/avid_api/view/ViewWrapper.js +++ b/src/avid_api/view/ViewWrapper.js @@ -2,6 +2,8 @@ * Copyright 2017 by Avid Technology, Inc. */ +import ReactDOM from 'react-dom'; + import ApplicationContainer from '../../app/index'; // Need to be bcs it is used in main App : @@ -11,7 +13,9 @@ export default class ViewWrapper { return Promise.resolve(this.el); } - onInit() { + onInit(config) { + this.state = config.state; + this.pane = new ApplicationContainer({ contextCallback: function (context) { this.trigger('contextChange', context); @@ -20,10 +24,16 @@ export default class ViewWrapper { } onRender() { - this.el.appendChild(this.pane.returnElement()); + this.pane.render(this.el); } - onDestroy(data) {} + onDestroy() { + ReactDOM.unmountComponentAtNode(this.el); + } + + getState() { + return this.pane.store.getState(); + } onRevalidate(data) {} @@ -48,6 +58,8 @@ export default class ViewWrapper { getMinWidth() {return 50;} get publicScope() { - return {}; + return { + getState: this.getState.bind(this), + }; } } diff --git a/src/index.js b/src/index.js index 1ae3a36..810a38f 100644 --- a/src/index.js +++ b/src/index.js @@ -9,6 +9,9 @@ import AppEntry from './avid_api/entry/EntryConfig'; import Action from './app/action'; import Binding from './app/binding'; +const isAdminApp = appConfig.avid.hasOwnProperty('mode') && appConfig.avid.mode[0] === 'admin'; +const providing = isAdminApp ? 'adminApps' : 'apps'; + export const avid = [ { name: `${appConfig['identity']['appName']}-view`, diff --git a/src/package.json b/src/package.json index 01428dc..e1d629f 100644 --- a/src/package.json +++ b/src/package.json @@ -1,10 +1,12 @@ { "identity": { - "appName": "CloudUX-Action-Example" + "appName": "Action-example" }, "main": "index.js", "avid": { "format": "amd", - "autoload": true + "autoload": true, + "alias": "your-avid-app-id", + "secret": "your-app-secred-from-myavid-com" } -} \ No newline at end of file +} diff --git a/src/project.act b/src/project.act index d6f44a7..9f6cad2 100644 --- a/src/project.act +++ b/src/project.act @@ -1,7 +1,6 @@ { "identity": { - "description": "My first Avid App", - "appID": "1", + "description": "test", "build": "1", "version": "0.01" }, @@ -12,7 +11,8 @@ "privateKeyPath": "" }, "connection": { - "hostIp": "localhost", - "hostPort": "8443" + "hostIp": "10.42.24.56", + "hostPort": "", + "proxyPort": "8080" } -} \ No newline at end of file +} diff --git a/src/store.js b/src/store.js new file mode 100644 index 0000000..0ff9887 --- /dev/null +++ b/src/store.js @@ -0,0 +1,12 @@ +import {applyMiddleware, createStore} from 'redux'; +import rootReducer from './app/redux/reducers/index'; +import createSagaMiddleware from 'redux-saga'; +import {composeWithDevTools} from 'redux-devtools-extension'; + +export const sagaMiddleware = createSagaMiddleware(); + +export const store = createStore(rootReducer, composeWithDevTools( + applyMiddleware(sagaMiddleware) +)); + +