@ismcagdas - thsnk, I can roll my own but it's always better to have a frame of reference. When designing the setup of the system features and features within editions are a key point of architecture.
Ishmael, there's a lot of code below because I can't work out what file extensions are allowed! The issue is trivial in that it creates a warning on Github which can be ignored, but here are the cli versions and package.json contents. Yarn.lock is too big to post here. Angular CLI:
Angular CLI: 1.6.3
Node: 8.9.1
OS: win32 x64
Angular: 5.1.2
... animations, common, compiler, compiler-cli, core, forms
... http, platform-browser, platform-browser-dynamic
... platform-server, router
@angular/cli: 1.6.3
@angular-devkit/build-optimizer: 0.0.36
@angular-devkit/core: 0.0.22
@angular-devkit/schematics: 0.0.42
@ngtools/json-schema: 1.1.0
@ngtools/webpack: 1.9.3
@schematics/angular: 0.1.11
@schematics/schematics: 0.0.11
typescript: 2.4.2
webpack: 3.10.0
package.json:
{
"name": "abp-zero-template",
"version": "4.0.0",
"license": "MIT",
"angular-cli": {},
"scripts": {
"ng": "ng",
"start": "ng serve --host 0.0.0.0 --port 4200",
"hmr": "ng serve --host 0.0.0.0 --port 4200 4201 --hmr -e=hmr",
"test": "ng test",
"pree2e": "webdriver-manager update --standalone false --gecko false",
"e2e": "protractor"
},
"private": true,
"dependencies": {
"@angular/animations": "^5.1.2",
"@angular/common": "^5.1.2",
"@angular/compiler": "^5.1.2",
"@angular/core": "^5.1.2",
"@angular/forms": "^5.1.2",
"@angular/http": "^5.1.2",
"@angular/platform-browser": "^5.1.2",
"@angular/platform-browser-dynamic": "^5.1.2",
"@angular/platform-server": "^5.1.2",
"@angular/router": "^5.1.2",
"@fancyapps/fancybox": "^3.1.25",
"abp-ng2-module": "^1.3.0",
"abp-web-resources": "^3.2.3",
"angular2-counto": "^1.2.3",
"animate.css": "3.5.2",
"autosize": "^4.0.0",
"block-ui": "^2.70.1",
"blueimp-file-upload": "^9.19.1",
"bootstrap": "^4.0.0",
"bootstrap-datepicker": "^1.7.1",
"bootstrap-daterangepicker": "^2.1.25",
"bootstrap-hover-dropdown": "^2.2.1",
"bootstrap-markdown": "^2.10.0",
"bootstrap-maxlength": "^1.6.0",
"bootstrap-notify": "^3.1.3",
"bootstrap-select": "^1.12.4",
"bootstrap-switch": "^3.3.4",
"bootstrap-timepicker": "^0.5.2",
"bootstrap-touchspin": "^3.1.1",
"bootstrap4-datetimepicker": "^5.2.3",
"bower": "*",
"chart.js": "^2.6.0",
"chartist": "^0.11.0",
"codelyzer": "^4.0.1",
"core-js": "^2.4.1",
"css-toggle-switch": "^4.0.3",
"d3": "^3.5.17",
"datamaps": "^0.5.8",
"detect-zoom": "^1.0.2",
"devextreme": "17.2.4",
"devextreme-angular": "17.2.4",
"dropzone": "^5.1.1",
"easy-pie-chart": "^2.1.7",
"eonasdan-bootstrap-datetimepicker": "^4.17.47",
"famfamfam-flags": "^1.0.0",
"file-saver": "^1.3.3",
"flot": "^0.8.0-alpha",
"font-awesome": "^4.7.0",
"gmaps": "^0.4.24",
"inputmask": "^3.3.7",
"ion-rangeslider": "^2.2.0",
"jasmine-spec-reporter": "^4.2.1",
"jquery": "^3.2.1",
"jquery-form": "^4.2.1",
"jquery-migrate": "^3.0.0",
"jquery-slimscroll": "^1.3.8",
"jquery-sparkline": "^2.4.0",
"jquery-ui": "^1.12.0",
"jquery-validation": "^1.15.1",
"jquery.counterup": "^2.1.0",
"jquery.flot.tooltip": "^0.9.0",
"jquery.inputmask": "^3.3.4",
"jquery.uniform": "^4.2.0",
"jqueryui": "^1.11.1",
"jqvmap": "^1.5.1",
"js-cookie": "^2.1.4",
"js-url": "^2.3.0",
"json2": "*",
"jstree": "^3.3.4",
"karma": "^1.7.0",
"localforage": "^1.5.0",
"lodash": "^4.17.4",
"malihu-custom-scrollbar-plugin": "^3.1.5",
"moment": "^2.18.1",
"moment-timezone": "^0.5.13",
"morris.js": "^0.5.0",
"mustache": "^2.3.0",
"ng-recaptcha": "^3.0.0",
"ng2-file-upload": "^1.2.1",
"ng2modules-easypiechart": "^0.0.4",
"ng2modules-flot": "^0.0.1",
"ngx-bootstrap": "^2.0.0-beta.8",
"pace-progress": "^1.0.2",
"popper.js": "^1.12.5",
"primeng": "4.2.2",
"prismjs": "^1.8.1",
"push.js": "1.0.4",
"quill": "^1.3.0",
"rangeslider.js": "^2.3.1",
"raphael": "^2.2.7",
"rtl-detect": "^1.0.0",
"rxjs": "^5.5.2",
"select2": "^4.0.3",
"select2-bootstrap-theme": "0.1.0-beta.9",
"signalr": "^2.2.1",
"simple-line-icons": "^2.4.1",
"socicon": "^3.0.5",
"spin.js": "^2.3.2",
"summernote": "^0.8.6",
"sweetalert": "^2.0.8",
"tether": "^1.4.0",
"timeago": "^1.6.1",
"toastr": "^2.1.2",
"topojson": "^3.0.2",
"ts-helpers": "^1.1.2",
"ts-node": "~3.3.0",
"typeahead.js": "^0.11.1",
"typescript": "2.4.2",
"underscore": "^1.8.3",
"urijs": "^1.19.0",
"waypoints": "^4.0.1",
"zone.js": "0.8.17"
},
"devDependencies": {
"@angular/cli": "^1.6.3",
"@angular/compiler-cli": "^5.1.2",
"@angularclass/hmr": "^2.1.3",
"@angularclass/hmr-loader": "^3.0.4",
"@types/bootstrap": "^3.3.33",
"@types/grecaptcha": "^2.0.31",
"@types/jasmine": "~2.5.53",
"@types/jasminewd2": "~2.0.2",
"@types/jquery": "^3.2.12",
"@types/jquery.blockui": "0.0.28",
"@types/jstree": "^3.3.34",
"@types/lodash": "^4.14.62",
"@types/moment": "^2.13.0",
"@types/moment-timezone": "^0.2.34",
"@types/morris.js": "^0.5.6",
"@types/node": "^8.0.27",
"@types/signalr": "^2.2.33",
"@types/tether": "^1.4.2",
"@types/toastr": "^2.1.33",
"codelyzer": "^4.0.1",
"jasmine-core": "~2.8.0",
"jasmine-spec-reporter": "^4.2.1",
"karma": "^1.7.0",
"karma-chrome-launcher": "~2.2.0",
"karma-cli": "~1.0.1",
"karma-coverage-istanbul-reporter": "^1.2.1",
"karma-jasmine": "~1.1.0",
"karma-jasmine-html-reporter": "^0.2.2",
"nswag": "11.12.7",
"protractor": "~5.1.2",
"ts-node": "~3.3.0",
"tslint": "~5.7.0",
"typescript": "2.4.2"
}
}
Now I see. The method CreateFeatureIfNotExists() is written to work with Boolean Features only, to support testing for chat features. By modifying the method as follows:
private void CreateFeatureIfNotExists(int editionId, string featureName, string value)
{
var defaultEditionChatFeature = _context.EditionFeatureSettings.IgnoreQueryFilters()
.FirstOrDefault(ef => ef.EditionId == editionId && ef.Name == featureName);
if (defaultEditionChatFeature == null)
{
_context.EditionFeatureSettings.Add(new EditionFeatureSetting
{
Name = featureName,
Value = value,
EditionId = editionId
});
}
}
And passing in a string value as opposed to a boolean for isEnabled. The method is written to work with Boolean Features only, the above method changes it to a Value Feature. In fact I believe the terminology is misleading here, a Boolean Feature is identical to a Value feature except that it holds a string value for "true" or "false". Correct me if I am wrong. I think the source would benefit from making the above changes, as it stands it is not possible to test Value features without modification.
MaxUserCount is the standard feature. I can not find any tests for feature implementation.
@alper - thanks. Upgrading @angular/cli is within the bounds of my limited skills. I will try this before the next iteration of tests.
@ismcagdas - erm, I downloaded your system and checked it into Github, twice. This was to test an upgrade procedure using 5.0.0 and 5.1.0. I checked both versions into Github as a fresh installs into framework branches. I only get this message in the angular project. It can be safely ignored but it is there. The header of the link "postcss-url version causing security warning #8521" is enough to give me stress. I read the contents with awe. I'm sure it's important but to me it remains an enigma. I can't fix it, I simply don't know how. I hope you understand, I have just learned Angular and I really don't want to get into another set of hieroglyphics.
From a third party system or from a data import of some kind?
@alper, you are correct, what I am planning is a use-case implementation. I bet you are also correct in assuming I am being lazy in looking for examples of the same use-case implementation! @ismcagdas, thanks, that's exactly what I was looking for.
Hi Vlad, Take a look at Postal: [http://aboutcode.net/postal/]). I have used this before with Hangfire. Save your template data from a wysiwyg component and load it into a cshtml file by passing a TemplateId to the Postal send email method. The Hangfire bit allows you to do this asynchronously.
Thanks, Vlad. Yes I've seen that. My thoughts were to use the
IExtendableObject
properties to hold arrays of key-value data against any entity and write a generic angular component to allow the user to add attributes. Thus, I would have an Attribute class containing generic data types and data input rules. For example an attribute called "Name" would be a string with definitions for max/min, required etc; "Age" would be a number with definitions for max/min/required etc. The admin user defines the attributes which may be used to describe an entity and these are used in data input forms. The user adds an item to a form array, a drop down would allow selection of an attribute, the Attribute object would dictate the input type and the results would be saved as key-value pairs in the
ExtensionData
field. Zero has get and set operations for this data and JSON functions in SQL Server would allow easy querying. In this way i would reduce requests from Tenants for extra or different data fields. They simply define an entity and then describe this entity through a series of attributes. The entity may be a person, a shop, a location or any other object. I was hoping for some simple get and set examples beyond the few lines of description in the Entity documentation.