diff --git a/client/web/compose/src/assets/PageBlocks/Geometry.png b/client/web/compose/src/assets/PageBlocks/Geometry.png new file mode 100644 index 000000000..30e96e93a Binary files /dev/null and b/client/web/compose/src/assets/PageBlocks/Geometry.png differ diff --git a/client/web/compose/src/assets/PageBlocks/index.js b/client/web/compose/src/assets/PageBlocks/index.js index 2b35a8e02..25e00db23 100644 --- a/client/web/compose/src/assets/PageBlocks/index.js +++ b/client/web/compose/src/assets/PageBlocks/index.js @@ -14,3 +14,4 @@ export const Comment = require('./Comment.png') export const Report = require('./Report.png') export const Progress = require('./Progress.png') export const Nylas = require('./Nylas.jpg') +export const Geometry = require('./Geometry.png') diff --git a/client/web/compose/src/components/Admin/Page/Builder/Selector.vue b/client/web/compose/src/components/Admin/Page/Builder/Selector.vue index 6143ce0a6..6638dd148 100644 --- a/client/web/compose/src/components/Admin/Page/Builder/Selector.vue +++ b/client/web/compose/src/components/Admin/Page/Builder/Selector.vue @@ -144,6 +144,11 @@ export default { block: new compose.PageBlockNylas(), image: images.Nylas, }, + { + label: this.$t('geometry.label'), + block: new compose.PageBlockGeometry(), + image: images.Geometry, + }, ], } }, diff --git a/client/web/compose/src/components/PageBlocks/GeometryBase.vue b/client/web/compose/src/components/PageBlocks/GeometryBase.vue new file mode 100644 index 000000000..3659cac82 --- /dev/null +++ b/client/web/compose/src/components/PageBlocks/GeometryBase.vue @@ -0,0 +1,233 @@ + + + + + + + + + + + + + + + + + + + diff --git a/client/web/compose/src/components/PageBlocks/GeometryConfigurator/Configurator.vue b/client/web/compose/src/components/PageBlocks/GeometryConfigurator/Configurator.vue new file mode 100644 index 000000000..4a6cca02d --- /dev/null +++ b/client/web/compose/src/components/PageBlocks/GeometryConfigurator/Configurator.vue @@ -0,0 +1,199 @@ + + + + + + + + {{ $t('geometry.mapHelpText') }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/web/compose/src/components/PageBlocks/GeometryConfigurator/FeedSource/configs/Record.vue b/client/web/compose/src/components/PageBlocks/GeometryConfigurator/FeedSource/configs/Record.vue new file mode 100644 index 000000000..89a760d79 --- /dev/null +++ b/client/web/compose/src/components/PageBlocks/GeometryConfigurator/FeedSource/configs/Record.vue @@ -0,0 +1,209 @@ + + + + + + + + + {{ $t('geometry.recordFeed.modulePlaceholder') }} + + + + + + + + + + + + + + + + + + {{ $t('geometry.recordFeed.titlePlaceholder') }} + + + + + + + + + + + + + + + + + + {{ $t('geometry.recordFeed.geometryFieldPlaceholder') }} + + + + + + + + + + + + + + + + diff --git a/client/web/compose/src/components/PageBlocks/GeometryConfigurator/FeedSource/configs/base.vue b/client/web/compose/src/components/PageBlocks/GeometryConfigurator/FeedSource/configs/base.vue new file mode 100644 index 000000000..f597ce7b5 --- /dev/null +++ b/client/web/compose/src/components/PageBlocks/GeometryConfigurator/FeedSource/configs/base.vue @@ -0,0 +1,36 @@ + diff --git a/client/web/compose/src/components/PageBlocks/GeometryConfigurator/FeedSource/configs/index.js b/client/web/compose/src/components/PageBlocks/GeometryConfigurator/FeedSource/configs/index.js new file mode 100644 index 000000000..b57597d15 --- /dev/null +++ b/client/web/compose/src/components/PageBlocks/GeometryConfigurator/FeedSource/configs/index.js @@ -0,0 +1 @@ +export { default as record } from './Record' diff --git a/client/web/compose/src/components/PageBlocks/GeometryConfigurator/FeedSource/index.vue b/client/web/compose/src/components/PageBlocks/GeometryConfigurator/FeedSource/index.vue new file mode 100644 index 000000000..a3aa43681 --- /dev/null +++ b/client/web/compose/src/components/PageBlocks/GeometryConfigurator/FeedSource/index.vue @@ -0,0 +1,117 @@ + + + + + + {{ $t('geometry.feedLabel') }} + + + + + + + + + + + + + + + + + + {{ $t('geometry.addSource') }} + + + + diff --git a/client/web/compose/src/components/PageBlocks/GeometryConfigurator/index.vue b/client/web/compose/src/components/PageBlocks/GeometryConfigurator/index.vue new file mode 100644 index 000000000..0463ae9e9 --- /dev/null +++ b/client/web/compose/src/components/PageBlocks/GeometryConfigurator/index.vue @@ -0,0 +1,35 @@ + + + + + + + + + + + + + diff --git a/client/web/compose/src/components/PageBlocks/base.vue b/client/web/compose/src/components/PageBlocks/base.vue index 6b1be800e..f3327c7bd 100644 --- a/client/web/compose/src/components/PageBlocks/base.vue +++ b/client/web/compose/src/components/PageBlocks/base.vue @@ -55,6 +55,12 @@ export default { required: false, default: '', }, + + editable: { + type: Boolean, + required: false, + default: false, + }, }, data () { diff --git a/client/web/compose/src/components/PageBlocks/index.js b/client/web/compose/src/components/PageBlocks/index.js index 334e5ec27..d71bb41d3 100644 --- a/client/web/compose/src/components/PageBlocks/index.js +++ b/client/web/compose/src/components/PageBlocks/index.js @@ -34,6 +34,8 @@ import ProgressBase from './ProgressBase' import ProgressConfigurator from './ProgressConfigurator' import NylasBase from './Nylas/NylasBase' import NylasConfigurator from './Nylas/NylasConfigurator' +import GeometryBase from './GeometryBase' +import GeometryConfigurator from './GeometryConfigurator/index' /** * List of all known page block components @@ -73,6 +75,8 @@ const Registry = { ProgressConfigurator, NylasBase, NylasConfigurator, + GeometryBase, + GeometryConfigurator, } const defaultMode = 'Base' diff --git a/client/web/compose/src/views/Admin/Pages/Builder.vue b/client/web/compose/src/views/Admin/Pages/Builder.vue index 9e26d7fed..9f7cf4e31 100644 --- a/client/web/compose/src/views/Admin/Pages/Builder.vue +++ b/client/web/compose/src/views/Admin/Pages/Builder.vue @@ -100,7 +100,7 @@ { + // Params for record fetching + const params = { + namespaceID: namespace.namespaceID, + moduleID: module.moduleID, + query: feed.options.prefilter, + } + + const events: Array = [] + return $ComposeAPI.recordList(params).then(({ set }) => { + return (set as Array<{ recordID: string }>) + // cast & freeze + .map(r => Object.freeze(new Record(module, r))) + }) +} diff --git a/lib/js/src/compose/types/page-block/geometry/feed.ts b/lib/js/src/compose/types/page-block/geometry/feed.ts new file mode 100644 index 000000000..c2f02258e --- /dev/null +++ b/lib/js/src/compose/types/page-block/geometry/feed.ts @@ -0,0 +1,56 @@ +import { Apply, NoID } from '../../../../cast' +import { IsOf } from '../../../../guards' + +interface FeedOptions { + color: string; + prefilter: string; + moduleID: string; + resource: string; + titleField: string; + geometryField: string; + displayMarker: boolean; + displayPolygon: boolean; +} + +export type FeedInput = Partial | Feed + +const defOptions = { + moduleID: NoID, + color: '#2f85cb', + prefilter: '', + resource: 'compose:record', + titleField: '', + geometryField: '', + displayMarker: false, + displayPolygon: true, +} + +/** + * Feed class represents an event feed for the given calendar + */ +export default class Feed { + public resource = 'compose:record' + public titleField = '' + public color = '#2f85cb' + public geometryField = '' + public displayMarker = false + public displayPolygon = true + public options: FeedOptions = { ...defOptions } + + constructor (i?: FeedInput) { + this.apply(i) + } + + apply (i?: FeedInput): void { + if (!i) return + + if (IsOf(i, 'resource')) { + Apply(this, i, String, 'resource', 'color', 'titleField', 'geometryField') + Apply(this, i, Boolean, 'displayMarker', 'displayPolygon') + + if (i.options) { + this.options = { ...this.options, ...i.options } + } + } + } +} diff --git a/lib/js/src/compose/types/page-block/geometry/index.ts b/lib/js/src/compose/types/page-block/geometry/index.ts new file mode 100644 index 000000000..1072afcac --- /dev/null +++ b/lib/js/src/compose/types/page-block/geometry/index.ts @@ -0,0 +1 @@ +export { PageBlockGeometry } from './page-block' diff --git a/lib/js/src/compose/types/page-block/geometry/page-block.ts b/lib/js/src/compose/types/page-block/geometry/page-block.ts new file mode 100644 index 000000000..56dc3dc7f --- /dev/null +++ b/lib/js/src/compose/types/page-block/geometry/page-block.ts @@ -0,0 +1,63 @@ +import { PageBlock, Registry } from '../base' +import { Apply } from '../../../../cast' +import Feed, { FeedInput } from './feed' +import { RecordFeed } from './feed-record' + +const kind = 'Geometry' + +type Bounds = number[][] + +interface Options { + defaultView: string; + center: Array; + feeds: Array; + zoomStarting: number; + zoomMin: number; + zoomMax: number; + bounds: Bounds | null; + lockBounds: boolean; +} + +const defaults: Readonly = Object.freeze({ + defaultView: '', + center: [35, -30], + feeds: [], + zoomStarting: 2, + zoomMin: 1, + zoomMax: 18, + bounds: null, + lockBounds: false, +}) + +export class PageBlockGeometry extends PageBlock { + readonly kind = kind + options: Options = { ...defaults } + + static feedResources = Object.freeze({ + record: 'compose:record', + }) + + constructor (i?: PageBlock | Partial) { + super(i) + this.applyOptions(i?.options as Partial) + } + + applyOptions (o?: Partial): void { + if (!o) return + + this.options.feeds = (o.feeds || []).map(f => new Feed(f)) + this.options.center = (o.center || []) + this.options.bounds = (o.bounds || null) + + Apply(this.options, o, Number, 'zoomStarting', 'zoomMin', 'zoomMax') + Apply(this.options, o, Boolean, 'lockBounds') + } + + static makeFeed (f?: FeedInput): Feed { + return new Feed(f) + } + + static RecordFeed = RecordFeed +} + +Registry.set(kind, PageBlockGeometry) diff --git a/lib/js/src/compose/types/page-block/geometry/resources.ts b/lib/js/src/compose/types/page-block/geometry/resources.ts new file mode 100644 index 000000000..e42511903 --- /dev/null +++ b/lib/js/src/compose/types/page-block/geometry/resources.ts @@ -0,0 +1,3 @@ +export const feedResources = { + record: 'compose:record', +} diff --git a/lib/js/src/compose/types/page-block/index.ts b/lib/js/src/compose/types/page-block/index.ts index c72deb99b..c982059ea 100644 --- a/lib/js/src/compose/types/page-block/index.ts +++ b/lib/js/src/compose/types/page-block/index.ts @@ -15,6 +15,8 @@ export { PageBlockComment } from './comment' export { PageBlockReport } from './report' export { PageBlockProgress } from './progress' export { PageBlockNylas } from './nylas' +export { PageBlockGeometry } from './geometry' + export function PageBlockMaker (i: { kind: string }): T { const PageBlockTemp = Registry.get(i.kind) diff --git a/locale/en/corteza-webapp-compose/block.yaml b/locale/en/corteza-webapp-compose/block.yaml index a1c70e86c..ec7b22b08 100644 --- a/locale/en/corteza-webapp-compose/block.yaml +++ b/locale/en/corteza-webapp-compose/block.yaml @@ -565,4 +565,34 @@ nylas: email: Email mailbox: Mailbox - +geometry: + label: Geometry + viewLabel: Geometry + feedLabel: Configure Sources + addSource: Add source + lock: Lock + mapHelpText: Move and scroll the map to the position that will be used as a default. You can also lock the position or zoom to prevent users from moving too far. + recordFeed: + moduleLabel: Select module + modulePlaceholder: (No module) + noMultiFields: Multi-value fields are currently not supported + optionLabel: Records + prefilterLabel: Prefilter sources + colorLabel: Marker color + geometryFieldLabel: Geometry field + titleLabel: Title + titlePlaceholder: Title + geometryFieldPlaceholder: Geometry field + displayMarker: Display marker + displayPolygon: Display polygon + centerLabel: Center + zoom: + zoomLabel: Zoom + zoomMinLabel: Zoom min + zoomMaxLabel: Zoom max + zoomStartingLabel: Zoom Starting + bounds: + boundsLabel: Bounds + lockBounds: Lock bounds + topLeft: Bounds top left + lowerRight: Bounds lower right diff --git a/locale/en/corteza-webapp-compose/field.yaml b/locale/en/corteza-webapp-compose/field.yaml index e89e000fd..f734987e5 100644 --- a/locale/en/corteza-webapp-compose/field.yaml +++ b/locale/en/corteza-webapp-compose/field.yaml @@ -96,6 +96,7 @@ kind: modulePlaceholder: Pick module queryFieldsLabel: Query fields on search moduleField: Module field + variantField: Variant field fieldFromModuleField: Label field from related module field pickField: Pick field suggestionPlaceholder: Start typing to search for records