├── .gitignore ├── Program.cs ├── Properties └── launchSettings.json ├── README.md ├── SharpData.csproj ├── Startup.cs ├── _bundle.ss ├── chinook.sqlite ├── dist-mix ├── chinook │ ├── .publish │ ├── app.settings │ ├── chinook.sqlite │ └── custom │ │ └── chinook.js └── northwind │ ├── .publish │ ├── app.settings │ ├── custom │ └── northwind.js │ └── northwind.sqlite ├── northwind.sqlite ├── package.json ├── scripts ├── deploy │ ├── .publish │ ├── app.multi.settings │ └── app.settings ├── pack-app.bat ├── pack-app.sh └── publish-app.bat ├── src ├── App.ts ├── ErrorView.ts ├── JsonViewer.ts ├── components │ ├── Results │ │ ├── SelectColumns.ts │ │ └── index.ts │ └── Viewer │ │ └── index.ts ├── css │ ├── layout.css │ └── styles.css ├── main.ts └── shared │ ├── index.ts │ └── router.ts ├── tsconfig.json ├── typings ├── @servicestack │ ├── client │ │ └── index.d.ts │ ├── desktop │ │ └── index.d.ts │ └── vue │ │ ├── components │ │ ├── Button.vue.d.ts │ │ ├── CheckBox.vue.d.ts │ │ ├── ErrorSummary.vue.d.ts │ │ ├── Forbidden.vue.d.ts │ │ ├── Input.vue.d.ts │ │ ├── Link.vue.d.ts │ │ ├── LinkButton.vue.d.ts │ │ ├── Nav.vue.d.ts │ │ ├── NavButtonGroup.vue.d.ts │ │ ├── NavLink.vue.d.ts │ │ ├── NavLinkButton.vue.d.ts │ │ ├── Navbar.vue.d.ts │ │ ├── Select.vue.d.ts │ │ └── SvgImage.vue.d.ts │ │ ├── core.d.ts │ │ └── index.d.ts ├── reflect-metadata │ └── index.d.ts ├── vue-class-component │ ├── component.d.ts │ ├── data.d.ts │ ├── declarations.d.ts │ ├── index.d.ts │ ├── reflect.d.ts │ └── util.d.ts ├── vue-property-decorator │ └── index.d.ts ├── vue-router │ ├── index.d.ts │ ├── router.d.ts │ └── vue.d.ts └── vue │ ├── index.d.ts │ ├── options.d.ts │ ├── plugin.d.ts │ ├── vnode.d.ts │ └── vue.d.ts └── wwwroot ├── _init.ss ├── _layout.html ├── custom ├── chinook.js ├── chinook.ts ├── northwind.js └── northwind.ts ├── db └── _db │ ├── _table │ ├── index.html │ ├── meta.html │ └── total.html │ └── totals.html ├── favicon.png └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | src/**/*.js 10 | *bundle.min.css 11 | *bundle.min.js 12 | dist/ 13 | GPUCache 14 | 15 | # User-specific files (MonoDevelop/Xamarin Studio) 16 | *.userprefs 17 | 18 | # Build results 19 | [Dd]ebug/ 20 | [Dd]ebugPublic/ 21 | [Rr]elease/ 22 | [Rr]eleases/ 23 | x64/ 24 | x86/ 25 | bld/ 26 | [Bb]in/ 27 | [Oo]bj/ 28 | [Ll]og/ 29 | 30 | # Visual Studio 2015 cache/options directory 31 | .vs/ 32 | # Uncomment if you have tasks that create the project's static files in wwwroot 33 | #wwwroot/ 34 | 35 | # MSTest test Results 36 | [Tt]est[Rr]esult*/ 37 | [Bb]uild[Ll]og.* 38 | 39 | # NUNIT 40 | *.VisualState.xml 41 | TestResult.xml 42 | 43 | # Build Results of an ATL Project 44 | [Dd]ebugPS/ 45 | [Rr]eleasePS/ 46 | dlldata.c 47 | 48 | # DNX 49 | project.lock.json 50 | artifacts/ 51 | 52 | *_i.c 53 | *_p.c 54 | *_i.h 55 | *.ilk 56 | *.meta 57 | *.obj 58 | *.pch 59 | *.pdb 60 | *.pgc 61 | *.pgd 62 | *.rsp 63 | *.sbr 64 | *.tlb 65 | *.tli 66 | *.tlh 67 | *.tmp 68 | *.tmp_proj 69 | *.log 70 | *.vspscc 71 | *.vssscc 72 | .builds 73 | *.pidb 74 | *.svclog 75 | *.scc 76 | 77 | # Chutzpah Test files 78 | _Chutzpah* 79 | 80 | # Visual C++ cache files 81 | ipch/ 82 | *.aps 83 | *.ncb 84 | *.opendb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | *.VC.db 89 | *.VC.VC.opendb 90 | 91 | # Visual Studio profiler 92 | *.psess 93 | *.vsp 94 | *.vspx 95 | *.sap 96 | 97 | # TFS 2012 Local Workspace 98 | $tf/ 99 | 100 | # Guidance Automation Toolkit 101 | *.gpState 102 | 103 | # ReSharper is a .NET coding add-in 104 | _ReSharper*/ 105 | *.[Rr]e[Ss]harper 106 | *.DotSettings.user 107 | 108 | # JustCode is a .NET coding add-in 109 | .JustCode 110 | 111 | # TeamCity is a build add-in 112 | _TeamCity* 113 | 114 | # DotCover is a Code Coverage Tool 115 | *.dotCover 116 | 117 | # NCrunch 118 | _NCrunch_* 119 | .*crunch*.local.xml 120 | nCrunchTemp_* 121 | 122 | # MightyMoose 123 | *.mm.* 124 | AutoTest.Net/ 125 | 126 | # Web workbench (sass) 127 | .sass-cache/ 128 | 129 | # Installshield output folder 130 | [Ee]xpress/ 131 | 132 | # DocProject is a documentation generator add-in 133 | DocProject/buildhelp/ 134 | DocProject/Help/*.HxT 135 | DocProject/Help/*.HxC 136 | DocProject/Help/*.hhc 137 | DocProject/Help/*.hhk 138 | DocProject/Help/*.hhp 139 | DocProject/Help/Html2 140 | DocProject/Help/html 141 | 142 | # Click-Once directory 143 | publish/ 144 | 145 | # Publish Web Output 146 | *.[Pp]ublish.xml 147 | *.azurePubxml 148 | # TODO: Comment the next line if you want to checkin your web deploy settings 149 | # but database connection strings (with potential passwords) will be unencrypted 150 | *.pubxml 151 | *.publishproj 152 | 153 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 154 | # checkin your Azure Web App publish settings, but sensitive information contained 155 | # in these scripts will be unencrypted 156 | PublishScripts/ 157 | 158 | # NuGet Packages 159 | *.nupkg 160 | # The packages folder can be ignored because of Package Restore 161 | **/packages/* 162 | # except build/, which is used as an MSBuild target. 163 | !**/packages/build/ 164 | # Uncomment if necessary however generally it will be regenerated when needed 165 | #!**/packages/repositories.config 166 | # NuGet v3's project.json files produces more ignoreable files 167 | *.nuget.props 168 | *.nuget.targets 169 | 170 | # Microsoft Azure Build Output 171 | csx/ 172 | *.build.csdef 173 | 174 | # Microsoft Azure Emulator 175 | ecf/ 176 | rcf/ 177 | 178 | # Windows Store app package directories and files 179 | AppPackages/ 180 | BundleArtifacts/ 181 | Package.StoreAssociation.xml 182 | _pkginfo.txt 183 | 184 | # Visual Studio cache files 185 | # files ending in .cache can be ignored 186 | *.[Cc]ache 187 | # but keep track of directories ending in .cache 188 | !*.[Cc]ache/ 189 | 190 | # Others 191 | ClientBin/ 192 | ~$* 193 | *~ 194 | *.dbmdl 195 | *.dbproj.schemaview 196 | *.pfx 197 | *.publishsettings 198 | node_modules/ 199 | orleans.codegen.cs 200 | 201 | # Since there are multiple workflows, uncomment next line to ignore bower_components 202 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 203 | #bower_components/ 204 | 205 | # RIA/Silverlight projects 206 | Generated_Code/ 207 | 208 | # Backup & report files from converting an old project file 209 | # to a newer Visual Studio version. Backup files are not needed, 210 | # because we have git ;-) 211 | _UpgradeReport_Files/ 212 | Backup*/ 213 | UpgradeLog*.XML 214 | UpgradeLog*.htm 215 | 216 | # SQL Server files 217 | *.mdf 218 | *.ldf 219 | 220 | # Business Intelligence projects 221 | *.rdl.data 222 | *.bim.layout 223 | *.bim_*.settings 224 | 225 | # Microsoft Fakes 226 | FakesAssemblies/ 227 | 228 | # GhostDoc plugin setting file 229 | *.GhostDoc.xml 230 | 231 | # Node.js Tools for Visual Studio 232 | .ntvs_analysis.dat 233 | 234 | # Visual Studio 6 build log 235 | *.plg 236 | 237 | # Visual Studio 6 workspace options file 238 | *.opt 239 | 240 | # Visual Studio LightSwitch build output 241 | **/*.HTMLClient/GeneratedArtifacts 242 | **/*.DesktopClient/GeneratedArtifacts 243 | **/*.DesktopClient/ModelManifest.xml 244 | **/*.Server/GeneratedArtifacts 245 | **/*.Server/ModelManifest.xml 246 | _Pvt_Extensions 247 | 248 | # Paket dependency manager 249 | .paket/paket.exe 250 | paket-files/ 251 | 252 | # FAKE - F# Make 253 | .fake/ 254 | 255 | # JetBrains Rider 256 | .idea/ 257 | *.sln.iml 258 | -------------------------------------------------------------------------------- /Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Hosting; 6 | using Microsoft.Extensions.Configuration; 7 | using Microsoft.Extensions.Hosting; 8 | using Microsoft.Extensions.Logging; 9 | 10 | namespace SharpData 11 | { 12 | public class Program 13 | { 14 | public static void Main(string[] args) 15 | { 16 | CreateHostBuilder(args).Build().Run(); 17 | } 18 | 19 | public static IHostBuilder CreateHostBuilder(string[] args) => 20 | Host.CreateDefaultBuilder(args) 21 | .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); 22 | } 23 | } -------------------------------------------------------------------------------- /Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:60177", 7 | "sslPort": 44390 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "SharpData": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:5001", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [SharpData](https://github.com/NetCoreApps/SharpData) is a generic app for providing an instant UI around multiple RDBMS's: 2 | 3 | > YouTube: [youtu.be/EJ-lDWshjcY](https://youtu.be/EJ-lDWshjcY) 4 | 5 | [![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/release-notes/v5.9/sharpdata-custom-appsettings.png)](https://youtu.be/EJ-lDWshjcY) 6 | 7 | For more info see [Sharp Data docs](https://sharpscript.net/sharp-apps/sharpdata). -------------------------------------------------------------------------------- /SharpData.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | true 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | PreserveNewest 25 | 26 | 27 | true 28 | PreserveNewest 29 | 30 | 31 | true 32 | PreserveNewest 33 | chinook.ts 34 | 35 | 36 | true 37 | PreserveNewest 38 | 39 | 40 | true 41 | PreserveNewest 42 | northwind.ts 43 | 44 | 45 | 46 | PreserveNewest 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Funq; 3 | using Microsoft.AspNetCore.Builder; 4 | using Microsoft.AspNetCore.Hosting; 5 | using Microsoft.Extensions.Configuration; 6 | using Microsoft.Extensions.DependencyInjection; 7 | using Microsoft.Extensions.Hosting; 8 | using ServiceStack; 9 | using ServiceStack.Data; 10 | using ServiceStack.Desktop; 11 | using ServiceStack.OrmLite; 12 | 13 | namespace SharpData 14 | { 15 | public class Startup 16 | { 17 | public Startup(IConfiguration configuration) 18 | { 19 | Configuration = configuration; 20 | } 21 | 22 | public IConfiguration Configuration { get; } 23 | 24 | // This method gets called by the runtime. Use this method to add services to the container. 25 | public void ConfigureServices(IServiceCollection services) { } 26 | 27 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 28 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 29 | { 30 | app.UseServiceStack(new AppHost { 31 | AppSettings = new NetCoreAppSettings(Configuration), 32 | }); 33 | } 34 | } 35 | 36 | public class Hello : IReturn 37 | { 38 | public string Name { get; set; } 39 | } 40 | 41 | public class MyServices : Service 42 | { 43 | public object Any(Hello request) => request; 44 | } 45 | 46 | public class AppHost : AppHostBase 47 | { 48 | public AppHost() 49 | : base(nameof(SharpData), typeof(MyServices).Assembly) { } 50 | 51 | public override void Configure(Container container) 52 | { 53 | SetConfig(new HostConfig { 54 | DebugMode = AppSettings.Get(nameof(HostConfig.DebugMode), HostingEnvironment.IsDevelopment()), 55 | }); 56 | 57 | container.Register(c => 58 | new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); 59 | 60 | // Example of registering multiple RDBMS's in code 61 | var dbFactory = container.Resolve(); 62 | 63 | dbFactory.RegisterConnection("northwind", 64 | MapProjectPath("~/northwind.sqlite"), SqliteDialect.Provider); 65 | dbFactory.RegisterConnection("chinook", 66 | MapProjectPath("~/chinook.sqlite"), SqliteDialect.Provider); 67 | 68 | // dbFactory.RegisterConnection("reporting", 69 | // Environment.GetEnvironmentVariable("MSSQL_CONNECTION"), 70 | // SqlServer2012Dialect.Provider); 71 | 72 | if (Config.DebugMode) 73 | { 74 | Plugins.Add(new HotReloadFeature { 75 | VirtualFiles = VirtualFiles, //Monitor all folders for changes including /src & /wwwroot 76 | }); 77 | } 78 | 79 | Plugins.Add(new DesktopFeature { 80 | AppName = "sharpdata" 81 | }); 82 | 83 | Plugins.Add(new SharpPagesFeature { 84 | EnableSpaFallback = true, 85 | ScriptMethods = { new DbScriptsAsync() }, 86 | }); 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /_bundle.ss: -------------------------------------------------------------------------------- 1 | ```code 2 | * run in .csproj AfterPublish, manual usage: `x run _bundle.ss -to ` * 3 | 4 | [ 'content:/src/css/' ] |> bundleCss({ minify:true, disk:true, out:`content:${to}/bundle.css` }) 5 | 6 | {{ [ 7 | 'content:/src/components/', 8 | 'content:/src/shared/', 9 | 'content:/src/', 10 | ] |> bundleJs({ minify:true, disk:true, out:`content:${to}/bundle.js`, iife:true }) }} 11 | ``` 12 | -------------------------------------------------------------------------------- /chinook.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/SharpData/c4b0e3e7d8306d253dfd42a2a622e083f0700e68/chinook.sqlite -------------------------------------------------------------------------------- /dist-mix/chinook/.publish: -------------------------------------------------------------------------------- 1 | gist 96b10369daf94897531810841cb097f2 -------------------------------------------------------------------------------- /dist-mix/chinook/app.settings: -------------------------------------------------------------------------------- 1 | debug false 2 | name Chinook SharpData UI 3 | appName sharpdata 4 | 5 | # Configure below. Supported dialects: sqlite, mysql, postgres, sqlserver 6 | db.connections[chinook] { db:sqlite, connection:'chinook.sqlite' } 7 | -------------------------------------------------------------------------------- /dist-mix/chinook/chinook.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/SharpData/c4b0e3e7d8306d253dfd42a2a622e083f0700e68/dist-mix/chinook/chinook.sqlite -------------------------------------------------------------------------------- /dist-mix/chinook/custom/chinook.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __extends = (this && this.__extends) || (function () { 3 | var extendStatics = Object.setPrototypeOf || 4 | ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 5 | function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; 6 | return function (d, b) { 7 | extendStatics(d, b); 8 | function __() { this.constructor = d; } 9 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 10 | }; 11 | })(); 12 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 13 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 14 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 15 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 16 | return c > 3 && r && Object.defineProperty(target, key, r), r; 17 | }; 18 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 19 | return new (P || (P = Promise))(function (resolve, reject) { 20 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 21 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 22 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } 23 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 24 | }); 25 | }; 26 | var __generator = (this && this.__generator) || function (thisArg, body) { 27 | var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; 28 | return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; 29 | function verb(n) { return function (v) { return step([n, v]); }; } 30 | function step(op) { 31 | if (f) throw new TypeError("Generator is already executing."); 32 | while (_) try { 33 | if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; 34 | if (y = 0, t) op = [0, t.value]; 35 | switch (op[0]) { 36 | case 0: case 1: t = op; break; 37 | case 4: _.label++; return { value: op[1], done: false }; 38 | case 5: _.label++; y = op[1]; op = [0]; continue; 39 | case 7: op = _.ops.pop(); _.trys.pop(); continue; 40 | default: 41 | if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } 42 | if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } 43 | if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } 44 | if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } 45 | if (t[2]) _.ops.pop(); 46 | _.trys.pop(); continue; 47 | } 48 | op = body.call(thisArg, _); 49 | } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } 50 | if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; 51 | } 52 | }; 53 | Object.defineProperty(exports, "__esModule", { value: true }); 54 | var shared_1 = require("../../src/shared"); 55 | var vue_property_decorator_1 = require("vue-property-decorator"); 56 | var client_1 = require("@servicestack/client"); 57 | var Artist = /** @class */ (function (_super) { 58 | __extends(Artist, _super); 59 | function Artist() { 60 | var _this = _super !== null && _super.apply(this, arguments) || this; 61 | _this.albums = []; 62 | return _this; 63 | } 64 | Object.defineProperty(Artist.prototype, "id", { 65 | get: function () { return this.row.ArtistId; }, 66 | enumerable: true, 67 | configurable: true 68 | }); 69 | Artist.prototype.albumHref = function (albumId) { return "albums?filter=AlbumId:" + albumId; }; 70 | Artist.prototype.mounted = function () { 71 | return __awaiter(this, void 0, void 0, function () { 72 | var _a; 73 | return __generator(this, function (_b) { 74 | switch (_b.label) { 75 | case 0: 76 | _a = this; 77 | return [4 /*yield*/, shared_1.sharpData(this.db, 'albums', { ArtistId: this.id })]; 78 | case 1: 79 | _a.albums = _b.sent(); 80 | return [2 /*return*/]; 81 | } 82 | }); 83 | }); 84 | }; 85 | Artist = __decorate([ 86 | vue_property_decorator_1.Component({ template: "
\n
Albums
\n \n
\n
Artist Id needs to be selected
" 87 | }) 88 | ], Artist); 89 | return Artist; 90 | }(shared_1.RowComponent)); 91 | exports.Artist = Artist; 92 | var Album = /** @class */ (function (_super) { 93 | __extends(Album, _super); 94 | function Album() { 95 | var _this = _super !== null && _super.apply(this, arguments) || this; 96 | _this.artist = null; 97 | _this.tracks = []; 98 | return _this; 99 | } 100 | Object.defineProperty(Album.prototype, "id", { 101 | get: function () { return this.row.AlbumId; }, 102 | enumerable: true, 103 | configurable: true 104 | }); 105 | Album.prototype.mounted = function () { 106 | return __awaiter(this, void 0, void 0, function () { 107 | var _a, secsToTime, genres, media, _b; 108 | return __generator(this, function (_c) { 109 | switch (_c.label) { 110 | case 0: 111 | _a = this; 112 | return [4 /*yield*/, shared_1.sharpData(this.db, 'artists', { ArtistId: this.row.ArtistId })]; 113 | case 1: 114 | _a.artist = (_c.sent())[0]; 115 | secsToTime = function (s) { return Math.floor(s / 60) + ":" + client_1.padInt(Math.round(s % 60)); }; 116 | genres = {}; 117 | return [4 /*yield*/, shared_1.sharpData(this.db, 'genres')]; 118 | case 2: 119 | (_c.sent()).forEach(function (x) { return genres[x.GenreId] = x.Name; }); 120 | media = {}; 121 | return [4 /*yield*/, shared_1.sharpData(this.db, 'media_types')]; 122 | case 3: 123 | (_c.sent()).forEach(function (x) { return media[x.MediaTypeId] = x.Name; }); 124 | _b = this; 125 | return [4 /*yield*/, shared_1.sharpData(this.db, 'tracks', { AlbumId: this.id })]; 126 | case 4: 127 | _b.tracks = (_c.sent()).map(function (x) { return ({ 128 | Name: x.Name, 129 | Genre: genres[x.GenreId], 130 | Duration: secsToTime(x.Milliseconds / 1000), 131 | Price: "$" + x.UnitPrice, 132 | Size: Math.floor(x.Bytes / 1024) + " kB", 133 | Media: media[x.MediaTypeId], 134 | }); }); 135 | return [2 /*return*/]; 136 | } 137 | }); 138 | }); 139 | }; 140 | Album = __decorate([ 141 | vue_property_decorator_1.Component({ template: "
\n

{{row.Title}} by {{artist.Name}}

