added feature flag

This commit is contained in:
Beverly Nguyen
2025-04-10 12:35:04 -07:00
parent d8ca53e08b
commit 6dd44fdc2d
9 changed files with 72 additions and 44 deletions

View File

@@ -151,7 +151,7 @@
"filename": "app/config.py",
"hashed_secret": "577a4c667e4af8682ca431857214b3a920883efc",
"is_verified": false,
"line_number": 118,
"line_number": 121,
"is_secret": false
}
],
@@ -674,5 +674,5 @@
}
]
},
"generated_at": "2025-03-20T18:22:36Z"
"generated_at": "2025-04-10T19:35:01Z"
}

View File

@@ -167,6 +167,7 @@ jobs:
run: make run-flask &
env:
NOTIFY_ENVIRONMENT: scanning
FEATURE_SOCKET_ENABLED: true
- name: Run OWASP Baseline Scan
uses: zaproxy/action-baseline@v0.14.0
with:

View File

@@ -172,15 +172,15 @@ def _csp(config):
def create_app(application):
# @application.context_processor
# def inject_feature_flags():
@application.context_processor
def inject_feature_flags():
# this is where feature flags can be easily added as a dictionary within context
# feature_about_page_enabled = application.config.get(
# "FEATURE_ABOUT_PAGE_ENABLED", False
# )
# return dict(
# FEATURE_ABOUT_PAGE_ENABLED=feature_about_page_enabled,
# )
feature_socket_enabled = application.config.get(
"FEATURE_SOCKET_ENABLED", False
)
return dict(
FEATURE_SOCKET_ENABLED=feature_socket_enabled,
)
@application.context_processor
def inject_initial_signin_url():

View File

@@ -10,29 +10,35 @@ document.addEventListener("DOMContentLoaded", function () {
const isJobPage = window.location.pathname.includes("/jobs/");
if (!isJobPage) return;
const jobId = document.querySelector("[data-job-id]")?.dataset?.jobId;
const jobEl = document.querySelector("[data-job-id]");
const jobId = jobEl?.dataset?.jobId;
const featureEnabled = jobEl?.dataset?.feature === "true";
if (!jobId) return;
const socket = io("http://localhost:6011");
socket.on("connect", () => {
console.log("Connected to Socket.IO server");
socket.emit("join", { room: `job-${jobId}` });
console.log("join", { room: `job-${jobId}` });
});
if (featureEnabled) {
const socket = io("http://localhost:6011");
window.addEventListener("beforeunload", () => {
socket.emit("leave", { room: `job-${jobId}` });
});
socket.on("connect", () => {
console.log("Connected to Socket.IO server");
socket.emit("join", { room: `job-${jobId}` });
console.log("join", { room: `job-${jobId}` });
});
const debouncedUpdate = debounce((data) => {
updateAllJobSections();
}, 1000);
window.addEventListener("beforeunload", () => {
socket.emit("leave", { room: `job-${jobId}` });
});
socket.on("job_updated", (data) => {
if (data.job_id !== jobId) return;
debouncedUpdate(data);
});
const debouncedUpdate = debounce((data) => {
updateAllJobSections();
}, 1000);
socket.on("job_updated", (data) => {
if (data.job_id !== jobId) return;
debouncedUpdate(data);
});
}
function updateAllJobSections() {
const resourceEl = document.querySelector('[data-socket-update="status"]');

View File

@@ -89,6 +89,9 @@ class Config(object):
}
FEATURE_SOCKET_ENABLED = getenv("FEATURE_SOCKET_ENABLED", "false") == "true"
def _s3_credentials_from_env(bucket_prefix):
return {
"bucket": getenv(

View File

@@ -25,15 +25,17 @@ from app.utils.user import user_is_logged_in
def check_feature_flags():
# Placeholder for future feature flag checks
# Example:
# if request.path.startswith("/some-feature") and not current_app.config.get("FEATURE_SOME_FEATURE_ENABLED", False):
# abort(404)
if request.path.startswith("/jobs") and not current_app.config.get(
"FEATURE_SOCKET_ENABLED", False
):
abort(404)
pass
@main.route("/test/feature-flags")
def test_feature_flags():
return jsonify(
{"FEATURE_ABOUT_PAGE_ENABLED": current_app.config["FEATURE_ABOUT_PAGE_ENABLED"]}
{"FEATURE_SOCKET_ENABLED": current_app.config["FEATURE_SOCKET_ENABLED"]}
)

View File

@@ -4,6 +4,7 @@ from functools import partial
from flask import (
Response,
current_app,
abort,
jsonify,
redirect,
@@ -59,6 +60,7 @@ def view_job(service_id, job_id):
filter_args["status"] = set_status_filters(filter_args)
return render_template(
"views/jobs/job.html",
FEATURE_SOCKET_ENABLED=current_app.config["FEATURE_SOCKET_ENABLED"],
job=job,
status=request.args.get("status", ""),
updates_url=url_for(

View File

@@ -3,7 +3,7 @@
{% from "components/page-footer.html" import page_footer %}
{% from "components/page-header.html" import page_header %}
{% from "components/components/back-link/macro.njk" import usaBackLink %}
{% from 'components/ajax-block.html' import socket_block %}
{% block service_page_title %}
{{ "Message status" }}
{% endblock %}
@@ -11,20 +11,33 @@
{% block maincolumn_content %}
{{ page_header("Message status") }}
<div
data-socket-update="status"
data-resource="{{ updates_url }}"
data-key="status"
data-job-id="{{ job.id }}"
>
<div data-job-id="{{ job.id }}" data-feature="{{FEATURE_SOCKET_ENABLED}}">
{% if not job.finished_processing %}
<div
data-resource="{{ updates_url }}"
{% if FEATURE_SOCKET_ENABLED %}
data-socket-update="status"
{% else %}
data-module="update-content"
{% endif %}
data-key="status"
data-form=""
>
{% endif %}
{{ partials['status']|safe }}
{% if not job.finished_processing %}
</div>
{% endif %}
{% if not finished %}
<div
data-socket-update="counts"
data-job-id="{{ job.id }}"
data-resource="{{ updates_url }}"
{% if FEATURE_SOCKET_ENABLED %}
data-socket-update="counts"
{% else %}
data-module="update-content"
{% endif %}
data-key="counts"
data-form=""
>
{% endif %}
{{ partials['counts']|safe }}
@@ -37,9 +50,12 @@
</p>
{% if not job.processing_finished %}
<div
data-socket-update="notifications"
data-job-id="{{ job.id }}"
data-resource="{{ updates_url }}"
{% if FEATURE_SOCKET_ENABLED %}
data-socket-update="notifications"
{% else %}
data-module="update-content"
{% endif %}
data-key="notifications"
data-form=""
>
@@ -48,7 +64,6 @@
{% if not job.processing_finished %}
</div>
{% endif %}
<div> </div>
</div>
{% endblock %}

View File

@@ -85,7 +85,6 @@ const javascripts = () => {
paths.src + 'javascripts/sidenav.js',
paths.src + 'javascripts/validation.js',
paths.src + 'javascripts/socketio.js',
])
.pipe(plugins.prettyerror())
.pipe(