Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an API to control certain Hajk features programmatically #1252

Closed
jacobwod opened this issue Dec 1, 2022 · 3 comments · Fixed by #1272
Closed

Add an API to control certain Hajk features programmatically #1252

jacobwod opened this issue Dec 1, 2022 · 3 comments · Fixed by #1272
Assignees
Labels
difficulty:complex Functionality is considered complex to port module:client/core Core functionality (not a plugin) new feature Request for adding/changing functionality
Milestone

Comments

@jacobwod
Copy link
Member

jacobwod commented Dec 1, 2022

Edit: Scroll down to read on about the methodology I'm thinking of for this issue.
A common use case for Hajk is to be embedded, as an IFRAME, on another website.

This has been known for a while, and the #192 Clean mode has been around ever since.

We now see an increasing demand for allowing programatic control of certain Hajk features, including:

  • zoom level (z param)
  • x and y coordinates (x and y)
  • search query string (q param)
  • layer visibility (l and gl params)

(Add more ideas!)


UPDATE 2023-02-08
How to enable

  • For now this functionality can only be activated on a per-map-basis using the setting in Admin UI
  • If you want to try it out on an entire instance, there's the possibility of adding ?enableAppStateInHash to your query string (e.g. https://localhost:3000/?enableAppStateInHash). This will force the functionality on all maps running on this instance, no matter the setting in Admin UI.