\n \n
\n
Album Id needs to be selected
" 142 | }) 143 | ], Album); 144 | return Album; 145 | }(shared_1.RowComponent)); 146 | exports.Album = Album; 147 | var Playlist = /** @class */ (function (_super) { 148 | __extends(Playlist, _super); 149 | function Playlist() { 150 | var _this = _super !== null && _super.apply(this, arguments) || this; 151 | _this.tracks = []; 152 | return _this; 153 | } 154 | Object.defineProperty(Playlist.prototype, "id", { 155 | get: function () { return this.row.PlaylistId; }, 156 | enumerable: true, 157 | configurable: true 158 | }); 159 | Playlist.prototype.trackHref = function (trackId) { return "tracks?filter=TrackId:" + trackId; }; 160 | Playlist.prototype.mounted = function () { 161 | return __awaiter(this, void 0, void 0, function () { 162 | var trackIds, _a; 163 | return __generator(this, function (_b) { 164 | switch (_b.label) { 165 | case 0: return [4 /*yield*/, shared_1.sharpData(this.db, 'playlist_track', { PlaylistId: this.id, take: 200 })]; 166 | case 1: 167 | trackIds = (_b.sent()).map(function (x) { return x.TrackId; }); 168 | _a = this; 169 | return [4 /*yield*/, shared_1.sharpData(this.db, 'tracks', { TrackId: trackIds.join(',') + ',' })]; 170 | case 2: 171 | _a.tracks = _b.sent(); 172 | return [2 /*return*/]; 173 | } 174 | }); 175 | }); 176 | }; 177 | Playlist = __decorate([ 178 | vue_property_decorator_1.Component({ template: "
\n
\n
Tracks
\n \n
\n
playlist has no tracks
\n
\n
Playlist Id needs to be selected
" 179 | }) 180 | ], Playlist); 181 | return Playlist; 182 | }(shared_1.RowComponent)); 183 | exports.Playlist = Playlist; 184 | shared_1.dbConfig('chinook', { 185 | showTables: 'albums,artists,playlists,tracks,genres,media_types,customers,employees,invoices'.split(','), 186 | tableName: shared_1.splitPascalCase, 187 | links: { 188 | albums: { 189 | ArtistId: function (id) { return "artists?filter=ArtistId:" + id; } 190 | }, 191 | employees: { 192 | ReportsTo: function (id) { return "employees?filter=EmployeeId:" + id; } 193 | }, 194 | invoices: { 195 | CustomerId: function (id) { return "customers?filter=CustomerId:" + id; } 196 | }, 197 | tracks: { 198 | AlbumId: function (id) { return "albums?filter=AlbumId:" + id; }, 199 | MediaTypeId: function (id) { return "media_types?filter=MediaTypeId:" + id; }, 200 | GenreId: function (id) { return "genres?filter=GenreId:" + id; }, 201 | } 202 | }, 203 | rowComponents: { 204 | albums: Album, 205 | artists: Artist, 206 | playlists: Playlist, 207 | } 208 | }); 209 | -------------------------------------------------------------------------------- /dist-mix/northwind/.publish: -------------------------------------------------------------------------------- 1 | gist 0ce0d5b828303f1cb4637450b563adbd -------------------------------------------------------------------------------- /dist-mix/northwind/app.settings: -------------------------------------------------------------------------------- 1 | debug false 2 | name Northwind SharpData UI 3 | appName sharpdata 4 | 5 | # Configure below. Supported dialects: sqlite, mysql, postgres, sqlserver 6 | db.connections[northwind] { db:sqlite, connection: 'northwind.sqlite' } 7 | -------------------------------------------------------------------------------- /dist-mix/northwind/custom/northwind.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __extends = (this && this.__extends) || (function () { 3 | var extendStatics = Object.setPrototypeOf || 4 | ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 5 | function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; 6 | return function (d, b) { 7 | extendStatics(d, b); 8 | function __() { this.constructor = d; } 9 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 10 | }; 11 | })(); 12 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 13 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 14 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 15 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 16 | return c > 3 && r && Object.defineProperty(target, key, r), r; 17 | }; 18 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 19 | return new (P || (P = Promise))(function (resolve, reject) { 20 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 21 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 22 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } 23 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 24 | }); 25 | }; 26 | var __generator = (this && this.__generator) || function (thisArg, body) { 27 | var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; 28 | return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; 29 | function verb(n) { return function (v) { return step([n, v]); }; } 30 | function step(op) { 31 | if (f) throw new TypeError("Generator is already executing."); 32 | while (_) try { 33 | if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; 34 | if (y = 0, t) op = [0, t.value]; 35 | switch (op[0]) { 36 | case 0: case 1: t = op; break; 37 | case 4: _.label++; return { value: op[1], done: false }; 38 | case 5: _.label++; y = op[1]; op = [0]; continue; 39 | case 7: op = _.ops.pop(); _.trys.pop(); continue; 40 | default: 41 | if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } 42 | if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } 43 | if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } 44 | if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } 45 | if (t[2]) _.ops.pop(); 46 | _.trys.pop(); continue; 47 | } 48 | op = body.call(thisArg, _); 49 | } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } 50 | if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; 51 | } 52 | }; 53 | Object.defineProperty(exports, "__esModule", { value: true }); 54 | var shared_1 = require("../../src/shared"); 55 | var vue_property_decorator_1 = require("vue-property-decorator"); 56 | var Customer = /** @class */ (function (_super) { 57 | __extends(Customer, _super); 58 | function Customer() { 59 | var _this = _super !== null && _super.apply(this, arguments) || this; 60 | _this.customer = null; 61 | _this.orders = []; 62 | return _this; 63 | } 64 | Object.defineProperty(Customer.prototype, "id", { 65 | get: function () { return this.row.Id; }, 66 | enumerable: true, 67 | configurable: true 68 | }); 69 | Customer.prototype.mounted = function () { 70 | return __awaiter(this, void 0, void 0, function () { 71 | var _a, fields, _b; 72 | return __generator(this, function (_c) { 73 | switch (_c.label) { 74 | case 0: 75 | _a = this; 76 | return [4 /*yield*/, shared_1.sharpData(this.db, this.table, { Id: this.id })]; 77 | case 1: 78 | _a.customer = (_c.sent())[0]; 79 | fields = 'Id,EmployeeId,OrderDate,Freight,ShipVia,ShipCity,ShipCountry'; 80 | _b = this; 81 | return [4 /*yield*/, shared_1.sharpData(this.db, 'Order', { CustomerId: this.id, fields: fields })]; 82 | case 2: 83 | _b.orders = _c.sent(); 84 | return [2 /*return*/]; 85 | } 86 | }); 87 | }); 88 | }; 89 | Customer = __decorate([ 90 | vue_property_decorator_1.Component({ template: "
\n

