{
    "version": "https://jsonfeed.org/version/1",
    "title": "micodify",
    "description": "",
    "home_page_url": "https://micodify.de",
    "feed_url": "https://micodify.de/feed.json",
    "user_comment": "",
    "author": {
        "name": "Maik Michel"
    },
    "items": [
        {
            "id": "https://micodify.de/dockapex-dockerize-your-world-oracle-apex-stack/",
            "url": "https://micodify.de/dockapex-dockerize-your-world-oracle-apex-stack/",
            "title": "dockAPEX - Dockerize your world Oracle APEX Stack",
            "summary": "Numerous articles about Docker and Oracle APEX are floating around the web&hellip;",
            "content_html": "\n  <p>\n    Numerous articles about Docker and Oracle APEX are floating around the web - this article is intended to add to the topic from a slightly different perspective. I started developing <strong>dockAPEX</strong>&nbsp;a long time ago. Back then, the tool was still called <strong>dockAWEX</strong>&nbsp;because I was able to provision a complete Docker-based environment in AWS with the help of <em>docker-machine</em>&nbsp;- which unfortunately no longer exists nowadays. Today, the tool is called <strong>dockAPEX</strong>&nbsp;and essentially consists of a single shell script. But what exactly is it all about?<br><br>Basically, the structure of an Oracle APEX environment always looks quite similar: We need a <strong>database</strong>, <strong>APEX</strong> must be installed, the <strong>Oracle REST Data Service (ORDS)</strong>&nbsp;is required - and depending on the setup, an application server or a proxy server is added. Often <strong>APEXOfficePrint (AOP)</strong>&nbsp;is also included to generate PDF documents or other formats.<br><br>The differences usually lie in the details - for example, whether it is a development, test or production environment. Or whether all components are to run on a single host or are distributed across several. However, the basic setup always remains similar - depending on the respective project or the customer's requirements.\n  </p>\n\n    <figure class=\"post__image post__image--center\">\n      <img loading=\"lazy\" src=\"https://micodify.de/media/posts/59/Containers.png\" height=\"473\" width=\"751\" alt=\"\"  sizes=\"(max-width: 1024px) 100vw, 1024px\" srcset=\"https://micodify.de/media/posts/59/responsive/Containers-xs.png 300w ,https://micodify.de/media/posts/59/responsive/Containers-sm.png 480w ,https://micodify.de/media/posts/59/responsive/Containers-md.png 768w ,https://micodify.de/media/posts/59/responsive/Containers-lg.png 1024w\">\n      \n    </figure>\n\n  <p>\n    With <strong>dockAPEX</strong>, the preferred environment can be easily configured using a single <strong>environment file</strong>. Depending on which containers or services are required - such as <strong>Database</strong>, <strong>APEX</strong>, <strong>ORDS</strong>, <strong>Tomcat</strong>, <strong>AOP</strong> or <strong>Traefik</strong>&nbsp;- the respective component is simply set to <code>true</code> in the environment file using a switch.<br><br>Additional settings such as <strong>Versions</strong>, <strong>Patchsets</strong>&nbsp;or other <strong>Parameters for fine-tuning</strong>&nbsp;are also defined centrally at this point. This allows the setup to be flexible and project-specific.<br><br>An example: If the database service is supposed to run as a container, you can also specify in the environment file that a <strong>second PDB is to be additionally created or cloned</strong>. This second PDB can then be ideally used as a <strong>build or test environment</strong>&nbsp;- for example, to check deployments in advance or to apply new releases in a controlled way.\n  </p>\n\n    <h2 id=\"installation-so-how-do-you-get-started\">\n      Installation - so how do you get started?\n    </h2>\n\n  <p>\n    <strong>dockAPEX</strong>&nbsp;is <strong>open source</strong>&nbsp;and is provided on <strong>GitHub</strong>&nbsp;(<a href=\"https://github.com/MaikMichel/dockAPEX\" target=\"_blank\">https://github.com/MaikMichel/dockAPEX</a>). It is recommended to integrate the tool directly into your own project as a <strong>Git submodule</strong>&nbsp;- so you can easily pull the latest version directly from the repository at any time.<br><br>In this way, GitHub acts more or less like a <strong>Package Manage</strong>r, similar to what you know from the <strong>Node.js world with NPM</strong>. The tool is kept cleanly versioned and always up-to-date without losing track of local customizations.\n  </p>\n<pre class=\" language-bash\"><code># creates the instancefolder, makes it a git repo and adds dockAPEX as submodul\n$ curl -sS https://raw.githubusercontent.com/MaikMichel/dockAPEX/main/install.sh | bash -s </code></pre>\n\n  <p>\n    The manual way:\n  </p>\n<pre class=\" language-bash\"><code># create a folder belonging to your project\n$ mkdir -p demo\n\n# change into it\n$ cd demo\n\n# make the folder a git project / repo\n$ git init\n\n# clone dockAPEX as submodule\"\n$ git submodule add https://github.com/MaikMichel/dockAPEX.git .dockAPEX</code></pre>\n\n  <p>\n    For operation, <strong>dockAPEX</strong>&nbsp;requires two central files: an <strong>environment file</strong>&nbsp;and a <strong>password file</strong>. The passwords stored in these files are later made available in the respective containers as <strong>secrets</strong>. Of course, these files can also be created manually - but it is much easier with the following command:<br>\n  </p>\n<pre class=\" language-bash\"><code>.dockapex/dpex.sh demo.env generate</code></pre>\n\n  <p>\n    This automatically creates two files: <code>demo.env</code>&nbsp;for the configuration and <code>demo.sec</code>&nbsp;for the passwords. Both contain all relevant parameters that can be adjusted as required. At the same time, the *.sec file is also added directly to <code>.gitignore</code>&nbsp;- because sensitive data has no place in version management.<br><br>For a local development environment, it is often sufficient to simply activate <strong>DB</strong>, <strong>APEX</strong>&nbsp;and <strong>ORDS</strong>&nbsp;in the environment file - and a complete environment is ready for development.\n  </p>\n<pre class=\" language-bash\"><code># ========================================================\n#  _____       _______       ____           _____ ______\n# |  __ \\   /\\|__   __|/\\   |  _ \\   /\\    / ____|  ____|\n# | |  | | /  \\  | |  /  \\  | |_) | /  \\  | (___ | |__\n# | |  | |/ /\\ \\ | | / /\\ \\ |  _ &lt; / /\\ \\  \\___ \\|  __|\n# | |__| / ____ \\| |/ ____ \\| |_) / ____ \\ ____) | |____\n# |_____/_/    \\_\\_/_/    \\_\\____/_/    \\_\\_____/|______|\n#\n# ========================================================\n\n# Enable DB Service\nDB=true\n\n# Vars to connect to and / or create the service\nDB_USER=\"sys\"\nDB_HOST=\"database\"\nDB_PORT=\"1521\"\nDB_NAME=\"freepdb1\"\n\n# ========================================================\n#           _____  ________   __\n#     /\\   |  __ \\|  ____\\ \\ / /\n#    /  \\  | |__) | |__   \\ V /\n#   / /\\ \\ |  ___/|  __|   &gt; &lt;\n#  / ____ \\| |    | |____ / . \\\n# /_/    \\_\\_|    |______/_/ \\_\\\n#\n# ========================================================\n\n# Enable APEX Service\nAPEX=true\n\n# Build ARGS, when build the image by your own\nAPEX_VERSION=24.2\nAPEX_FULL_VERSION=24.2.0\nAPEX_URL=\"https://download.oracle.com/otn_software/apex/apex_${APEX_VERSION}_en.zip\"\n\n...\n\n#   ____  _____  _____   _____\n#  / __ \\|  __ \\|  __ \\ / ____|\n# | |  | | |__) | |  | | (___\n# | |  | |  _  /| |  | |\\___ \\\n# | |__| | | \\ \\| |__| |____) |\n#  \\____/|_|  \\_\\_____/|_____/\n#\n# ========================================================\nORDS=true\n\n# BUILD ARGS\nORDS_FULL_VERSION=\"24.4.0.345.1601\"\nORDS_VERSION=\"24.4.0\"\nORDS_URL=\"https://download.oracle.com/otn_software/java/ords/ords-${ORDS_FULL_VERSION}.zip\"\n\nORDS_PORT=\"8080\"\n\n...\n</code></pre>\n\n  <p>\n    Especially in local development, it is also worth activating the <strong>second PDB</strong>. This can be used for <strong>deployment tests</strong>, for example, without affecting the main environment. ORDS then automatically controls this additional PDB via a separate path - for example via:&nbsp;<code>http://localhost:8080/ords/build/…</code><br>This makes it easy to distinguish between regular development operations and test deployments - without the need for separate setups or additional infrastructure.\n  </p>\n<pre class=\" language-bash\"><code>...\n# Do we need a copy of PDB1?\nAPEX_SECND_PDB=true\nAPEX_FIRST_PDB_TBL_SPACE=\"/opt/oracle/oradata/FREE/FREEPDB1\"\nAPEX_SECND_PDB_TBL_SPACE=\"/opt/oracle/oradata/FREE/FREEPDB2\"\nAPEX_SECND_PDB_POOL_NAME=\"build\"\nAPEX_SECND_PDB_NAME=\"freepdb2\"\n...</code></pre>\n\n  <p>\n    If you have the option of configuring a <strong>subdomain via a DynDNS service</strong>, another practical solution opens up: the use of a <strong>reverse proxy with Traefik</strong>.<br><br><strong>Traefik</strong> takes over the routing and makes the environment conveniently accessible via a speaking URL. After installing <strong>ORDS</strong>, the <strong>IP address of the caller is automatically stored in the DynDNS service</strong>&nbsp;via <code>curl</code>, so that the domain always points to the correct instance - without any manual readjustment.\n  </p>\n<pre class=\" language-bash\"><code>#  _______ _____            ______ ______ _____ _  __\n# |__   __|  __ \\     /\\   |  ____|  ____|_   _| |/ /\n#    | |  | |__) |   /  \\  | |__  | |__    | | | ' /\n#    | |  |  _  /   / /\\ \\ |  __| |  __|   | | |  &lt;\n#    | |  | | \\ \\  / ____ \\| |____| |     _| |_| . \\\n#    |_|  |_|  \\_\\/_/    \\_\\______|_|    |_____|_|\\_\\\n#\n# ========================================================\nTRAEFIK=true\nTRAEFIK_VERSION=3.3\nTRAEFIK_DEFAULT_ROUTE=\"ords/r/dockapex/demo\"\nTRAEFIK_DOMAIN=\"dockapex.examplde.com\"\nTRAEFIK_DASHBOARD=true</code></pre>\n\n  <p>\n    If, for example, you use a <strong>database service in the Oracle Cloud Infrastructure (OCI)</strong>&nbsp;or operate your own <strong>dedicated database server</strong>, the database container does not necessarily have to be started. In this case, you can simply set the DB service to <code>false</code>&nbsp;in the <strong>environment file</strong> and instead specify the <strong>connection parameters to the external database directly</strong>.<br><br>This means that the setup remains flexible and can be easily adapted to existing infrastructure - whether local, in the cloud or hybrid.\n  </p>\n<pre class=\" language-bash\"><code># Enable DB Service\nDB=false\n\n# Vars to connect to and / or create the service\nDB_USER=\"sys\"\nDB_HOST=\"1.2.3.4\" # just an example IP\nDB_PORT=\"1521\"\nDB_NAME=\"your.service.name.is.here\"</code></pre>\n\n    <h2 id=\"how-does-it-work\">\n      How does it work?\n    </h2>\n\n  <p>\n    In essence, <strong>dockAPEX</strong>&nbsp;uses the possibilities of <strong>Docker Compose</strong>&nbsp;- more precisely the function of combining several <strong>Compose files</strong>&nbsp;with each other. A complete configuration is dynamically assembled based on the information in the <strong>environment file</strong>. This creates a flexible setup that can be controlled modularly.<br><br>Every instruction or command that is executed after the environment file is passed on <strong>one-to-one</strong>&nbsp;to <code>docker-compose</code>. This means that anyone already working with Docker Compose will find their way around immediately - just with the addition of convenient control by dockAPEX.\n  </p>\n<pre class=\" language-bash\"><code>.dockAPEX/dpex.sh demo.env logs -f\n</code></pre>\n\n  <p>\n    If you want to view the <strong>completely assembled Docker Compose configuration</strong>, a simple command is sufficient:\n  </p>\n<pre class=\" language-bash\"><code>.dockAPEX/dpex.sh demo.env config</code></pre>\n\n  <p>\n    This displays the effective compose file - i.e. the result of all combined configuration blocks. Here too, dockAPEX remains very close to the <strong>Docker Compose</strong>&nbsp;standards.<br><br>Most commands are passed through directly, but there are a few <strong>dockAPEX-specific extensions</strong>:\n  </p>\n\n  <ul>\n    <li><code>genfiles</code>&nbsp;- as mentioned above, this command automatically creates the environment and password files.</li><li><code>clear</code>&nbsp;- ensures a complete cleanup process: <strong>stop containers</strong>, <strong>delete containers</strong>, <strong>remove images</strong>, <strong>delete volumes</strong>&nbsp;- effectively a hard reset for the environment.</li>\n  </ul>\n\n  <p>\n    And if you get stuck: Simply call the command <strong>without arguments</strong> - then a <strong>help overview with all available options</strong> appears automatically.\n  </p>\n<pre class=\" language-bash\"><code>Please call script by using all params in this order!\n    .dockAPEX/dpex.sh env-file genfiles|clear|compose-comand\n-----------------------------------------------------\n\n  commands: \n    genfile &gt; creates an .env and .sec file based on all known vars\n    clear   &gt; removes all container and images, prunes allocated space\n\n    compose-comand   &gt; redirected to docker-compose\n\n-----------------------------------------------------\n\n  examples: \n    .dockAPEX/dpex.sh demo.env genfiles\n    .dockAPEX/dpex.sh demo.env up --build --detach\n    .dockAPEX/dpex.sh demo.env ps -a\n    .dockAPEX/dpex.sh demo.env down\n    .dockAPEX/dpex.sh demo.env clear\n\n-----------------------------------------------------</code></pre>\n\n  <p>\n    The individual <strong>components or services</strong>&nbsp;are - if activated - <strong>dependent on each other</strong>. This means that <strong>APEX only starts</strong>&nbsp;when the <strong>database reports the status <code>healthy</code></strong>. Similarly, <strong>ORDS waits for APEX</strong>&nbsp;before starting itself - of course only if APEX is also part of the environment.<br><br>This <strong>clean start sequence</strong>&nbsp;ensures that each component only starts when its respective <strong>dependencies are fully ready and functional</strong>. For example, the database can first perform an update or setup at startup before other containers become dependent on it. This makes the entire setup more <strong>stable, robust and error-resistant</strong>&nbsp;- especially in the case of automated deployments or frequent restarts of the environment.\n  </p>\n\n    <h2 id=\"updating-components\">\n      Updating components\n    </h2>\n\n  <p>\n    The special feature of this concept is that <strong>APEX</strong>, <strong>ORDS</strong>&nbsp;and <strong>AOP</strong>&nbsp;each have a dedicated <strong>update mechanism</strong>. This checks directly in the target database which versions are already installed and takes care of installing or updating them if necessary.<br>When the <strong>APEX container</strong>&nbsp;is started, for example, it checks whether <strong>APEX</strong>&nbsp;already exists in the database. If so, it also checks whether an <strong>update to the version</strong>&nbsp;specified in the environment file is required. The same applies to <strong>ORDS</strong>&nbsp;and the <strong>database components of AOP</strong>.<br><br>So if you now want to update APEX in your DB, it is sufficient to stop the container and start it with a new version.\n  </p>\n<pre class=\" language-bash\"><code># stop and remove apex service\n.dockAPEX/dpex.sh demo.env down apex\n\n# remove apex image (apex_(APEX_FULL_VERSION):demo)\ndocker rmi apex_24.2.3:demo\n\n# now modifiy the version identifier and optionally update the URL to the patchset\n\n# and just build and start the service\n.dockAPEX/dpex.sh demo.env up apex --build --detach\n</code></pre>\n\n    <blockquote class=\"blockquote\">\n      <strong>IMPORTANT</strong>: The solution is open source and completely sufficient for smaller productive applications. You still need to know what you are doing. No support is available here.\n    </blockquote>",
            "image": "https://micodify.de/media/posts/59/venti-views-1cqIcrWFQBI-unsplash.jpg",
            "author": {
                "name": "Maik Michel"
            },
            "tags": [
                   "Oracle",
                   "Docker",
                   "Database",
                   "APEX"
            ],
            "date_published": "2025-03-18T12:22:27+01:00",
            "date_modified": "2025-03-18T12:22:27+01:00"
        },
        {
            "id": "https://micodify.de/react-on-rds-pagchange/",
            "url": "https://micodify.de/react-on-rds-pagchange/",
            "title": "React on RDS Page Change",
            "summary": "With the RDS and the region template tab container, APEX offers two&hellip;",
            "content_html": "\n  <p>\n    With the RDS and the region template tab container, APEX offers two options for grouping regions in such a way that they can be stacked on top of each other to save space. The RDS also has the option of showing all contained regions at once. I like to make use of both options. In the article (here) I had already described how to react to the activation of the individual tabs. This article will now focus on how to react to the change of tabs in an RDS.\n  </p>\n\n    <figure class=\"post__image post__image--center\">\n      <img loading=\"lazy\" src=\"https://micodify.de/media/posts/58/record-default-behaviour-rds.gif\" height=\"1154\" width=\"1166\" alt=\"Recording default behavior of a RDS\" >\n      \n    </figure>\n\n  <p>\n    Unlike with tab containers, the titles of the respective tabs are always displayed in an RDS, or are always hidden. Sounds strange. What I mean is, if I decide to show the special tab <strong>ShowAll</strong>, I want the regions to show all their titles. But as soon as I click on a \"normal\" tab, I don't want the title to be displayed. Why? Well, from a UI point of view, the title of the region would now be displayed twice. Once on the tab and once as a region title. I think that's a bit of a duplicate and doesn't look good either.<br>\n  </p>\n\n  <p>\n    If you look at the DOM and define hard in APEX that a region header should be hidden, you will find the class <code>t-Region--hideHeader</code> in the div of the region. This means that whenever this class is present, the title is not visible. In addition, we find the ID of the first list element in the DOM. This is <code>SHOW_ALL_tab</code>. Each time this is activated, the element has the class <code>apex-rds-selected</code>.\n<br>\n<br>We have to check whether the class <code>apex-rds-selected</code>&nbsp;is present in the element <code>#SHOW_ALL_tab</code> on the change event or not and use the class <code>t-Region--hideHeader</code> to hide the titles of the regions. For this I use a bit of Knockout.js and jQuery\n  </p>\n<pre class=\" language-javascript\"><code>// this will hold the model\nvar viewModel = {};\n\n// check if given element is using the class given\nfunction hasClass(elemID, className) {\n  return (' ' + document.getElementById(elemID).className + ' ').indexOf(' ' + className+ ' ') &gt; -1;\n}\n\n\nfunction initPage () {\n  // whenever the RDS is clicked, we check whether the region title should be visible\n  // this has the binding defined in the custom attributes: data-bind=\"class: hideRegionHeader”\n  apex.jQuery('.apex-rds').data('onRegionChange', function(mode, activeTab) {\n    viewModel.hideRegionHeader(hasClass(\"SHOW_ALL_tab\", 'apex-rds-selected') ? \"\" : \"t-Region--hideHeader\");\n  });\n\n  // define the model\n  viewModel = {\n    hideRegionHeader: ko.observable(hasClass(\"SHOW_ALL_tab\", 'apex-rds-selected') ? \"\" : \"t-Region--hideHeader\")\n  }\n\n  // activate binding with knockout\n  ko.applyBindings(viewModel, document.querySelector(\"html\"));\n}\n</code></pre>\n\n  <p>\n    We define a model and create the hideRegionHeader property. This contains the class name <code>t-Region--hideHeader</code>&nbsp;or nothing. The property itself should always be calculated when the TabPage is changed. For this we use the event <code>onRegionChange</code> and bind it via JQuery. Whenever the event is triggered, the function <mark>hasClass </mark>is used to check whether the class is contained in the specified selector and thus the value of the property is recalculated using knockoutjs. \n<br>\n<br>To make this working, you have to reference knockoutjs <code>#JET_BASE_DIRECTORY#js/libs/knockout/knockout-3.5.1.js</code>&nbsp;and call then initPage method on PageLoad.\n  </p>\n\n    <figure class=\"post__image post__image--center\">\n      <img loading=\"lazy\" src=\"https://micodify.de/media/posts/58/apex_page_properties_showin_js.png\" height=\"633\" width=\"713\" alt=\"Screenshot of page properties showing JavaScript\"  sizes=\"(max-width: 1024px) 100vw, 1024px\" srcset=\"https://micodify.de/media/posts/58/responsive/apex_page_properties_showin_js-xs.png 300w ,https://micodify.de/media/posts/58/responsive/apex_page_properties_showin_js-sm.png 480w ,https://micodify.de/media/posts/58/responsive/apex_page_properties_showin_js-md.png 768w ,https://micodify.de/media/posts/58/responsive/apex_page_properties_showin_js-lg.png 1024w\">\n      \n    </figure>\n\n  <p>\n    We bind the property itself to all regions that are displayed by the RDS. <code>data-bind=\"class: hideRegionHeader\"</code>\n  </p>\n\n    <figure class=\"post__image post__image--center\">\n      <img loading=\"lazy\" src=\"https://micodify.de/media/posts/58/apex_region_properties_showin_custom_attributes.png\" height=\"327\" width=\"716\" alt=\"Screenhot showing custom attributes data binding\"  sizes=\"(max-width: 1024px) 100vw, 1024px\" srcset=\"https://micodify.de/media/posts/58/responsive/apex_region_properties_showin_custom_attributes-xs.png 300w ,https://micodify.de/media/posts/58/responsive/apex_region_properties_showin_custom_attributes-sm.png 480w ,https://micodify.de/media/posts/58/responsive/apex_region_properties_showin_custom_attributes-md.png 768w ,https://micodify.de/media/posts/58/responsive/apex_region_properties_showin_custom_attributes-lg.png 1024w\">\n      \n    </figure>\n\n  <p>\n    Done.\n  </p>\n\n    <figure class=\"post__image post__image--center\">\n      <img loading=\"lazy\" src=\"https://micodify.de/media/posts/58/record-customized-behaviour-rds.gif\" height=\"1154\" width=\"1166\" alt=\"Screenrecording of a customized RDS\" >\n      \n    </figure>\n\n  <p>\n    \n<br>As usual, you can find a demo here: <a href=\"https://apex.oracle.com/pls/apex/r/die21/demos/rdspage\" target=\"_blank\">https://apex.oracle.com/pls/apex/r/die21/demos/rdspage</a>\n  </p>\n\n  <p>\n    \n  </p>",
            "image": "https://micodify.de/media/posts/58/DALLE-2025-01-19-21.08.10-A-user-interface-of-a-modern-web-application-featuring-a-region-with-multiple-tabs-in-a-horizontal-layout.-Each-tab-is-clearly-labeled-such-as-Dashb.webp",
            "author": {
                "name": "Maik Michel"
            },
            "tags": [
                   "Javascript",
                   "APEX"
            ],
            "date_published": "2025-01-19T21:11:49+01:00",
            "date_modified": "2025-01-23T11:19:09+01:00"
        },
        {
            "id": "https://micodify.de/pluginrun-accessibility-tests-streamline-accessibility-checks-in-apex/",
            "url": "https://micodify.de/pluginrun-accessibility-tests-streamline-accessibility-checks-in-apex/",
            "title": "New Plugin - Run Accessibility Tests - Streamline Accessibility Checks in APEX ",
            "summary": "I am thrilled to introduce my very first APEX plugin! The inspiration&hellip;",
            "content_html": "\n  <p>\n    I am thrilled to introduce my very first APEX plugin! The inspiration for this idea came to me shortly before the last APEX Connect, and it has been a source of excitement and motivation ever since. This plugin allows you to evaluate your pages or entire applications for accessibility, an essential consideration for fostering an inclusive user experience. It leverages the powerful open-source library <strong><a href=\"https://github.com/dequelabs/axe-core\" target=\"_blank\" class=\"\" data-link-popup-id=\"c5aa95e3-177c-4c1c-8a40-f2d308967334\">axe-core</a></strong> from <a href=\"https://www.deque.com\" target=\"_blank\">Deque</a>, a tool that Deque itself uses in its comprehensive accessibility solutions.<br><br>The plugin is designed as a dynamic action, offering flexible integration into your applications. You can add it to specific pages or, for maximum utility, integrate it on page 0 to make it available across your entire application. For instance, you can activate the plugin via a key combination or by triggering a button, ensuring seamless usability.\n  </p>\n\n    <figure class=\"post__image post__image--center\">\n      <img loading=\"lazy\" src=\"https://micodify.de/media/posts/57/screenshot_properties_of_the_plugin.png\" height=\"190\" width=\"597\" alt=\"Properties of plugin the filter by tags and toggle storing\"  sizes=\"(max-width: 1024px) 100vw, 1024px\" srcset=\"https://micodify.de/media/posts/57/responsive/screenshot_properties_of_the_plugin-xs.png 300w ,https://micodify.de/media/posts/57/responsive/screenshot_properties_of_the_plugin-sm.png 480w ,https://micodify.de/media/posts/57/responsive/screenshot_properties_of_the_plugin-md.png 768w ,https://micodify.de/media/posts/57/responsive/screenshot_properties_of_the_plugin-lg.png 1024w\">\n      \n    </figure>\n\n  <p>\n    Currently, the plugin includes two configurable parameters: <br><br>1. <strong>Run with Tags</strong>: This attribute allows you to specify the types of tests to be executed.  <br>2. <strong>Store Results</strong>: This attribute serves as a toggle to decide whether the test results should be saved in a dedicated table. <br><br>The table is installed along with the accompanying app, <strong>A11Y-View</strong>, where you can review the results in detail. A link in the console provides direct access to the test results, enhancing the plugin's ease of use.<br>\n  </p>\n\n    <figure class=\"post__image post__image--center\">\n      <img loading=\"lazy\" src=\"https://micodify.de/media/posts/57/screen-record-show-plugin-with-companion-app-small.gif\" height=\"571\" width=\"1279\" alt=\"APEX App as companion to the plugin\" >\n      \n    </figure>\n\n  <p>\n    I still have many more ideas for the app and the plugin. I will put a bit more energy into this over the next few weeks. I have already collected the following ideas:<br>\n  </p>\n\n  <ul>\n    <li>Floating button or message to open the app directly after a test</li><li>Tracking of violations to exclude them for later tests if necessary, so that you are only informed of newer violations</li><li>Improve the display</li><li>If applicable, you can also integrate the playwright reporter<br></li>\n  </ul>\n\n  <p>\n    You can try out a demo at <a href=\"https://apex.oracle.com/pls/apex/r/die21/tasks\" target=\"_blank\">https://apex.oracle.com/pls/apex/r/die21/tasks</a>. And if you have any other ideas for improvement, let me know.\n  </p>\n\n  <p>\n    \n  </p>",
            "image": "https://micodify.de/media/posts/57/pexels-eren-li-7188802.jpg",
            "author": {
                "name": "Maik Michel"
            },
            "tags": [
                   "APEX"
            ],
            "date_published": "2024-11-20T18:07:36+01:00",
            "date_modified": "2024-11-21T18:39:20+01:00"
        },
        {
            "id": "https://micodify.de/dbflux-now-finally-supports-apex-plugins/",
            "url": "https://micodify.de/dbflux-now-finally-supports-apex-plugins/",
            "title": "dbFlux now finally supports APEX plugins",
            "summary": "Hi guys, finally the time has come. I am happy to announce&hellip;",
            "content_html": "\n  <p>\n    Hi guys, finally the time has come. I am happy to announce that I have released the latest version of <strong>dbFlux </strong>this week. For those who don't know <strong>dbFlux </strong>yet: <strong>dbFlux </strong>is an extension for VSCode that supports you as a developer in your daily work within the development of Oracle database applications, and here mainly for APEX applications. <strong>dbFlux </strong>compiles SQL, PL/SQL, JavaScript, CSS for you and uploads your binary files into your APEX application. It can export your applications, compile multiple schemas, run unit tests, export REST modules and so on... As you can see, <strong>dbFlux </strong>is the Swiss army knife for APEX application development.\n  </p>\n\n  <p>\n    But now to the actual topic. <strong>dbFlux </strong>can now support you in the development of APEX plugins. After you have created the actual plugin within your application, you need to add it to your <strong>dbFlux </strong>workspace.&nbsp;\n  </p>\n\n    <figure class=\"post__image post__image--center\">\n      <img loading=\"lazy\" src=\"https://micodify.de/media/posts/56/screen_of_apex_plugin.png\" height=\"898\" width=\"1764\" alt=\"Screenshot showing the plugin editor inside APEX\"  sizes=\"(max-width: 1024px) 100vw, 1024px\" srcset=\"https://micodify.de/media/posts/56/responsive/screen_of_apex_plugin-xs.png 300w ,https://micodify.de/media/posts/56/responsive/screen_of_apex_plugin-sm.png 480w ,https://micodify.de/media/posts/56/responsive/screen_of_apex_plugin-md.png 768w ,https://micodify.de/media/posts/56/responsive/screen_of_apex_plugin-lg.png 1024w\">\n      <figcaption>APEX Plugin</figcaption>\n    </figure>\n\n  <p>\n    By executing the command \"<mark>dbFlux: Add APEX Plugin</mark>\", <strong>dbFlux </strong>prompts you under which application the plugin can be found. You then have to enter the internal name of the plugin as a static identifier. <strong>dbFlux </strong>will now create empty folders for this plugin. These can be found for example under: <code>./plugin/f101/DE.DIE21.APEX.A11Y/src</code>.\n  </p>\n\n    <figure class=\"post__image post__image--center\">\n      <img loading=\"lazy\" src=\"https://micodify.de/media/posts/56/record_add_plugin.gif\" height=\"818\" width=\"1303\" alt=\"Recording of adding a APEX Plugin with dbFlux\" >\n      <figcaption>Add APEX Plugin</figcaption>\n    </figure>\n\n  <p>\n    The basic structure is now in place. Now we just need to export the plugin from APEX. We do this by executing the command: \"<mark>dbFlux: Export APEX Plugin</mark>\". Here we are asked again for the plugin to be exported. The whole process takes a short moment and then we find the corresponding SQL file in the <code>src </code>directory of the plugin. This can now be deployed. Additionally you are able to create a <em>apexplugin.json</em> file in order to publish it to apex.world.\n  </p>\n\n    <figure class=\"post__image post__image--center\">\n      <img loading=\"lazy\" src=\"https://micodify.de/media/posts/56/record_export_plugin.gif\" height=\"818\" width=\"1303\" alt=\"Recording showing the export of a APEX Plugin\" >\n      <figcaption>Export Plugin</figcaption>\n    </figure>\n\n  <p>\n    The real advantage of using VSCode and <strong>dbFlux </strong>is, of course, that you can use your favorite editor for development. And that includes, for example, editing the JavaScript files contained in such a plugin. With the command \"<mark>dbFlux: Export Plugin Files</mark>\" the static files of the plugin are downloaded and unpacked into the plugin directory. You can then simply edit the files accordingly and then compile them with <code>Ctrl+Alt+B</code>, minify them and upload them to the actual plugin in the database.\n  </p>\n\n    <figure class=\"post__image post__image--center\">\n      <img loading=\"lazy\" src=\"https://micodify.de/media/posts/56/record_export_files_and_compile.gif\" height=\"818\" width=\"1303\" alt=\"Recording of exporting a Static Plugin File and compile to upload it again\" >\n      <figcaption>Export Static Plugin File and compile to upload it</figcaption>\n    </figure>\n\n  <p>\n    Now you can edit the JavaScript or CSS files of the plugin directly in VS Code. This saves a lot of time. No annoying navigation to the plugin, then to the files and then to editing... Simply change and press <code>Ctrl+Alt+B</code> ⇒ Done.\n  </p>\n\n  <p>\n    \n  </p>",
            "image": "https://micodify.de/media/posts/56/rylie-howerter-JXIFjYVbAS8-unsplash.jpg",
            "author": {
                "name": "Maik Michel"
            },
            "tags": [
                   "VSCode",
                   "APEX"
            ],
            "date_published": "2024-06-29T17:07:10+02:00",
            "date_modified": "2024-06-29T17:08:23+02:00"
        },
        {
            "id": "https://micodify.de/optimal-amount-of-columns-in-a-card-report/",
            "url": "https://micodify.de/optimal-amount-of-columns-in-a-card-report/",
            "title": "Optimal amount of columns in a card report",
            "summary": "I often create card reports in my projects. These reports are about&hellip;",
            "content_html": "\n  <p>\n    I often create card reports in my projects. These reports are about showing the data on cards. Depending on the use case, it doesn't always make sense to show this data in tabular form. That's what cards are for. Especially in a mobile environment, i.e. on a mobile phone or tablet, it makes sense to display the cards.\n<br>\n<br>However, it can sometimes happen that there are so few data records that the display on the monitor or tablet is not fully utilized. For example, if you define that there are always 4 columns in a card report, and you unfortunately only have two or three cards in the display. This makes the layout of the page asymmetrical and often looks strange.\n  </p>\n\n    <figure class=\"post__image post__image--center\">\n      <img loading=\"lazy\" src=\"https://micodify.de/media/posts/55/screenshot_three_cards.png\" height=\"416\" width=\"1908\" alt=\"Report showing 3 cards with example data. The space inside the report region is not used optimally.\"  sizes=\"(max-width: 1024px) 100vw, 1024px\" srcset=\"https://micodify.de/media/posts/55/responsive/screenshot_three_cards-xs.png 300w ,https://micodify.de/media/posts/55/responsive/screenshot_three_cards-sm.png 480w ,https://micodify.de/media/posts/55/responsive/screenshot_three_cards-md.png 768w ,https://micodify.de/media/posts/55/responsive/screenshot_three_cards-lg.png 1024w\">\n      \n    </figure>\n\n  <p>\n    Wouldn't it be practical to utilize the full width in such a case?\n<br>\n<br>With a little CSS hack, this is easily possible. In the example above, the report is designed to have 4 columns.\n  </p>\n\n    <figure class=\"post__image post__image--center\">\n      <img loading=\"lazy\" src=\"https://micodify.de/media/posts/55/screenshot_template_options.png\" height=\"768\" width=\"793\" alt=\"Screenshot of APEX template options, pointing the user to the property which will define the amount of columns in a card report.\"  sizes=\"(max-width: 1024px) 100vw, 1024px\" srcset=\"https://micodify.de/media/posts/55/responsive/screenshot_template_options-xs.png 300w ,https://micodify.de/media/posts/55/responsive/screenshot_template_options-sm.png 480w ,https://micodify.de/media/posts/55/responsive/screenshot_template_options-md.png 768w ,https://micodify.de/media/posts/55/responsive/screenshot_template_options-lg.png 1024w\">\n      \n    </figure>\n\n  <p>\n    This leads to the following CSS rule being used in the Universal Theme:\n  </p>\n\n    <figure class=\"post__image post__image--center\">\n      <img loading=\"lazy\" src=\"https://micodify.de/media/posts/55/screenshot_css_developer_tools.png\" height=\"108\" width=\"810\" alt=\"Screenshot showing the CSS-Rule of a 4 column card report.\"  sizes=\"(max-width: 1024px) 100vw, 1024px\" srcset=\"https://micodify.de/media/posts/55/responsive/screenshot_css_developer_tools-xs.png 300w ,https://micodify.de/media/posts/55/responsive/screenshot_css_developer_tools-sm.png 480w ,https://micodify.de/media/posts/55/responsive/screenshot_css_developer_tools-md.png 768w ,https://micodify.de/media/posts/55/responsive/screenshot_css_developer_tools-lg.png 1024w\">\n      \n    </figure>\n\n  <p>\n    This rule must therefore be overwritten. For example, if you define the number of columns in such a way that it fits optimally. You can divide the number of records by 4, 3 or 2. If there is no remaining number, this would be the optimum number of columns. If there is a remainder, the number with the largest residual value could win.\n<br>\n<br>If you have this value, you overwrite the above rule using <code>apex_css.add</code> and placing this call as a page process to be executed before headers.\n  </p>\n<pre class=\" language-sql\"><code>apex_css.add (\n    p_css =&gt; '@media (min-width: 768px) {\n                .t-Cards--4cols {\n                  grid-template-columns: repeat('||:P10_MAX_CARDS_PER_ROW||', 1fr) !important; \n                }\n              }',\n    p_key =&gt; 't-Cards--4cols' );\n} </code></pre>\n\n  <p>\n    And then you can make sure that the rows of cards are optimally filled.\n  </p>\n\n    <figure class=\"post__image post__image--center\">\n      <img loading=\"lazy\" src=\"https://micodify.de/media/posts/55/screenshot_four_cards.png\" height=\"421\" width=\"1900\" alt=\"Screenshot showing the same report as above, Now the 3 columns are using the whole space of the region.\"  sizes=\"(max-width: 1024px) 100vw, 1024px\" srcset=\"https://micodify.de/media/posts/55/responsive/screenshot_four_cards-xs.png 300w ,https://micodify.de/media/posts/55/responsive/screenshot_four_cards-sm.png 480w ,https://micodify.de/media/posts/55/responsive/screenshot_four_cards-md.png 768w ,https://micodify.de/media/posts/55/responsive/screenshot_four_cards-lg.png 1024w\">\n      \n    </figure>\n\n  <p>\n    You can find a demo here: <a href=\"https://apex.oracle.com/pls/apex/r/die21/demos/variable-cards\" target=\"_blank\">https://apex.oracle.com/pls/apex/r/die21/demos/variable-cards</a>\n  </p>\n\n  <p>\n    Featured Image by <a href=\"https://unsplash.com/@kellysikkema?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash\">Kelly Sikkema</a> on <a href=\"https://unsplash.com/photos/blue-sharpie-beside-yellow-sticky-notes-BoAbPMRKLS0?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash\">Unsplash</a>\n<br>\n  </p>\n\n  <p>\n    \n  </p>",
            "image": "https://micodify.de/media/posts/55/kelly-sikkema-BoAbPMRKLS0-unsplash.jpg",
            "author": {
                "name": "Maik Michel"
            },
            "tags": [
                   "CSS",
                   "APEX"
            ],
            "date_published": "2024-03-29T14:41:01+01:00",
            "date_modified": "2024-03-29T14:43:10+01:00"
        },
        {
            "id": "https://micodify.de/improve-reusability-in-oracle-apex-and-plsql-projects/",
            "url": "https://micodify.de/improve-reusability-in-oracle-apex-and-plsql-projects/",
            "title": "Improve reusability in Oracle APEX and PL/SQL projects",
            "summary": "In most of the projects I manage, I often have to reimplement&hellip;",
            "content_html": "\n  <p>\n    In most of the projects I manage, I often have to reimplement a lot of functionalities from other projects. Especially in the consulting sector, I can't switch off my knowledge. And that's not something you want. Rather, all customers unconsciously benefit from each other. Solutions that I design for one customer may be used in a similar way by another customer.\n<br>\n<br>Copying code snippets is also not really good or useful here. What we are missing in the database world around Oracle is a kind of package manager similar to NPM or Maven. And due to the dependency on the database and the associated restrictions, it is also difficult to implement. Let's imagine that the use of a package requires the existence of a certain table. A table that may not be there or has yet to be created. Surely such a package could be written completely with dynamic code. The disadvantage of such an implementation would be that any errors would only appear at runtime and not during compilation.\n<br>\n<br>Personally, I find it better if such a package is directly invalid on the DB and does not throw a specific error at runtime, which I then have to painstakingly debug later.\n<br><br>\n  </p>\n\n    <h2 id=\"so-how-can-you-provide-a-package-for-example\">\n      So how can you provide a package, for example?\n    </h2>\n\n  <p>\n    The following approach has already proven itself in many projects. An atomic package is developed. This means that this package has no dependencies on objects that need to be brought along to install the package. Sometimes it happens that such a package has to make use of some configuration. I recommend a simple package header for this. This header only contains the variables that are customized by the developer who is responsible for the actual implementation in the target system. Here it makes sense to standardize the naming of such a Configuration-PackageHeader. I always use the suffix `_config` for this.\n<br>\n<br>For a package that contains, for example, unit tests for compliance with various standards in an APEX application, there could therefore be a generic package that looks something like this:\n  </p>\n<pre class=\" language-sql\"><code>create or replace package test_apex_application_quality is\n\n...\n\nend;\n\n/\n\n\n\ncreate or replace package body test_apex_application_quality is\n\n...\n\n  cursor cur_app_items is (select ...\n\n                            from apex_application_items\n\n                           where apex_application = test_apex_application_quality_config.C_APP_ID );\n\n\n\n...\n\nend;\n\n/</code></pre>\n\n  <p>\n    This is just an example, but you can clearly see how the configuration package is used to restrict the items of the application to be tested.\n  </p>\n<pre class=\" language-sql\"><code>create or replace package test_apex_application_quality_config is\n\n  C_APP_ID constant number := 1000;\n\nend;\n\n/ \n</code></pre>\n\n  <p>\n    This means that the 3 files could be delivered initially. If the test package is now extended to perform other tests on the application, it is sufficient to update the actual package.\n<br>\n\n  </p>\n\n  <p>\n    Cool, is there any way to update this?<br>\n  </p>\n\n    <h2 id=\"yes-you-can-with-dbflux\">\n      Yes, you can. With dbFlux\n    </h2>\n\n  <p>\n    <strong><a href=\"https://marketplace.visualstudio.com/items?itemName=MaikMichel.dbflow\" target=\"_blank\">dbFlux </a></strong>is a VSCode extension and offers a command for exactly this purpose. Here it is called `<code>Add FeatureSet as SubModule</code>`. Such a FeatureSet is available for exactly this scenario. Simply enter the GitURL that points to such a FeatureSet. <strong><a href=\"https://marketplace.visualstudio.com/items?itemName=MaikMichel.dbflow\" target=\"_blank\">dbFlux</a></strong> will create / clone this repository as a Git-Submodule in the existing project folder. Such a FeatureSet must contain a <em>manifest.json</em> file. This file contains the information required to copy the corresponding files of the FeatureSet into the current project.\n<br>The developer of the FeatureSet can provide the files with the flag `\"initial\": true`. This is then only copied during initial creation and is no longer overwritten. In addition, the <em>manifest.json</em> file contains the version number of the FeatureSet. If this changes, <strong><a href=\"https://marketplace.visualstudio.com/items?itemName=MaikMichel.dbflow\" target=\"_blank\">dbFlux </a></strong>will ask whether these changes should be transferred to the current project. <strong><a href=\"https://marketplace.visualstudio.com/items?itemName=MaikMichel.dbflow\" target=\"_blank\">dbFlux </a></strong>will not install anything on its own, but only copy the files. These can then be installed in the development database by the developer. And with the support of <strong><a href=\"https://github.com/MaikMichel/dbFlow\" target=\"_blank\">dbFlow</a></strong>, those files will be shipped and install as usual with your project.\n  </p>\n\n    <figure class=\"post__image post__image--center\">\n      <img loading=\"lazy\" src=\"https://micodify.de/media/posts/54/record_add_feature_set.gif\" height=\"918\" width=\"1604\" alt=\"screen recording using dbFlux to add a reusable FeatureSet\" >\n      <figcaption>screen recording using dbFlux to add a reusable FeatureSet</figcaption>\n    </figure>\n\n  <p>\n    \n  </p>",
            "image": "https://micodify.de/media/posts/54/markus-spiske-n2HoOVk3tGY-unsplash.jpg",
            "author": {
                "name": "Maik Michel"
            },
            "tags": [
                   "VSCode",
                   "PL/SQL",
                   "APEX"
            ],
            "date_published": "2023-12-30T19:51:36+01:00",
            "date_modified": "2023-12-30T20:03:11+01:00"
        },
        {
            "id": "https://micodify.de/using-authenticator-based-mfa-in-oracle-apex-joelkallmanday/",
            "url": "https://micodify.de/using-authenticator-based-mfa-in-oracle-apex-joelkallmanday/",
            "title": "Using Authenticator Based MFA in Oracle APEX #JoelKallmanDay",
            "summary": "Many of you are certainly familiar with multifactor authentication, or MFA for&hellip;",
            "content_html": "\n  <p>\n    Many of you are certainly familiar with multifactor authentication, or MFA for short. With MFA, another factor is requested in addition to the user name and password, which basically represents the first factor. An additional one-time password is generated, sent and requested by the application or service to which you want to log in. Usually, an SMS or email is sent to a previously configured account or mobile phone. This contains a small password or a token that must be entered in the corresponding application.\n<br>\n<br>Another possibility for MFA is the use of an authenticator application. There are various applications for the most common mobile phone operating systems. In my company, for example, we use the Microsoft Authenticator. Such an authenticator app supports several authentication methods. Among others also the TOTP method. See: https://de.wikipedia.org/wiki/Time-based_One-time_Password_Algorithmus\n<br>\n<br>In general, an encrypted secret is exchanged and the validity is calculated with an algorithm. The calculated token changes every 30 seconds.\n  </p>\n\n    <h3 id=\"how-to-implement-such-an-mfa-in-apex\">\n      How to implement such an MFA in APEX?\n    </h3>\n\n  <p>\n    A few years ago, someone on the Oracle forum posted the actual code for the generation. See: <a href=\"https://forums.oracle.com/ords/apexds/post/google-authenticator-totp-0920\" target=\"_blank\">https://forums.oracle.com/ords/apexds/post/google-authenticator-totp-0920</a>\n  </p>\n\n  <p>\n    We use this code as the basis for calculating a token that is based on a secret assigned to the user. We wrap the code from the forum in its own method and return the determined token here. We have to compare this with the user's input at the appropriate locations.\n<br>\n<br>Please understand that I cannot show the whole code here. Unfortunately, I cannot host a demo application on <a href=\"https://apex.oracle.com\" target=\"_blank\">https://apex.oracle.com</a> because the package <strong>dbms_crypto </strong>is not available there.\n<br>\n<br>So to set up the second factor, we create a secret and then store it with the user.\n  </p>\n<pre class=\" language-sql\"><code>C_BASE32_CHARS  constant varchar2(32)   := 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';\n\nfunction generate_random_base32_string(length number) return varchar2 is\n  l_random_string varchar2(32767);\nbegin\n  for i in 1..length loop\n    l_random_string := l_random_string || \n                       substr(C_BASE32_CHARS, 1 + floor(dbms_random.value(0, 32)), 1);\n  end loop;\n\n  return l_random_string;\nend;\n</code></pre>\n\n  <p>\n    In order to make the whole process as simple as possible for the user, we offer him <strong>(1)</strong> a corresponding Authenticator App directly for installation.\n  </p>\n\n    <figure class=\"post__image post__image--center\">\n      <img loading=\"lazy\" src=\"https://micodify.de/media/posts/52/Untitled.png\" height=\"1752\" width=\"737\" alt=\"Configuring a MFA\"  sizes=\"(max-width: 1024px) 100vw, 1024px\" srcset=\"https://micodify.de/media/posts/52/responsive/Untitled-xs.png 300w ,https://micodify.de/media/posts/52/responsive/Untitled-sm.png 480w ,https://micodify.de/media/posts/52/responsive/Untitled-md.png 768w ,https://micodify.de/media/posts/52/responsive/Untitled-lg.png 1024w\">\n      <figcaption>Configuring a MFA</figcaption>\n    </figure>\n\n  <p>\n    The user can then enter the generated secret <strong>(2)</strong> manually into the application or simply scan the QR code <strong>(3)</strong>. This has a special structure (see code excerpt).\n  </p>\n<pre class=\" language-sql\"><code>C_OTP_AUTH_LINK constant varchar2(1000) := 'otpauth://totp/%0?secret=%1&issuer=%2&algorithm=SHA1&digits=6&period=30';\n\nfunction get_otpauth_link(p_secret  in varchar2,\n                          p_name    in varchar2,\n                          p_issuer  in varchar2,\n                          p_prefix  in varchar2 default null)\n                          return varchar2 is\n  l_otp_auth_link varchar2(4000);\nbegin\n  l_otp_auth_link := apex_string.format(p_message =&gt; C_OTP_AUTH_LINK,\n                                        p0        =&gt; p_name,\n                                        p1        =&gt; p_secret,\n                                        p2        =&gt; p_issuer);\n\n  return p_prefix || case when p_prefix is null then l_otp_auth_link \n\t\t\t\t\t\t\t\t\t\t else apex_util.url_encode(l_otp_auth_link) end;\nend;</code></pre>\n\n  <p>\n    The image, in my case an SVG image, of the QR code is created here with the package ZT_QR from the repo:&nbsp;<a href=\"https://github.com/zorantica/plsql-qr-code\" target=\"_blank\">https://github.com/zorantica/plsql-qr-code</a>\n  </p>\n\n  <p>\n    As soon as the user has scanned the QR code, a new entry for authentication is displayed in his Authenticator app. With the code displayed there, they can then confirm directly in the application <strong>(4)</strong> that the authentication works using the additional factor.\n  </p>\n\n    <figure class=\"post__image post__image--center\">\n      <img loading=\"lazy\" src=\"https://micodify.de/media/posts/52/record_mfa_validation.gif\" height=\"1797\" width=\"1869\" alt=\"Recording of config MFA service using 2FAS Application\" >\n      <figcaption>Recording of config MFA service using 2FAS Application</figcaption>\n    </figure>\n\n  <p>\n    Here you can see what the process might look like.\n  </p>\n\n  <p>\n    The next step is then only to implement the additional factor in the login screen of the actual application. Here, the user name and the password must first be validated. Then the input fields for the token are displayed. Only after validation of this input does the actual login to the application become valid.\n  </p>\n\n    <figure class=\"post__image post__image--center\">\n      <img loading=\"lazy\" src=\"https://micodify.de/media/posts/52/Screenshot-2023-10-11-125721.png\" height=\"801\" width=\"708\" alt=\"Screenshot with enter Token to Sign In process\"  sizes=\"(max-width: 1024px) 100vw, 1024px\" srcset=\"https://micodify.de/media/posts/52/responsive/Screenshot-2023-10-11-125721-xs.png 300w ,https://micodify.de/media/posts/52/responsive/Screenshot-2023-10-11-125721-sm.png 480w ,https://micodify.de/media/posts/52/responsive/Screenshot-2023-10-11-125721-md.png 768w ,https://micodify.de/media/posts/52/responsive/Screenshot-2023-10-11-125721-lg.png 1024w\">\n      <figcaption>Enter Token to Sign In</figcaption>\n    </figure>\n\n    <blockquote class=\"blockquote\">\n      I don't know Joel personally. I have seen him at some conferences and in videos. I think that with Oracle's commitment to APEX as the Cloud Application Development Platform, it's certainly a very big dream of Joel's come true. I hope we all do as you have wished.\n    </blockquote>\n\n  <p>\n    \n  </p>\n<div id=\"image-by-mahesh-patel-from-pixabay\"><p><small><i>Image by Mahesh Patel from Pixabay</i></small></p></div>\n\n  <p>\n    \n  </p>",
            "image": "https://micodify.de/media/posts/52/access-3509495_1280.jpg",
            "author": {
                "name": "Maik Michel"
            },
            "tags": [
                   "PL/SQL",
                   "APEX"
            ],
            "date_published": "2023-10-11T12:47:17+02:00",
            "date_modified": "2023-10-11T12:58:56+02:00"
        },
        {
            "id": "https://micodify.de/use-apex-api-to-display-version-infos-in-your-apps/",
            "url": "https://micodify.de/use-apex-api-to-display-version-infos-in-your-apps/",
            "title": "Use APEX API to display version infos in your apps",
            "summary": "Many projects require the current version of the application. Oracle APEX applications&hellip;",
            "content_html": "\n  <p>\n    Many projects require the current version of the application. Oracle APEX applications have a version identifier stored in the application settings by default. This is usually \"Release 1.0\". In the past, I have stored a version information in semantic form and a log from the commits, matching this version, with the release. To do this, I wrote the version information in a release table during deployment and stored a global application process that reads this information when the application or session is started and writes it to an application item that then displays the corresponding version in the settings at runtime using substitution notation.\n  </p>\n\n    <figure class=\"post__image post__image--center\">\n      <img loading=\"lazy\" src=\"https://micodify.de/media/posts/51/application_properties.png\" height=\"533\" width=\"1141\" alt=\"application properties showing substitution variable in version field \"  sizes=\"(max-width: 1024px) 100vw, 1024px\" srcset=\"https://micodify.de/media/posts/51/responsive/application_properties-xs.png 300w ,https://micodify.de/media/posts/51/responsive/application_properties-sm.png 480w ,https://micodify.de/media/posts/51/responsive/application_properties-md.png 768w ,https://micodify.de/media/posts/51/responsive/application_properties-lg.png 1024w\">\n      \n    </figure>\n\n  <p>\n    For some applications, this is quite an overhead.\n  </p>\n\n  <p>\n    Since version 23.1, APEX also offers a solution for this. It is now possible to set the version via API. Setting the workspace and actually calling the API is sufficient here.\n  </p>\n<pre class=\" language-sql\"><code>begin\n  apex_application_install.set_workspace (p_workspace =&gt; 'DEMO' );\n  apex_application_admin.set_application_version ( p_application_id =&gt; 1000,\n\t\t\t\t\t\t\t\t\t\t           p_version        =&gt; 'Release 1.0');\nend;</code></pre>\n\n  <p>\n    Actually quite simple.\n  </p>\n\n  <p>\n    The whole thing makes even more sense if you include this call in your CI/CD pipeline. If you use <a href=\"https://github.com/MaikMichel/dbFlow\" target=\"_blank\"><strong>dbFlow</strong></a>, for example, you could simply write a global hook script that calls this API directly at the end of a deployment.\n  </p>\n\n    <figure class=\"post__image post__image--center\">\n      <img loading=\"lazy\" src=\"https://micodify.de/media/posts/51/vscode_hooks.png\" height=\"226\" width=\"423\" alt=\"VS Code Treeview with a post hook file selected\"  sizes=\"(max-width: 1024px) 100vw, 1024px\" srcset=\"https://micodify.de/media/posts/51/responsive/vscode_hooks-xs.png 300w ,https://micodify.de/media/posts/51/responsive/vscode_hooks-sm.png 480w ,https://micodify.de/media/posts/51/responsive/vscode_hooks-md.png 768w ,https://micodify.de/media/posts/51/responsive/vscode_hooks-lg.png 1024w\">\n      \n    </figure>\n\n  <p>\n    This script is called by <a href=\"https://github.com/MaikMichel/dbFlow\" target=\"_blank\"><strong>dbFlow </strong></a>at the end (post) of the main installation. The project here is called TAYRA and the schema used to import the applications is TAYRA_APP. This is a multi-schema setup that maps to a classic 3-tier model. <a href=\"https://github.com/MaikMichel/dbFlow\" target=\"_blank\"><strong>dbFlow </strong></a>always calls these scripts with the parameters for the version and the import mode. Therefore, such a script can look something like this.\n  </p>\n<pre class=\" language-sql\"><code>set define '^'\nset concat on\nset concat .\nset verify off\nset serveroutput on\nset linesize 2000\nset wrap off\nSET TERMOUT OFF\nCOLUMN 1 NEW_VALUE 1\nCOLUMN 2 NEW_VALUE 2\n\nSELECT '' \"1\" FROM dual WHERE ROWNUM = 0;\nSELECT '' \"2\" FROM dual WHERE ROWNUM = 0;\n\n-- Set params to internal vars\nDEFINE _parameter_01 = ^1 \"0.0.0\"\nDEFINE _parameter_02 = ^2 \"undefined\"\n\ndefine VERSION = ^_parameter_01\ndefine MODE = ^_parameter_02\n\nSET TERMOUT ON\nPROMPT ********************************************************************\nPROMPT * VERSION    &lt;^VERSION&gt;\nPROMPT * MODE       &lt;^MODE&gt;\nPROMPT ********************************************************************\n\nset timing on;\nprompt ............................................................................\nprompt ............................................................................\nprompt ..                                                                        ..\nprompt ..      Setting Versioninfos                                              ..\nprompt ..                                                                        ..\nprompt ............................................................................\nprompt ............................................................................\nbegin\n  apex_application_install.set_workspace (p_workspace =&gt; 'TAYRA' );\n  for apps in (select column_value\n                 from table(apex_string.split_numbers('1000:2000:3000', ':')))\n  loop\n    apex_application_admin.set_application_version(p_application_id =&gt; apps.column_value,\n                                                   p_version        =&gt; 'Release ^VERSION ('||to_char(sysdate, 'DD.MM.YYYY HH24:MI')||')');\n  end loop;\nend;\n/</code></pre>\n\n  <p>\n    After installing, the corresponding applications show the appropriate version.\n  </p>\n\n    <figure class=\"post__image post__image--center\">\n      <img loading=\"lazy\" src=\"https://micodify.de/media/posts/51/apex_footer-2.png\" height=\"85\" width=\"623\" alt=\"APEX default footer showing version number\"  sizes=\"(max-width: 1024px) 100vw, 1024px\" srcset=\"https://micodify.de/media/posts/51/responsive/apex_footer-2-xs.png 300w ,https://micodify.de/media/posts/51/responsive/apex_footer-2-sm.png 480w ,https://micodify.de/media/posts/51/responsive/apex_footer-2-md.png 768w ,https://micodify.de/media/posts/51/responsive/apex_footer-2-lg.png 1024w\">\n      \n    </figure>\n\n  <p>\n    I tend to always display a version identifier to give a context to screenshot which shows a part or the app.\n  </p>\n\n  <p>\n    \n  </p>",
            "image": "https://micodify.de/media/posts/51/glen-carrie-HpMihL323k0-unsplash.jpg",
            "author": {
                "name": "Maik Michel"
            },
            "tags": [
                   "PL/SQL",
                   "APEX"
            ],
            "date_published": "2023-10-06T16:42:48+02:00",
            "date_modified": "2023-10-06T16:46:12+02:00"
        },
        {
            "id": "https://micodify.de/maximizing-application-insights-with-column-prefixes/",
            "url": "https://micodify.de/maximizing-application-insights-with-column-prefixes/",
            "title": "Maximizing Application Insights with Column Prefixes",
            "summary": "In many projects, I keep encountering negative opinions towards column prefixes. Just&hellip;",
            "content_html": "\n  <p>\n    In many projects, I keep encountering negative opinions towards column prefixes. Just recently I started a small poll on Twitter about this topic. And also there the opinion was 75% against column prefixes.<br><br>\n  </p>\n<div><center><blockquote class=\"twitter-tweet\"><p lang=\"en\" dir=\"ltr\">Column names with or without prefix? Leave a comment why you prefer the one over the other. <a href=\"https://twitter.com/hashtag/orclAPEX?src=hash&amp;ref_src=twsrc%5Etfw\">#orclAPEX</a> <a href=\"https://twitter.com/hashtag/oracle?src=hash&amp;ref_src=twsrc%5Etfw\">#oracle</a> <a href=\"https://twitter.com/hashtag/Database?src=hash&amp;ref_src=twsrc%5Etfw\">#Database</a></p>&mdash; Maik Michel (@Maik__Michel) <a href=\"https://twitter.com/Maik__Michel/status/1672663551209611267?ref_src=twsrc%5Etfw\">June 24, 2023</a></blockquote> <script async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script></center>\n</div>\n\n  <p>\n    I can't even say exactly where this comes from. But I suspect more from the <em>non-SQL /PLSQL</em> side. In other languages like Java the use of prefixes makes no sense at all and yes, if you have an object relational mapper that generates code that is prefixed, it's pretty ugly.\n<br>\n<br>Here in my example it is primarily about <strong>Oracle SQL/PLSQL</strong> and also <strong>APEX</strong> applications. I think we agree that there should be some rules regarding the naming convention, meaning the notation of columns and objects within the database. From many projects I know the following rules:\n  </p>\n\n  <p>\n    \n  </p>\n\n  <ol>\n    <li>No prefixes\n</li><li>Columns with PrimaryKey are name by tablename_ID\n</li><li>Columns which are linked by a ForeignKey relation are named by their own PrimaryKey column</li>\n  </ol>\n\n  <p>\n    Here is an example with the tables PROJECTS and TASKS, which are related to each other.\n  </p>\n<pre class=\" language-sql\"><code>create table projects (\n  projects_id      number                    not null, -- primary key\n  name             varchar2(250 char)        not null,\n  start_date       date,\n  end_date         date,\n  created_at       date                      not null,\n  created_by       varchar2(250 char)        not null,\n  modified_at      date                      not null,\n  modified_by      varchar2(250 char)        not null\n);\n\ncreate table tasks (\n  tasks_id         number                    not null, -- primary key\n  name             varchar2(250 char)        not null,\n  hours_estimates  number(5),\n  projects_id      number                    not null, -- foreign key\n  created_at       date                      not null,\n  created_by       varchar2(250 char)        not null,\n  modified_at      date                      not null,\n  modified_by      varchar2(250 char)        not null\n);\n</code></pre>\n\n  <p>\n    With this principle it is noticeable that we must take in a select statement, which works with a join, definitely an alias per table, since here the ID columns are never unique. In addition, the audit columns are also named identically, which makes the simple joining of two tables much more complicated.\n<br>\n<br>Another impact, and in my opinion a big one, is the maintainability of the database PL/SQL code that results from such naming. So let's imagine a project where there are a lot of packages and additionally a lot of APEX pages where the corresponding information is displayed or edited. And now we have to change the logic concerning the column \"name\" of the Tasks table. We have to check all places in the code where this column is used.\n<br>\n\n  </p>\n\n    <blockquote class=\"blockquote\">\n      That is really annoying<br>\n    </blockquote>\n\n  <p>\n    And now how about a naming convention that provides column prefixes?\n<br>\n<br>The following rule has worked well in all my projects:\n  </p>\n\n  <ol>\n    <li>Each column of a table gets assigned a prefix that is unique per table. (The naming / glossary becomes part of the source code and is directly visible to all developers)</li><li>Columns with PrimaryKey get the prefix and ID (xyz_id)</li><li>Columns which are linked by a ForeignKey relation are named like their PrimaryKey column but with Prefix.</li>\n  </ol>\n\n  <p>\n    Thus each column is unique\n  </p>\n<pre class=\" language-sql\"><code>create table projects (\n  prj_id               number                    not null, -- primary key\n  prj_name             varchar2(250 char)        not null,\n  prj_start            date,\n  prj_end              date,\n  prj_created_at       date                      not null,\n  prj_created_by       varchar2(250 char)        not null,\n  prj_modified_at      date                      not null,\n  prj_modified_by      varchar2(250 char)        not null\n);\n\ncreate table tasks (\n  tsk_id               number                    not null, -- primary key\n  tsk_name             varchar2(250 char)        not null,\n  tsk_hours_estimates  number(5),\n  tsk_prj_id           number                    not null, -- foreign key\n  tsk_created_at       date                      not null,\n  tsk_created_by       varchar2(250 char)        not null,\n  tsk_modified_at      date                      not null,\n  tsk_modified_by      varchar2(250 char)        not null\n);\n</code></pre>\n\n    <blockquote class=\"blockquote\">\n      Which prefixes are chosen and whether they are 3, 4 or 5 digits must be made dependent on the project size. Important is a kind of glosar, in which the mapping can be looked up.\n    </blockquote>\n\n  <p>\n    Besides the actual advantage for the impact analysis, there is also the advantage in the naming to exclude certain words as column names. I cannot name a column <u>end</u> in SQL. I would have to surround this column with double quotation marks or name it something else.\n  </p>\n\n  <p>\n    And now we can look for our Impact:\n  </p>\n\n    <figure class=\"post__image post__image--center\">\n      <img loading=\"lazy\" src=\"https://micodify.de/media/posts/50/impactsearch_ordr_name.gif\" height=\"961\" width=\"1824\" alt=\"\" >\n      <figcaption>Impact analysis - Find in Files / Database Objects the use of a specific columns</figcaption>\n    </figure>\n\n    <h3 id=\"bam-in-just-1-second-i-see-the-impact\">\n      Bam, in just 1 second I see the impact\n    </h3>\n\n  <p>\n    \n  </p>",
            "image": "https://micodify.de/media/posts/50/playing-card-842037_1280.jpg",
            "author": {
                "name": "Maik Michel"
            },
            "tags": [
                   "SQL",
                   "Oracle",
                   "Database",
                   "APEX"
            ],
            "date_published": "2023-08-07T21:30:24+02:00",
            "date_modified": "2023-08-07T21:30:24+02:00"
        },
        {
            "id": "https://micodify.de/optimize-your-project-organization-with-vscodes-file-nesting-feature/",
            "url": "https://micodify.de/optimize-your-project-organization-with-vscodes-file-nesting-feature/",
            "title": "Optimize Your Project Organization with VSCode&#x27;s File Nesting Feature!",
            "summary": "Greetings, fellow developers! Have you ever found yourself wrestling with a growing&hellip;",
            "content_html": "\n  <p>\n    Greetings, fellow developers! Have you ever found yourself wrestling with a growing number of components in your project? Tables, packages, and files galore! Keeping everything organized can be quite a task. But fear not, because I have an exciting solution to share with you: VSCode's File Nesting feature.\n<br>\n<br>Let me paint a serene picture for you. Picture yourself in the tranquil realm of your coding environment, where order reigns supreme. With File Nesting, you have the power to create a virtual folder beneath your main file, providing a dedicated space for related files. It's like having a personal assistant that effortlessly organizes your project structure.\n<br>\n<br>Using File Nesting is a breeze. Just create a file within the folder you wish to organize. It could be any file type, but I personally find Markdown to be elegantly simple. To give it prominence, prefix its filename with an underscore. This clever trick ensures it appears at the top of the directory, catching your eye immediately.\n<br>\n<br>Now, let's unlock the full potential of File Nesting. Open up your VSCode settings and prepare to customize your organization magic:\n  </p>\n<pre class=\" language-bash\"><code>...\n\"explorer.fileNesting.enabled\": true,\n\"explorer.fileNesting.patterns\": {\n  \"_common.md\": \"app_defaults.pk*, apx_app_util.pk*, apx_ui_util.pk*, generic_templates.pk*\",\n}\n...</code></pre>\n\n  <p>\n    Enabling <code>explorer.fileNesting.enabled</code> sets the stage for a beautifully organized coding experience. With <code>explorer.fileNesting.patterns</code>, you can define your own rules to tailor the nesting behavior. This is where you can exercise your creativity and create a structure that aligns with your project's needs.\n<br>\n<br>Imagine the sheer joy of effortlessly locating the files you need, with a logical structure that simplifies your workflow. No more endless scrolling or searching for that elusive file buried deep within the hierarchy. With File Nesting, harmony and efficiency become your trusted companions.\n\n  </p>\n\n    <figure class=\"post__image post__image--center\">\n      <img loading=\"lazy\" src=\"https://micodify.de/media/posts/49/filenesting.gif\" height=\"908\" width=\"1824\" alt=\"\" >\n      \n    </figure>\n\n  <p>\n    So, my friends, it's time to embrace the elegance of File Nesting. Let VSCode be your partner as you conquer the challenges of managing large-scale projects. Enjoy the serenity of a clutter-free workspace, and let your creativity flourish.\n  </p>\n\n  <p>\n    \nMore infos: <a href=\"https://code.visualstudio.com/updates/v1_67#_explorer-file-nesting\" target=\"_blank\" class=\"\">https://code.visualstudio.com/updates/v1_67#_explorer-file-nesting</a>\n  </p>\n\n  <p>\n    &nbsp;Happy coding, my fellow seekers of order!\n  </p>\n\n  <p>\n    \n  </p>",
            "image": "https://micodify.de/media/posts/49/jon-tyson-UJN_XAg0ECI-unsplash.jpg",
            "author": {
                "name": "Maik Michel"
            },
            "tags": [
                   "VSCode"
            ],
            "date_published": "2023-07-18T20:24:56+02:00",
            "date_modified": "2023-07-19T11:07:22+02:00"
        }
    ]
}