What it does

  • Hajk reacts to changes in hash portion of the URL string
  • Hajk keeps the hash updated
  • The following parameters work:
    • m (map config)
    • x, y (coordinates)
    • z (zoom level)
    • q (search query)
    • l (layers)
    • gl (sublayers [for group layers]
    • p (visible plugins)

DEMO
This demo also showcases how to embed (and control) Hajk programatically by modifying the hash part of IFRAME's SRC attribute.

Skarminspelning.2023-01-24.kl.14.55.43.mov

I will create a branch where we can work upon this, complete with a nice example with an embedded Hajk:

Skarminspelning.2022-12-01.kl.13.43.10.mov

Methodology

This feature can be broadly broken up into the following three components:

  1. Retrieve app state and show an updated list of hash params in URL
  2. Ensure that initial app state is derived from hash params too
  3. Act when any of the hash parameters' value changes

1. Retrieve app state and show an updated list of hash params in URL

This is quite easy as we already have a mechanism in place that reads out the "relevant" parts of app state and encodes them into a string: we do exactly this in AnchorModel.js. So the only thing needed is to update window.location.hash when any parameter changes.

2. Ensure that initial app state is derived from hash params too

This part is not consolidated, as opposed to part 1. Some parameter values are read in AppModel.js, some are read in their respective plugins (e.g. Search looks for values on q). And some are on even different places (index.js reads out the m parameter to know which map should be loaded).

3. Act when any of the hash parameters' value changes

This part is, just as part 2, not consolidated. Each layer has a listener where it looks out for its' own id in the list of l parameter. Search doesn't care about q other than for the initial load. And so on.

So we need to set up a lot of listeners to act upon relevant changes. Some will go into bindHandlers in AppModel.js (perhaps those related to the Map state, such as x, y and z. Some will go into layers. Some will go into respective plugins.

@jacobwod jacobwod added difficulty:complex Functionality is considered complex to port module:client/core Core functionality (not a plugin) new feature Request for adding/changing functionality labels Dec 1, 2022
@jacobwod jacobwod added this to the 3.x milestone Dec 1, 2022
@jacobwod jacobwod self-assigned this Dec 1, 2022
@jacobwod jacobwod changed the title Add an API to control certain Hajk features programatically Add an API to control certain Hajk features programmatically Dec 1, 2022
jacobwod added a commit that referenced this issue Dec 1, 2022
- Added an example page that embeds the locally running Hajk instance.
- Added two buttons to the example. They can be used to control the zoom level.
- Added a listener to App.js that will trigger onhashchange.
- Implemeted changing zoom level by changing the z-value of hash string.
@Hallbergs
Copy link
Member

Fantastic!!

@jacobwod
Copy link
Member Author

jacobwod commented Dec 6, 2022

We should really built in a state management into the URL hash.

Ooops, it's here already… what!? 😄

Skarminspelning.2022-12-06.kl.12.00.27.mov

jacobwod added a commit that referenced this issue Dec 9, 2022
@jacobwod
Copy link
Member Author

An example of what could be possible if we publish the globalObserver object:

Skarminspelning.2022-12-13.kl.13.06.48.mov

@jacobwod jacobwod linked a pull request Jan 24, 2023 that will close this issue
jacobwod added a commit that referenced this issue Jan 25, 2023
* Initial commit for #1252:
- Added an example page that embeds the locally running Hajk instance.
- Added two buttons to the example. They can be used to control the zoom level.
- Added a listener to App.js that will trigger onhashchange.
- Implemeted changing zoom level by changing the z-value of hash string.

* Added a generic text field that can be used to try out any hash params

* Major addition to index.js that we'll need to investigate:
- In order to allow embedding parent documents to read out some values from our Hajk instance, I had to add an object to the global object of Hajk.
- It's called 'hajkPublicApi', but it's not a real API (yet?). It only exposes the View's zoom limits.
- This can be expanded to a real public API with executable functions, or completely removed if we see problems with this approach.

* Quite a lot in here, but I'm basically done with 1 & 2 of the Methodology, as described in #1252.

* Added 'env: browser' to eslintrc in order to get rid of 'Unknown variable: window'

* Experimental: Added the OL Map object to the public Hajk API.

* Implemented search functionality in the hash API:
- The q paramter is updated when user types in the search bar
- If the map loads with the q parameter OR the q parameter's value changes, search is invoked.
- Added a debouncer to utils, can come in handy in other places too.

* Very much WIP, but I'll commit it for the record:
- AnchorModel now part of core, will get initated no matter the settings for Anchor plugin
- A asynchronous debounce helper takes care of not re-creating the URL too often.
- Anchor plugin needs some more work to work with the new solution. The main question that remains is: how should we treat the 'clean' parameter? If we update it in the URL immitiately, we would expect the map to get cleaned up and the Anchor view would disappear. But if we don't put 'clean' into the hash, it must be taken care of somewhere else, or else it will be overriden the next time user does something that triggers URL regeneration, so that 'clean's value will be set to false again. Fixable but we need to decide on this one.

* Cleaned up the AnchorModel API by making private properties private.

* The 'clean' param is only added to the AnchorView's URL, never to the hash in browser's URL field.

* URLs generated by anchor now only include the hash portion:
- Search params are used only internally but removed prior return
- We still support both search and hash params on init (as we merge them both in AppModel), but I see no need in generating the search params portion now, when we work with the hash portion under the hood.

* A little longer default delay on debounce

* Added support for x & y, plus new param: p:
- Changes to x & y trigger now View animation, just as z change does. This means we have a map that stores its' state in the URL's hash, including full compatibility with browser's history mechanism.
- Added a new param: p. It is meant to store the currently visible plugin(s). With this option, app's state now also includes the most recently shown plugins. They also follow with the link, so when URL is shared, the plugin visibility is also shared.

* Minor fix: separator must by specified when calling .split()

* Some comments and cleanups

* Layer history and toggling almost done:
- As usual, group layers are an issue. They toggel correctly in map, but the sublayers aren't selected correctly in LayerSwitcher. Will need to take a look into that too.
- But I'm commiting now, as this has grown pretty big already. So, two things:
  - l and gl parameters are now respected
  - THIS ENTIRE FUNCTIONALITY IS NOW BEHIND A FLAG IN ADMIN: enableAppStateInHash. I think it's neccessary to make it optional at this stage.

* Fixed functionality for Hajk's group layers:
- I think this is it. What a horrible mess… We must get rid of group layers

* I had a nice long comment explaining the mess. Forgot to put the code next to it, fixes here.

* Removed a log message

* Got rid of a (probably) unneeded timeout.

* Extended the embedded example page.

* Added `enableAppStateInHash` option to dotnet backend

* Fixed scroll-zoom "jump"-issue.

Zoom should be parsed as float - not int

* Fixed another zoom-parsing issue

* Fixed missing delay in debounce

Co-authored-by: Henrik Hallberg <43059093+Hallbergs@users.noreply.github.com>
@jacobwod jacobwod modified the milestones: 3.x, 3.12 Jan 25, 2023
jacobwod added a commit that referenced this issue Feb 6, 2023
- Without this we had a href=# in some places which rendered problematic with the new live hash params (the m-param's value changed which made the app to reload itself).
jacobwod added a commit that referenced this issue Feb 6, 2023
…:3000/\?enableAppStateInHash) will activate live params.
jacobwod added a commit that referenced this issue Feb 6, 2023
- MapSwitcher (if active) will change m in hash instead of query param. It still triggers a full reload as live reload of map would require substantial changes in the init process.
- AppModels listens for changes to m (e.g. when browser's back button is used) and acts upon change.
jacobwod added a commit that referenced this issue Feb 8, 2023
- I moved the await statement inside the state callback, so the UI state is updated instantly. Way better.
@jacobwod jacobwod closed this as completed Jun 9, 2023
jacobwod added a commit that referenced this issue Aug 25, 2023
…ow though since I need to investigate some strange behaviour in LayerGroupItem related to #1252.
jacobwod added a commit that referenced this issue Mar 7, 2024
* npm up

* Added the ENABLE_WEBSOCKETS variable to .env so we can easily turn this functionality on and off.

* Streamlining Halmstad's production branch, removed unused components.

* Changed browserslist to a simple 'defaults' only.

* Added an optional hyphen and centered the app load text.

* Deps bump for Backend

* Since the separation of V1 and V2 APIs, hajkLogger has been moved to utils.

* First step towards making Backend fully ESM-compatible:
- Necessary changes made in package.json
- Most other changes are due to a missing file extension in most imports.
- One small change was that __dirname isn't available when using ESM, so I changed the way we resolve path to the YAML specifications by using process.cwd(), as we do in other fs.* functions.
- I'm testing the VSCode-GitHub integration now, hence the branch name that does not follow our convention - sorry

* Removed Babel, etc:
- Removed Babel, including: 'compile' step in package.json and other commands, all dependencies and configuration file
- Replaced the 'compile' step with a basic copy of directory to dist/. The reasoning behind this is that it let's us continue using current Dockerfiles etc without any changes.
- Major cleanups in ESlint config. Seems good so far, check out the screenshot in this issue: https://github.com/hajkmap/Hajk/issues/1328\#issuecomment-1517542129
- Moved Prettier's config to an own file
- Prettier seems fine too, see screenshot above
- If this works as intended, we have a much cleaner toolchain. NodeJS 16+ is now required but it shouldn't be a major problem.

* Added missing definition, no idea how it got lost.

* New lock file after clean deps install. Should close #1328.

* Workaround the fact that __dirname isn't available in ESM. This pretty much closes #1328.

* Removed Windows Service references as they're not needed in our environment.

* Fixes to the WebSocket part that exists in this branch, its imports must also be converted to ESM of course.

* Ensure that the OpenApiValidator runs _after_ any async routes have been imported:
- This was discovered in #1332 but the problem first came up in #1309.
- OAV will only take care of routes that exists when the middleware runs. Hence, any async imports that haven't yet run will be unknown to the OAV and render a 404.
- This ugly setTimeout fix takes care of it but I'm open for a better solution (including discussing the future of OAV in our Backend).

* npm i

* Upgraded query-string that awaited the completition of #1328.

* I need to bump the version number across the product to easily keep track of running versions.

* This has grown pretty big since yesterday, time for an initial commit:
- WIP so expect a lot of warnings
- See #1360 for issue
- See also the README.md in the plugin's dir for more info on configuration.

* Now also passing down the coordinates of clicked point.

* Revert "Merge pull request #1346 from hajkmap/feature/1316-PermanentDrawerOption"

This reverts commit 38564d6, reversing
changes made to dbbc37e.

This will be re-merged once #1367 is closed.

* GeosuiteExport is not part of our toolset.

* We've successfully migrated Draw->Sketch so there's no need to include it in the build anymore.

* Fix for #1309: import of XMLParser fell behind in the V2 API after the split. Corrected now.

* Some significant dependencies bumped to latest versions:
- Most notably a couple of our dependencies now dropped support for Node 8 (which we don't support anyway), so shouldn't be breaking to us.

* Infoclick: allow for some common Markdown and URL characters inside the infoclick placeholder string:
- I've implemented both of the proposals from #1368 in this commit
- Closes #1368.

* A refined approach towards grabbing and replacing infoclick placeholders with values, closes #1368.

* Ensure that useMapService always evaluates to a boolean. Fix for 'new' API's loading of simpleMapConfig if no mapserviceBase is specified.

* Bumped version across the project to reflect the latest changes.

* Manually added CSS class definition for .material-icons:
- For reasons unknown, the definition has disappeard recently.
- We should look into this further, but to fix it as quickly as possible, I'm adding it manually for now.

* v.3.13.4

* Turns out the solution in 6b6429a was the correct one:
- According to the docs, adding the .material-icons class is exactly what has to be done.
- I'm doing another commit on it thought, to reflect the official structure inside the class, as specified in https://fontsource.org/docs/getting-started/material-icons

* Removed all references to the legacy 'shortcode' feature in FeatureInfo, also removed unused deps.

* Removed legacy/unused plugins:
- Draw
- Measure
- VTSearch

* Latest package-lock

* Used 'npx depcheck' to identify missing deps. Fixed by adding.

* Migrated from 'magic' module resolving to relative paths, this will be needed to further migrate to e.g. Vite anyway, so it's good to fix it right away.

* Version bump

* Succesfully upgraded a couple of deps:
- The upgrades here are verified to work
- Notable change is the major version bump on ESlint and Prettier. There have been some new defaults, among which new default for https://prettier.io/docs/en/options.html\#trailing-commas caused some confusion. The team has decided to disable it in our project, hence the change in .prettierrc.
- I also ran 'npx prettier -w .' so there are some minor changes to the formatting in various files.

* Fixed what was necessary to upgrade react-number-format. Didn't have time to properly replace this (as we seem to use it solely for the thousands separator) as I suggested elsewhere. Nevertheless, closes #1207.

* Upgraded IntroJS and deps to latest version.

* Upgraded MUI's DataGrid to v6

* Major upgrade: PDFjs.

* Added plugin-proposal-private-property-in-object to the list of dependencies in order to get rid of a warning from Babel

* Finalized the migration to consolidated loading approach, first started in #682:
- Ensured that the static approach (aka simpleMapConfig loading) works in the consolidated loading part of code
- Merged simpleMapConfig and simpleLayersConfig into a new file. Added keys needed for consolidated parser. Removed legacy files.
- This could still be rewritten to async/await rather than the current Promise callback hell way of doing things, but I leave it for now.

* Removed 'experimentalNewApi' from appConfig

* Rewrote initial loading to async/await, added new Error page:
- I got rid of the nested promise callbacks, now it's all in one try/catch
- A new error page is added. It's (hopefully) nice and clean. It also features a reload button that will attempt to reset the application's state by redirecting to '/'. Should this not work, there are more things to try out (parsing the documnent.location and removing searchParams manually).

* Version bump

* Much better placement of loading error box across different screen sizes.

* Make it possible to have a clean appConfig.json by emulating default values for some required properties in index.js.

* Version bump

* Ensure that the default API path in Swagger leads to V2.

* Typo

* Added the 'Simple Edit Workflow' to edit plugin, closes #1377.

* Version bump

* Hotfix to 7decf9c, #1377:
- Ensure that we auto-activate the modify tool if user goes backwards in the Simple Edit workflow.

* Version bump

* Get rid of warning about 'preset' not being part of active plugins: it's core nowadays, hence it can be hard-coded as active.

* Bug fix: the 'missing plugins' message was not so silent after all. Fixed. Shows only if it detects something.

* Deps bump

* Removed unused keys from default appConfig

* Removed unused dependency from hook deps array in Measurer.

* This has grown pretty big since yesterday, time for an initial commit:
- WIP so expect a lot of warnings
- See #1360 for issue
- See also the README.md in the plugin's dir for more info on configuration.

* Now also passing down the coordinates of clicked point.

* New approach towards setting layers' visibility. Taking a break for now though since I need to investigate some strange behaviour in LayerGroupItem related to #1252.

* Added two comments about lines modified in #1304 to fix #1291 that don't do much.

* Some progress once I gave up the sublayers functionality:
- Toggeling a sublayer will toggle all sublayers under the same layer. This is a trade-off.
- Some nice functionality added, such as the layer toggler, better listing including nice icon (from infoclick config), etc.

* init commit, changed logic that prev removed drawerButtons

* minor fix

* Major additions:
- UI revised
- Quick toggle buttons for often accessed layers
- and more…

* Added the optional bgColor setter for features in MapClickViewer, closes #1385.

* v3.13.10

* Revert "Revert "Merge pull request #1346 from hajkmap/feature/1316-PermanentDrawerOption""

This reverts commit 55b01ed.

* v3.13.11

* Addded the CHANGELOG.md with some initial (incomplete) entries.

* CHANGELOG additions

* CHANGELOG.md is up-to-date with the current state in hstd-main.

* Upgraded deps.

* Corrected the UI, added info that shows when no features are returned. Other fixes.

* Updated changelog

* The QuickLayer toggle buttons now show both icon and caption.

* Multiple additions:
- Features that belong to the same layer (but different sublayers) are now shown next to each other.
- The control whether the layer actually exists in OLMap or not happens outside the FeatureItem view. This means that the component could be simplified by removing unneccesary checks that were previously required.
- UI changes, hopefully for the better.
- Some preparations for sending the GetFeatureInfo for specific layer (i.e. auto-trigger MapClickViewer). This will however require more work and refactoring in MapClickModel.

* Added a nice little snackbar that informs user to click in map to select a property.

* Made it easier to toggle layer visibility by allowing click on the entire list item

* Added a help dialog that explains how to use this tool.

* Terminology change after dialog with reference group.

* Info about #1403 in changelog

* v3.13.12, see CHANGELOG.md for more info

* QuickLayerToggleButtons correctly reflect the initial layer visibility state.

* Better help desc, according to focus group.

* Fix to stop propagation in the help dialog.

* Added the Report Dialog:
- For each property that got matched, users can now make a selection of layers that have been 'controlled' (in some way, depending on the procedure).
- Layers with ticked checkboxes will now appear in a separate Dialog window, called Report Dialog.
- From here, users will be able to select the text (I'll probably add some copy-to-clipboard soon) and paste into their reports/other systems.

* Minor fixes

* The Report dialog has been greatly enhanced with a copy-to-clipboard function that copies both as plain text and rich text (suitable for e.g. pasting into Word).

* Typo

* Updates in CHANGELOG

* Added a script to ease deps install.

* The Report dialog looks better, the list now has bullets too.

* Removed the 360px width limit in MapClickViewer lists. Closes #1411.

* Added note on #1411 to changelog.

* v.3.13.13

* The `/ad/findCommonADGroupsForUsers` endpoint works again. Closes #1415.

* v.3.13.14

* Made the layer ids visible in Admins layer manager list.

* Initial changes required to expand this plugin with another view - Digital Plans:
- As the requirements have changed a bit, I'm not making some refactoring. The plan is to expand the plugin with a new view that will show
  another list of properties, different from the list created from the initial request ('check layer').
- I'm not implementing the new view yet, as it's not really clear how we want to display it. But we're ready from now on.

* Rough WIP: added Tabs to separate the check layer features from digital plan features. This will need refactoring, comming up soon.

* Major refactoring after a meeting with the client: this way it'll be easier to maintain and expand in the future. Nothing new in the UI since the last commit.

* Big commit with the following:
- Completely rewritten the way that we render list of check layer items. In addition to visual changes, there's a new field available that allows users to write simple notations on each item, that will get transferred to the final report.
- I've started the initial implementation of showing those notes in the final report. I'm not done yet though as I await response from the client regarding which form this should be presented in.
- Speaking of response from client: it turns out that they'd want to use this tool to show another report that showcases which digital layers affect the clicked point. This led me to rewrite and add more parts to the plugin. The new concept is called Digital Plans and shows up as a second tab (next to the Check Layer items). The new Digital Plans check will become a part of the final report as well, but I'm awaiting feedback here too.

* Preparations for the first Public Beta of PropertyChecker:
- Cleaned up the report generator, ensured same output to different formats.
- Removed some logs messages.
- Other fixes.

* Upgraded deps in Client and Backend

* v3.13.15: First Public Beta of Property Checker

* Fixes a bug where GetFeatureInfo used wrong resolution.

* v3.13.16

* Tightened security in backend: if AD_LOOKUP_ACTIVE is 'false' but RESTRICT_ADMIN_ACCESS_TO_AD_GROUPS has a value, access to admin-only endpoints will be restricted (to everyone).

* v3.13.17

* v3.13.17

* Avoid float values in z param in URL hash, closes #1422.

* Added #1422 to the changelog.

* Added an option to Admin that allows setting autofocus in Search field on app load, closes #1424.

* v3.13.18

* Fix to #1257: ensure that even non-togglable groups are marked with bold font. Plus a minor change from 'style' to 'sx' in one element.

* Bump to v3.13.19

* Upgraded deps, among those react-markdown, which required some work. Closes #1425.

* Changes in changelog

* Don't render tabs in LayerSwitcher if no layers are to be shown inside, closes #1431.

* Support for the EPSG:5847 in Admin UI. Keep in mind that you still need to add appropriate projection definitions to each map config.

* v3.13.20

* The tools list in Admin is now refreshed: only current tools are available, sorting is alphabetical.

* WMSLayer's onImageError should also result in the load failed indicator in LayerSwitcher.

* Sorting in PropertyChecker now takes layer's caption into account.

* Show layer load error indicator in PropertyChecker's layers list, if loading failed.

* Changelog

* Merged two new PRs from upstream

* Fix for #1439 and its LdapService: 'this' refers to something else than what could be expected when inside an instance of ActiveDirectory. Let's save and use a variable reference to the logger.

* Added #1439 to the changelog

* Backend: show 403 Forbidden rather than 500 if access was not allowed:
- I created a custom error class, AccessError, in order to distinguish access errors from the rest in our handleStandardResponse().
- The Service will now send an AccessError if the reason is that the authenticated user lacks autorizaton to a certain resource.

* Updated changelog

* Updated deps in Client and Backend

* Fixed some irritating whitespace formatting mismatches between current and older ESlint versions.

* Prettier fixes in Backend too.

* Cleanups in PropertyChecker to get rid of some warnings.

* A whole lot of refactoring. The plugin is growing, I need to separate the views.

* Important additions, implemented a first view of digital plans. Some work remains, such as adding checkboxes etc (as in the Check Layers view), the Report and so on. But it's a good start.

* PropertyChecker: added an option to disable the Generate Report functionality. Needed when we want to release this tool to a broader public audience.

* Major additions to PropertyChecker, main feature is the new Digital Plans view and correpsonding Report.

* Replaced all hard-coded attribute names with values retrived from Admin. This will aid anyone wanting to adapt it into their own setup.

* PropertyChecker: important improvment - clicks that'd give results from more than 1 property are disallowed. Also, marker feature is added only for the property layer, not digital plans layer.

* Updated changelog for v3.13.22

* Warning fix

* PropertyChecker: Fix to hide unneeded UI elements when enableDigitalPlansReport is false.

* Missed two files in v3.13.22

* Prepared the v3.13.23 release.

* Implemented auto-rotation (to an admin-specified value) for background layers. Closes #1451.

* Release v3.13.24

* Added recent changes, merged from develop, to the changelog.

* The reinstall dependencies script now also runs audit fix.

* Updated deps, version number

* Fixed missing keys in Docker's appConfig.json

* Revert Halmstad-specific branding

* Updated CHANGELOG to reflect recent merge

---------

Co-authored-by: OlofSvahnVbg <svahnolof.vbg@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
difficulty:complex Functionality is considered complex to port module:client/core Core functionality (not a plugin) new feature Request for adding/changing functionality
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants