From c71e2cf0ee98141443014a2b94cf64750d2ff0e2 Mon Sep 17 00:00:00 2001 From: Martin Donnelly Date: Wed, 8 May 2024 15:04:13 +0100 Subject: [PATCH] Init --- .gitignore | 259 +++++++++++++++ README.md | 65 +++- angular.json | 3 +- image.png | Bin 0 -> 26508 bytes notes.md | 37 +++ src/_models/mode.ts | 9 + src/_models/modifier.ts | 7 + src/_models/searchFragment.ts | 45 +++ src/app/app.component.html | 314 +----------------- src/app/app.component.ts | 118 +++++++ src/app/app.module.ts | 8 +- .../omni-search-box.component.css | 11 + .../omni-search-box.component.html | 48 +++ .../omni-search-box.component.spec.ts | 23 ++ .../omni-search-box.component.ts | 145 ++++++++ src/hammer.css | 2 + src/styles.css | 1 + structure.json | 71 ++++ tsconfig.json | 1 + 19 files changed, 839 insertions(+), 328 deletions(-) create mode 100644 image.png create mode 100644 notes.md create mode 100644 src/_models/mode.ts create mode 100644 src/_models/modifier.ts create mode 100644 src/_models/searchFragment.ts create mode 100644 src/app/omni-search-box/omni-search-box.component.css create mode 100644 src/app/omni-search-box/omni-search-box.component.html create mode 100644 src/app/omni-search-box/omni-search-box.component.spec.ts create mode 100644 src/app/omni-search-box/omni-search-box.component.ts create mode 100644 src/hammer.css create mode 100644 structure.json diff --git a/.gitignore b/.gitignore index 0711527..96a6724 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,262 @@ testem.log # System files .DS_Store Thumbs.db +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Node template +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +### WebStorm template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff + +# AWS User-specific + +# Generated files + +# Sensitive or high-churn files + +# Gradle + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake + +# Mongo Explorer plugin + +# File-based project format + +# IntelliJ + +# mpeltonen/sbt-idea plugin + +# JIRA plugin + +# Cursive Clojure plugin + +# SonarLint plugin + +# Crashlytics plugin (for Android Studio and IntelliJ) + +# Editor-based Rest Client + +# Android studio 3.1+ serialized cache file + diff --git a/README.md b/README.md index c92ea49..c2d211d 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,64 @@ -# SearchTest +# Omni Search Dev Harness -This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.3.6. +![](/home/martin/dev/js/search-test/image.png) -## Development server -Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. +I have created a small test harness for a basic Omni Search box, it is not complete as it's a simple test harness to get the concept essentiall "down on paper". -## Code scaffolding +The options are specified in JSON contained within the `src/app/app.component.ts` file. -Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. +The JSON is structured as an array of SearchFragments: -## Build +```json -Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. +[ + { + "mode" : { + "title" : "Project", + "accepted" : ".+", + "output" : "Project title {{$modifier}} {{$value}}", + "hint" : "Project title" + }, + "modifiers" : [ + { + "title" : "Is", + "accepted" : "is", + "output" : "IS", + "hint" : "Is Operator" + }, + { + "title" : "Isn't", + "accepted" : "isn't", + "output" : "IS NOT", + "hint" : "Is Not Operator" + }, + { + "title" : "Contains", + "accepted" : "contains", + "output" : "CONTAINS", + "hint" : "Contains Operator" + } + ] -## Running unit tests + }, +] -Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). -## Running end-to-end tests +``` -Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. +Each fragment contains a single mode, which details what the mode should be. As for modifiers, that is an array so it can hold as many as required. -## Further help +If you look in `src/app/app.component.ts`, there is a commented out entry, if that is uncommented, it should add a fourth entry with four modifiers. + +Code wise, it is fairly simple, not much error checking or even testing as it's a simple harness to get a concept working. + +## Taking it forward + +If work were to continue with it, it would definitely need to be refined to look like the proper search bar. + +I would like to make the Omni Bar items be removable by clicking a cross button or something. + +The output for each item was planned to be a pseudo SQL like structure, but it really needs refinement, and probably multiple parts to make a coherent sql query. + +It also needs testing, which this has none of. -To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. diff --git a/angular.json b/angular.json index 168e81b..b8de5c5 100644 --- a/angular.json +++ b/angular.json @@ -35,7 +35,8 @@ "src/assets" ], "styles": [ - "src/styles.css" + "src/styles.css", + "src/hammer.css" ], "scripts": [] }, diff --git a/image.png b/image.png new file mode 100644 index 0000000000000000000000000000000000000000..0c6965a110296d8139b7bbdd126d140d45a22d3d GIT binary patch literal 26508 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 literal 0 HcmV?d00001 diff --git a/notes.md b/notes.md new file mode 100644 index 0000000..599a466 --- /dev/null +++ b/notes.md @@ -0,0 +1,37 @@ +# Development notes + + + +## Search Fragments + +| Item | Notes | +|------|---------------------------------| +| Mode | Project / Assignee / Status etc | + | Modifier | Is / is not etc | +| Target | What to be searched for | +| Operator? | And / or / Not ? Maybe to implement: Bob AND Stuart OR Status = Done | + + +## Mode / Modifier Structure + +| Item | Notes | +|---|---| +| Title | Actual title of the mode: Project / Assignee etc | +| Accepted | Regex to filter whats need. Datetime / Only allow certains words etc | +| Output | The fragment builder text | +| Hint | An alt text hint | + +> Output could be text, could be a string that can be formatted. Have to see which works +> best + + +## Modes + +- Project +- Assignee +- Creator +- Status +- Creation Date +- Due Date +- Tag +- Contains matching text "*" diff --git a/src/_models/mode.ts b/src/_models/mode.ts new file mode 100644 index 0000000..e51f240 --- /dev/null +++ b/src/_models/mode.ts @@ -0,0 +1,9 @@ +export interface ModeItem { + title: string; + accepted: string; + output: string; + hint: string; + +} + + diff --git a/src/_models/modifier.ts b/src/_models/modifier.ts new file mode 100644 index 0000000..86ee96d --- /dev/null +++ b/src/_models/modifier.ts @@ -0,0 +1,7 @@ +export interface ModifierItem { + title: string; + accepted: string; + output: string; + hint: string; + +} diff --git a/src/_models/searchFragment.ts b/src/_models/searchFragment.ts new file mode 100644 index 0000000..fe8dbb3 --- /dev/null +++ b/src/_models/searchFragment.ts @@ -0,0 +1,45 @@ +import { ModeItem} from "./mode"; +import {ModifierItem} from "./modifier"; + +export interface SearchFragment { + + mode: ModeItem; + modifiers: ModifierItem[]; + +} + +export interface SolidSearchFragment { + mode: ModeItem; + modifier: ModifierItem; + searchTerm: string; +} + +/* + + +{ + "mode" : { + "title" : "Project", + "accepted" : ".+", + "output" : "Project title {{$modifier}} {{$value}}", + "hint" : "Project title" + }, + "modifiers" : [ + { + "title" : "Is", + "accepted" : "is", + "output" : "IS", + "hint" : "Is Operator" + }, + { + "title" : "Isn't", + "accepted" : "isn't", + "output" : "IS NOT", + "hint" : "Is Not Operator" + } + ] + + } + + + */ diff --git a/src/app/app.component.html b/src/app/app.component.html index 36093e1..1c0d1d1 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -8,320 +8,12 @@ -
-
-
- -