{{customer.ContactName}}

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Contact{{ customer.ContactName }} ({{ customer.ContactTitle }})
Address\n
{{ customer.Address }}
\n
{{ customer.City }}, {{ customer.PostalCode }}, {{ customer.Country }}
\n
Phone{{ customer.Phone }}
Fax{{ customer.Fax }}
\n \n
\n
Customer Id needs to be selected
" 91 | }) 92 | ], Customer); 93 | return Customer; 94 | }(shared_1.RowComponent)); 95 | var Order = /** @class */ (function (_super) { 96 | __extends(Order, _super); 97 | function Order() { 98 | var _this = _super !== null && _super.apply(this, arguments) || this; 99 | _this.details = []; 100 | return _this; 101 | } 102 | Object.defineProperty(Order.prototype, "id", { 103 | get: function () { return this.row.Id; }, 104 | enumerable: true, 105 | configurable: true 106 | }); 107 | Order.prototype.mounted = function () { 108 | return __awaiter(this, void 0, void 0, function () { 109 | var _a; 110 | return __generator(this, function (_b) { 111 | switch (_b.label) { 112 | case 0: 113 | _a = this; 114 | return [4 /*yield*/, shared_1.sharpData(this.db, 'OrderDetail', { OrderId: this.id })]; 115 | case 1: 116 | _a.details = _b.sent(); 117 | return [2 /*return*/]; 118 | } 119 | }); 120 | }); 121 | }; 122 | Order = __decorate([ 123 | vue_property_decorator_1.Component({ template: "
\n \n
\n
Order Id needs to be selected
" 124 | }) 125 | ], Order); 126 | return Order; 127 | }(shared_1.RowComponent)); 128 | shared_1.dbConfig('northwind', { 129 | showTables: 'Customer,Order,OrderDetail,Category,Product,Employee,Shipper,Supplier,Region,Territory'.split(','), 130 | tableName: shared_1.splitPascalCase, 131 | links: { 132 | Order: { 133 | CustomerId: function (id) { return "Customer?filter=Id:" + id; }, 134 | EmployeeId: function (id) { return "Employee?filter=Id:" + id; }, 135 | ShipVia: function (id) { return "Shipper?filter=Id:" + id; }, 136 | }, 137 | OrderDetail: { 138 | OrderId: function (id) { return "Order?filter=Id:" + id; }, 139 | ProductId: function (id) { return "Product?filter=Id:" + id; }, 140 | }, 141 | Product: { 142 | SupplierId: function (id) { return "Supplier?filter=Id:" + id; }, 143 | CategoryId: function (id) { return "Category?filter=Id:" + id; }, 144 | }, 145 | Territory: { 146 | RegionId: function (id) { return "Region?filter=Id:" + id; }, 147 | }, 148 | }, 149 | rowComponents: { 150 | Order: Order, 151 | Customer: Customer, 152 | } 153 | }); 154 | -------------------------------------------------------------------------------- /dist-mix/northwind/northwind.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/SharpData/c4b0e3e7d8306d253dfd42a2a622e083f0700e68/dist-mix/northwind/northwind.sqlite -------------------------------------------------------------------------------- /northwind.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/SharpData/c4b0e3e7d8306d253dfd42a2a622e083f0700e68/northwind.sqlite -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "dev": "tsc -w", 4 | "start": "app -debug start https://localhost:5001", 5 | "pack-app": "cd scripts && pack-app.bat", 6 | "publish-app": "cd scripts && publish-app.bat", 7 | "publish-northwind": "cd dist-mix\\northwind && x publish -token %GISTLYN_TOKEN%", 8 | "publish-chinook": "cd dist-mix\\chinook && x publish -token %GISTLYN_TOKEN%", 9 | "run-test": "cd dist && app -debug", 10 | "mix-chinook": "xcopy /E /Y dist-mix\\chinook dist", 11 | "mix-northwind": "xcopy /E /Y dist-mix\\northwind dist" 12 | }, 13 | "dependencies": { 14 | "vue": "2.6.12", 15 | "vue-router": "3.4.9" 16 | }, 17 | "devDependencies": { 18 | "typescript": "^4.1.4" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /scripts/deploy/.publish: -------------------------------------------------------------------------------- 1 | gist f0349678d7f09f38c66bb1ecd89b09a5 -------------------------------------------------------------------------------- /scripts/deploy/app.multi.settings: -------------------------------------------------------------------------------- 1 | debug false 2 | name SharpData UI 3 | appName sharpdata 4 | 5 | # Configure below. Supported dialects: sqlite, mysql, postgres, sqlserver 6 | db sqlite 7 | db.connection northwind.sqlite 8 | # db.connections[techstacks] { db:postgres, connection:$TECHSTACKS_DB } 9 | # db.connections[reporting] { db:sqlserver, connection:$MSSQL_CONNECTION } 10 | 11 | args.tables Customer,Order,OrderDetail,Category,Product,Employee,EmployeeTerritory,Shipper,Supplier,Region,Territory 12 | # args.tables_techstacks technology,technology_stack,technology_choice,organization,organization_member,post,post_comment,post_vote,custom_user_auth,user_auth_details,user_activity,page_stats 13 | -------------------------------------------------------------------------------- /scripts/deploy/app.settings: -------------------------------------------------------------------------------- 1 | debug false 2 | name Northwind SharpData UI 3 | appName sharpdata 4 | 5 | # Configure below. Supported dialects: sqlite, mysql, postgres, sqlserver 6 | db.connections[northwind] { db:sqlite, connection: 'northwind.sqlite' } 7 | -------------------------------------------------------------------------------- /scripts/pack-app.bat: -------------------------------------------------------------------------------- 1 | PUSHD .. 2 | rd /q /s dist 3 | md dist\assets dist\db dist\custom 4 | xcopy /E wwwroot\assets .\dist\assets\ 5 | xcopy /E wwwroot\db .\dist\db\ 6 | x run _bundle.ss -to /dist 7 | copy wwwroot\* dist 8 | copy scripts\deploy\app.settings dist 9 | 10 | copy wwwroot\custom\northwind.js dist-mix\northwind\custom 11 | copy northwind.sqlite dist-mix\northwind 12 | copy wwwroot\custom\chinook.js dist-mix\chinook\custom 13 | copy chinook.sqlite dist-mix\chinook 14 | 15 | REM Uncomment if app requires a .NET .dll: 16 | rem dotnet publish -c release 17 | rem md dist\plugins 18 | rem copy bin\release\netcoreapp3.1\publish\SharpData.dll dist\plugins\ 19 | POPD -------------------------------------------------------------------------------- /scripts/pack-app.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | rm -rf dist 3 | mkdir -p dist/assets 4 | mkdir -p dist/db 5 | mkdir -p dist/custom 6 | 7 | x run _bundle.ss -to dist 8 | 9 | cp -r wwwroot/* dist/ 10 | cp scripts/deploy/app.settings dist/app.settings 11 | 12 | cp wwwroot/custom/northwind.js dist-mix/northwind/ 13 | cp northwind.sqlite dist-mix/northwindcustom 14 | 15 | cp wwwroot/custom/chinook.js dist-mix/chinook/custom 16 | cp chinook.sqlite dist-mix/chinook 17 | 18 | -------------------------------------------------------------------------------- /scripts/publish-app.bat: -------------------------------------------------------------------------------- 1 | COPY deploy\.publish ..\dist 2 | PUSHD ..\dist 3 | x publish -token %GISTLYN_TOKEN% 4 | POPD -------------------------------------------------------------------------------- /src/App.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import { Component, Prop } from 'vue-property-decorator'; 3 | import { bus, store } from './shared'; 4 | 5 | @Component({ template: 6 | `
7 | 8 |
` 9 | }) 10 | export class App extends Vue { 11 | get store() { return store; } 12 | } 13 | export default App; 14 | -------------------------------------------------------------------------------- /src/ErrorView.ts: -------------------------------------------------------------------------------- 1 | import {Component, Prop, Vue, Watch} from 'vue-property-decorator'; 2 | 3 | @Component({ template: 4 | `
5 |
{{responseStatus.errorCode}}: {{responseStatus.message}}
6 |
7 | 9 |
{{responseStatus.stackTrace}}
10 |
11 |
` 12 | }) 13 | export class ErrorView extends Vue { 14 | @Prop({ default: null }) responseStatus: any; 15 | showStackTrace = false; 16 | } 17 | export default ErrorView; 18 | Vue.component('error-view', ErrorView); -------------------------------------------------------------------------------- /src/JsonViewer.ts: -------------------------------------------------------------------------------- 1 | import { Component, Prop, Vue } from 'vue-property-decorator'; 2 | import {humanize, toDate, toPascalCase} from "@servicestack/client"; 3 | 4 | const show = (k:any) => typeof k !== "string" || k.substr(0, 2) !== "__"; 5 | const keyFmt = (t:string) => humanize(toPascalCase(t)); 6 | const uniqueKeys = (m: any[]): any => { 7 | var h:any = {}; 8 | for (var i = 0, len = m.length; i < len; i++) { 9 | const values:any = m[i]; 10 | for (let k in values) { 11 | if (values.hasOwnProperty(k) && show(k)) { 12 | h[k] = k; 13 | } 14 | } 15 | } 16 | return h; 17 | }; 18 | 19 | var valueFmt = (k:string, v:any, vFmt:string) => vFmt; 20 | 21 | const num = (m:number) => m; 22 | const date = (s:string) => toDate(s); 23 | const pad = (d:number) => d < 10 ? '0' + d : d; 24 | const dmft = (d:Date) => d.getFullYear() + '/' + pad(d.getMonth() + 1) + '/' + pad(d.getDate()); 25 | var str = (m:string) => m.substr(0, 6) === '/Date(' ? dmft(date(m)) : m; 26 | 27 | const obj = (m:any):string => { 28 | return (`
29 | ${Object.keys(m).filter(show).map(k => ( 30 | `
${keyFmt(k)}
${valueFmt(k, m[k], val(m[k]))}
` 31 | )).join('')} 32 |
`); 33 | }; 34 | 35 | const arr = (m: any[]):string => { 36 | if (typeof m[0] == 'string' || typeof m[0] == 'number') 37 | return `${m.join(', ')}`; 38 | 39 | var h = uniqueKeys(m); 40 | return (` 41 | 42 | 43 | 44 | ${Object.keys(h).map(k => (``)).join('')} 45 | 46 | 47 | 48 | ${m.map(row => ( 49 | ` 50 | ${Object.keys(h).filter(show).map(k => ``).join('')} 51 | `)).join('')} 52 | 53 |
${keyFmt(k)}
${valueFmt(k, row[k], val(row[k]) )}
`); 54 | }; 55 | 56 | const val = (m: any, valueFn?: (k: string, v: any, vFmt: string) => string):string => { 57 | if (valueFn) 58 | valueFmt = valueFn; 59 | if (m == null) return ""; 60 | if (typeof m == "number") return `${num(m)}`; 61 | if (typeof m == "string") return str(m); 62 | if (typeof m == "boolean") return m ? "true" : "false"; 63 | return m.length ? arr(m) : obj(m); 64 | }; 65 | 66 | @Component({ template: 67 | `
68 |
69 | 70 |
` 71 | }) 72 | export class JsonViewer extends Vue { 73 | @Prop({ default: null }) value: any; 74 | @Prop({ default: null }) json: string; 75 | 76 | get html() { return this.json ? val(JSON.parse(this.json)) : val(this.value); } 77 | } 78 | export default JsonViewer; 79 | Vue.component('jsonviewer',JsonViewer); -------------------------------------------------------------------------------- /src/components/Results/SelectColumns.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import {Component, Emit, Prop} from 'vue-property-decorator'; 3 | import {ColumnSchema} from '../../shared'; 4 | 5 | @Component({ template: 6 | ``, 36 | }) 37 | class SelectColumns extends Vue { 38 | @Prop() public columns: ColumnSchema[]; 39 | @Prop({ default: () => ([])}) value: string[]; 40 | 41 | selectedColumns:string[] = []; 42 | 43 | mounted() { 44 | this.selectedColumns = this.value; 45 | this.$nextTick(() => (document.querySelector('.modal') as HTMLElement)?.focus()); 46 | } 47 | 48 | @Emit('input') 49 | protected onInputValues(e:InputEvent) { 50 | return this.selectedColumns; 51 | } 52 | } 53 | Vue.component('select-columns', SelectColumns); 54 | -------------------------------------------------------------------------------- /src/components/Results/index.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import {Component, Prop, Watch} from 'vue-property-decorator'; 3 | import { 4 | bus, 5 | ColumnSchema, dateFmtHMS, 6 | exec, 7 | getTableSettings, 8 | loadTable, 9 | log, 10 | openUrl, 11 | saveTableSettings, 12 | store, 13 | getRowComponent, 14 | TableSettings 15 | } from '../../shared'; 16 | import {getField, humanize, normalizeKey, splitOnFirst, toCamelCase, toDateFmt} from "@servicestack/client"; 17 | import {Route} from "vue-router"; 18 | import {desktopSaveDownloadUrl, evaluateCode} from "@servicestack/desktop"; 19 | 20 | @Component({ template: 21 | `{{url}} 22 | 23 | 24 | {{format}} 25 | {{format}} 26 | `}) 27 | class FormatString extends Vue { 28 | @Prop({ default: '' }) public value: any; 29 | @Prop({ default: '' }) public href: string|null; 30 | 31 | get lower() { return `${this.value}`.toLowerCase(); } 32 | get isUrl() { return typeof this.value == "string" && this.value.startsWith('http'); } 33 | get url() { return typeof this.value == "string" && this.value.substring(this.value.indexOf('://') + 3); } 34 | get format(){ return typeof this.value == "string" && this.value.startsWith('/Date(') ? toDateFmt(this.value) : this.value; } 35 | } 36 | Vue.component('format', FormatString); 37 | 38 | @Component({ template: 39 | `
40 |
41 | 42 | 43 | 44 | 45 | 46 | Showing Results {{skip+1}} - {{min(skip + results.length,total)}} of {{total}} 47 | 48 | 50 | html 51 | csv 52 | json 53 |
54 |
55 | Loading {{ this.columns?.length ? 'results' : 'schema' }}... 56 |
57 |
58 | 59 |
60 | 61 | 62 | 69 | 70 | 71 | 72 | 76 | 77 | 90 | 91 |
63 |
64 | {{ humanize(f) }} 65 | 66 | 67 |
68 |
73 | 74 | 75 |
92 | 93 |
`, 94 | }) 95 | export class Results extends Vue { 96 | @Prop() public db: string; 97 | @Prop() public table: string; 98 | 99 | showSelectColumns = false; 100 | skip = 0; 101 | take = 100; 102 | total:number|null = null; 103 | orderBy = ''; 104 | filters:{[id:string]:string} = {}; 105 | fields:string[] = []; 106 | results = []; 107 | openComponents:number[] = []; 108 | 109 | loading = false; 110 | responseStatus:any = null; 111 | 112 | get store() { return store; } 113 | get columns() { return store.getColumnSchemas(this.db, this.table); } 114 | get dirty() { return this.skip || this.orderBy || Object.keys(this.filters).length > 0 || this.fields.length > 0; } 115 | get rowComponent(){ return getRowComponent(this.db, this.table); } 116 | get fieldNames() { 117 | let ret = this.columns?.map(x => x.columnName); 118 | if (this.fields.length > 0) { 119 | ret = ret.filter(x => this.fields.indexOf(x) >= 0); 120 | } 121 | return ret; 122 | } 123 | 124 | showRowComponent(rowIndex:number) { return this.openComponents.indexOf(rowIndex) >= 0; } 125 | 126 | toggleRowComponent(rowIndex:number) { 127 | if (this.showRowComponent(rowIndex)) 128 | this.openComponents = this.openComponents.filter(x => x != rowIndex); 129 | else 130 | this.openComponents.push(rowIndex); 131 | } 132 | 133 | rowComponentClass(rowIndex:number) { 134 | return `svg svg-chevron-${this.showRowComponent(rowIndex) ? 'down' : 'right'} svg-md btn-link align-top`; 135 | } 136 | 137 | min(num1:number,num2:number) { return Math.min(num1, num2); } 138 | 139 | @Watch('$route', { immediate: true, deep: true }) 140 | async onUrlChange(newVal: Route) { 141 | await this.reset(); 142 | } 143 | 144 | async clear() { 145 | if (this.$route.query.filter) { 146 | this.$router.push(this.$route.path); 147 | } 148 | await saveTableSettings(this.db, this.table, null); 149 | await this.reset(); 150 | } 151 | 152 | async reset() { 153 | const settings = getTableSettings(this.db, this.table) || {}; 154 | this.skip = settings.skip || 0; 155 | this.orderBy = settings.orderBy || ''; 156 | this.filters = settings.filters || {}; 157 | this.fields = settings.fields || []; 158 | 159 | if (this.$route.query.filter) { 160 | const parts = splitOnFirst(this.$route.query.filter as string,':'); 161 | this.filters = { [parts[0]]: parts[1] }; 162 | } 163 | 164 | this.results = []; 165 | await loadTable(this, this.db, this.table); 166 | await this.search(); 167 | } 168 | 169 | async handleSelectColumns(e:any) { 170 | this.showSelectColumns = false; 171 | await this.search(); 172 | } 173 | 174 | async viewNext(skip:number) { 175 | this.skip += skip; 176 | if (typeof this.total != 'number') return; 177 | const lastPage = Math.floor(this.total / 100) * 100; 178 | if (this.skip > lastPage) { 179 | this.skip = lastPage; 180 | } 181 | if (this.skip < 0) { 182 | this.skip = 0; 183 | } 184 | await this.search(); 185 | } 186 | 187 | get filterQuery() { 188 | let url = ''; 189 | Object.keys(this.filters).forEach(k => { 190 | if (this.filters[k]) { 191 | url += '&' 192 | url += encodeURIComponent(k) + '=' + encodeURIComponent(this.filters[k]); 193 | } 194 | }); 195 | return url; 196 | } 197 | 198 | async filterSearch() { 199 | this.skip = 0; 200 | await this.search(); 201 | } 202 | 203 | createFilteredUrl(format="json") { 204 | let url = `/db/${this.db}/${this.table}?format=${format}`; 205 | url += this.filterQuery; 206 | if (this.fields.length > 0) { 207 | url += '&fields=' + encodeURIComponent(this.fields.join(',')); 208 | } 209 | if (this.orderBy) { 210 | url += '&orderBy=' + encodeURIComponent(this.orderBy); 211 | } 212 | return url; 213 | } 214 | 215 | createUrl(format="json") { 216 | let url = this.createFilteredUrl(format); 217 | if (this.skip > 0) { 218 | url += '&skip=' + this.skip; 219 | } 220 | if (this.take) { 221 | url += '&take=' + this.take; 222 | } 223 | //log('createUrl, filters', this.filters, 'orderBy', this.orderBy, 'take', this.take, 'URL', url); 224 | return url; 225 | } 226 | 227 | async search() { 228 | this.openComponents = []; 229 | this.results = await exec(this, async () => { 230 | const url = this.createUrl(); 231 | let r = await fetch(url); 232 | let json = await r.text(); 233 | return json && JSON.parse(json) || []; 234 | }); 235 | if (this.rowComponent && this.results.length == 1) { 236 | this.openComponents.push(0); 237 | } 238 | this.total = await exec(this, async () => { 239 | let url = `/db/${this.db}/${this.table}/total?format=json`; 240 | url += this.filterQuery; 241 | let r = await fetch(url); 242 | let txtTotal = await r.text(); 243 | return parseInt(txtTotal) || null; 244 | }); 245 | await saveTableSettings(this.db, this.table, { 246 | skip:this.skip, 247 | filters:this.filters, 248 | orderBy:this.orderBy, 249 | fields:this.fields, 250 | }) 251 | } 252 | 253 | async openCsv() { 254 | const url = this.createFilteredUrl("csv"); 255 | let downloadUrl = desktopSaveDownloadUrl(`${this.db}-${this.table}-${dateFmtHMS()}.csv`, url) + "?open=true"; 256 | if (store.hasExcel) { 257 | downloadUrl += '&start=excel'; 258 | } 259 | await fetch(downloadUrl); 260 | } 261 | 262 | async open(format:string) { 263 | const url = this.createUrl(format); 264 | await openUrl(url); 265 | } 266 | 267 | async mounted() { 268 | bus.$on('settings', async () => await this.reset()); 269 | await this.reset(); 270 | } 271 | 272 | humanize(s:string) { return humanize(s); } 273 | 274 | renderValue(o: any) { 275 | return Array.isArray(o) 276 | ? o.join(', ') 277 | : typeof o == "undefined" 278 | ? "" 279 | : typeof o == "object" 280 | ? JSON.stringify(o) 281 | : o + ""; 282 | } 283 | 284 | getField(o: any, name: string) { return getField(o,name); } 285 | 286 | getLink(o: any, name: string) { 287 | const config = store.dbConfigs[this.db]; 288 | const fnLink = config && config.links && config.links[this.table] && config.links[this.table][name]; 289 | return fnLink && fnLink(getField(o,name)); 290 | } 291 | 292 | async setOrderBy(field:string) { 293 | if (this.orderBy == field) { 294 | this.orderBy = '-' + field; 295 | } else if (this.orderBy == '-' + field) { 296 | this.orderBy = ''; 297 | } else { 298 | this.orderBy = field; 299 | } 300 | await this.search(); 301 | } 302 | 303 | helpFilters() { 304 | return `Search Filters: 305 | Use '=null' or '!=null' to search NULL columns 306 | Use '<= < > >= <> !=' prefix to search with that operator 307 | Use ',' suffix to perform an IN(values) search on integers 308 | Use '%' prefix or suffix to perform a LIKE wildcard search 309 | Use '=' prefix to perform an exact coerced search 310 | Otherwise a 'string equality' search is performed` 311 | } 312 | } 313 | export default Results; 314 | Vue.component('results',Results); 315 | -------------------------------------------------------------------------------- /src/components/Viewer/index.ts: -------------------------------------------------------------------------------- 1 | import {Vue, Component, Prop, Watch} from 'vue-property-decorator'; 2 | import { 3 | store, 4 | client, 5 | bus, 6 | exec, 7 | } from '../../shared'; 8 | 9 | @Component({ template: 10 | `
11 | 33 | 34 | 56 | 57 |
58 |
59 | 60 |
61 |
62 |
63 | 64 |
`, 65 | }) 66 | export class Viewer extends Vue { 67 | @Prop({ default: '' }) name: string; 68 | txtFilter = ''; 69 | 70 | results:any[] = []; 71 | 72 | loading = false; 73 | responseStatus = null; 74 | 75 | get store() { return store; } 76 | get db() { return this.$route.params.db; } 77 | get table() { return this.$route.params.table; } 78 | 79 | filtered(tables:string[]) { 80 | return this.txtFilter 81 | ? tables.filter(x => x.toLowerCase().indexOf(this.txtFilter.toLowerCase()) >= 0) 82 | : tables; 83 | } 84 | link(d:string,t:string) { return `/${d}/${t}`; } 85 | 86 | tableName(db:string, table:string) { 87 | const config = store.dbConfigs[db]; 88 | return config && config.tableName ? config.tableName(table) ?? table : table; 89 | } 90 | 91 | async mounted() { 92 | } 93 | 94 | async submit() { 95 | } 96 | } 97 | export default Viewer; 98 | Vue.component('viewer', Viewer); 99 | 100 | -------------------------------------------------------------------------------- /src/css/layout.css: -------------------------------------------------------------------------------- 1 | .grid-layout { 2 | display: grid; 3 | width: 100vw; 4 | height: 100vh; 5 | grid-column-gap: 5px; 6 | grid-template-columns: 250px auto; 7 | grid-template-rows: 80px auto; 8 | grid-template-areas: 9 | "head head" 10 | "nav main" 11 | } 12 | header { 13 | background: #fff; 14 | grid-area: head; 15 | display: grid; 16 | grid-template-columns: auto auto; 17 | grid-template-areas: "breadcrumb auth" 18 | } 19 | #header {} 20 | .site-breadcrumbs { 21 | padding-left: 0; 22 | height: 80px; 23 | } 24 | nav { 25 | background: #fff; 26 | grid-area: nav; 27 | padding: 0 2px 0 10px; 28 | overflow-x: hidden; 29 | overflow-y: auto; 30 | display: grid; 31 | grid-template-rows: 40px auto; 32 | grid-template-areas: 33 | "filter" 34 | "sidebar" 35 | } 36 | #nav-filter { 37 | grid-area: filter; 38 | margin: 2px 0 0 0; 39 | } 40 | #sidebar { 41 | grid-area: sidebar; 42 | overflow-x: hidden; 43 | overflow-y: scroll; 44 | } 45 | main { 46 | background: #fff; 47 | grid-area: main; 48 | padding: 2px; 49 | grid-row-gap: 5px; 50 | overflow: auto; 51 | display: grid; 52 | } 53 | .main-query, .loading-query { 54 | height: 38px; 55 | font-size: 20px; 56 | padding-top: 1px; 57 | } 58 | .main-container { 59 | overflow-y: scroll; 60 | } 61 | -------------------------------------------------------------------------------- /src/css/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | } 3 | ::-webkit-scrollbar { 4 | width: 10px; 5 | height: 10px; 6 | } 7 | ::-webkit-scrollbar-thumb { 8 | background-color: #f1f1f1; 9 | } 10 | .navbar { 11 | border-radius: 0; 12 | background: #4183B8 !important; 13 | } 14 | a { 15 | color: #4183B8; 16 | } 17 | a:hover { 18 | text-decoration: none; 19 | } 20 | .form-check input[type=checkbox], .form-check input[type=radio] { 21 | margin-top:7px; 22 | } 23 | .breadcrumb { 24 | background: none; 25 | } 26 | .result { 27 | margin: 10px; 28 | color: #349268; 29 | } 30 | .stacktrace { 31 | background: #f1f1f1; 32 | padding: 1em; 33 | margin: 1em 0 .5em 0; 34 | border-radius: 5px; 35 | border: 1px solid #ccc; 36 | white-space: pre-wrap; 37 | } 38 | .results-none { 39 | color: #6c757d; 40 | } 41 | table.results { 42 | /*box-shadow: 0 1px 4px 0 rgba(0,0,0,0.14);*/ 43 | border: 1px solid #eee; 44 | background: #fefefe; 45 | } 46 | table.results thead tr { 47 | background: #eee; 48 | } 49 | table.results th { 50 | text-align: left; 51 | color: #757575; 52 | font-size: 13px; 53 | line-height: 18px; 54 | border-bottom: 1px solid #e0e0e0; 55 | padding: 5px; 56 | overflow: hidden; 57 | white-space: nowrap; 58 | } 59 | table.results td { 60 | color: #212121; 61 | font-size: 12px; 62 | padding: 5px; 63 | max-width: 300px; 64 | overflow: hidden; 65 | white-space: nowrap; 66 | text-overflow: ellipsis; 67 | } 68 | table.results td.row-component { 69 | max-width: 900px; 70 | } 71 | table.results tr.filters td { 72 | text-overflow: unset; 73 | } 74 | th .modal-content, td .modal-content { 75 | font-size: 1rem; /*revert*/ 76 | } 77 | .noselect { 78 | -webkit-touch-callout: none; /* iOS Safari */ 79 | -webkit-user-select: none; /* Chrome/Safari/Opera */ 80 | -moz-user-select: none; /* Firefox */ 81 | -ms-user-select: none; /* IE/Edge */ 82 | user-select: none; /* non-prefixed version, currently 83 | not supported by any browser */ 84 | } 85 | .svg-btn, .btn-link, .th-link { 86 | cursor: pointer; 87 | user-select: none; 88 | } 89 | .btn-link { 90 | text-decoration: none; 91 | } 92 | #sidebar .selected { 93 | font-weight: bold; 94 | } 95 | .datamodel { 96 | white-space: nowrap; 97 | } 98 | .close,.text-close { 99 | user-select: none; 100 | } 101 | .text-close { 102 | cursor: pointer; 103 | font-size: 1.5em; 104 | color: #999; 105 | } 106 | .text-close:hover { 107 | color: #666; 108 | } 109 | .results-label { 110 | color: #666; 111 | vertical-align: bottom; 112 | line-height: 36px; 113 | } 114 | table.results .filters td { 115 | padding: 0 1px; 116 | margin: 0; 117 | } 118 | .filters input { 119 | min-width: 50px; 120 | width: 100%; 121 | font-size: 11px; 122 | } 123 | .btn-compact.btn-sm { 124 | padding:.10rem .4rem; 125 | } 126 | 127 | .jsonviewer .ib { display: inline-block; } 128 | .jsonviewer table { border-collapse:collapse; border: solid 1px #ccc; clear: left; } 129 | .jsonviewer th { text-align: left; padding: 4px 8px; text-shadow: #fff 1px 1px -1px; background: #f1f1f1; white-space:nowrap; font-weight: bold; } 130 | .jsonviewer td { padding: 8px 8px 0 8px; vertical-align: top; line-height: 18px; } 131 | .jsonviewer dl { margin: 0; clear: left; } 132 | .jsonviewer dt { font-weight: bold; width: 160px; clear: left; float: left; display:block; white-space:nowrap; line-height: 26px; } 133 | .jsonviewer dd { display: block; float: left; line-height: 26px; max-width: 600px; margin: 0; } 134 | .jsonviewer dl dl dt { font-weight: bold; } 135 | .jsonviewer hr { display:none; } 136 | .jsonviewer td dl HR { display:block; padding: 0; clear: left; border: none; } 137 | .jsonviewer td dl { padding: 4px; margin: 0; height:100%; max-width: 700px; } 138 | .jsonviewer dl td dl dt { padding: 2px; margin: 0 10px 0 0; font-weight: bold; width: 120px; overflow: hidden; clear: left; float: left; display:block; } 139 | .jsonviewer dl td dl dd { margin: 0; padding: 2px; display: block; float: left; } 140 | 141 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import './app.scss'; 2 | import 'es6-shim'; 3 | 4 | import Vue, {VueConstructor} from 'vue'; 5 | 6 | import Controls from '@servicestack/vue'; 7 | Vue.use(Controls); 8 | 9 | import { App } from './App'; 10 | 11 | import { router } from './shared/router'; 12 | 13 | const app = new Vue({ 14 | el: '#app', 15 | render: (h) => h(App), 16 | router, 17 | }); 18 | -------------------------------------------------------------------------------- /src/shared/index.ts: -------------------------------------------------------------------------------- 1 | import Vue, {VueConstructor} from 'vue'; 2 | import { 3 | JsonServiceClient, 4 | normalizeKey, 5 | toDate, getField, splitOnFirst, 6 | errorResponse, errorResponseExcept, 7 | toPascalCase, 8 | queryString, padInt, appendQueryString, humanize, 9 | } from '@servicestack/client'; 10 | 11 | declare let global: any; // populated from package.json/jest 12 | 13 | export const client = new JsonServiceClient('/'); 14 | 15 | import {desktopInfo, desktopTextFile, evaluateCode, desktopSaveTextFile} from '@servicestack/desktop'; 16 | import {Prop} from "vue-property-decorator"; 17 | 18 | export class RowComponent extends Vue { 19 | @Prop() public db: string; 20 | @Prop() public table: string; 21 | @Prop() row: any; 22 | @Prop() columns: ColumnSchema[]; 23 | } 24 | 25 | const rowComponents:{[id:string]:{[id:string]:string}} = {}; 26 | export function getRowComponent(db:string, table:string) { 27 | db = db.toLowerCase(); 28 | table = table.toLowerCase(); 29 | return rowComponents[db] && rowComponents[db][table] || null; 30 | } 31 | export function registerRowComponent(db:string, table:string, constructor:VC, component:string) { 32 | Vue.component(component, constructor); 33 | db = db.toLowerCase(); 34 | table = table.toLowerCase(); 35 | if (!rowComponents[db]) 36 | rowComponents[db] = {}; 37 | rowComponents[db][table] = component; 38 | } 39 | 40 | export enum Roles { 41 | Admin = 'Admin', 42 | } 43 | 44 | export interface DesktopInfo { 45 | tool:string; 46 | toolVersion:string; 47 | chromeVersion:string; 48 | } 49 | export interface ColumnSchema { 50 | columnName: string; 51 | columnOrdinal: number; 52 | isUnique: boolean; 53 | isKey: boolean; 54 | isAutoIncrement: boolean; 55 | isRowVersion: boolean; 56 | isExpression: boolean; 57 | dataType: string; 58 | dataTypeName: string; 59 | allowDBNull: boolean; 60 | columnDefinition: string; 61 | numericPrecision: number; 62 | numericScale: number; 63 | baseCatalogName: string; 64 | baseColumnName: string; 65 | baseSchemaName: string; 66 | baseTableName: string; 67 | } 68 | 69 | // Shared state between all Components 70 | interface State { 71 | debug: boolean|null; 72 | desktop: DesktopInfo|null; 73 | hasExcel: boolean|null; 74 | namedDbs: string[], 75 | tables: {[id:string]:string[]}; 76 | totals: {[id:string]:{[id:string]:number}}; 77 | columns: {[id:string]:{[id:string]:ColumnSchema[]}}; 78 | getColumnTotal(db:string,table:string):number|null; 79 | getColumnSchemas(db:string,table:string):ColumnSchema[]; 80 | dbConfigs: {[id:string]:DbConfig}; 81 | } 82 | export const store: State = { 83 | debug: global.CONFIG.debug as boolean, 84 | desktop: global.CONFIG.desktop as DesktopInfo, 85 | hasExcel: global.CONFIG.hasExcel as boolean, 86 | namedDbs: global.CONFIG.namedDbs as string[], 87 | tables: global.CONFIG.tables as {[id:string]:string[]}, 88 | totals: {}, 89 | columns: {}, 90 | getColumnTotal(db: string, table: string) { 91 | const ret = this.totals[db] && this.totals[db][table]; 92 | return ret != null ? ret : null; 93 | }, 94 | getColumnSchemas(db: string, table: string) { 95 | return this.columns[db] && this.columns[db][table] || []; 96 | }, 97 | dbConfigs: {}, 98 | }; 99 | 100 | interface DbConfig { 101 | tableName?(name:string):string; 102 | showTables?:string[]; 103 | links?:any; 104 | rowComponents?:{[table:string]:VueConstructor}; 105 | } 106 | 107 | export function dbConfig(db:string, config:DbConfig) { 108 | if (db != 'main' && store.namedDbs.indexOf(db) < 0) return; 109 | 110 | if (config.showTables && config.showTables.length > 0) { 111 | Vue.set(store.tables, db, config.showTables); 112 | } 113 | if (config.rowComponents) { 114 | for (let table of Object.keys(config.rowComponents)) { 115 | registerRowComponent(db, table, config.rowComponents[table], table); 116 | } 117 | } 118 | Vue.set(store.dbConfigs, db, config); 119 | } 120 | 121 | export const splitPascalCase = (table:string) => 122 | humanize(table).split(' ').map(toPascalCase).join(' ') 123 | 124 | class EventBus extends Vue { 125 | store = store; 126 | } 127 | export const bus = new EventBus({ data: store }); 128 | 129 | export interface DesktopSettings 130 | { 131 | [db:string]:{[table:string]:TableSettings}; 132 | } 133 | export interface TableSettings 134 | { 135 | skip?:number; 136 | orderBy?:string; 137 | filters?:any; 138 | fields?:string[]; 139 | } 140 | let settings:DesktopSettings = {}; 141 | let settingsLoaded = false; 142 | export async function loadSettings() { 143 | try { 144 | const settingsJson = store.desktop 145 | ? await desktopTextFile('settings.json') 146 | : localStorage.getItem('settings.json'); 147 | if (settingsJson) { 148 | settings = JSON.parse(settingsJson) as DesktopSettings || {}; 149 | log('loaded', settings); 150 | bus.$emit('settings'); 151 | } 152 | } catch (e) { 153 | log(`Could not retrieve desktopTextFile 'settings.json'`, e); 154 | } finally { 155 | settingsLoaded = true; 156 | } 157 | } 158 | 159 | export async function saveSettings() { 160 | try { 161 | //log('saveSettings', settings, store.desktop); 162 | const settingsJson = JSON.stringify(settings); 163 | if (store.desktop) { 164 | await desktopSaveTextFile('settings.json', settingsJson); 165 | } else { 166 | localStorage.setItem('settings.json', settingsJson); 167 | } 168 | } catch (e) { 169 | log(`Could not retrieve saveDesktopTextFile 'settings.json'`, e); 170 | } 171 | } 172 | export function getTableSettings(db:string,table:string):TableSettings { 173 | return settings[db] && settings[db][table] || null; 174 | } 175 | export async function saveTableSettings(db:string,table:string,tableSettings:TableSettings|null) { 176 | if (!settingsLoaded) return; 177 | if (!settings[db]) { 178 | settings[db] = {}; 179 | } 180 | if (tableSettings) { 181 | settings[db][table] = tableSettings; 182 | } 183 | else { 184 | delete settings[db][table]; 185 | } 186 | await saveSettings(); 187 | } 188 | 189 | export function log(...o:any[]) { 190 | if (store.debug) 191 | console.log.apply(console, arguments as any); 192 | return o; 193 | } 194 | 195 | export const dateFmtHMS = (d: Date = new Date()) => 196 | `${d.getFullYear()-2000}${padInt(d.getMonth() + 1)}${padInt(d.getDate())}-${padInt(d.getHours())}${padInt(d.getMinutes())}${padInt(d.getSeconds())}`; 197 | 198 | export async function openUrl(url:string) { 199 | if (store.desktop) { 200 | await evaluateCode(`openUrl('${url}')`); 201 | } else { 202 | window.open(url); 203 | } 204 | } 205 | 206 | export async function exec(c:any, fn:() => Promise) { 207 | try { 208 | c.loading = true; 209 | c.responseStatus = null; 210 | 211 | return await fn(); 212 | 213 | } catch (e) { 214 | log(e); 215 | c.responseStatus = e.responseStatus || (typeof e == 'string' ? { errorCode:'Error', message:e } : null) || e; 216 | c.$emit('error', c.responseStatus); 217 | } finally { 218 | c.loading = false; 219 | } 220 | } 221 | 222 | export async function loadTable(c:any, db:string,table:string) { 223 | if (store.getColumnSchemas(db, table).length > 0) return; 224 | await exec(c, async () => { 225 | const r = await fetch(`/db/${db}/${table}/meta?format=json`); 226 | const json = await r.text(); 227 | if (json) { 228 | const obj = JSON.parse(json); 229 | if (!store.columns[db]) 230 | Vue.set(store.columns, db, {}); 231 | Vue.set(store.columns[db], table, obj); 232 | } 233 | }) 234 | } 235 | 236 | export async function sharpData(db:string,table:string,args?:any) { 237 | let url = `/db/${db}/${table}?format=json`; 238 | if (args) { 239 | url = appendQueryString(url, args); 240 | } 241 | return await (await fetch(url)).json() 242 | } 243 | 244 | 245 | Vue.filter('upper', function (value:string) { 246 | return value?.toUpperCase(); 247 | }); 248 | Vue.filter('json', function (value:any) { 249 | return value && JSON.stringify(value); 250 | }); 251 | 252 | (async () => { await loadSettings(); })(); 253 | 254 | (async () => { 255 | for (let db in store.tables) { 256 | try { 257 | let r = await fetch(`/db/${db}/totals?format=json`); 258 | let json = await r.text(); 259 | if (json) { 260 | let kvps = JSON.parse(json); 261 | let columnTotals:any = {}; 262 | kvps.forEach((x:any) => { 263 | columnTotals[x.key] = x.value; 264 | }) 265 | Vue.set(store.totals, db, columnTotals); 266 | } 267 | } catch (e) { 268 | log(`Can't retrieve totals for '${db}':`, e); 269 | } 270 | } 271 | })(); 272 | 273 | (async () => { 274 | try { 275 | store.desktop = await desktopInfo(); 276 | log('In Desktop app:', store.desktop); 277 | } catch (e) { 278 | log(`Not in Desktop app:`, e); 279 | } 280 | })(); 281 | -------------------------------------------------------------------------------- /src/shared/router.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Router, { Route } from 'vue-router'; 3 | 4 | import { Forbidden } from '@servicestack/vue'; 5 | import { Viewer } from '../components/Viewer'; 6 | 7 | export enum Routes { 8 | Home = '/', 9 | ViewTable = '/:db/:table', 10 | Forbidden = '/forbidden', 11 | } 12 | 13 | Vue.use(Router); 14 | 15 | const routes = [ 16 | { path: Routes.Home, component: Viewer }, 17 | { path: Routes.ViewTable, component: Viewer }, 18 | { path: Routes.Forbidden, component: Forbidden }, 19 | { path: '*', redirect: '/' }, 20 | ]; 21 | 22 | export const router = new Router ({ 23 | mode: 'history', 24 | linkActiveClass: 'active', 25 | routes, 26 | }); 27 | export default router; 28 | 29 | export const redirect = (path: string) => { 30 | const externalUrl = path.indexOf('://') >= 0; 31 | if (!externalUrl) { 32 | router.push({ path }); 33 | } else { 34 | location.href = path; 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ 4 | "lib": [ "dom", "es2015" ], /* Specify library files to be included in the compilation. */ 5 | "strict": true, /* Enable all strict type-checking options. */ 6 | "strictPropertyInitialization": false, /* Enable strict checking of property initialization in classes. */ 7 | "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 8 | "baseUrl": "./", 9 | "paths": { 10 | "*": [ 11 | "wwwroot/lib/*", 12 | "wwwroot/lib/js/*", 13 | "typings/*", 14 | "src/*" 15 | ] 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /typings/@servicestack/client/index.d.ts: -------------------------------------------------------------------------------- 1 | import 'fetch-everywhere'; 2 | export interface IReturnVoid { 3 | createResponse(): any; 4 | } 5 | export interface IReturn { 6 | createResponse(): T; 7 | } 8 | export declare class ResponseStatus { 9 | constructor(init?: Partial); 10 | errorCode: string; 11 | message: string; 12 | stackTrace: string; 13 | errors: ResponseError[]; 14 | meta: { 15 | [index: string]: string; 16 | }; 17 | } 18 | export declare class ResponseError { 19 | constructor(init?: Partial); 20 | errorCode: string; 21 | fieldName: string; 22 | message: string; 23 | meta: { 24 | [index: string]: string; 25 | }; 26 | } 27 | export declare class ErrorResponse { 28 | constructor(init?: Partial); 29 | type: ErrorResponseType; 30 | responseStatus: ResponseStatus; 31 | } 32 | export declare class NavItem { 33 | label: string; 34 | href: string; 35 | exact: boolean; 36 | id: string; 37 | className: string; 38 | iconClass: string; 39 | show: string; 40 | hide: string; 41 | children: NavItem[]; 42 | meta: { 43 | [index: string]: string; 44 | }; 45 | constructor(init?: Partial); 46 | } 47 | export declare class GetNavItems { 48 | constructor(init?: Partial); 49 | createResponse(): GetNavItemsResponse; 50 | getTypeName(): string; 51 | } 52 | export declare class GetNavItemsResponse { 53 | baseUrl: string; 54 | results: NavItem[]; 55 | navItemsMap: { 56 | [index: string]: NavItem[]; 57 | }; 58 | meta: { 59 | [index: string]: string; 60 | }; 61 | responseStatus: ResponseStatus; 62 | constructor(init?: Partial); 63 | } 64 | export declare type ErrorResponseType = null | "RefreshTokenException"; 65 | export interface IAuthSession { 66 | userName: string; 67 | displayName: string; 68 | userId?: string; 69 | roles?: string[]; 70 | permissions?: string[]; 71 | profileUrl?: string; 72 | } 73 | export interface IResolver { 74 | tryResolve(Function: any): any; 75 | } 76 | export declare class NewInstanceResolver implements IResolver { 77 | tryResolve(ctor: ObjectConstructor): any; 78 | } 79 | export declare class SingletonInstanceResolver implements IResolver { 80 | tryResolve(ctor: ObjectConstructor): any; 81 | } 82 | export interface ServerEventMessage { 83 | type: "ServerEventConnect" | "ServerEventHeartbeat" | "ServerEventJoin" | "ServerEventLeave" | "ServerEventUpdate" | "ServerEventMessage"; 84 | eventId: number; 85 | channel: string; 86 | data: string; 87 | selector: string; 88 | json: string; 89 | op: string; 90 | target: string; 91 | cssSelector: string; 92 | body: any; 93 | meta: { 94 | [index: string]: string; 95 | }; 96 | } 97 | export interface ServerEventCommand extends ServerEventMessage { 98 | userId: string; 99 | displayName: string; 100 | channels: string; 101 | profileUrl: string; 102 | } 103 | export interface ServerEventConnect extends ServerEventCommand { 104 | id: string; 105 | unRegisterUrl: string; 106 | heartbeatUrl: string; 107 | updateSubscriberUrl: string; 108 | heartbeatIntervalMs: number; 109 | idleTimeoutMs: number; 110 | } 111 | export interface ServerEventHeartbeat extends ServerEventCommand { 112 | } 113 | export interface ServerEventJoin extends ServerEventCommand { 114 | } 115 | export interface ServerEventLeave extends ServerEventCommand { 116 | } 117 | export interface ServerEventUpdate extends ServerEventCommand { 118 | } 119 | export interface IReconnectServerEventsOptions { 120 | url?: string; 121 | onerror?: (...args: any[]) => void; 122 | onmessage?: (...args: any[]) => void; 123 | error?: Error; 124 | } 125 | /** 126 | * EventSource 127 | */ 128 | export declare enum ReadyState { 129 | CONNECTING = 0, 130 | OPEN = 1, 131 | CLOSED = 2, 132 | } 133 | export interface IEventSourceStatic extends EventTarget { 134 | new (url: string, eventSourceInitDict?: IEventSourceInit): IEventSourceStatic; 135 | url: string; 136 | withCredentials: boolean; 137 | CONNECTING: ReadyState; 138 | OPEN: ReadyState; 139 | CLOSED: ReadyState; 140 | readyState: ReadyState; 141 | onopen: Function; 142 | onmessage: (event: IOnMessageEvent) => void; 143 | onerror: Function; 144 | close: () => void; 145 | } 146 | export interface IEventSourceInit { 147 | withCredentials?: boolean; 148 | } 149 | export interface IOnMessageEvent { 150 | data: string; 151 | } 152 | export interface IEventSourceOptions { 153 | channels?: string; 154 | handlers?: any; 155 | receivers?: any; 156 | onException?: Function; 157 | onReconnect?: Function; 158 | onTick?: Function; 159 | resolver?: IResolver; 160 | validate?: (request: ServerEventMessage) => boolean; 161 | heartbeatUrl?: string; 162 | unRegisterUrl?: string; 163 | updateSubscriberUrl?: string; 164 | heartbeatIntervalMs?: number; 165 | heartbeat?: number; 166 | resolveStreamUrl?: (url: string) => string; 167 | } 168 | export declare class ServerEventsClient { 169 | channels: string[]; 170 | options: IEventSourceOptions; 171 | eventSource: IEventSourceStatic; 172 | static UnknownChannel: string; 173 | eventStreamUri: string; 174 | updateSubscriberUrl: string; 175 | connectionInfo: ServerEventConnect; 176 | serviceClient: JsonServiceClient; 177 | stopped: boolean; 178 | resolver: IResolver; 179 | listeners: { 180 | [index: string]: ((e: ServerEventMessage) => void)[]; 181 | }; 182 | EventSource: IEventSourceStatic; 183 | withCredentials: boolean; 184 | constructor(baseUrl: string, channels: string[], options?: IEventSourceOptions, eventSource?: IEventSourceStatic); 185 | onMessage: (e: IOnMessageEvent) => void; 186 | onError: (error?: any) => void; 187 | getEventSourceOptions(): { 188 | withCredentials: boolean; 189 | }; 190 | reconnectServerEvents(opt?: IReconnectServerEventsOptions): IEventSourceStatic; 191 | start(): this; 192 | stop(): Promise; 193 | invokeReceiver(r: any, cmd: string, el: Element, request: ServerEventMessage, name: string): void; 194 | hasConnected(): boolean; 195 | registerHandler(name: string, fn: Function): this; 196 | setResolver(resolver: IResolver): this; 197 | registerReceiver(receiver: any): this; 198 | registerNamedReceiver(name: string, receiver: any): this; 199 | unregisterReceiver(name?: string): this; 200 | updateChannels(channels: string[]): void; 201 | update(subscribe: string | string[], unsubscribe: string | string[]): void; 202 | addListener(eventName: string, handler: ((e: ServerEventMessage) => void)): this; 203 | removeListener(eventName: string, handler: ((e: ServerEventMessage) => void)): this; 204 | raiseEvent(eventName: string, msg: ServerEventMessage): void; 205 | getConnectionInfo(): ServerEventConnect; 206 | getSubscriptionId(): string; 207 | updateSubscriber(request: UpdateEventSubscriber): Promise; 208 | subscribeToChannels(...channels: string[]): Promise; 209 | unsubscribeFromChannels(...channels: string[]): Promise; 210 | getChannelSubscribers(): Promise; 211 | toServerEventUser(map: { 212 | [id: string]: string; 213 | }): ServerEventUser; 214 | } 215 | export interface IReceiver { 216 | noSuchMethod(selector: string, message: any): any; 217 | } 218 | export declare class ServerEventReceiver implements IReceiver { 219 | client: ServerEventsClient; 220 | request: ServerEventMessage; 221 | noSuchMethod(selector: string, message: any): void; 222 | } 223 | export declare class UpdateEventSubscriber implements IReturn { 224 | id: string; 225 | subscribeChannels: string[]; 226 | unsubscribeChannels: string[]; 227 | createResponse(): UpdateEventSubscriberResponse; 228 | getTypeName(): string; 229 | } 230 | export declare class UpdateEventSubscriberResponse { 231 | responseStatus: ResponseStatus; 232 | } 233 | export declare class GetEventSubscribers implements IReturn { 234 | channels: string[]; 235 | createResponse(): any[]; 236 | getTypeName(): string; 237 | } 238 | export declare class ServerEventUser { 239 | userId: string; 240 | displayName: string; 241 | profileUrl: string; 242 | channels: string[]; 243 | meta: { 244 | [index: string]: string; 245 | }; 246 | } 247 | export declare class HttpMethods { 248 | static Get: string; 249 | static Post: string; 250 | static Put: string; 251 | static Delete: string; 252 | static Patch: string; 253 | static Head: string; 254 | static Options: string; 255 | static hasRequestBody: (method: string) => boolean; 256 | } 257 | export interface IRequestFilterOptions { 258 | url: string; 259 | } 260 | export interface IRequestInit extends RequestInit { 261 | url?: string; 262 | compress?: boolean; 263 | } 264 | export interface Cookie { 265 | name: string; 266 | value: string; 267 | path: string; 268 | domain?: string; 269 | expires?: Date; 270 | httpOnly?: boolean; 271 | secure?: boolean; 272 | sameSite?: string; 273 | } 274 | export declare class GetAccessTokenResponse { 275 | accessToken: string; 276 | responseStatus: ResponseStatus; 277 | } 278 | export interface ISendRequest { 279 | method: string; 280 | request: any | null; 281 | body?: any | null; 282 | args?: any; 283 | url?: string; 284 | returns?: { 285 | createResponse: () => any; 286 | }; 287 | } 288 | export declare class JsonServiceClient { 289 | baseUrl: string; 290 | replyBaseUrl: string; 291 | oneWayBaseUrl: string; 292 | mode: RequestMode; 293 | credentials: RequestCredentials; 294 | headers: Headers; 295 | userName: string; 296 | password: string; 297 | bearerToken: string; 298 | refreshToken: string; 299 | refreshTokenUri: string; 300 | useTokenCookie: boolean; 301 | requestFilter: (req: IRequestInit) => void; 302 | responseFilter: (res: Response) => void; 303 | exceptionFilter: (res: Response, error: any) => void; 304 | urlFilter: (url: string) => void; 305 | onAuthenticationRequired: () => Promise; 306 | manageCookies: boolean; 307 | cookies: { 308 | [index: string]: Cookie; 309 | }; 310 | static toBase64: (rawString: string) => string; 311 | constructor(baseUrl?: string); 312 | setCredentials(userName: string, password: string): void; 313 | setBearerToken(token: string): void; 314 | get(request: IReturn | string, args?: any): Promise; 315 | delete(request: IReturn | string, args?: any): Promise; 316 | post(request: IReturn, args?: any): Promise; 317 | postToUrl(url: string, request: IReturn, args?: any): Promise; 318 | postBody(request: IReturn, body: string | any, args?: any): Promise; 319 | put(request: IReturn, args?: any): Promise; 320 | putToUrl(url: string, request: IReturn, args?: any): Promise; 321 | putBody(request: IReturn, body: string | any, args?: any): Promise; 322 | patch(request: IReturn, args?: any): Promise; 323 | patchToUrl(url: string, request: IReturn, args?: any): Promise; 324 | patchBody(request: IReturn, body: string | any, args?: any): Promise; 325 | publish(request: IReturnVoid, args?: any): Promise; 326 | sendOneWay(request: IReturn | IReturnVoid, args?: any): Promise; 327 | sendAll(requests: IReturn[]): Promise; 328 | sendAllOneWay(requests: IReturn[]): Promise; 329 | createUrlFromDto(method: string, request: IReturn): string; 330 | toAbsoluteUrl(relativeOrAbsoluteUrl: string): string; 331 | deleteCookie(name: string): void; 332 | private createRequest({method, request, url, args, body}); 333 | private createResponse(res, request); 334 | private handleError(holdRes, res, type?); 335 | send(method: string, request: any | null, args?: any, url?: string): Promise; 336 | private sendBody(method, request, body, args?); 337 | sendRequest(info: ISendRequest): Promise; 338 | raiseError(res: Response, error: any): any; 339 | } 340 | export declare const isFormData: (body: any) => boolean; 341 | export declare const toCamelCase: (s: string) => string; 342 | export declare const toPascalCase: (s: string) => string; 343 | export declare const sanitize: (status: any) => any; 344 | export declare const nameOf: (o: any) => any; 345 | export declare const css: (selector: string | NodeListOf, name: string, value: string) => void; 346 | export declare const splitOnFirst: (s: string, c: string) => string[]; 347 | export declare const splitOnLast: (s: string, c: string) => string[]; 348 | export declare const humanize: (s: any) => any; 349 | export declare const queryString: (url: string) => any; 350 | export declare const combinePaths: (...paths: string[]) => string; 351 | export declare const createPath: (route: string, args: any) => string; 352 | export declare const createUrl: (route: string, args: any) => string; 353 | export declare const appendQueryString: (url: string, args: any) => string; 354 | export declare const bytesToBase64: (aBytes: Uint8Array) => string; 355 | export declare const stripQuotes: (s: string) => string; 356 | export declare const tryDecode: (s: string) => string; 357 | export declare const parseCookie: (setCookie: string) => Cookie; 358 | export declare const normalizeKey: (key: string) => string; 359 | export declare const normalize: (dto: any, deep?: boolean) => any; 360 | export declare const getField: (o: any, name: string) => any; 361 | export declare const parseResponseStatus: (json: string, defaultMsg?: any) => any; 362 | export declare function toFormData(o: any): FormData; 363 | export declare function toObject(keys: any): {}; 364 | export declare function errorResponseSummary(): any; 365 | export declare function errorResponseExcept(fieldNames: string[] | string): any; 366 | export declare function errorResponse(fieldName: string): any; 367 | export declare const toDate: (s: any) => Date; 368 | export declare const toDateFmt: (s: string) => string; 369 | export declare const padInt: (n: number) => string | number; 370 | export declare const dateFmt: (d?: Date) => string; 371 | export declare const dateFmtHM: (d?: Date) => string; 372 | export declare const timeFmt12: (d?: Date) => string; 373 | export interface ICreateElementOptions { 374 | insertAfter?: Element | null; 375 | } 376 | export declare function createElement(tagName: string, options?: ICreateElementOptions, attrs?: any): HTMLElement; 377 | export declare function bootstrap(el?: Element): void; 378 | export declare function bindHandlers(handlers: any, el?: Document | Element): void; 379 | export interface IAjaxFormOptions { 380 | type?: string; 381 | url?: string; 382 | model?: any; 383 | credentials?: RequestCredentials; 384 | validate?: (this: HTMLFormElement) => boolean; 385 | onSubmitDisable?: string; 386 | submit?: (this: HTMLFormElement, options: IAjaxFormOptions) => Promise; 387 | success?: (this: HTMLFormElement, result: any) => void; 388 | error?: (this: HTMLFormElement, e: any) => void; 389 | complete?: (this: HTMLFormElement) => void; 390 | requestFilter?: (req: IRequestInit) => void; 391 | responseFilter?: (res: Response) => void; 392 | errorFilter?: (this: IValidation, message: string, errorCode: string, type: string) => void; 393 | messages?: { 394 | [index: string]: string; 395 | }; 396 | } 397 | export declare function bootstrapForm(form: HTMLFormElement | null, options: IAjaxFormOptions): void; 398 | export interface IValidation { 399 | overrideMessages: boolean; 400 | messages: { 401 | [index: string]: string; 402 | }; 403 | errorFilter?: (this: IValidation, message: string, errorCode: string, type: string) => void; 404 | } 405 | export declare const toVarNames: (names: string | string[]) => string[]; 406 | export declare function formSubmit(this: HTMLFormElement, options?: IAjaxFormOptions): Promise; 407 | export declare function ajaxSubmit(f: HTMLFormElement, options?: IAjaxFormOptions): any; 408 | export declare function serializeForm(form: HTMLFormElement, contentType?: string | null): string | FormData; 409 | export declare const serializeToObject: (form: HTMLFormElement) => any; 410 | export declare function serializeToUrlEncoded(form: HTMLFormElement): string; 411 | export declare const serializeToFormData: (form: HTMLFormElement) => FormData; 412 | export declare function triggerEvent(el: Element, name: string, data?: any): void; 413 | export declare function populateForm(form: HTMLFormElement, model: any): void; 414 | export declare function trimEnd(s: string, c: string): string; 415 | export declare function safeVarName(s: string): string; 416 | export declare function pick(o: any, keys: string[]): {}; 417 | export declare function omit(o: any, keys: string[]): {}; 418 | export declare function activeClassNav(x: NavItem, activePath: string): string; 419 | export declare function activeClass(href: string | null, activePath: string, exact?: boolean): string; 420 | export declare const BootstrapColors: string[]; 421 | export declare function btnColorClass(props: any): string; 422 | export declare const BootstrapSizes: string[]; 423 | export declare function btnSizeClass(props: any): string; 424 | export declare function btnClasses(props: any): any[]; 425 | export declare class NavDefaults { 426 | static navClass: string; 427 | static navItemClass: string; 428 | static navLinkClass: string; 429 | static childNavItemClass: string; 430 | static childNavLinkClass: string; 431 | static childNavMenuClass: string; 432 | static childNavMenuItemClass: string; 433 | static create(): NavOptions; 434 | static forNav(options?: NavOptions | null): NavOptions; 435 | static overrideDefaults(targets: NavOptions | null | undefined, source: NavOptions): NavOptions; 436 | static showNav(navItem: NavItem, attributes: string[]): boolean; 437 | } 438 | export declare class NavLinkDefaults { 439 | static forNavLink(options?: NavOptions | null): NavOptions; 440 | } 441 | export declare class NavbarDefaults { 442 | static navClass: string; 443 | static create(): NavOptions; 444 | static forNavbar(options?: NavOptions | null): NavOptions; 445 | } 446 | export declare class NavButtonGroupDefaults { 447 | static navClass: string; 448 | static navItemClass: string; 449 | static create(): NavOptions; 450 | static forNavButtonGroup(options?: NavOptions | null): NavOptions; 451 | } 452 | export declare class LinkButtonDefaults { 453 | static navItemClass: string; 454 | static create(): NavOptions; 455 | static forLinkButton(options?: NavOptions | null): NavOptions; 456 | } 457 | export declare class UserAttributes { 458 | static fromSession(session: IAuthSession | null): string[]; 459 | } 460 | export declare class NavOptions { 461 | static fromSession(session: IAuthSession | null, to?: NavOptions): NavOptions; 462 | attributes: string[]; 463 | activePath?: string; 464 | baseHref?: string; 465 | navClass?: string; 466 | navItemClass?: string; 467 | navLinkClass?: string; 468 | childNavItemClass?: string; 469 | childNavLinkClass?: string; 470 | childNavMenuClass?: string; 471 | childNavMenuItemClass?: string; 472 | constructor(init?: Partial); 473 | } 474 | export declare function classNames(...args: any[]): string; 475 | -------------------------------------------------------------------------------- /typings/@servicestack/desktop/index.d.ts: -------------------------------------------------------------------------------- 1 | export declare function invokeHostJsonMethod(target: string, args: { 2 | [id: string]: any; 3 | }): Promise; 4 | export declare function invokeHostTextMethod(target: string, args: { 5 | [id: string]: any; 6 | }): Promise; 7 | export declare function combinePaths(...paths: string[]): string; 8 | export declare function evaluateScript(scriptSrc: string): Promise; 9 | export declare function evaluateCode(scriptSrc: string): Promise; 10 | export declare function evaluateLisp(scriptSrc: string): Promise; 11 | export declare function renderScript(scriptSrc: string): Promise; 12 | export declare function renderCode(scriptSrc: string): Promise; 13 | export declare function renderLisp(scriptSrc: string): Promise; 14 | export declare function evaluateScriptAsync(scriptSrc: string): Promise; 15 | export declare function evaluateCodeAsync(scriptSrc: string): Promise; 16 | export declare function evaluateLispAsync(scriptSrc: string): Promise; 17 | export declare function renderScriptAsync(scriptSrc: string): Promise; 18 | export declare function renderCodeAsync(scriptSrc: string): Promise; 19 | export declare function renderLispAsync(scriptSrc: string): Promise; 20 | export declare function quote(text: string): string; 21 | export interface DesktopInfo { 22 | tool: string; 23 | toolVersion: string; 24 | chromeVersion: string; 25 | } 26 | export declare function evalToBool(scriptSrc: string): Promise; 27 | export declare function evalToBoolAsync(scriptSrc: string): Promise; 28 | export declare function desktopInfo(): Promise; 29 | export declare function openUrl(url: string): Promise; 30 | export declare function start(url: string): Promise; 31 | export declare function expandEnvVars(name: string): Promise; 32 | export declare function findWindowByName(name: string): Promise; 33 | /** 34 | * Get Clipboard Contents as a UTF-8 string 35 | */ 36 | export declare function clipboard(): Promise; 37 | /** 38 | * Set the Clipboard Contents with a UTF-8 string 39 | */ 40 | export declare function setClipboard(contents: string): Promise; 41 | export interface Size { 42 | width: number; 43 | height: number; 44 | } 45 | export interface Rectangle { 46 | top: number; 47 | left: number; 48 | bottom: number; 49 | right: number; 50 | } 51 | export interface MonitorInfo { 52 | monitor: Rectangle; 53 | work: Rectangle; 54 | flags: number; 55 | } 56 | export declare function deviceScreenResolution(): Promise; 57 | export declare function primaryMonitorInfo(): Promise; 58 | export declare function windowSendToForeground(): Promise; 59 | export declare function windowCenterToScreen(useWorkArea?: boolean): Promise; 60 | export declare function windowSetFullScreen(): Promise; 61 | export declare function windowSetFocus(): Promise; 62 | export declare function windowShowScrollBar(show: boolean): Promise; 63 | export declare function windowSetPosition(x: number, y: number, width?: number, height?: number): Promise; 64 | export declare function windowSetSize(width: number, height: number): Promise; 65 | export declare function windowRedrawFrame(): Promise; 66 | export declare function windowIsVisible(): Promise; 67 | export declare function windowIsEnabled(): Promise; 68 | export declare function windowShow(): Promise; 69 | export declare function windowHide(): Promise; 70 | export declare function windowText(): Promise; 71 | export declare function windowSetText(text: string): Promise; 72 | export declare function windowSize(): Promise; 73 | export declare function windowClientSize(): Promise; 74 | export declare function windowClientRect(): Promise; 75 | export declare function windowSetState(state: ShowWindowCommands): Promise; 76 | export declare function knownFolder(folder: KnownFolders): Promise; 77 | export declare function desktopTextFile(fileName: string): Promise; 78 | export declare function desktopSaveTextFile(fileName: string, body: string): Promise; 79 | export declare function desktopDownloadsTextFile(fileName: string): Promise; 80 | export declare function desktopSaveDownloadsTextFile(fileName: string, body: string): Promise; 81 | export declare function desktopSaveDownloadUrl(fileName: string, url: string): string; 82 | /** 83 | * refer to http://pinvoke.net/default.aspx/Enums/ShowWindowCommand.html 84 | */ 85 | export declare enum ShowWindowCommands { 86 | /** 87 | * Hides the window and activates another window. 88 | */ 89 | Hide = 0, 90 | /** 91 | * Activates and displays a window. If the window is minimized or 92 | * maximized, the system restores it to its original size and position. 93 | * An application should specify this flag when displaying the window 94 | * for the first time. 95 | */ 96 | Normal = 1, 97 | /** 98 | * Activates the window and displays it as a minimized window. 99 | */ 100 | ShowMinimized = 2, 101 | /** 102 | * Maximizes the specified window 103 | */ 104 | Maximize = 3, 105 | /** 106 | * Activates the window and displays it as a maximized window. 107 | */ 108 | ShowMaximized = 3, 109 | /** 110 | * Displays a window in its most recent size and position. This value 111 | * is similar to , except 112 | * the window is not activated. 113 | */ 114 | ShowNoActivate = 4, 115 | /** 116 | * Activates the window and displays it in its current size and position. 117 | */ 118 | Show = 5, 119 | /** 120 | * Minimizes the specified window and activates the next top-level 121 | * window in the Z order. 122 | */ 123 | Minimize = 6, 124 | /** 125 | * Displays the window as a minimized window. This value is similar to 126 | * , except the 127 | * window is not activated. 128 | */ 129 | ShowMinNoActive = 7, 130 | /** 131 | * Displays the window in its current size and position. This value is 132 | * similar to , except the 133 | * window is not activated. 134 | */ 135 | ShowNA = 8, 136 | /** 137 | * Activates and displays the window. If the window is minimized or 138 | * maximized, the system restores it to its original size and position. 139 | * An application should specify this flag when restoring a minimized window. 140 | */ 141 | Restore = 9, 142 | /** 143 | * Sets the show state based on the SW_* value specified in the 144 | * STARTUPINFO structure passed to the CreateProcess function by the 145 | * program that started the application. 146 | */ 147 | ShowDefault = 10, 148 | /** 149 | * Windows 2000/XP: Minimizes a window, even if the thread 150 | * that owns the window is not responding. This flag should only be 151 | * used when minimizing windows from a different thread. 152 | */ 153 | ForceMinimize = 11 154 | } 155 | export declare enum OpenFolderFlags { 156 | AllowMultiSelect = 512, 157 | CreatePrompt = 8192, 158 | DontAddToRecent = 33554432, 159 | EnableHook = 32, 160 | EnableIncludeNotify = 4194304, 161 | EnableSizing = 8388608, 162 | EnableTemplate = 64, 163 | EnableTemplateHandle = 128, 164 | Explorer = 524288, 165 | ExtensionIsDifferent = 1024, 166 | FileMustExist = 4096, 167 | ForceShowHidden = 268435456, 168 | HideReadOnly = 4, 169 | LongNames = 2097152, 170 | NoChangeDir = 8, 171 | NoDereferenceLinks = 1048576, 172 | NoLongNames = 262144, 173 | NoNetworkButton = 131072, 174 | NoReadOnlyReturn = 32768, 175 | NoTestFileCreate = 65536, 176 | NoValidate = 256, 177 | OverwritePrompt = 2, 178 | PathMustExist = 2048, 179 | ReadOnly = 1, 180 | ShareAware = 16384, 181 | ShowHelp = 16 182 | } 183 | /** 184 | * Refer to the Win32 GetOpenFileName options at: 185 | * https://docs.microsoft.com/en-us/windows/win32/api/commdlg/ns-commdlg-openfilenamea 186 | */ 187 | export interface OpenFileOptions { 188 | flags?: OpenFolderFlags; 189 | title?: string; 190 | filter?: string; 191 | filterIndex?: number; 192 | initialDir?: string; 193 | defaultExt?: string; 194 | templateName?: string; 195 | isFolderPicker?: boolean; 196 | } 197 | export interface DialogResult { 198 | file: string | null; 199 | fileTitle: string | null; 200 | ok: boolean | null; 201 | } 202 | export declare function openFile(options: OpenFileOptions): Promise; 203 | export declare enum MessageBoxType { 204 | AbortRetryIgnore = 2, 205 | CancelTryContinue = 6, 206 | Help = 16384, 207 | Ok = 0, 208 | OkCancel = 1, 209 | RetryCancel = 5, 210 | YesNo = 4, 211 | YesNoCancel = 3, 212 | IconExclamation = 48, 213 | IconWarning = 48, 214 | IconInformation = 64, 215 | IconQuestion = 32, 216 | IconStop = 16, 217 | DefaultButton1 = 0, 218 | DefaultButton2 = 256, 219 | DefaultButton3 = 512, 220 | DefaultButton4 = 768, 221 | AppModal = 0, 222 | SystemModal = 4096, 223 | TaskModal = 8192, 224 | DefaultDesktopOnly = 131072, 225 | RightJustified = 524288, 226 | RightToLeftReading = 1048576, 227 | SetForeground = 65536, 228 | TopMost = 262144, 229 | ServiceNotification = 2097152 230 | } 231 | export declare enum MessageBoxReturn { 232 | Abort = 3, 233 | Cancel = 2, 234 | Continue = 11, 235 | Ignore = 5, 236 | No = 7, 237 | Ok = 1, 238 | Retry = 4, 239 | TryAgain = 10, 240 | Yes = 6 241 | } 242 | export declare enum KnownFolders { 243 | Contacts = "Contacts", 244 | Desktop = "Desktop", 245 | Documents = "Documents", 246 | Downloads = "Downloads", 247 | Favorites = "Favorites", 248 | Links = "Links", 249 | Music = "Music", 250 | Pictures = "Pictures", 251 | SavedGames = "SavedGames", 252 | SavedSearches = "SavedSearches", 253 | Videos = "Videos" 254 | } 255 | /** 256 | * Refer to Win32 API 257 | * https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebox 258 | * @param title 259 | * @param caption 260 | * @param type 261 | */ 262 | export declare function messageBox(title: string, caption?: string, type?: MessageBoxType): Promise; 263 | -------------------------------------------------------------------------------- /typings/@servicestack/vue/components/Button.vue.d.ts: -------------------------------------------------------------------------------- 1 | import { NavOptions } from '@servicestack/client'; 2 | import { BootstrapBase } from '../core'; 3 | export declare class Button extends BootstrapBase { 4 | options: NavOptions; 5 | id: string; 6 | name: string; 7 | type: string; 8 | value: string; 9 | disabled: boolean; 10 | click: () => void; 11 | protected readonly attrs: {}; 12 | protected readonly btnCls: any[]; 13 | } 14 | export default Button; 15 | -------------------------------------------------------------------------------- /typings/@servicestack/vue/components/CheckBox.vue.d.ts: -------------------------------------------------------------------------------- 1 | import { Vue } from 'vue-property-decorator'; 2 | export declare class CheckBox extends Vue { 3 | responseStatus: object; 4 | id: string; 5 | placeholder: string; 6 | value: boolean; 7 | help: string; 8 | inputClass: string; 9 | protected readonly errorField: any; 10 | protected onInput(e: InputEvent): boolean; 11 | } 12 | export default CheckBox; 13 | -------------------------------------------------------------------------------- /typings/@servicestack/vue/components/ErrorSummary.vue.d.ts: -------------------------------------------------------------------------------- 1 | import { Vue } from 'vue-property-decorator'; 2 | export declare class ErrorSummary extends Vue { 3 | responseStatus: object; 4 | except: string; 5 | readonly errorSummary: any; 6 | } 7 | export default ErrorSummary; 8 | -------------------------------------------------------------------------------- /typings/@servicestack/vue/components/Forbidden.vue.d.ts: -------------------------------------------------------------------------------- 1 | import { Vue } from 'vue-property-decorator'; 2 | export declare class Forbidden extends Vue { 3 | message: string; 4 | path: string; 5 | role: string; 6 | permission: string; 7 | protected readonly query: any; 8 | protected readonly usePath: string | null; 9 | protected readonly useRole: string | null; 10 | protected readonly usePermission: string | null; 11 | } 12 | export default Forbidden; 13 | -------------------------------------------------------------------------------- /typings/@servicestack/vue/components/Input.vue.d.ts: -------------------------------------------------------------------------------- 1 | import { Vue } from 'vue-property-decorator'; 2 | export declare class Input extends Vue { 3 | responseStatus: object; 4 | type: string; 5 | id: string; 6 | statusField: string; 7 | label: string; 8 | help: string; 9 | inputClass: string; 10 | inline: boolean; 11 | value: string[] | string; 12 | values: any[]; 13 | protected concat(prefix: string, id: string, suffix: string): string; 14 | protected readonly isCheck: boolean; 15 | protected readonly errorField: any; 16 | protected readonly hasError: boolean; 17 | protected readonly kvpValues: any[]; 18 | protected onInput(e: InputEvent): string; 19 | protected onInputValues(e: InputEvent): string[]; 20 | protected hasValue(elValue: string): boolean; 21 | } 22 | export default Input; 23 | -------------------------------------------------------------------------------- /typings/@servicestack/vue/components/Link.vue.d.ts: -------------------------------------------------------------------------------- 1 | import { Vue } from 'vue-property-decorator'; 2 | export declare class Link extends Vue { 3 | to: string; 4 | attrs: any; 5 | exact: boolean; 6 | click: () => void; 7 | protected readonly isAbsolute: boolean | ""; 8 | } 9 | export default Link; 10 | -------------------------------------------------------------------------------- /typings/@servicestack/vue/components/LinkButton.vue.d.ts: -------------------------------------------------------------------------------- 1 | import { NavOptions } from '@servicestack/client'; 2 | import { BootstrapBase } from '../core'; 3 | export declare class LinkButton extends BootstrapBase { 4 | href: string; 5 | options: NavOptions; 6 | id: string; 7 | navItemClass: string; 8 | exact: boolean; 9 | click: () => void; 10 | protected readonly opt: any; 11 | protected readonly activeHref: any; 12 | protected readonly hashPrefix: string; 13 | protected readonly attrs: {}; 14 | protected readonly activeCls: string; 15 | protected readonly btnCls: any[]; 16 | } 17 | export default LinkButton; 18 | -------------------------------------------------------------------------------- /typings/@servicestack/vue/components/Nav.vue.d.ts: -------------------------------------------------------------------------------- 1 | import { NavBase } from '../core'; 2 | export declare class Nav extends NavBase { 3 | protected readonly opt: any; 4 | } 5 | export default Nav; 6 | -------------------------------------------------------------------------------- /typings/@servicestack/vue/components/NavButtonGroup.vue.d.ts: -------------------------------------------------------------------------------- 1 | import { NavBootstrapBase } from '../core'; 2 | export declare class NavButtonGroup extends NavBootstrapBase { 3 | block?: boolean; 4 | vertical?: boolean; 5 | protected readonly opt: any; 6 | protected readonly cls: any; 7 | } 8 | export default NavButtonGroup; 9 | -------------------------------------------------------------------------------- /typings/@servicestack/vue/components/NavLink.vue.d.ts: -------------------------------------------------------------------------------- 1 | import { Vue } from 'vue-property-decorator'; 2 | import { NavItem, NavOptions } from '@servicestack/client'; 3 | export declare class NavLink extends Vue { 4 | item: NavItem; 5 | options: NavOptions; 6 | activePath: string; 7 | navItemClass: string; 8 | navLinkClass: string; 9 | protected readonly opt: any; 10 | protected readonly show: boolean; 11 | protected readonly useActivePath: any; 12 | protected readonly hasChildren: boolean; 13 | protected readonly navItemCls: any; 14 | protected readonly navLinkCls: any; 15 | protected readonly childProps: { 16 | 'role': string; 17 | 'data-toggle': string; 18 | 'aria-haspopup': string; 19 | 'aria-expanded': string; 20 | } | { 21 | 'role'?: undefined; 22 | 'data-toggle'?: undefined; 23 | 'aria-haspopup'?: undefined; 24 | 'aria-expanded'?: undefined; 25 | }; 26 | protected readonly id: string | null; 27 | protected readonly activeCls: string; 28 | protected activeClassNav(x: NavItem, activePath: string): string; 29 | } 30 | export default NavLink; 31 | -------------------------------------------------------------------------------- /typings/@servicestack/vue/components/NavLinkButton.vue.d.ts: -------------------------------------------------------------------------------- 1 | import { NavItem, NavOptions } from '@servicestack/client'; 2 | import { BootstrapBase } from '../core'; 3 | export declare class NavLinkButton extends BootstrapBase { 4 | href: string; 5 | item: NavItem; 6 | options: NavOptions; 7 | id: string; 8 | baseHref: string; 9 | activePath: string; 10 | navItemClass: string; 11 | exact: boolean; 12 | click: () => void; 13 | protected readonly opt: any; 14 | protected readonly show: boolean; 15 | protected readonly useActivePath: any; 16 | protected readonly hashPrefix: string; 17 | protected readonly activeCls: string; 18 | protected readonly btnCls: any[]; 19 | } 20 | export default NavLinkButton; 21 | -------------------------------------------------------------------------------- /typings/@servicestack/vue/components/Navbar.vue.d.ts: -------------------------------------------------------------------------------- 1 | import { NavBase } from '../core'; 2 | export declare class Navbar extends NavBase { 3 | protected readonly opt: any; 4 | } 5 | export default Navbar; 6 | -------------------------------------------------------------------------------- /typings/@servicestack/vue/components/Select.vue.d.ts: -------------------------------------------------------------------------------- 1 | import { Vue } from 'vue-property-decorator'; 2 | export declare class Select extends Vue { 3 | responseStatus: object; 4 | id: string; 5 | label: string; 6 | help: string; 7 | selectClass: string; 8 | multiple: boolean; 9 | value: string[] | string; 10 | values: any[]; 11 | protected readonly errorField: any; 12 | protected readonly hasError: boolean; 13 | protected readonly kvpValues: any[]; 14 | protected hasValue(elValue: string): boolean; 15 | protected onInputValues(e: InputEvent): string | string[]; 16 | } 17 | export default Select; 18 | -------------------------------------------------------------------------------- /typings/@servicestack/vue/components/SvgImage.vue.d.ts: -------------------------------------------------------------------------------- 1 | import { Vue } from 'vue-property-decorator'; 2 | export declare class SvgImage extends Vue { 3 | id: string; 4 | fill: string; 5 | width: number; 6 | height: number; 7 | baseUrl: string; 8 | protected readonly src: string; 9 | protected readonly styles: any; 10 | } 11 | export default SvgImage; 12 | -------------------------------------------------------------------------------- /typings/@servicestack/vue/core.d.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import { NavItem, NavOptions } from '@servicestack/client'; 3 | export declare class BootstrapBase extends Vue { 4 | primary?: boolean; 5 | outlinePrimary?: boolean; 6 | secondary?: boolean; 7 | outlineSecondary?: boolean; 8 | success?: boolean; 9 | outlineSuccess?: boolean; 10 | info?: boolean; 11 | outlineInfo?: boolean; 12 | warning?: boolean; 13 | outlineWarning?: boolean; 14 | danger?: boolean; 15 | outlineDanger?: boolean; 16 | light?: boolean; 17 | outlineLight?: boolean; 18 | dark?: boolean; 19 | outlineDark?: boolean; 20 | lg?: boolean; 21 | md?: boolean; 22 | sm?: boolean; 23 | xs?: boolean; 24 | block?: boolean; 25 | vertical?: boolean; 26 | horizontal?: boolean; 27 | protected readonly bootstrapClasses: any; 28 | } 29 | export declare class NavBootstrapBase extends BootstrapBase { 30 | items: NavItem[]; 31 | options?: NavOptions; 32 | attributes?: string[]; 33 | activePath?: string; 34 | baseHref?: string; 35 | navClass?: string; 36 | navItemClass?: string; 37 | navLinkClass?: string; 38 | childNavItemClass?: string; 39 | childNavLinkClass?: string; 40 | childNavMenuClass?: string; 41 | childNavMenuItemClass?: string; 42 | } 43 | export declare class NavBase extends Vue { 44 | message?: string; 45 | items: NavItem[]; 46 | options?: NavOptions; 47 | attributes?: string[]; 48 | activePath?: string; 49 | baseHref?: string; 50 | navClass?: string; 51 | navItemClass?: string; 52 | navLinkClass?: string; 53 | childNavItemClass?: string; 54 | childNavLinkClass?: string; 55 | childNavMenuClass?: string; 56 | childNavMenuItemClass?: string; 57 | } 58 | export declare function optionProps(props: any): any; 59 | export declare function sanitizeOptions(opt: any): any; 60 | export declare function routePath(component: Vue): any; 61 | -------------------------------------------------------------------------------- /typings/@servicestack/vue/index.d.ts: -------------------------------------------------------------------------------- 1 | import Forbidden from './components/Forbidden.vue'; 2 | import ErrorSummary from './components/ErrorSummary.vue'; 3 | import Input from './components/Input.vue'; 4 | import Select from './components/Select.vue'; 5 | import CheckBox from './components/CheckBox.vue'; 6 | import Button from './components/Button.vue'; 7 | import SvgImage from './components/SvgImage.vue'; 8 | import Link from './components/Link.vue'; 9 | import LinkButton from './components/LinkButton.vue'; 10 | import Nav from './components/Nav.vue'; 11 | import Navbar from './components/Navbar.vue'; 12 | import NavLink from './components/NavLink.vue'; 13 | import NavButtonGroup from './components/NavButtonGroup.vue'; 14 | import NavLinkButton from './components/NavLinkButton.vue'; 15 | declare function install(Vue: any): void; 16 | declare const plugin: { 17 | install: typeof install; 18 | }; 19 | export default plugin; 20 | export { Forbidden, ErrorSummary, Input, Select, CheckBox, Button, SvgImage, Link, LinkButton, Nav, Navbar, NavLink, NavButtonGroup, NavLinkButton, }; 21 | -------------------------------------------------------------------------------- /typings/reflect-metadata/index.d.ts: -------------------------------------------------------------------------------- 1 | /*! ***************************************************************************** 2 | Copyright (C) Microsoft. All rights reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 8 | KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 9 | WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 10 | MERCHANTABLITY OR NON-INFRINGEMENT. 11 | 12 | See the Apache Version 2.0 License for specific language governing permissions 13 | and limitations under the License. 14 | ***************************************************************************** */ 15 | 16 | // The "reflect-metadata" module has no imports or exports, but can be imported by modules to load the polyfill. 17 | export { }; 18 | 19 | declare global { 20 | namespace Reflect { 21 | /** 22 | * Applies a set of decorators to a target object. 23 | * @param decorators An array of decorators. 24 | * @param target The target object. 25 | * @returns The result of applying the provided decorators. 26 | * @remarks Decorators are applied in reverse order of their positions in the array. 27 | * @example 28 | * 29 | * class Example { } 30 | * 31 | * // constructor 32 | * Example = Reflect.decorate(decoratorsArray, Example); 33 | * 34 | */ 35 | function decorate(decorators: ClassDecorator[], target: Function): Function; 36 | /** 37 | * Applies a set of decorators to a property of a target object. 38 | * @param decorators An array of decorators. 39 | * @param target The target object. 40 | * @param propertyKey The property key to decorate. 41 | * @param attributes A property descriptor. 42 | * @remarks Decorators are applied in reverse order. 43 | * @example 44 | * 45 | * class Example { 46 | * // property declarations are not part of ES6, though they are valid in TypeScript: 47 | * // static staticProperty; 48 | * // property; 49 | * 50 | * static staticMethod() { } 51 | * method() { } 52 | * } 53 | * 54 | * // property (on constructor) 55 | * Reflect.decorate(decoratorsArray, Example, "staticProperty"); 56 | * 57 | * // property (on prototype) 58 | * Reflect.decorate(decoratorsArray, Example.prototype, "property"); 59 | * 60 | * // method (on constructor) 61 | * Object.defineProperty(Example, "staticMethod", 62 | * Reflect.decorate(decoratorsArray, Example, "staticMethod", 63 | * Object.getOwnPropertyDescriptor(Example, "staticMethod"))); 64 | * 65 | * // method (on prototype) 66 | * Object.defineProperty(Example.prototype, "method", 67 | * Reflect.decorate(decoratorsArray, Example.prototype, "method", 68 | * Object.getOwnPropertyDescriptor(Example.prototype, "method"))); 69 | * 70 | */ 71 | function decorate(decorators: (PropertyDecorator | MethodDecorator)[], target: Object, propertyKey: string | symbol, attributes?: PropertyDescriptor): PropertyDescriptor; 72 | /** 73 | * A default metadata decorator factory that can be used on a class, class member, or parameter. 74 | * @param metadataKey The key for the metadata entry. 75 | * @param metadataValue The value for the metadata entry. 76 | * @returns A decorator function. 77 | * @remarks 78 | * If `metadataKey` is already defined for the target and target key, the 79 | * metadataValue for that key will be overwritten. 80 | * @example 81 | * 82 | * // constructor 83 | * @Reflect.metadata(key, value) 84 | * class Example { 85 | * } 86 | * 87 | * // property (on constructor, TypeScript only) 88 | * class Example { 89 | * @Reflect.metadata(key, value) 90 | * static staticProperty; 91 | * } 92 | * 93 | * // property (on prototype, TypeScript only) 94 | * class Example { 95 | * @Reflect.metadata(key, value) 96 | * property; 97 | * } 98 | * 99 | * // method (on constructor) 100 | * class Example { 101 | * @Reflect.metadata(key, value) 102 | * static staticMethod() { } 103 | * } 104 | * 105 | * // method (on prototype) 106 | * class Example { 107 | * @Reflect.metadata(key, value) 108 | * method() { } 109 | * } 110 | * 111 | */ 112 | function metadata(metadataKey: any, metadataValue: any): { 113 | (target: Function): void; 114 | (target: Object, propertyKey: string | symbol): void; 115 | }; 116 | /** 117 | * Define a unique metadata entry on the target. 118 | * @param metadataKey A key used to store and retrieve metadata. 119 | * @param metadataValue A value that contains attached metadata. 120 | * @param target The target object on which to define metadata. 121 | * @example 122 | * 123 | * class Example { 124 | * } 125 | * 126 | * // constructor 127 | * Reflect.defineMetadata("custom:annotation", options, Example); 128 | * 129 | * // decorator factory as metadata-producing annotation. 130 | * function MyAnnotation(options): ClassDecorator { 131 | * return target => Reflect.defineMetadata("custom:annotation", options, target); 132 | * } 133 | * 134 | */ 135 | function defineMetadata(metadataKey: any, metadataValue: any, target: Object): void; 136 | /** 137 | * Define a unique metadata entry on the target. 138 | * @param metadataKey A key used to store and retrieve metadata. 139 | * @param metadataValue A value that contains attached metadata. 140 | * @param target The target object on which to define metadata. 141 | * @param propertyKey The property key for the target. 142 | * @example 143 | * 144 | * class Example { 145 | * // property declarations are not part of ES6, though they are valid in TypeScript: 146 | * // static staticProperty; 147 | * // property; 148 | * 149 | * static staticMethod(p) { } 150 | * method(p) { } 151 | * } 152 | * 153 | * // property (on constructor) 154 | * Reflect.defineMetadata("custom:annotation", Number, Example, "staticProperty"); 155 | * 156 | * // property (on prototype) 157 | * Reflect.defineMetadata("custom:annotation", Number, Example.prototype, "property"); 158 | * 159 | * // method (on constructor) 160 | * Reflect.defineMetadata("custom:annotation", Number, Example, "staticMethod"); 161 | * 162 | * // method (on prototype) 163 | * Reflect.defineMetadata("custom:annotation", Number, Example.prototype, "method"); 164 | * 165 | * // decorator factory as metadata-producing annotation. 166 | * function MyAnnotation(options): PropertyDecorator { 167 | * return (target, key) => Reflect.defineMetadata("custom:annotation", options, target, key); 168 | * } 169 | * 170 | */ 171 | function defineMetadata(metadataKey: any, metadataValue: any, target: Object, propertyKey: string | symbol): void; 172 | /** 173 | * Gets a value indicating whether the target object or its prototype chain has the provided metadata key defined. 174 | * @param metadataKey A key used to store and retrieve metadata. 175 | * @param target The target object on which the metadata is defined. 176 | * @returns `true` if the metadata key was defined on the target object or its prototype chain; otherwise, `false`. 177 | * @example 178 | * 179 | * class Example { 180 | * } 181 | * 182 | * // constructor 183 | * result = Reflect.hasMetadata("custom:annotation", Example); 184 | * 185 | */ 186 | function hasMetadata(metadataKey: any, target: Object): boolean; 187 | /** 188 | * Gets a value indicating whether the target object or its prototype chain has the provided metadata key defined. 189 | * @param metadataKey A key used to store and retrieve metadata. 190 | * @param target The target object on which the metadata is defined. 191 | * @param propertyKey The property key for the target. 192 | * @returns `true` if the metadata key was defined on the target object or its prototype chain; otherwise, `false`. 193 | * @example 194 | * 195 | * class Example { 196 | * // property declarations are not part of ES6, though they are valid in TypeScript: 197 | * // static staticProperty; 198 | * // property; 199 | * 200 | * static staticMethod(p) { } 201 | * method(p) { } 202 | * } 203 | * 204 | * // property (on constructor) 205 | * result = Reflect.hasMetadata("custom:annotation", Example, "staticProperty"); 206 | * 207 | * // property (on prototype) 208 | * result = Reflect.hasMetadata("custom:annotation", Example.prototype, "property"); 209 | * 210 | * // method (on constructor) 211 | * result = Reflect.hasMetadata("custom:annotation", Example, "staticMethod"); 212 | * 213 | * // method (on prototype) 214 | * result = Reflect.hasMetadata("custom:annotation", Example.prototype, "method"); 215 | * 216 | */ 217 | function hasMetadata(metadataKey: any, target: Object, propertyKey: string | symbol): boolean; 218 | /** 219 | * Gets a value indicating whether the target object has the provided metadata key defined. 220 | * @param metadataKey A key used to store and retrieve metadata. 221 | * @param target The target object on which the metadata is defined. 222 | * @returns `true` if the metadata key was defined on the target object; otherwise, `false`. 223 | * @example 224 | * 225 | * class Example { 226 | * } 227 | * 228 | * // constructor 229 | * result = Reflect.hasOwnMetadata("custom:annotation", Example); 230 | * 231 | */ 232 | function hasOwnMetadata(metadataKey: any, target: Object): boolean; 233 | /** 234 | * Gets a value indicating whether the target object has the provided metadata key defined. 235 | * @param metadataKey A key used to store and retrieve metadata. 236 | * @param target The target object on which the metadata is defined. 237 | * @param propertyKey The property key for the target. 238 | * @returns `true` if the metadata key was defined on the target object; otherwise, `false`. 239 | * @example 240 | * 241 | * class Example { 242 | * // property declarations are not part of ES6, though they are valid in TypeScript: 243 | * // static staticProperty; 244 | * // property; 245 | * 246 | * static staticMethod(p) { } 247 | * method(p) { } 248 | * } 249 | * 250 | * // property (on constructor) 251 | * result = Reflect.hasOwnMetadata("custom:annotation", Example, "staticProperty"); 252 | * 253 | * // property (on prototype) 254 | * result = Reflect.hasOwnMetadata("custom:annotation", Example.prototype, "property"); 255 | * 256 | * // method (on constructor) 257 | * result = Reflect.hasOwnMetadata("custom:annotation", Example, "staticMethod"); 258 | * 259 | * // method (on prototype) 260 | * result = Reflect.hasOwnMetadata("custom:annotation", Example.prototype, "method"); 261 | * 262 | */ 263 | function hasOwnMetadata(metadataKey: any, target: Object, propertyKey: string | symbol): boolean; 264 | /** 265 | * Gets the metadata value for the provided metadata key on the target object or its prototype chain. 266 | * @param metadataKey A key used to store and retrieve metadata. 267 | * @param target The target object on which the metadata is defined. 268 | * @returns The metadata value for the metadata key if found; otherwise, `undefined`. 269 | * @example 270 | * 271 | * class Example { 272 | * } 273 | * 274 | * // constructor 275 | * result = Reflect.getMetadata("custom:annotation", Example); 276 | * 277 | */ 278 | function getMetadata(metadataKey: any, target: Object): any; 279 | /** 280 | * Gets the metadata value for the provided metadata key on the target object or its prototype chain. 281 | * @param metadataKey A key used to store and retrieve metadata. 282 | * @param target The target object on which the metadata is defined. 283 | * @param propertyKey The property key for the target. 284 | * @returns The metadata value for the metadata key if found; otherwise, `undefined`. 285 | * @example 286 | * 287 | * class Example { 288 | * // property declarations are not part of ES6, though they are valid in TypeScript: 289 | * // static staticProperty; 290 | * // property; 291 | * 292 | * static staticMethod(p) { } 293 | * method(p) { } 294 | * } 295 | * 296 | * // property (on constructor) 297 | * result = Reflect.getMetadata("custom:annotation", Example, "staticProperty"); 298 | * 299 | * // property (on prototype) 300 | * result = Reflect.getMetadata("custom:annotation", Example.prototype, "property"); 301 | * 302 | * // method (on constructor) 303 | * result = Reflect.getMetadata("custom:annotation", Example, "staticMethod"); 304 | * 305 | * // method (on prototype) 306 | * result = Reflect.getMetadata("custom:annotation", Example.prototype, "method"); 307 | * 308 | */ 309 | function getMetadata(metadataKey: any, target: Object, propertyKey: string | symbol): any; 310 | /** 311 | * Gets the metadata value for the provided metadata key on the target object. 312 | * @param metadataKey A key used to store and retrieve metadata. 313 | * @param target The target object on which the metadata is defined. 314 | * @returns The metadata value for the metadata key if found; otherwise, `undefined`. 315 | * @example 316 | * 317 | * class Example { 318 | * } 319 | * 320 | * // constructor 321 | * result = Reflect.getOwnMetadata("custom:annotation", Example); 322 | * 323 | */ 324 | function getOwnMetadata(metadataKey: any, target: Object): any; 325 | /** 326 | * Gets the metadata value for the provided metadata key on the target object. 327 | * @param metadataKey A key used to store and retrieve metadata. 328 | * @param target The target object on which the metadata is defined. 329 | * @param propertyKey The property key for the target. 330 | * @returns The metadata value for the metadata key if found; otherwise, `undefined`. 331 | * @example 332 | * 333 | * class Example { 334 | * // property declarations are not part of ES6, though they are valid in TypeScript: 335 | * // static staticProperty; 336 | * // property; 337 | * 338 | * static staticMethod(p) { } 339 | * method(p) { } 340 | * } 341 | * 342 | * // property (on constructor) 343 | * result = Reflect.getOwnMetadata("custom:annotation", Example, "staticProperty"); 344 | * 345 | * // property (on prototype) 346 | * result = Reflect.getOwnMetadata("custom:annotation", Example.prototype, "property"); 347 | * 348 | * // method (on constructor) 349 | * result = Reflect.getOwnMetadata("custom:annotation", Example, "staticMethod"); 350 | * 351 | * // method (on prototype) 352 | * result = Reflect.getOwnMetadata("custom:annotation", Example.prototype, "method"); 353 | * 354 | */ 355 | function getOwnMetadata(metadataKey: any, target: Object, propertyKey: string | symbol): any; 356 | /** 357 | * Gets the metadata keys defined on the target object or its prototype chain. 358 | * @param target The target object on which the metadata is defined. 359 | * @returns An array of unique metadata keys. 360 | * @example 361 | * 362 | * class Example { 363 | * } 364 | * 365 | * // constructor 366 | * result = Reflect.getMetadataKeys(Example); 367 | * 368 | */ 369 | function getMetadataKeys(target: Object): any[]; 370 | /** 371 | * Gets the metadata keys defined on the target object or its prototype chain. 372 | * @param target The target object on which the metadata is defined. 373 | * @param propertyKey The property key for the target. 374 | * @returns An array of unique metadata keys. 375 | * @example 376 | * 377 | * class Example { 378 | * // property declarations are not part of ES6, though they are valid in TypeScript: 379 | * // static staticProperty; 380 | * // property; 381 | * 382 | * static staticMethod(p) { } 383 | * method(p) { } 384 | * } 385 | * 386 | * // property (on constructor) 387 | * result = Reflect.getMetadataKeys(Example, "staticProperty"); 388 | * 389 | * // property (on prototype) 390 | * result = Reflect.getMetadataKeys(Example.prototype, "property"); 391 | * 392 | * // method (on constructor) 393 | * result = Reflect.getMetadataKeys(Example, "staticMethod"); 394 | * 395 | * // method (on prototype) 396 | * result = Reflect.getMetadataKeys(Example.prototype, "method"); 397 | * 398 | */ 399 | function getMetadataKeys(target: Object, propertyKey: string | symbol): any[]; 400 | /** 401 | * Gets the unique metadata keys defined on the target object. 402 | * @param target The target object on which the metadata is defined. 403 | * @returns An array of unique metadata keys. 404 | * @example 405 | * 406 | * class Example { 407 | * } 408 | * 409 | * // constructor 410 | * result = Reflect.getOwnMetadataKeys(Example); 411 | * 412 | */ 413 | function getOwnMetadataKeys(target: Object): any[]; 414 | /** 415 | * Gets the unique metadata keys defined on the target object. 416 | * @param target The target object on which the metadata is defined. 417 | * @param propertyKey The property key for the target. 418 | * @returns An array of unique metadata keys. 419 | * @example 420 | * 421 | * class Example { 422 | * // property declarations are not part of ES6, though they are valid in TypeScript: 423 | * // static staticProperty; 424 | * // property; 425 | * 426 | * static staticMethod(p) { } 427 | * method(p) { } 428 | * } 429 | * 430 | * // property (on constructor) 431 | * result = Reflect.getOwnMetadataKeys(Example, "staticProperty"); 432 | * 433 | * // property (on prototype) 434 | * result = Reflect.getOwnMetadataKeys(Example.prototype, "property"); 435 | * 436 | * // method (on constructor) 437 | * result = Reflect.getOwnMetadataKeys(Example, "staticMethod"); 438 | * 439 | * // method (on prototype) 440 | * result = Reflect.getOwnMetadataKeys(Example.prototype, "method"); 441 | * 442 | */ 443 | function getOwnMetadataKeys(target: Object, propertyKey: string | symbol): any[]; 444 | /** 445 | * Deletes the metadata entry from the target object with the provided key. 446 | * @param metadataKey A key used to store and retrieve metadata. 447 | * @param target The target object on which the metadata is defined. 448 | * @returns `true` if the metadata entry was found and deleted; otherwise, false. 449 | * @example 450 | * 451 | * class Example { 452 | * } 453 | * 454 | * // constructor 455 | * result = Reflect.deleteMetadata("custom:annotation", Example); 456 | * 457 | */ 458 | function deleteMetadata(metadataKey: any, target: Object): boolean; 459 | /** 460 | * Deletes the metadata entry from the target object with the provided key. 461 | * @param metadataKey A key used to store and retrieve metadata. 462 | * @param target The target object on which the metadata is defined. 463 | * @param propertyKey The property key for the target. 464 | * @returns `true` if the metadata entry was found and deleted; otherwise, false. 465 | * @example 466 | * 467 | * class Example { 468 | * // property declarations are not part of ES6, though they are valid in TypeScript: 469 | * // static staticProperty; 470 | * // property; 471 | * 472 | * static staticMethod(p) { } 473 | * method(p) { } 474 | * } 475 | * 476 | * // property (on constructor) 477 | * result = Reflect.deleteMetadata("custom:annotation", Example, "staticProperty"); 478 | * 479 | * // property (on prototype) 480 | * result = Reflect.deleteMetadata("custom:annotation", Example.prototype, "property"); 481 | * 482 | * // method (on constructor) 483 | * result = Reflect.deleteMetadata("custom:annotation", Example, "staticMethod"); 484 | * 485 | * // method (on prototype) 486 | * result = Reflect.deleteMetadata("custom:annotation", Example.prototype, "method"); 487 | * 488 | */ 489 | function deleteMetadata(metadataKey: any, target: Object, propertyKey: string | symbol): boolean; 490 | } 491 | } -------------------------------------------------------------------------------- /typings/vue-class-component/component.d.ts: -------------------------------------------------------------------------------- 1 | import Vue, { ComponentOptions } from 'vue'; 2 | import { VueClass } from './declarations'; 3 | export declare const $internalHooks: string[]; 4 | export declare function componentFactory(Component: VueClass, options?: ComponentOptions): VueClass; 5 | -------------------------------------------------------------------------------- /typings/vue-class-component/data.d.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import { VueClass } from './declarations'; 3 | export declare function collectDataFromConstructor(vm: Vue, Component: VueClass): {}; 4 | -------------------------------------------------------------------------------- /typings/vue-class-component/declarations.d.ts: -------------------------------------------------------------------------------- 1 | import Vue, { ComponentOptions } from 'vue'; 2 | export declare type VueClass = { 3 | new (...args: any[]): V & Vue; 4 | } & typeof Vue; 5 | export declare type DecoratedClass = VueClass & { 6 | __decorators__?: ((options: ComponentOptions) => void)[]; 7 | }; 8 | -------------------------------------------------------------------------------- /typings/vue-class-component/index.d.ts: -------------------------------------------------------------------------------- 1 | import Vue, { ComponentOptions } from 'vue'; 2 | import { VueClass } from './declarations'; 3 | export { createDecorator, VueDecorator, mixins } from './util'; 4 | declare function Component(options: ComponentOptions & ThisType): >(target: VC) => VC; 5 | declare namespace Component { 6 | var registerHooks: (keys: string[]) => void; 7 | } 8 | declare function Component>(target: VC): VC; 9 | declare namespace Component { 10 | var registerHooks: (keys: string[]) => void; 11 | } 12 | export default Component; 13 | -------------------------------------------------------------------------------- /typings/vue-class-component/reflect.d.ts: -------------------------------------------------------------------------------- 1 | import Vue, { VueConstructor } from 'vue'; 2 | import { VueClass } from './declarations'; 3 | export declare const reflectionIsSupported: false | typeof Reflect.getOwnMetadataKeys; 4 | export declare function copyReflectionMetadata(to: VueConstructor, from: VueClass): void; 5 | -------------------------------------------------------------------------------- /typings/vue-class-component/util.d.ts: -------------------------------------------------------------------------------- 1 | import Vue, { ComponentOptions } from 'vue'; 2 | import { VueClass } from './declarations'; 3 | export declare const noop: () => void; 4 | export declare const hasProto: boolean; 5 | export interface VueDecorator { 6 | (Ctor: typeof Vue): void; 7 | (target: Vue, key: string): void; 8 | (target: Vue, key: string, index: number): void; 9 | } 10 | export declare function createDecorator(factory: (options: ComponentOptions, key: string, index: number) => void): VueDecorator; 11 | export declare function mixins(CtorA: VueClass): VueClass; 12 | export declare function mixins(CtorA: VueClass, CtorB: VueClass): VueClass; 13 | export declare function mixins(CtorA: VueClass, CtorB: VueClass, CtorC: VueClass): VueClass; 14 | export declare function mixins(CtorA: VueClass, CtorB: VueClass, CtorC: VueClass, CtorD: VueClass): VueClass; 15 | export declare function mixins(CtorA: VueClass, CtorB: VueClass, CtorC: VueClass, CtorD: VueClass, CtorE: VueClass): VueClass; 16 | export declare function mixins(...Ctors: VueClass[]): VueClass; 17 | export declare function isPrimitive(value: any): boolean; 18 | export declare function warn(message: string): void; 19 | -------------------------------------------------------------------------------- /typings/vue-property-decorator/index.d.ts: -------------------------------------------------------------------------------- 1 | /** vue-property-decorator verson 8.0.0 MIT LICENSE copyright 2018 kaorun343 */ 2 | import Vue, { PropOptions, WatchOptions } from 'vue'; 3 | import Component, { mixins } from 'vue-class-component'; 4 | import { InjectKey } from '../vue/options'; 5 | export declare type Constructor = { 6 | new (...args: any[]): any; 7 | }; 8 | export { Component, Vue, mixins as Mixins }; 9 | /** 10 | * decorator of an inject 11 | * @param from key 12 | * @return PropertyDecorator 13 | */ 14 | export declare function Inject(options?: { 15 | from?: InjectKey; 16 | default?: any; 17 | } | InjectKey): PropertyDecorator; 18 | /** 19 | * decorator of a provide 20 | * @param key key 21 | * @return PropertyDecorator | void 22 | */ 23 | export declare function Provide(key?: string | symbol): PropertyDecorator; 24 | /** 25 | * decorator of model 26 | * @param event event name 27 | * @param options options 28 | * @return PropertyDecorator 29 | */ 30 | export declare function Model(event?: string, options?: (PropOptions | Constructor[] | Constructor)): PropertyDecorator; 31 | /** 32 | * decorator of a prop 33 | * @param options the options for the prop 34 | * @return PropertyDecorator | void 35 | */ 36 | export declare function Prop(options?: (PropOptions | Constructor[] | Constructor)): PropertyDecorator; 37 | /** 38 | * decorator of a watch function 39 | * @param path the path or the expression to observe 40 | * @param WatchOption 41 | * @return MethodDecorator 42 | */ 43 | export declare function Watch(path: string, options?: WatchOptions): MethodDecorator; 44 | /** 45 | * decorator of an event-emitter function 46 | * @param event The name of the event 47 | * @return MethodDecorator 48 | */ 49 | export declare function Emit(event?: string): MethodDecorator; 50 | -------------------------------------------------------------------------------- /typings/vue-router/index.d.ts: -------------------------------------------------------------------------------- 1 | import "./vue"; 2 | import { VueRouter } from "./router"; 3 | 4 | export default VueRouter; 5 | 6 | export { 7 | RouterMode, 8 | RawLocation, 9 | RedirectOption, 10 | RouterOptions, 11 | RouteConfig, 12 | RouteRecord, 13 | Location, 14 | Route, 15 | NavigationGuard 16 | } from "./router"; 17 | -------------------------------------------------------------------------------- /typings/vue-router/router.d.ts: -------------------------------------------------------------------------------- 1 | import Vue, { ComponentOptions, PluginFunction, AsyncComponent } from "vue"; 2 | 3 | type Component = ComponentOptions | typeof Vue | AsyncComponent; 4 | type Dictionary = { [key: string]: T }; 5 | type ErrorHandler = (err: Error) => void; 6 | 7 | export type RouterMode = "hash" | "history" | "abstract"; 8 | export type RawLocation = string | Location; 9 | export type RedirectOption = RawLocation | ((to: Route) => RawLocation); 10 | export type NavigationGuard = ( 11 | to: Route, 12 | from: Route, 13 | next: (to?: RawLocation | false | ((vm: V) => any) | void) => void 14 | ) => any 15 | 16 | export declare class VueRouter { 17 | constructor (options?: RouterOptions); 18 | 19 | app: Vue; 20 | mode: RouterMode; 21 | currentRoute: Route; 22 | 23 | beforeEach (guard: NavigationGuard): Function; 24 | beforeResolve (guard: NavigationGuard): Function; 25 | afterEach (hook: (to: Route, from: Route) => any): Function; 26 | push (location: RawLocation, onComplete?: Function, onAbort?: ErrorHandler): void; 27 | replace (location: RawLocation, onComplete?: Function, onAbort?: ErrorHandler): void; 28 | go (n: number): void; 29 | back (): void; 30 | forward (): void; 31 | getMatchedComponents (to?: RawLocation | Route): Component[]; 32 | onReady (cb: Function, errorCb?: ErrorHandler): void; 33 | onError (cb: ErrorHandler): void; 34 | addRoutes (routes: RouteConfig[]): void; 35 | resolve (to: RawLocation, current?: Route, append?: boolean): { 36 | location: Location; 37 | route: Route; 38 | href: string; 39 | // backwards compat 40 | normalizedTo: Location; 41 | resolved: Route; 42 | }; 43 | 44 | static install: PluginFunction; 45 | } 46 | 47 | type Position = { x: number, y: number }; 48 | type PositionResult = Position | { selector: string, offset?: Position } | void; 49 | 50 | export interface RouterOptions { 51 | routes?: RouteConfig[]; 52 | mode?: RouterMode; 53 | fallback?: boolean; 54 | base?: string; 55 | linkActiveClass?: string; 56 | linkExactActiveClass?: string; 57 | parseQuery?: (query: string) => Object; 58 | stringifyQuery?: (query: Object) => string; 59 | scrollBehavior?: ( 60 | to: Route, 61 | from: Route, 62 | savedPosition: Position | void 63 | ) => PositionResult | Promise; 64 | } 65 | 66 | type RoutePropsFunction = (route: Route) => Object; 67 | 68 | export interface PathToRegexpOptions { 69 | sensitive?: boolean; 70 | strict?: boolean; 71 | end?: boolean; 72 | } 73 | 74 | export interface RouteConfig { 75 | path: string; 76 | name?: string; 77 | component?: Component; 78 | components?: Dictionary; 79 | redirect?: RedirectOption; 80 | alias?: string | string[]; 81 | children?: RouteConfig[]; 82 | meta?: any; 83 | beforeEnter?: NavigationGuard; 84 | props?: boolean | Object | RoutePropsFunction; 85 | caseSensitive?: boolean; 86 | pathToRegexpOptions?: PathToRegexpOptions; 87 | } 88 | 89 | export interface RouteRecord { 90 | path: string; 91 | regex: RegExp; 92 | components: Dictionary; 93 | instances: Dictionary; 94 | name?: string; 95 | parent?: RouteRecord; 96 | redirect?: RedirectOption; 97 | matchAs?: string; 98 | meta: any; 99 | beforeEnter?: ( 100 | route: Route, 101 | redirect: (location: RawLocation) => void, 102 | next: () => void 103 | ) => any; 104 | props: boolean | Object | RoutePropsFunction | Dictionary; 105 | } 106 | 107 | export interface Location { 108 | name?: string; 109 | path?: string; 110 | hash?: string; 111 | query?: Dictionary; 112 | params?: Dictionary; 113 | append?: boolean; 114 | replace?: boolean; 115 | } 116 | 117 | export interface Route { 118 | path: string; 119 | name?: string; 120 | hash: string; 121 | query: Dictionary; 122 | params: Dictionary; 123 | fullPath: string; 124 | matched: RouteRecord[]; 125 | redirectedFrom?: string; 126 | meta?: any; 127 | } 128 | -------------------------------------------------------------------------------- /typings/vue-router/vue.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Augment the typings of Vue.js 3 | */ 4 | 5 | import Vue from "vue"; 6 | import VueRouter, { Route, RawLocation, NavigationGuard } from "./index"; 7 | 8 | declare module "vue/vue" { 9 | interface Vue { 10 | $router: VueRouter; 11 | $route: Route; 12 | } 13 | } 14 | 15 | declare module "vue/options" { 16 | interface ComponentOptions { 17 | router?: VueRouter; 18 | beforeRouteEnter?: NavigationGuard; 19 | beforeRouteLeave?: NavigationGuard; 20 | beforeRouteUpdate?: NavigationGuard; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /typings/vue/index.d.ts: -------------------------------------------------------------------------------- 1 | import { Vue } from "./vue"; 2 | 3 | export default Vue; 4 | 5 | export as namespace Vue; 6 | 7 | export { 8 | CreateElement, 9 | VueConstructor 10 | } from "./vue"; 11 | 12 | export { 13 | Component, 14 | AsyncComponent, 15 | ComponentOptions, 16 | FunctionalComponentOptions, 17 | RenderContext, 18 | PropType, 19 | PropOptions, 20 | ComputedOptions, 21 | WatchHandler, 22 | WatchOptions, 23 | WatchOptionsWithHandler, 24 | DirectiveFunction, 25 | DirectiveOptions 26 | } from "./options"; 27 | 28 | export { 29 | PluginFunction, 30 | PluginObject 31 | } from "./plugin"; 32 | 33 | export { 34 | VNodeChildren, 35 | VNodeChildrenArrayContents, 36 | VNode, 37 | VNodeComponentOptions, 38 | VNodeData, 39 | VNodeDirective 40 | } from "./vnode"; 41 | -------------------------------------------------------------------------------- /typings/vue/options.d.ts: -------------------------------------------------------------------------------- 1 | import { Vue, CreateElement, CombinedVueInstance } from "./vue"; 2 | import { VNode, VNodeData, VNodeDirective, ScopedSlot } from "./vnode"; 3 | 4 | type Constructor = { 5 | new (...args: any[]): any; 6 | } 7 | 8 | // we don't support infer props in async component 9 | // N.B. ComponentOptions is contravariant, the default generic should be bottom type 10 | export type Component, Methods=DefaultMethods, Computed=DefaultComputed, Props=DefaultProps> = 11 | | typeof Vue 12 | | FunctionalComponentOptions 13 | | ComponentOptions 14 | 15 | interface EsModuleComponent { 16 | default: Component 17 | } 18 | 19 | export type AsyncComponent, Methods=DefaultMethods, Computed=DefaultComputed, Props=DefaultProps> 20 | = AsyncComponentPromise 21 | | AsyncComponentFactory 22 | 23 | export type AsyncComponentPromise, Methods=DefaultMethods, Computed=DefaultComputed, Props=DefaultProps> = ( 24 | resolve: (component: Component) => void, 25 | reject: (reason?: any) => void 26 | ) => Promise | void; 27 | 28 | export type AsyncComponentFactory, Methods=DefaultMethods, Computed=DefaultComputed, Props=DefaultProps> = () => { 29 | component: AsyncComponentPromise; 30 | loading?: Component | EsModuleComponent; 31 | error?: Component | EsModuleComponent; 32 | delay?: number; 33 | timeout?: number; 34 | } 35 | 36 | /** 37 | * When the `Computed` type parameter on `ComponentOptions` is inferred, 38 | * it should have a property with the return type of every get-accessor. 39 | * Since there isn't a way to query for the return type of a function, we allow TypeScript 40 | * to infer from the shape of `Accessors` and work backwards. 41 | */ 42 | export type Accessors = { 43 | [K in keyof T]: (() => T[K]) | ComputedOptions 44 | } 45 | 46 | type DataDef = Data | ((this: Readonly & V) => Data) 47 | /** 48 | * This type should be used when an array of strings is used for a component's `props` value. 49 | */ 50 | export type ThisTypedComponentOptionsWithArrayProps = 51 | object & 52 | ComponentOptions, V>, Methods, Computed, PropNames[], Record> & 53 | ThisType>>>; 54 | 55 | /** 56 | * This type should be used when an object mapped to `PropOptions` is used for a component's `props` value. 57 | */ 58 | export type ThisTypedComponentOptionsWithRecordProps = 59 | object & 60 | ComponentOptions, Methods, Computed, RecordPropsDefinition, Props> & 61 | ThisType>>; 62 | 63 | type DefaultData = object | ((this: V) => object); 64 | type DefaultProps = Record; 65 | type DefaultMethods = { [key: string]: (this: V, ...args: any[]) => any }; 66 | type DefaultComputed = { [key: string]: any }; 67 | export interface ComponentOptions< 68 | V extends Vue, 69 | Data=DefaultData, 70 | Methods=DefaultMethods, 71 | Computed=DefaultComputed, 72 | PropsDef=PropsDefinition, 73 | Props=DefaultProps> { 74 | data?: Data; 75 | props?: PropsDef; 76 | propsData?: object; 77 | computed?: Accessors; 78 | methods?: Methods; 79 | watch?: Record | WatchHandler | string>; 80 | 81 | el?: Element | string; 82 | template?: string; 83 | // hack is for functional component type inference, should not be used in user code 84 | render?(createElement: CreateElement, hack: RenderContext): VNode; 85 | renderError?(createElement: CreateElement, err: Error): VNode; 86 | staticRenderFns?: ((createElement: CreateElement) => VNode)[]; 87 | 88 | beforeCreate?(this: V): void; 89 | created?(): void; 90 | beforeDestroy?(): void; 91 | destroyed?(): void; 92 | beforeMount?(): void; 93 | mounted?(): void; 94 | beforeUpdate?(): void; 95 | updated?(): void; 96 | activated?(): void; 97 | deactivated?(): void; 98 | errorCaptured?(err: Error, vm: Vue, info: string): boolean | void; 99 | serverPrefetch?(this: V): Promise; 100 | 101 | directives?: { [key: string]: DirectiveFunction | DirectiveOptions }; 102 | components?: { [key: string]: Component | AsyncComponent }; 103 | transitions?: { [key: string]: object }; 104 | filters?: { [key: string]: Function }; 105 | 106 | provide?: object | (() => object); 107 | inject?: InjectOptions; 108 | 109 | model?: { 110 | prop?: string; 111 | event?: string; 112 | }; 113 | 114 | parent?: Vue; 115 | mixins?: (ComponentOptions | typeof Vue)[]; 116 | name?: string; 117 | // TODO: support properly inferred 'extends' 118 | extends?: ComponentOptions | typeof Vue; 119 | delimiters?: [string, string]; 120 | comments?: boolean; 121 | inheritAttrs?: boolean; 122 | } 123 | 124 | export interface FunctionalComponentOptions> { 125 | name?: string; 126 | props?: PropDefs; 127 | model?: { 128 | prop?: string; 129 | event?: string; 130 | }; 131 | inject?: InjectOptions; 132 | functional: boolean; 133 | render?(this: undefined, createElement: CreateElement, context: RenderContext): VNode | VNode[]; 134 | } 135 | 136 | export interface RenderContext { 137 | props: Props; 138 | children: VNode[]; 139 | slots(): any; 140 | data: VNodeData; 141 | parent: Vue; 142 | listeners: { [key: string]: Function | Function[] }; 143 | scopedSlots: { [key: string]: ScopedSlot }; 144 | injections: any 145 | } 146 | 147 | export type Prop = { (): T } | { new(...args: any[]): T & object } 148 | 149 | export type PropType = Prop | Prop[]; 150 | 151 | export type PropValidator = PropOptions | PropType; 152 | 153 | export interface PropOptions { 154 | type?: PropType; 155 | required?: boolean; 156 | default?: T | null | undefined | (() => T | null | undefined); 157 | validator?(value: T): boolean; 158 | } 159 | 160 | export type RecordPropsDefinition = { 161 | [K in keyof T]: PropValidator 162 | } 163 | export type ArrayPropsDefinition = (keyof T)[]; 164 | export type PropsDefinition = ArrayPropsDefinition | RecordPropsDefinition; 165 | 166 | export interface ComputedOptions { 167 | get?(): T; 168 | set?(value: T): void; 169 | cache?: boolean; 170 | } 171 | 172 | export type WatchHandler = (val: T, oldVal: T) => void; 173 | 174 | export interface WatchOptions { 175 | deep?: boolean; 176 | immediate?: boolean; 177 | } 178 | 179 | export interface WatchOptionsWithHandler extends WatchOptions { 180 | handler: WatchHandler; 181 | } 182 | 183 | export interface DirectiveBinding extends Readonly { 184 | readonly modifiers: { [key: string]: boolean }; 185 | } 186 | 187 | export type DirectiveFunction = ( 188 | el: HTMLElement, 189 | binding: DirectiveBinding, 190 | vnode: VNode, 191 | oldVnode: VNode 192 | ) => void; 193 | 194 | export interface DirectiveOptions { 195 | bind?: DirectiveFunction; 196 | inserted?: DirectiveFunction; 197 | update?: DirectiveFunction; 198 | componentUpdated?: DirectiveFunction; 199 | unbind?: DirectiveFunction; 200 | } 201 | 202 | export type InjectKey = string | symbol; 203 | 204 | export type InjectOptions = { 205 | [key: string]: InjectKey | { from?: InjectKey, default?: any } 206 | } | string[]; 207 | -------------------------------------------------------------------------------- /typings/vue/plugin.d.ts: -------------------------------------------------------------------------------- 1 | import { Vue as _Vue } from "./vue"; 2 | 3 | export type PluginFunction = (Vue: typeof _Vue, options?: T) => void; 4 | 5 | export interface PluginObject { 6 | install: PluginFunction; 7 | [key: string]: any; 8 | } 9 | -------------------------------------------------------------------------------- /typings/vue/vnode.d.ts: -------------------------------------------------------------------------------- 1 | import { Vue } from "./vue"; 2 | 3 | export type ScopedSlot = (props: any) => ScopedSlotReturnValue; 4 | type ScopedSlotReturnValue = VNode | string | boolean | null | undefined | ScopedSlotReturnArray; 5 | interface ScopedSlotReturnArray extends Array {} 6 | 7 | // Scoped slots are guaranteed to return Array of VNodes starting in 2.6 8 | export type NormalizedScopedSlot = (props: any) => ScopedSlotChildren; 9 | export type ScopedSlotChildren = VNode[] | undefined; 10 | 11 | // Relaxed type compatible with $createElement 12 | export type VNodeChildren = VNodeChildrenArrayContents | [ScopedSlot] | string | boolean | null | undefined; 13 | export interface VNodeChildrenArrayContents extends Array {} 14 | 15 | export interface VNode { 16 | tag?: string; 17 | data?: VNodeData; 18 | children?: VNode[]; 19 | text?: string; 20 | elm?: Node; 21 | ns?: string; 22 | context?: Vue; 23 | key?: string | number; 24 | componentOptions?: VNodeComponentOptions; 25 | componentInstance?: Vue; 26 | parent?: VNode; 27 | raw?: boolean; 28 | isStatic?: boolean; 29 | isRootInsert: boolean; 30 | isComment: boolean; 31 | } 32 | 33 | export interface VNodeComponentOptions { 34 | Ctor: typeof Vue; 35 | propsData?: object; 36 | listeners?: object; 37 | children?: VNode[]; 38 | tag?: string; 39 | } 40 | 41 | export interface VNodeData { 42 | key?: string | number; 43 | slot?: string; 44 | scopedSlots?: { [key: string]: ScopedSlot | undefined }; 45 | ref?: string; 46 | refInFor?: boolean; 47 | tag?: string; 48 | staticClass?: string; 49 | class?: any; 50 | staticStyle?: { [key: string]: any }; 51 | style?: object[] | object; 52 | props?: { [key: string]: any }; 53 | attrs?: { [key: string]: any }; 54 | domProps?: { [key: string]: any }; 55 | hook?: { [key: string]: Function }; 56 | on?: { [key: string]: Function | Function[] }; 57 | nativeOn?: { [key: string]: Function | Function[] }; 58 | transition?: object; 59 | show?: boolean; 60 | inlineTemplate?: { 61 | render: Function; 62 | staticRenderFns: Function[]; 63 | }; 64 | directives?: VNodeDirective[]; 65 | keepAlive?: boolean; 66 | } 67 | 68 | export interface VNodeDirective { 69 | name: string; 70 | value?: any; 71 | oldValue?: any; 72 | expression?: any; 73 | arg?: string; 74 | oldArg?: string; 75 | modifiers?: { [key: string]: boolean }; 76 | } 77 | -------------------------------------------------------------------------------- /typings/vue/vue.d.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Component, 3 | AsyncComponent, 4 | ComponentOptions, 5 | FunctionalComponentOptions, 6 | WatchOptionsWithHandler, 7 | WatchHandler, 8 | DirectiveOptions, 9 | DirectiveFunction, 10 | RecordPropsDefinition, 11 | ThisTypedComponentOptionsWithArrayProps, 12 | ThisTypedComponentOptionsWithRecordProps, 13 | WatchOptions, 14 | } from "./options"; 15 | import { VNode, VNodeData, VNodeChildren, ScopedSlot, NormalizedScopedSlot } from "./vnode"; 16 | import { PluginFunction, PluginObject } from "./plugin"; 17 | 18 | export interface CreateElement { 19 | (tag?: string | Component | AsyncComponent | (() => Component), children?: VNodeChildren): VNode; 20 | (tag?: string | Component | AsyncComponent | (() => Component), data?: VNodeData, children?: VNodeChildren): VNode; 21 | } 22 | 23 | export interface Vue { 24 | readonly $el: Element; 25 | readonly $options: ComponentOptions; 26 | readonly $parent: Vue; 27 | readonly $root: Vue; 28 | readonly $children: Vue[]; 29 | readonly $refs: { [key: string]: Vue | Element | Vue[] | Element[] }; 30 | readonly $slots: { [key: string]: VNode[] | undefined }; 31 | readonly $scopedSlots: { [key: string]: NormalizedScopedSlot | undefined }; 32 | readonly $isServer: boolean; 33 | readonly $data: Record; 34 | readonly $props: Record; 35 | readonly $ssrContext: any; 36 | readonly $vnode: VNode; 37 | readonly $attrs: Record; 38 | readonly $listeners: Record; 39 | 40 | $mount(elementOrSelector?: Element | string, hydrating?: boolean): this; 41 | $forceUpdate(): void; 42 | $destroy(): void; 43 | $set: typeof Vue.set; 44 | $delete: typeof Vue.delete; 45 | $watch( 46 | expOrFn: string, 47 | callback: (this: this, n: any, o: any) => void, 48 | options?: WatchOptions 49 | ): (() => void); 50 | $watch( 51 | expOrFn: (this: this) => T, 52 | callback: (this: this, n: T, o: T) => void, 53 | options?: WatchOptions 54 | ): (() => void); 55 | $on(event: string | string[], callback: Function): this; 56 | $once(event: string | string[], callback: Function): this; 57 | $off(event?: string | string[], callback?: Function): this; 58 | $emit(event: string, ...args: any[]): this; 59 | $nextTick(callback: (this: this) => void): void; 60 | $nextTick(): Promise; 61 | $createElement: CreateElement; 62 | } 63 | 64 | export type CombinedVueInstance = Data & Methods & Computed & Props & Instance; 65 | export type ExtendedVue = VueConstructor & Vue>; 66 | 67 | export interface VueConfiguration { 68 | silent: boolean; 69 | optionMergeStrategies: any; 70 | devtools: boolean; 71 | productionTip: boolean; 72 | performance: boolean; 73 | errorHandler(err: Error, vm: Vue, info: string): void; 74 | warnHandler(msg: string, vm: Vue, trace: string): void; 75 | ignoredElements: (string | RegExp)[]; 76 | keyCodes: { [key: string]: number | number[] }; 77 | async: boolean; 78 | } 79 | 80 | export interface VueConstructor { 81 | new (options?: ThisTypedComponentOptionsWithArrayProps): CombinedVueInstance>; 82 | // ideally, the return type should just contain Props, not Record. But TS requires to have Base constructors with the same return type. 83 | new (options?: ThisTypedComponentOptionsWithRecordProps): CombinedVueInstance>; 84 | new (options?: ComponentOptions): CombinedVueInstance>; 85 | 86 | extend(options?: ThisTypedComponentOptionsWithArrayProps): ExtendedVue>; 87 | extend(options?: ThisTypedComponentOptionsWithRecordProps): ExtendedVue; 88 | extend(definition: FunctionalComponentOptions, PropNames[]>): ExtendedVue>; 89 | extend(definition: FunctionalComponentOptions>): ExtendedVue; 90 | extend(options?: ComponentOptions): ExtendedVue; 91 | 92 | nextTick(callback: (this: T) => void, context?: T): void; 93 | nextTick(): Promise 94 | set(object: object, key: string | number, value: T): T; 95 | set(array: T[], key: number, value: T): T; 96 | delete(object: object, key: string | number): void; 97 | delete(array: T[], key: number): void; 98 | 99 | directive( 100 | id: string, 101 | definition?: DirectiveOptions | DirectiveFunction 102 | ): DirectiveOptions; 103 | filter(id: string, definition?: Function): Function; 104 | 105 | component(id: string): VueConstructor; 106 | component(id: string, constructor: VC): VC; 107 | component(id: string, definition: AsyncComponent): ExtendedVue; 108 | component(id: string, definition?: ThisTypedComponentOptionsWithArrayProps): ExtendedVue>; 109 | component(id: string, definition?: ThisTypedComponentOptionsWithRecordProps): ExtendedVue; 110 | component(id: string, definition: FunctionalComponentOptions, PropNames[]>): ExtendedVue>; 111 | component(id: string, definition: FunctionalComponentOptions>): ExtendedVue; 112 | component(id: string, definition?: ComponentOptions): ExtendedVue; 113 | 114 | use(plugin: PluginObject | PluginFunction, options?: T): VueConstructor; 115 | use(plugin: PluginObject | PluginFunction, ...options: any[]): VueConstructor; 116 | mixin(mixin: VueConstructor | ComponentOptions): VueConstructor; 117 | compile(template: string): { 118 | render(createElement: typeof Vue.prototype.$createElement): VNode; 119 | staticRenderFns: (() => VNode)[]; 120 | }; 121 | 122 | observable(obj: T): T; 123 | 124 | config: VueConfiguration; 125 | version: string; 126 | } 127 | 128 | export const Vue: VueConstructor; 129 | -------------------------------------------------------------------------------- /wwwroot/_init.ss: -------------------------------------------------------------------------------- 1 | {{ 2 | var AppSvgs = { 3 | 'action/home.svg': 'home', 4 | 'device/storage.svg': 'db', 5 | 'action/list.svg': 'table', 6 | 'navigation/first_page.svg': 'chevron-first', 7 | 'navigation/last_page.svg': 'chevron-last', 8 | 'navigation/expand_more.svg': 'chevron-down', 9 | 'navigation/chevron_left.svg': 'chevron-left', 10 | 'navigation/chevron_right.svg': 'chevron-right', 11 | 'navigation/expand_less.svg': 'chevron-up', 12 | 'content/clear.svg': 'clear', 13 | 'content/filter_list.svg': 'filter', 14 | } 15 | }} 16 | 17 | {{#each AppSvgs}} 18 | {{`/lib/svg/material/${it.Key}` |> svgAddFile(it.Value,'app')}} 19 | {{/each}} 20 | 21 | {{#svg fields app}} 22 | 23 | 24 | 25 | 26 | {{/svg}} 27 | 28 | {{#svg external-link app}} 29 | 30 | 31 | 32 | 33 | 34 | {{/svg}} 35 | 36 | {{#svg loading app}} 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | {{/svg}} 55 | 56 | {{#svg logo app}} 57 | 58 | 59 | 60 | 61 | {{/svg}} 62 | 63 | {{#svg excel app}} 64 | 65 | 66 | 67 | 68 | 69 | 70 | {{/svg}} 71 | 72 | {{htmlError}} 73 | -------------------------------------------------------------------------------- /wwwroot/_layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | {{ title ?? 'Sharp Data' }} 10 | 11 | 12 | {{ 'buttons,buttons-svg' |> cssIncludes }} 13 | {{ 'app' |> cssIncludes |> svgFill('#444') }} 14 | 15 | {{#if fileExists('/bundle.css') }} 16 | 17 | {{else}} 18 | {{ 'content:/src/css/' |> bundleCss({ minify:false, cache:false, out:'/app.bundle.css' }) }} 19 | {{/if}} 20 | 21 | 32 | 33 | 34 | 55 | 56 | 57 | 58 | {{page}} 59 | 60 | {{ [ 61 | `/lib/js/vue/vue.min.js`, 62 | `/lib/js/vue-router/vue-router.min.js`, 63 | `/lib/js/vue-class-component/vue-class-component.min.js`, 64 | `/lib/js/vue-property-decorator/vue-property-decorator.min.js`, 65 | `/lib/js/@servicestack/desktop/servicestack-desktop.min.js`, 66 | `/lib/js/@servicestack/client/servicestack-client.min.js`, 67 | `/lib/js/@servicestack/vue/servicestack-vue.min.js`, 68 | ] |> map => `` |> joinln |> raw }} 69 | 70 | 85 | 86 | {{#if fileExists('/bundle.js') }} 87 | 88 | {{else}} 89 | 90 | {{ [ 91 | 'content:/src/components/', 92 | 'content:/src/shared/', 93 | 'content:/src/', 94 | ] |> bundleJs({ minify:false, cache:false, iife:true, out:`/app.bundle.js` }) }} 95 | 96 | {{/if}} 97 | 98 | {{ ['custom/'] |> bundleJs({ minify:false, bundle:false }) }} 99 | 100 | {{ scripts |> raw }} 101 | 102 | {{initError |> htmlError}} 103 | {{htmlError}} 104 | 105 | 106 | -------------------------------------------------------------------------------- /wwwroot/custom/chinook.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __extends = (this && this.__extends) || (function () { 3 | var extendStatics = function (d, b) { 4 | extendStatics = Object.setPrototypeOf || 5 | ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 6 | function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; 7 | return extendStatics(d, b); 8 | }; 9 | return function (d, b) { 10 | if (typeof b !== "function" && b !== null) 11 | throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); 12 | extendStatics(d, b); 13 | function __() { this.constructor = d; } 14 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 15 | }; 16 | })(); 17 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 18 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 19 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 20 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 21 | return c > 3 && r && Object.defineProperty(target, key, r), r; 22 | }; 23 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 24 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 25 | return new (P || (P = Promise))(function (resolve, reject) { 26 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 27 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 28 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 29 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 30 | }); 31 | }; 32 | var __generator = (this && this.__generator) || function (thisArg, body) { 33 | var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; 34 | return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; 35 | function verb(n) { return function (v) { return step([n, v]); }; } 36 | function step(op) { 37 | if (f) throw new TypeError("Generator is already executing."); 38 | while (g && (g = 0, op[0] && (_ = 0)), _) try { 39 | if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; 40 | if (y = 0, t) op = [op[0] & 2, t.value]; 41 | switch (op[0]) { 42 | case 0: case 1: t = op; break; 43 | case 4: _.label++; return { value: op[1], done: false }; 44 | case 5: _.label++; y = op[1]; op = [0]; continue; 45 | case 7: op = _.ops.pop(); _.trys.pop(); continue; 46 | default: 47 | if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } 48 | if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } 49 | if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } 50 | if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } 51 | if (t[2]) _.ops.pop(); 52 | _.trys.pop(); continue; 53 | } 54 | op = body.call(thisArg, _); 55 | } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } 56 | if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; 57 | } 58 | }; 59 | Object.defineProperty(exports, "__esModule", { value: true }); 60 | exports.Playlist = exports.Album = exports.Artist = void 0; 61 | var shared_1 = require("../../src/shared"); 62 | var vue_property_decorator_1 = require("vue-property-decorator"); 63 | var client_1 = require("@servicestack/client"); 64 | var Artist = /** @class */ (function (_super) { 65 | __extends(Artist, _super); 66 | function Artist() { 67 | var _this = _super !== null && _super.apply(this, arguments) || this; 68 | _this.albums = []; 69 | return _this; 70 | } 71 | Object.defineProperty(Artist.prototype, "id", { 72 | get: function () { return this.row.ArtistId; }, 73 | enumerable: false, 74 | configurable: true 75 | }); 76 | Artist.prototype.albumHref = function (albumId) { return "albums?filter=AlbumId:".concat(albumId); }; 77 | Artist.prototype.mounted = function () { 78 | return __awaiter(this, void 0, void 0, function () { 79 | var _a; 80 | return __generator(this, function (_b) { 81 | switch (_b.label) { 82 | case 0: 83 | _a = this; 84 | return [4 /*yield*/, (0, shared_1.sharpData)(this.db, 'albums', { ArtistId: this.id })]; 85 | case 1: 86 | _a.albums = _b.sent(); 87 | return [2 /*return*/]; 88 | } 89 | }); 90 | }); 91 | }; 92 | Artist = __decorate([ 93 | (0, vue_property_decorator_1.Component)({ template: "\n
Artist Id needs to be selected
" 94 | }) 95 | ], Artist); 96 | return Artist; 97 | }(shared_1.RowComponent)); 98 | exports.Artist = Artist; 99 | var Album = /** @class */ (function (_super) { 100 | __extends(Album, _super); 101 | function Album() { 102 | var _this = _super !== null && _super.apply(this, arguments) || this; 103 | _this.artist = null; 104 | _this.tracks = []; 105 | return _this; 106 | } 107 | Object.defineProperty(Album.prototype, "id", { 108 | get: function () { return this.row.AlbumId; }, 109 | enumerable: false, 110 | configurable: true 111 | }); 112 | Album.prototype.mounted = function () { 113 | return __awaiter(this, void 0, void 0, function () { 114 | var _a, secsToTime, genres, media, _b; 115 | return __generator(this, function (_c) { 116 | switch (_c.label) { 117 | case 0: 118 | _a = this; 119 | return [4 /*yield*/, (0, shared_1.sharpData)(this.db, 'artists', { ArtistId: this.row.ArtistId })]; 120 | case 1: 121 | _a.artist = (_c.sent())[0]; 122 | secsToTime = function (s) { return "".concat(Math.floor(s / 60), ":").concat((0, client_1.padInt)(Math.round(s % 60))); }; 123 | genres = {}; 124 | return [4 /*yield*/, (0, shared_1.sharpData)(this.db, 'genres')]; 125 | case 2: 126 | (_c.sent()).forEach(function (x) { return genres[x.GenreId] = x.Name; }); 127 | media = {}; 128 | return [4 /*yield*/, (0, shared_1.sharpData)(this.db, 'media_types')]; 129 | case 3: 130 | (_c.sent()).forEach(function (x) { return media[x.MediaTypeId] = x.Name; }); 131 | _b = this; 132 | return [4 /*yield*/, (0, shared_1.sharpData)(this.db, 'tracks', { AlbumId: this.id })]; 133 | case 4: 134 | _b.tracks = (_c.sent()).map(function (x) { return ({ 135 | Name: x.Name, 136 | Genre: genres[x.GenreId], 137 | Duration: secsToTime(x.Milliseconds / 1000), 138 | Price: "$".concat(x.UnitPrice), 139 | Size: Math.floor(x.Bytes / 1024) + " kB", 140 | Media: media[x.MediaTypeId], 141 | }); }); 142 | return [2 /*return*/]; 143 | } 144 | }); 145 | }); 146 | }; 147 | Album = __decorate([ 148 | (0, vue_property_decorator_1.Component)({ template: "
\n

{{row.Title}} by {{artist.Name}}

\n \n
\n
Album Id needs to be selected
" 149 | }) 150 | ], Album); 151 | return Album; 152 | }(shared_1.RowComponent)); 153 | exports.Album = Album; 154 | var Playlist = /** @class */ (function (_super) { 155 | __extends(Playlist, _super); 156 | function Playlist() { 157 | var _this = _super !== null && _super.apply(this, arguments) || this; 158 | _this.tracks = []; 159 | return _this; 160 | } 161 | Object.defineProperty(Playlist.prototype, "id", { 162 | get: function () { return this.row.PlaylistId; }, 163 | enumerable: false, 164 | configurable: true 165 | }); 166 | Playlist.prototype.trackHref = function (trackId) { return "tracks?filter=TrackId:".concat(trackId); }; 167 | Playlist.prototype.mounted = function () { 168 | return __awaiter(this, void 0, void 0, function () { 169 | var trackIds, _a; 170 | return __generator(this, function (_b) { 171 | switch (_b.label) { 172 | case 0: return [4 /*yield*/, (0, shared_1.sharpData)(this.db, 'playlist_track', { PlaylistId: this.id, take: 200 })]; 173 | case 1: 174 | trackIds = (_b.sent()).map(function (x) { return x.TrackId; }); 175 | _a = this; 176 | return [4 /*yield*/, (0, shared_1.sharpData)(this.db, 'tracks', { TrackId: trackIds.join(',') + ',' })]; 177 | case 2: 178 | _a.tracks = _b.sent(); 179 | return [2 /*return*/]; 180 | } 181 | }); 182 | }); 183 | }; 184 | Playlist = __decorate([ 185 | (0, vue_property_decorator_1.Component)({ template: "
\n
\n
Tracks
\n \n
\n
playlist has no tracks
\n
\n
Playlist Id needs to be selected
" 186 | }) 187 | ], Playlist); 188 | return Playlist; 189 | }(shared_1.RowComponent)); 190 | exports.Playlist = Playlist; 191 | (0, shared_1.dbConfig)('chinook', { 192 | showTables: 'albums,artists,playlists,tracks,genres,media_types,customers,employees,invoices'.split(','), 193 | tableName: shared_1.splitPascalCase, 194 | links: { 195 | albums: { 196 | ArtistId: function (id) { return "artists?filter=ArtistId:".concat(id); } 197 | }, 198 | employees: { 199 | ReportsTo: function (id) { return "employees?filter=EmployeeId:".concat(id); } 200 | }, 201 | invoices: { 202 | CustomerId: function (id) { return "customers?filter=CustomerId:".concat(id); } 203 | }, 204 | tracks: { 205 | AlbumId: function (id) { return "albums?filter=AlbumId:".concat(id); }, 206 | MediaTypeId: function (id) { return "media_types?filter=MediaTypeId:".concat(id); }, 207 | GenreId: function (id) { return "genres?filter=GenreId:".concat(id); }, 208 | } 209 | }, 210 | rowComponents: { 211 | albums: Album, 212 | artists: Artist, 213 | playlists: Playlist, 214 | } 215 | }); 216 | -------------------------------------------------------------------------------- /wwwroot/custom/chinook.ts: -------------------------------------------------------------------------------- 1 | import { dbConfig, RowComponent, sharpData, splitPascalCase } from "../../src/shared"; 2 | import { Component } from "vue-property-decorator"; 3 | import { padInt } from "@servicestack/client"; 4 | 5 | @Component({ template: 6 | `
7 |
Albums
8 | 11 |
12 |
Artist Id needs to be selected
` 13 | }) 14 | export class Artist extends RowComponent { 15 | 16 | albums:any[] = []; 17 | 18 | get id() { return this.row.ArtistId; } 19 | 20 | albumHref(albumId:string) { return `albums?filter=AlbumId:${albumId}`;} 21 | 22 | async mounted() { 23 | this.albums = await sharpData(this.db,'albums',{ ArtistId: this.id }); 24 | } 25 | } 26 | 27 | @Component({ template: 28 | `
29 |

{{row.Title}} by {{artist.Name}}

30 | 31 |
32 |
Album Id needs to be selected
` 33 | }) 34 | export class Album extends RowComponent { 35 | 36 | artist:any = null; 37 | tracks:any[] = []; 38 | 39 | get id() { return this.row.AlbumId; } 40 | 41 | async mounted() { 42 | this.artist = (await sharpData(this.db,'artists',{ ArtistId: this.row.ArtistId }))[0]; 43 | const secsToTime = (s:number) => `${Math.floor(s / 60)}:${padInt(Math.round(s % 60))}`; 44 | const genres:any = {}; 45 | (await sharpData(this.db,'genres')).forEach((x:any) => genres[x.GenreId] = x.Name); 46 | const media:any = {}; 47 | (await sharpData(this.db,'media_types')).forEach((x:any) => media[x.MediaTypeId] = x.Name); 48 | this.tracks = (await sharpData(this.db,'tracks',{ AlbumId: this.id })).map((x:any) => ({ 49 | Name: x.Name, 50 | Genre: genres[x.GenreId], 51 | Duration: secsToTime(x.Milliseconds / 1000), 52 | Price: `$${x.UnitPrice}`, 53 | Size: Math.floor(x.Bytes / 1024) + " kB", 54 | Media: media[x.MediaTypeId], 55 | })); 56 | } 57 | } 58 | 59 | @Component({ template: 60 | `
61 |
62 |
Tracks
63 | 66 |
67 |
playlist has no tracks
68 |
69 |
Playlist Id needs to be selected
` 70 | }) 71 | export class Playlist extends RowComponent { 72 | 73 | tracks:any[] = []; 74 | 75 | get id() { return this.row.PlaylistId; } 76 | 77 | trackHref(trackId:string) { return `tracks?filter=TrackId:${trackId}`;} 78 | 79 | async mounted() { 80 | const trackIds = (await sharpData(this.db,'playlist_track',{ PlaylistId: this.id, take:200 })).map((x:any) => x.TrackId); 81 | this.tracks = await sharpData(this.db,'tracks',{ TrackId: trackIds.join(',') + ',' }); 82 | } 83 | } 84 | 85 | dbConfig('chinook', { 86 | showTables: 'albums,artists,playlists,tracks,genres,media_types,customers,employees,invoices'.split(','), 87 | tableName: splitPascalCase, 88 | links: { 89 | albums: { 90 | ArtistId: (id:number) => `artists?filter=ArtistId:${id}` 91 | }, 92 | employees: { 93 | ReportsTo: (id:number) => `employees?filter=EmployeeId:${id}` 94 | }, 95 | invoices: { 96 | CustomerId: (id:number) => `customers?filter=CustomerId:${id}` 97 | }, 98 | tracks: { 99 | AlbumId: (id:number) => `albums?filter=AlbumId:${id}`, 100 | MediaTypeId: (id:number) => `media_types?filter=MediaTypeId:${id}`, 101 | GenreId: (id:number) => `genres?filter=GenreId:${id}`, 102 | } 103 | }, 104 | rowComponents: { 105 | albums: Album, 106 | artists: Artist, 107 | playlists: Playlist, 108 | } 109 | }); 110 | -------------------------------------------------------------------------------- /wwwroot/custom/northwind.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __extends = (this && this.__extends) || (function () { 3 | var extendStatics = function (d, b) { 4 | extendStatics = Object.setPrototypeOf || 5 | ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 6 | function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; 7 | return extendStatics(d, b); 8 | }; 9 | return function (d, b) { 10 | if (typeof b !== "function" && b !== null) 11 | throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); 12 | extendStatics(d, b); 13 | function __() { this.constructor = d; } 14 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 15 | }; 16 | })(); 17 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 18 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 19 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 20 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 21 | return c > 3 && r && Object.defineProperty(target, key, r), r; 22 | }; 23 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 24 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 25 | return new (P || (P = Promise))(function (resolve, reject) { 26 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 27 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 28 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 29 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 30 | }); 31 | }; 32 | var __generator = (this && this.__generator) || function (thisArg, body) { 33 | var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; 34 | return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; 35 | function verb(n) { return function (v) { return step([n, v]); }; } 36 | function step(op) { 37 | if (f) throw new TypeError("Generator is already executing."); 38 | while (g && (g = 0, op[0] && (_ = 0)), _) try { 39 | if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; 40 | if (y = 0, t) op = [op[0] & 2, t.value]; 41 | switch (op[0]) { 42 | case 0: case 1: t = op; break; 43 | case 4: _.label++; return { value: op[1], done: false }; 44 | case 5: _.label++; y = op[1]; op = [0]; continue; 45 | case 7: op = _.ops.pop(); _.trys.pop(); continue; 46 | default: 47 | if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } 48 | if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } 49 | if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } 50 | if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } 51 | if (t[2]) _.ops.pop(); 52 | _.trys.pop(); continue; 53 | } 54 | op = body.call(thisArg, _); 55 | } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } 56 | if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; 57 | } 58 | }; 59 | Object.defineProperty(exports, "__esModule", { value: true }); 60 | var shared_1 = require("../../src/shared"); 61 | var vue_property_decorator_1 = require("vue-property-decorator"); 62 | var Customer = /** @class */ (function (_super) { 63 | __extends(Customer, _super); 64 | function Customer() { 65 | var _this = _super !== null && _super.apply(this, arguments) || this; 66 | _this.customer = null; 67 | _this.orders = []; 68 | return _this; 69 | } 70 | Object.defineProperty(Customer.prototype, "id", { 71 | get: function () { return this.row.Id; }, 72 | enumerable: false, 73 | configurable: true 74 | }); 75 | Customer.prototype.mounted = function () { 76 | return __awaiter(this, void 0, void 0, function () { 77 | var _a, fields, _b; 78 | return __generator(this, function (_c) { 79 | switch (_c.label) { 80 | case 0: 81 | _a = this; 82 | return [4 /*yield*/, (0, shared_1.sharpData)(this.db, this.table, { Id: this.id })]; 83 | case 1: 84 | _a.customer = (_c.sent())[0]; 85 | fields = 'Id,EmployeeId,OrderDate,Freight,ShipVia,ShipCity,ShipCountry'; 86 | _b = this; 87 | return [4 /*yield*/, (0, shared_1.sharpData)(this.db, 'Order', { CustomerId: this.id, fields: fields })]; 88 | case 2: 89 | _b.orders = _c.sent(); 90 | return [2 /*return*/]; 91 | } 92 | }); 93 | }); 94 | }; 95 | Customer = __decorate([ 96 | (0, vue_property_decorator_1.Component)({ template: "
\n

{{customer.ContactName}}

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Contact{{ customer.ContactName }} ({{ customer.ContactTitle }})
Address\n
{{ customer.Address }}
\n
{{ customer.City }}, {{ customer.PostalCode }}, {{ customer.Country }}
\n
Phone{{ customer.Phone }}
Fax{{ customer.Fax }}
\n \n
\n
Customer Id needs to be selected
" 97 | }) 98 | ], Customer); 99 | return Customer; 100 | }(shared_1.RowComponent)); 101 | var Order = /** @class */ (function (_super) { 102 | __extends(Order, _super); 103 | function Order() { 104 | var _this = _super !== null && _super.apply(this, arguments) || this; 105 | _this.details = []; 106 | return _this; 107 | } 108 | Object.defineProperty(Order.prototype, "id", { 109 | get: function () { return this.row.Id; }, 110 | enumerable: false, 111 | configurable: true 112 | }); 113 | Order.prototype.mounted = function () { 114 | return __awaiter(this, void 0, void 0, function () { 115 | var _a; 116 | return __generator(this, function (_b) { 117 | switch (_b.label) { 118 | case 0: 119 | _a = this; 120 | return [4 /*yield*/, (0, shared_1.sharpData)(this.db, 'OrderDetail', { OrderId: this.id })]; 121 | case 1: 122 | _a.details = _b.sent(); 123 | return [2 /*return*/]; 124 | } 125 | }); 126 | }); 127 | }; 128 | Order = __decorate([ 129 | (0, vue_property_decorator_1.Component)({ template: "
\n \n
\n
Order Id needs to be selected
" 130 | }) 131 | ], Order); 132 | return Order; 133 | }(shared_1.RowComponent)); 134 | (0, shared_1.dbConfig)('northwind', { 135 | showTables: 'Customer,Order,OrderDetail,Category,Product,Employee,Shipper,Supplier,Region,Territory'.split(','), 136 | tableName: shared_1.splitPascalCase, 137 | links: { 138 | Order: { 139 | CustomerId: function (id) { return "Customer?filter=Id:".concat(id); }, 140 | EmployeeId: function (id) { return "Employee?filter=Id:".concat(id); }, 141 | ShipVia: function (id) { return "Shipper?filter=Id:".concat(id); }, 142 | }, 143 | OrderDetail: { 144 | OrderId: function (id) { return "Order?filter=Id:".concat(id); }, 145 | ProductId: function (id) { return "Product?filter=Id:".concat(id); }, 146 | }, 147 | Product: { 148 | SupplierId: function (id) { return "Supplier?filter=Id:".concat(id); }, 149 | CategoryId: function (id) { return "Category?filter=Id:".concat(id); }, 150 | }, 151 | Territory: { 152 | RegionId: function (id) { return "Region?filter=Id:".concat(id); }, 153 | }, 154 | }, 155 | rowComponents: { 156 | Order: Order, 157 | Customer: Customer, 158 | } 159 | }); 160 | -------------------------------------------------------------------------------- /wwwroot/custom/northwind.ts: -------------------------------------------------------------------------------- 1 | import { dbConfig, RowComponent, sharpData, splitPascalCase } from "../../src/shared"; 2 | import { Component } from "vue-property-decorator"; 3 | 4 | @Component({ template: 5 | `
6 |