Hello, {{ title }}

-

Congratulations! Your app is running. 🎉

-
- -
-
- @for (item of [ - { title: 'Explore the Docs', link: 'https://angular.dev' }, - { title: 'Learn with Tutorials', link: 'https://angular.dev/tutorials' }, - { title: 'CLI Docs', link: 'https://angular.dev/tools/cli' }, - { title: 'Angular Language Service', link: 'https://angular.dev/tools/language-service' }, - { title: 'Angular DevTools', link: 'https://angular.dev/tools/devtools' }, - ]; track item.title) { - - {{ item.title }} - - - - - } -
- -
-
+
+

OmniSearch Dev Harness

+
diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 5c3892f..745808e 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,4 +1,5 @@ import { Component } from '@angular/core'; +import { SearchFragment} from "../_models/searchFragment"; @Component({ selector: 'app-root', @@ -7,4 +8,121 @@ import { Component } from '@angular/core'; }) export class AppComponent { title = 'search-test'; + + + omniSearchOptions: SearchFragment[] = [ + { + "mode" : { + "title" : "Project", + "accepted" : ".+", + "output" : "Project title {{$modifier}} {{$value}}", + "hint" : "Project title" + }, + "modifiers" : [ + { + "title" : "Is", + "accepted" : "is", + "output" : "IS", + "hint" : "Is Operator" + }, + { + "title" : "Isn't", + "accepted" : "isn't", + "output" : "IS NOT", + "hint" : "Is Not Operator" + }, + { + "title" : "Contains", + "accepted" : "contains", + "output" : "CONTAINS", + "hint" : "Contains Operator" + } + ] + + }, + { + "mode" : { + "title" : "Assignee", + "accepted" : ".+", + "output" : "Assignee {{$modifier}} {{$value}}", + "hint" : "Assignee ID" + }, + "modifiers" : [ + { + "title" : "Is", + "accepted" : "is", + "output" : "IS", + "hint" : "Is Operator" + }, + { + "title" : "Isn't", + "accepted" : "isn't", + "output" : "IS NOT", + "hint" : "Is Not Operator" + } + ] + + }, + { + "mode" : { + "title" : "Creation Date", + "accepted" : ".+", + "output" : "Assignee is {{}}", + "hint" : "Assignee ID" + }, + "modifiers" : [ + { + "title" : "Is", + "accepted" : "is", + "output" : "IS", + "hint" : "Is Operator" + }, + { + "title" : "Isn't", + "accepted" : "isn't", + "output" : "IS NOT", + "hint" : "Is Not Operator" + } + ] + + } + , + /*{ + "mode" : { + "title" : "Tag", + "accepted" : ".+", + "output" : "Tag is {{}}", + "hint" : "Tag" + }, + "modifiers" : [ + { + "title" : "Is", + "accepted" : "is", + "output" : "IS", + "hint" : "Is Operator" + }, + { + "title" : "Isn't", + "accepted" : "isn't", + "output" : "IS NOT", + "hint" : "Is Not Operator" + }, + { + "title" : "Contains", + "accepted" : "contains", + "output" : "CONTAINS", + "hint" : "Contains Operator" + }, + { + "title" : "Doesn't contain", + "accepted" : "doesn't contain", + "output" : "DOES NOT CONTAIN", + "hint" : "Does Not Contain Operator" + } + ] + + }*/ + + ] + } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index b1c6c96..2f460e8 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -3,14 +3,18 @@ import { BrowserModule } from '@angular/platform-browser'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; +import { OmniSearchBoxComponent } from './omni-search-box/omni-search-box.component'; +import {FormsModule} from "@angular/forms"; @NgModule({ declarations: [ - AppComponent + AppComponent, + OmniSearchBoxComponent ], imports: [ BrowserModule, - AppRoutingModule + AppRoutingModule, + FormsModule ], providers: [], bootstrap: [AppComponent] diff --git a/src/app/omni-search-box/omni-search-box.component.css b/src/app/omni-search-box/omni-search-box.component.css new file mode 100644 index 0000000..7a26e92 --- /dev/null +++ b/src/app/omni-search-box/omni-search-box.component.css @@ -0,0 +1,11 @@ +.omnibox { + + border: 1px solid red; + padding: 3px; +} + + +.surround { + border: 1px solid blue; + padding: 2px; +} diff --git a/src/app/omni-search-box/omni-search-box.component.html b/src/app/omni-search-box/omni-search-box.component.html new file mode 100644 index 0000000..9e7f42b --- /dev/null +++ b/src/app/omni-search-box/omni-search-box.component.html @@ -0,0 +1,48 @@ +{{optionsCount}} items in the config + +
+ + {{omniItem.mode.title}} + {{omniItem.modifier.title}} + {{omniItem.searchTerm}} + + + +
+
{{fullSearch.length}} items in the omni search
+
+
+ +
+ + + +
selectedOption:{{selectedOption}}
+ +
+
+ + +
selectedModifier:{{selectedModifier}}
+
+ +
+ + +
+
+ +
+
+ + +
diff --git a/src/app/omni-search-box/omni-search-box.component.spec.ts b/src/app/omni-search-box/omni-search-box.component.spec.ts new file mode 100644 index 0000000..26b541d --- /dev/null +++ b/src/app/omni-search-box/omni-search-box.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { OmniSearchBoxComponent } from './omni-search-box.component'; + +describe('OmniSearchBoxComponent', () => { + let component: OmniSearchBoxComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [OmniSearchBoxComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(OmniSearchBoxComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/omni-search-box/omni-search-box.component.ts b/src/app/omni-search-box/omni-search-box.component.ts new file mode 100644 index 0000000..7fddeea --- /dev/null +++ b/src/app/omni-search-box/omni-search-box.component.ts @@ -0,0 +1,145 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {SearchFragment, SolidSearchFragment} from "../../_models/searchFragment"; +import {ModifierItem} from "../../_models/modifier"; + +@Component({ + selector: 'app-omni-search-box', + templateUrl: './omni-search-box.component.html', + styleUrl: './omni-search-box.component.css' +}) +export class OmniSearchBoxComponent implements OnInit { + + @Input() searchConfig: SearchFragment[]; + + fullSearch: SolidSearchFragment[] = []; + + optionsCount: number = 0; + currentModifierList: ModifierItem[]; + modifiersListLength: number = 0 + + modifiersDisabled: boolean = true; + searchTextDisabled: boolean = true; + buttonDisabled: boolean = true; + + selectedOption: string; + selectedModifier: string; + searchText: string; + + newSearchItem: SolidSearchFragment; + + ngOnInit() { + + this.resetForm(); + + this.optionsCount = this.searchConfig.length; + + } + + /** + * Reset the form and variables for a new entry + */ + + resetForm() { + this.newSearchItem = this.emptyNewSearchItem(); + this.currentModifierList = []; + this.modifiersListLength = 0; + this.selectedOption = ''; + this.selectedModifier = ''; + this.searchText = '' + + this.modifiersDisabled = true; + this.searchTextDisabled = true; + this.buttonDisabled = true; + } + + /** + * Update the Mode Selection item, and build the operator list + */ + updateModeSelection() { + + this.newSearchItem = this.emptyNewSearchItem(); + this.currentModifierList = []; + + // Find the search Item and add it to the newSearchItem + + let foundMode = this.searchConfig.find((item) => { + + return item.mode.title === this.selectedOption + + }) + + // If we found an item, populate the newSearchItem, and get the modifiers for this selected item + if (foundMode) { + this.newSearchItem.mode = {...foundMode.mode} + + this.currentModifierList = [...foundMode.modifiers] + + this.modifiersListLength = this.currentModifierList.length + + this.modifiersDisabled = false; + } + + } + + /** + * Update the Modifier Selection and put it in the newSearchItem + */ + updateModifierSelection() { + + let foundModifier = this.currentModifierList.find((item) => { + + return item.title === this.selectedModifier; + + }); + + // If we find the correct modifier, populate the newSearchItem's modifier and enable the button and text entry + if (foundModifier) { + this.newSearchItem.modifier = {...foundModifier} + this.buttonDisabled = this.searchTextDisabled = false; + } + + } + + /** + * Search Text Filter, based on the mode text filter + */ + searchTextFilter() { + // todo: Some text / item filtering here + } + + /** + * AddButton click handler + */ + addClickHandler() { + + this.newSearchItem.searchTerm = this.searchText; + + this.fullSearch.push(this.newSearchItem); + + this.resetForm(); + } + + + /** + * Return an empty SolidSearchFragment + */ + emptyNewSearchItem(): SolidSearchFragment { + return { + mode: { + title: '', + accepted: '', + output: '', + hint: '', + }, + modifier: { + title: '', + accepted: '', + output: '', + hint: '', + }, + searchTerm: '' + + } + + } +} diff --git a/src/hammer.css b/src/hammer.css new file mode 100644 index 0000000..4e19761 --- /dev/null +++ b/src/hammer.css @@ -0,0 +1,2 @@ +@import url("https://fonts.googleapis.com/css?family=Roboto+Condensed");*,:after,:before{-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:0}body{font-family:Roboto Condensed,sans-serif;font-size:12px;height:100%;line-height:1.6;overflow-x:hidden}a{color:#5e81ac;text-decoration:none}a:hover{color:#666}a.active{color:#b48ead}ul{list-style:none}img{width:100%}.container{margin:auto;max-width:1100px;padding:0 2rem}hr{border-width:0;border-top:1px solid #2e3440;margin-bottom:2rem;margin-top:2.2rem}.flex{display:-webkit-box;display:-ms-flexbox;display:flex}.pad{padding:.5rem}.pad--1{padding:1rem}.pad--2{padding:2rem}.pad--3{padding:3rem}.pady{padding:.5rem 0}.pady--top{padding-top:.5rem}.pady--bottom{padding-bottom:.5rem}.pady--1{padding:1rem 0}.pady--2{padding:2rem 0}.pady--3{padding:3rem 0}.padx{padding:0 .5rem}.padx--right{padding-right:.5rem}.padx--left{padding-left:.5rem}.padx--1{padding:0 1rem}.padx--2{padding:0 2rem}.padx--3{padding:0 3rem}.grid{display:-webkit-box;display:flex;display:-ms-flexbox;-ms-flex-wrap:wrap;flex-wrap:wrap}.grid--1{grid-gap:1rem;display:grid;grid-template-columns:repeat(1,1fr)}.grid--2{grid-gap:1rem;display:grid;grid-template-columns:repeat(2,1fr)}.grid--3{grid-gap:1px;display:grid;grid-template-columns:repeat(3,1fr)}.grid--4{grid-gap:1rem;display:grid;grid-template-columns:repeat(4,1fr)}.row{margin-left:3px;margin-right:3px}.row:after,.row:before{content:" ";display:table}.row:after{clear:both}.column,.columns{margin-left:4%}.column:first-child,.columns:first-child{margin-left:0}.col-1{width:8.33333%}.col-2{width:16.66667%}.col-3{width:25%}.col-4{width:33.33333%}.col-5{width:41.66667%}.col-6{width:50%}.col-7{width:58.33333%}.col-8{width:66.66667%}.col-9{width:75%}.col-10{width:83.33333%}.col-11{width:91.66667%}.col-12{margin-left:0;width:100%}.col-1-3rd{width:32.666667%}.col-2-3rd{width:65.3333333333%}.col-half{width:48%}.offset-1-col{margin-left:8.66666666667%}.offset-2-col{margin-left:17.3333333333%}.offset-3-col{margin-left:26%}.offset-4-col{margin-left:34.6666666667%}.offset-5-col{margin-left:43.3333333333%}.offset-6-col{margin-left:52%}.offset-7-col{margin-left:60.6666666667%}.offset-8-col{margin-left:69.3333333333%}.offset-9-col{margin-left:78%}.offset-10-col{margin-left:86.6666666667%}.offset-11-col{margin-left:95.3333333333%}.offset-1-3rd-col{margin-left:34.6666666667%}.offset-2-3rd-col{margin-left:69.3333333333%}.offset-half-col{margin-left:52%}.x-large{font-size:4rem}.large,.x-large{line-height:1.2;margin-bottom:1rem}.large{font-size:3rem}.lead{font-size:1.5rem;margin-bottom:1rem}.text-primary{color:#5e81ac}.text-dark,.text-light{color:#2e3440}.text-success{color:#a3be8c}.text-danger{color:#bf616a}.text-highlight{color:#b48ead}.text-highlight2{color:#ebcb8b}.text-center{text-align:center}.text-right{text-align:right}.text-left{text-align:left}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-display1,h1{font-size:34px;font-weight:400;line-height:40px}.text-title,h3{font-size:20px;font-weight:400;line-height:28px}.text-subhead,h4{font-size:16px;font-weight:400;line-height:24px}.text-body2,h5{font-size:14px;font-weight:500;line-height:24px}.text-body1{font-size:14px;font-weight:400;line-height:20px}.text-caption{font-size:12px;font-weight:400;line-height:16px}.align-middle{vertical-align:middle!important}.all-center{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;justify-content:center;margin:auto;text-align:center;width:100%}.text-justify{text-align:justify!important}.text-nowrap{white-space:nowrap!important}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-bottom{vertical-align:bottom!important}.btn,.btn--slim{background:#e5e9f0;border:none;color:#333;cursor:pointer;display:inline-block;font-size:1rem;margin-right:.5rem;outline:none;padding:.4rem 1.3rem;-webkit-transition:opacity .2s ease-in;transition:opacity .2s ease-in}.btn--slim:disabled,.btn:disabled{-webkit-box-shadow:none;box-shadow:none;cursor:not-allowed;opacity:.6;pointer-events:none}.btn--slim:enabled:hover,.btn:enabled:hover{opacity:.8}.btn--slim{padding:.4rem}.btn-link{background:none;margin:0;padding:0}.btn-block{display:block;width:100%}.btn-sm,.btn-sm--slim{font-size:.8rem;margin-right:.2rem;padding:.3rem 1rem}.btn-sm--slim{padding:.3rem}.badge{border-radius:3px;display:inline-block;font-size:.6rem;margin:.3rem;padding:.1rem .4rem;text-align:center}.alert,.badge{background:#e5e9f0;color:#333}.alert{margin:1rem 0;opacity:.9;padding:.7rem}.alert-primary,.badge-primary,.bg-primary,.btn-primary{background:#5e81ac;color:#fff}.alert-light,.badge-light,.bg-light,.btn-light{background:#e5e9f0;color:#333}.alert-dark,.badge-dark,.bg-dark,.btn-dark{background:#2e3440;color:#fff}.alert-danger,.badge-danger,.bg-danger,.btn-danger{background:#bf616a;color:#fff}.alert-success,.badge-success,.bg-success,.btn-success{background:#a3be8c;color:#fff}.alert-white,.badge-white,.bg-white,.btn-white{background:#fff;border:1px solid #ccc;color:#333}.badge-light,.bg-light{border:1px solid #ccc}.table-responsive{display:block;overflow-x:auto;width:100%}table{border:0;border-collapse:collapse;margin-bottom:1rem;max-width:100%;width:100%}tr{border-top:1px solid #ccc}tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.04)}tbody td{border-top:1px solid #e1e1e1}.navbar{-webkit-box-pack:justify;-ms-flex-pack:justify;-webkit-box-align:center;-ms-flex-align:center;align-items:center;justify-content:space-between;margin-bottom:1rem;min-height:56px;opacity:.9;position:fixed;width:100%;z-index:2}.navbar,.navbar ul{display:-webkit-box;display:-ms-flexbox;display:flex}.navbar a{color:#fff;margin:0 .25rem;padding:.45rem}.navbar a:hover{color:#e5e9f0}.navbar .welcome span{margin-right:.6rem}.navbar .navbar-section{-webkit-box-align:center;-webkit-box-flex:1;-ms-flex-align:center;align-items:center;display:-webkit-box;display:flex;display:-ms-flexbox;-ms-flex:1 0 0;flex:1 0 0}.navbar .navbar-section:not(:first-child):last-child{-ms-flex-pack:end;-webkit-box-pack:end;justify-content:flex-end}.navbar .navbar-brand{font-size:200%;font-weight:700}header+div.container{height:calc(100vh - 56px);max-height:calc(100vh - 56px);overflow:auto;position:relative;top:56px}.m{margin:.5rem}.m--1{margin:1rem}.m--2{margin:2rem}.m--3{margin:3rem}.mb{margin-bottom:.1rem!important}.mb--1{margin-bottom:.2rem!important}.mb--2{margin-bottom:.4rem!important}.ml{margin-left:.1rem!important}.ml--1{margin-left:.2rem!important}.ml--2{margin-left:.4rem!important}.mr{margin-right:.1rem!important}.mr--1{margin-right:.2rem!important}.mr .mr-2{margin-right:.4rem!important}.mt{margin-top:.1rem!important}.mt--1{margin-top:.2rem!important}.mt--2{margin-top:.4rem!important}.mx{margin-left:.5rem!important;margin-right:.5rem!important}.mx--1{margin-left:1rem!important;margin-right:1rem!important}.mx--2{margin-left:2rem!important;margin-right:2rem!important}.my{margin:.5rem 0}.my--1{margin:1rem 0}.my--2{margin:2rem 0}.my--3{margin:3rem 0}.card,.card--slim{border:1px dotted #ccc;margin:.7rem 0;padding:1rem}.card--slim{padding:5px}.cardTitle{border-bottom:1px solid #eee;margin-bottom:15px}.cardV2{background-color:#fff;border-radius:4px;-webkit-box-shadow:0 0 4px 0 rgba(0,0,0,.14),0 3px 4px 0 rgba(0,0,0,.12),0 1px 5px 0 rgba(0,0,0,.2);box-shadow:0 0 4px 0 rgba(0,0,0,.14),0 3px 4px 0 rgba(0,0,0,.12),0 1px 5px 0 rgba(0,0,0,.2);min-width:0}.seemore{font-size:14px;font-weight:500}.cardLink{color:#2196f3;margin-top:10px}input{margin:.2rem 0}.form-text{color:#888;display:block;margin-top:.3rem}input[type=date],input[type=email],input[type=password],input[type=text],select,textarea{border:1px solid #ccc;display:block;padding:.1rem;width:100%}button,input[type=submit]{font:inherit}label,legend{display:block;font-weight:600;margin-bottom:.1rem}input[type=checkbox],input[type=radio]{display:inline}label>.label-body{background-color:#dcc894;display:inline-block;font-weight:400;margin-left:.5rem}table td,table th{padding:1rem;text-align:left}table th{background:var(--light-color)}.list{margin:.5rem 0}.list li{padding-bottom:.3rem}.dataRow{cursor:pointer}.modalWindow{background:rgba(0,0,0,.2);bottom:0;left:0;opacity:0;pointer-events:none;position:fixed;right:0;text-align:center;top:0;z-index:99999}.modalWindow:target{opacity:1;pointer-events:auto}.modalWindow>div{background:#fff;margin:10% auto;position:relative;width:500px}.alias{cursor:alias}.all-scroll{cursor:all-scroll}.auto{cursor:auto}.cell{cursor:cell}.context-menu{cursor:context-menu}.col-resize{cursor:col-resize}.copy{cursor:copy}.crosshair{cursor:crosshair}.default{cursor:default}.e-resize{cursor:e-resize}.ew-resize{cursor:ew-resize}.grab{cursor:-webkit-grab;cursor:grab}.grabbing{cursor:-webkit-grabbing;cursor:grabbing}.help{cursor:help}.move{cursor:move}.n-resize{cursor:n-resize}.ne-resize{cursor:ne-resize}.nesw-resize{cursor:nesw-resize}.ns-resize{cursor:ns-resize}.nw-resize{cursor:nw-resize}.nwse-resize{cursor:nwse-resize}.no-drop{cursor:no-drop}.none{cursor:none}.not-allowed{cursor:not-allowed}.pointer{cursor:pointer}.progress{cursor:progress}.row-resize{cursor:row-resize}.s-resize{cursor:s-resize}.se-resize{cursor:se-resize}.sw-resize{cursor:sw-resize}.text{cursor:text}.url{cursor:pointer}.w-resize{cursor:w-resize}.wait{cursor:wait}.zoom-in{cursor:-webkit-zoom-in;cursor:zoom-in}.zoom-out{cursor:-webkit-zoom-out;cursor:zoom-out}.panel{background-color:#fff;border-radius:0;-webkit-box-shadow:0 2px 2px 0 rgba(0,0,0,.16),0 0 2px 0 rgba(0,0,0,.12);box-shadow:0 2px 2px 0 rgba(0,0,0,.16),0 0 2px 0 rgba(0,0,0,.12);margin-bottom:20px;padding:15px}.panel:after,.panel:before{content:" ";display:table}.panel:after{clear:both}.glassy{-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(2px);background-color:rgba(31,28,23,.6)}@media (max-width:480px){.container{max-width:98vw;overflow-y:scroll;padding:0}}@media (max-height:480px){.navbar{min-height:36px}header+div.container{max-height:calc(100vh - 36px);position:relative;top:36px}.navbar .navbar-brand{font-size:125%;font-weight:700}}.nrccAlert a{color:#00ffa2} +/*# sourceMappingURL=hammer.css.map */ diff --git a/src/styles.css b/src/styles.css index 90d4ee0..dd3e7eb 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1 +1,2 @@ /* You can add global styles to this file, and also import other style files */ + diff --git a/structure.json b/structure.json new file mode 100644 index 0000000..d764241 --- /dev/null +++ b/structure.json @@ -0,0 +1,71 @@ +[ + { + "mode" : { + "title" : "Project", + "accepted" : ".+", + "output" : "Project title {{$modifier}} {{$value}}", + "hint" : "Project title" + }, + "modifiers" : [ + { + "title" : "Is", + "accepted" : "is", + "output" : "IS", + "hint" : "Is Operator" + }, + { + "title" : "Isn't", + "accepted" : "isn't", + "output" : "IS NOT", + "hint" : "Is Not Operator" + } + ] + + }, + { + "mode" : { + "title" : "Assignee", + "accepted" : ".+", + "output" : "Assignee {{$modifier}} {{$value}}", + "hint" : "Assignee ID" + }, + "modifiers" : [ + { + "title" : "Is", + "accepted" : "is", + "output" : "IS", + "hint" : "Is Operator" + }, + { + "title" : "Isn't", + "accepted" : "isn't", + "output" : "IS NOT", + "hint" : "Is Not Operator" + } + ] + + }, + { + "mode" : { + "title" : "Creation Date", + "accepted" : ".+", + "output" : "Assignee is {{}}", + "hint" : "Assignee ID" + }, + "modifiers" : [ + { + "title" : "Is", + "accepted" : "is", + "output" : "IS", + "hint" : "Is Operator" + }, + { + "title" : "Isn't", + "accepted" : "isn't", + "output" : "IS NOT", + "hint" : "Is Not Operator" + } + ] + + } +] diff --git a/tsconfig.json b/tsconfig.json index eb49734..abd88bb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,6 +18,7 @@ "target": "ES2022", "module": "ES2022", "useDefineForClassFields": false, + "strictPropertyInitialization": false, "lib": [ "ES2022", "dom"