{{customer.ContactName}}

7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
Contact{{ customer.ContactName }} ({{ customer.ContactTitle }})
Address 15 |
{{ customer.Address }}
16 |
{{ customer.City }}, {{ customer.PostalCode }}, {{ customer.Country }}
17 |
Phone{{ customer.Phone }}
Fax{{ customer.Fax }}
28 | 29 |
30 |
Customer Id needs to be selected
` 31 | }) 32 | class Customer extends RowComponent { 33 | 34 | customer:any = null; 35 | orders:any[] = []; 36 | 37 | get id() { return this.row.Id; } 38 | 39 | async mounted() { 40 | this.customer = (await sharpData(this.db,this.table,{ Id: this.id }))[0]; 41 | const fields = 'Id,EmployeeId,OrderDate,Freight,ShipVia,ShipCity,ShipCountry'; 42 | this.orders = await sharpData(this.db,'Order',{ CustomerId: this.id, fields }) 43 | } 44 | } 45 | 46 | @Component({ template: 47 | `
48 | 49 |
50 |
Order Id needs to be selected
` 51 | }) 52 | class Order extends RowComponent { 53 | details:any[] = []; 54 | 55 | get id() { return this.row.Id; } 56 | 57 | async mounted() { 58 | this.details = await sharpData(this.db,'OrderDetail',{ OrderId: this.id }); 59 | } 60 | } 61 | 62 | dbConfig('northwind', { 63 | showTables: 'Customer,Order,OrderDetail,Category,Product,Employee,Shipper,Supplier,Region,Territory'.split(','), 64 | tableName: splitPascalCase, 65 | links: { 66 | Order: { 67 | CustomerId: (id:string) => `Customer?filter=Id:${id}`, 68 | EmployeeId: (id:string) => `Employee?filter=Id:${id}`, 69 | ShipVia: (id:number) => `Shipper?filter=Id:${id}`, 70 | }, 71 | OrderDetail: { 72 | OrderId: (id:string) => `Order?filter=Id:${id}`, 73 | ProductId: (id:string) => `Product?filter=Id:${id}`, 74 | }, 75 | Product: { 76 | SupplierId: (id:number) => `Supplier?filter=Id:${id}`, 77 | CategoryId: (id:number) => `Category?filter=Id:${id}`, 78 | }, 79 | Territory: { 80 | RegionId: (id:number) => `Region?filter=Id:${id}`, 81 | }, 82 | }, 83 | rowComponents: { 84 | Order, 85 | Customer, 86 | } 87 | }); 88 | -------------------------------------------------------------------------------- /wwwroot/db/_db/_table/index.html: -------------------------------------------------------------------------------- 1 | {{ {namedConnection:db} |> if (db && db != 'main') |> useDb }} 2 | 3 | ```code|quiet 4 | var ignore = ['db','fields','format','skip','take','orderBy'] 5 | var fields = qs.fields ? qs.fields.split(',').map(x => sqlQuote(x)).join(',') : '*' 6 | var sql = `SELECT ${fields} FROM ${sqlQuote(table)}` 7 | var filters = [] 8 | var queryMap = qs.toObjectDictionary().withoutKeys(ignore) 9 | #each queryMap.Keys.toList() 10 | var search = queryMap[it.sqlVerifyFragment()].sqlVerifyFragment(); 11 | #if search == '=null' || search == '!=null' 12 | `${sqlQuote(it)} ${search=='=null' ? 'IS' : 'IS NOT'} NULL` |> addTo => filters 13 | queryMap[it] = null 14 | else if search.startsWith('=') 15 | `${sqlQuote(it)} = @${it}` |> addTo => filters 16 | queryMap[it] = search.substring(1).coerce() 17 | else if search.startsWith('<=') || search.startsWith('>=') || search.startsWith('<>') || search.startsWith('!=') 18 | `${sqlQuote(it)} ${search.substring(0,2)} @${it}` |> addTo => filters 19 | queryMap[it] = search.substring(2).coerce() 20 | else if search.startsWith('<') || search.startsWith('>') 21 | `${sqlQuote(it)} ${search.substring(0,1)} @${it}` |> addTo => filters 22 | queryMap[it] = search.substring(1).coerce() 23 | else if search.endsWith(',') 24 | `${sqlQuote(it)} IN (${search.trimEnd(',').split(',').map(i => i.toLong()).join(',')})` |> addTo => filters 25 | queryMap[it] = null 26 | else if search.startsWith('%') || search.endsWith('%') 27 | `${sqlQuote(it).sqlCast('varchar')} LIKE @${it}` |> addTo => filters 28 | else 29 | `${sqlQuote(it).sqlCast('varchar')} = @${it}` |> addTo => filters 30 | /if 31 | /each 32 | #if !filters.isEmpty() 33 | sql = `${sql} WHERE ${filters.join(' AND ')}` 34 | /if 35 | #if qs.orderBy 36 | sql = `${sql} ORDER BY ${sqlOrderByFields(qs.orderBy)}` 37 | /if 38 | #if qs.skip || qs.take 39 | sql = `${sql} ${sqlLimit(qs.skip,qs.take)}` 40 | /if 41 | sql |> dbSelect(queryMap) |> return 42 | ``` 43 | {{ ifError |> show(sql) }} 44 | {{htmlError}} 45 | -------------------------------------------------------------------------------- /wwwroot/db/_db/_table/meta.html: -------------------------------------------------------------------------------- 1 | {{ {namedConnection:db} |> if (db && db != 'main') |> useDb }} 2 | {{ table |> dbColumns |> return }} 3 | {{htmlError}} 4 | -------------------------------------------------------------------------------- /wwwroot/db/_db/_table/total.html: -------------------------------------------------------------------------------- 1 | {{ {namedConnection:db} |> if (db && db != 'main') |> useDb }} 2 | 3 | ```code|quiet 4 | var ignore = ['db','fields','format','orderby','skip','take'] 5 | var sql = `SELECT COUNT(*) FROM ${sqlQuote(table)}` 6 | var filters = [] 7 | var queryMap = qs.toObjectDictionary().withoutKeys(ignore) 8 | #each queryMap.Keys.toList() 9 | var search = queryMap[it.sqlVerifyFragment()].sqlVerifyFragment(); 10 | #if search == '=null' || search == '!=null' 11 | `${sqlQuote(it)} ${search=='=null' ? 'IS' : 'IS NOT'} NULL` |> addTo => filters 12 | queryMap[it] = null 13 | else if search.startsWith('=') 14 | `${sqlQuote(it)} = @${it}` |> addTo => filters 15 | queryMap[it] = search.substring(1).coerce() 16 | else if search.startsWith('<=') || search.startsWith('>=') || search.startsWith('<>') || search.startsWith('!=') 17 | `${sqlQuote(it)} ${search.substring(0,2)} @${it}` |> addTo => filters 18 | queryMap[it] = search.substring(2).coerce() 19 | else if search.startsWith('<') || search.startsWith('>') 20 | `${sqlQuote(it)} ${search.substring(0,1)} @${it}` |> addTo => filters 21 | queryMap[it] = search.substring(1).coerce() 22 | else if search.endsWith(',') 23 | `${sqlQuote(it)} IN (${search.trimEnd(',').split(',').map(i => i.toLong()).join(',')})` |> addTo => filters 24 | queryMap[it] = null 25 | else if search.startsWith('%') || search.endsWith('%') 26 | `${sqlQuote(it).sqlCast('varchar')} LIKE @${it}` |> addTo => filters 27 | else 28 | `${sqlQuote(it).sqlCast('varchar')} = @${it}` |> addTo => filters 29 | /if 30 | /each 31 | #if !filters.isEmpty() 32 | sql = `${sql} WHERE ${filters.join(' AND ')}` 33 | /if 34 | sql |> dbScalar(queryMap) |> return 35 | ``` 36 | {{ ifError |> show(sql) }} 37 | {{htmlError}} 38 | -------------------------------------------------------------------------------- /wwwroot/db/_db/totals.html: -------------------------------------------------------------------------------- 1 | {{ {namedConnection:db} |> if (db && db != 'main') |> useDb }} 2 | {{ {live:true} |> dbTableNamesWithRowCounts |> return }} 3 | {{htmlError}} 4 | -------------------------------------------------------------------------------- /wwwroot/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCoreApps/SharpData/c4b0e3e7d8306d253dfd42a2a622e083f0700e68/wwwroot/favicon.png -------------------------------------------------------------------------------- /wwwroot/index.html: -------------------------------------------------------------------------------- 1 | {{#raw}} 2 |
3 |
4 |
5 |
6 | 7 |
8 |
9 |
10 |
11 | {{/raw}} 12 | --------------------------------------------------------------------------------