mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-24 00:07:02 -04:00
added feature flag
This commit is contained in:
@@ -151,7 +151,7 @@
|
|||||||
"filename": "app/config.py",
|
"filename": "app/config.py",
|
||||||
"hashed_secret": "577a4c667e4af8682ca431857214b3a920883efc",
|
"hashed_secret": "577a4c667e4af8682ca431857214b3a920883efc",
|
||||||
"is_verified": false,
|
"is_verified": false,
|
||||||
"line_number": 118,
|
"line_number": 121,
|
||||||
"is_secret": false
|
"is_secret": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -674,5 +674,5 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"generated_at": "2025-03-20T18:22:36Z"
|
"generated_at": "2025-04-10T19:35:01Z"
|
||||||
}
|
}
|
||||||
|
|||||||
1
.github/workflows/checks.yml
vendored
1
.github/workflows/checks.yml
vendored
@@ -167,6 +167,7 @@ jobs:
|
|||||||
run: make run-flask &
|
run: make run-flask &
|
||||||
env:
|
env:
|
||||||
NOTIFY_ENVIRONMENT: scanning
|
NOTIFY_ENVIRONMENT: scanning
|
||||||
|
FEATURE_SOCKET_ENABLED: true
|
||||||
- name: Run OWASP Baseline Scan
|
- name: Run OWASP Baseline Scan
|
||||||
uses: zaproxy/action-baseline@v0.14.0
|
uses: zaproxy/action-baseline@v0.14.0
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -172,15 +172,15 @@ def _csp(config):
|
|||||||
|
|
||||||
|
|
||||||
def create_app(application):
|
def create_app(application):
|
||||||
# @application.context_processor
|
@application.context_processor
|
||||||
# def inject_feature_flags():
|
def inject_feature_flags():
|
||||||
# this is where feature flags can be easily added as a dictionary within context
|
# this is where feature flags can be easily added as a dictionary within context
|
||||||
# feature_about_page_enabled = application.config.get(
|
feature_socket_enabled = application.config.get(
|
||||||
# "FEATURE_ABOUT_PAGE_ENABLED", False
|
"FEATURE_SOCKET_ENABLED", False
|
||||||
# )
|
)
|
||||||
# return dict(
|
return dict(
|
||||||
# FEATURE_ABOUT_PAGE_ENABLED=feature_about_page_enabled,
|
FEATURE_SOCKET_ENABLED=feature_socket_enabled,
|
||||||
# )
|
)
|
||||||
|
|
||||||
@application.context_processor
|
@application.context_processor
|
||||||
def inject_initial_signin_url():
|
def inject_initial_signin_url():
|
||||||
|
|||||||
@@ -10,29 +10,35 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
const isJobPage = window.location.pathname.includes("/jobs/");
|
const isJobPage = window.location.pathname.includes("/jobs/");
|
||||||
if (!isJobPage) return;
|
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;
|
if (!jobId) return;
|
||||||
|
|
||||||
const socket = io("http://localhost:6011");
|
|
||||||
|
|
||||||
socket.on("connect", () => {
|
if (featureEnabled) {
|
||||||
console.log("Connected to Socket.IO server");
|
const socket = io("http://localhost:6011");
|
||||||
socket.emit("join", { room: `job-${jobId}` });
|
|
||||||
console.log("join", { room: `job-${jobId}` });
|
|
||||||
});
|
|
||||||
|
|
||||||
window.addEventListener("beforeunload", () => {
|
socket.on("connect", () => {
|
||||||
socket.emit("leave", { room: `job-${jobId}` });
|
console.log("Connected to Socket.IO server");
|
||||||
});
|
socket.emit("join", { room: `job-${jobId}` });
|
||||||
|
console.log("join", { room: `job-${jobId}` });
|
||||||
|
});
|
||||||
|
|
||||||
const debouncedUpdate = debounce((data) => {
|
window.addEventListener("beforeunload", () => {
|
||||||
updateAllJobSections();
|
socket.emit("leave", { room: `job-${jobId}` });
|
||||||
}, 1000);
|
});
|
||||||
|
|
||||||
socket.on("job_updated", (data) => {
|
const debouncedUpdate = debounce((data) => {
|
||||||
if (data.job_id !== jobId) return;
|
updateAllJobSections();
|
||||||
debouncedUpdate(data);
|
}, 1000);
|
||||||
});
|
|
||||||
|
socket.on("job_updated", (data) => {
|
||||||
|
if (data.job_id !== jobId) return;
|
||||||
|
debouncedUpdate(data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function updateAllJobSections() {
|
function updateAllJobSections() {
|
||||||
const resourceEl = document.querySelector('[data-socket-update="status"]');
|
const resourceEl = document.querySelector('[data-socket-update="status"]');
|
||||||
|
|||||||
@@ -89,6 +89,9 @@ class Config(object):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FEATURE_SOCKET_ENABLED = getenv("FEATURE_SOCKET_ENABLED", "false") == "true"
|
||||||
|
|
||||||
|
|
||||||
def _s3_credentials_from_env(bucket_prefix):
|
def _s3_credentials_from_env(bucket_prefix):
|
||||||
return {
|
return {
|
||||||
"bucket": getenv(
|
"bucket": getenv(
|
||||||
|
|||||||
@@ -25,15 +25,17 @@ from app.utils.user import user_is_logged_in
|
|||||||
def check_feature_flags():
|
def check_feature_flags():
|
||||||
# Placeholder for future feature flag checks
|
# Placeholder for future feature flag checks
|
||||||
# Example:
|
# Example:
|
||||||
# if request.path.startswith("/some-feature") and not current_app.config.get("FEATURE_SOME_FEATURE_ENABLED", False):
|
if request.path.startswith("/jobs") and not current_app.config.get(
|
||||||
# abort(404)
|
"FEATURE_SOCKET_ENABLED", False
|
||||||
|
):
|
||||||
|
abort(404)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@main.route("/test/feature-flags")
|
@main.route("/test/feature-flags")
|
||||||
def test_feature_flags():
|
def test_feature_flags():
|
||||||
return jsonify(
|
return jsonify(
|
||||||
{"FEATURE_ABOUT_PAGE_ENABLED": current_app.config["FEATURE_ABOUT_PAGE_ENABLED"]}
|
{"FEATURE_SOCKET_ENABLED": current_app.config["FEATURE_SOCKET_ENABLED"]}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from functools import partial
|
|||||||
|
|
||||||
from flask import (
|
from flask import (
|
||||||
Response,
|
Response,
|
||||||
|
current_app,
|
||||||
abort,
|
abort,
|
||||||
jsonify,
|
jsonify,
|
||||||
redirect,
|
redirect,
|
||||||
@@ -59,6 +60,7 @@ def view_job(service_id, job_id):
|
|||||||
filter_args["status"] = set_status_filters(filter_args)
|
filter_args["status"] = set_status_filters(filter_args)
|
||||||
return render_template(
|
return render_template(
|
||||||
"views/jobs/job.html",
|
"views/jobs/job.html",
|
||||||
|
FEATURE_SOCKET_ENABLED=current_app.config["FEATURE_SOCKET_ENABLED"],
|
||||||
job=job,
|
job=job,
|
||||||
status=request.args.get("status", ""),
|
status=request.args.get("status", ""),
|
||||||
updates_url=url_for(
|
updates_url=url_for(
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
{% from "components/page-footer.html" import page_footer %}
|
{% from "components/page-footer.html" import page_footer %}
|
||||||
{% from "components/page-header.html" import page_header %}
|
{% from "components/page-header.html" import page_header %}
|
||||||
{% from "components/components/back-link/macro.njk" import usaBackLink %}
|
{% from "components/components/back-link/macro.njk" import usaBackLink %}
|
||||||
{% from 'components/ajax-block.html' import socket_block %}
|
|
||||||
{% block service_page_title %}
|
{% block service_page_title %}
|
||||||
{{ "Message status" }}
|
{{ "Message status" }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -11,20 +11,33 @@
|
|||||||
{% block maincolumn_content %}
|
{% block maincolumn_content %}
|
||||||
|
|
||||||
{{ page_header("Message status") }}
|
{{ page_header("Message status") }}
|
||||||
<div
|
<div data-job-id="{{ job.id }}" data-feature="{{FEATURE_SOCKET_ENABLED}}">
|
||||||
data-socket-update="status"
|
{% if not job.finished_processing %}
|
||||||
data-resource="{{ updates_url }}"
|
<div
|
||||||
data-key="status"
|
data-resource="{{ updates_url }}"
|
||||||
data-job-id="{{ job.id }}"
|
{% if FEATURE_SOCKET_ENABLED %}
|
||||||
>
|
data-socket-update="status"
|
||||||
|
{% else %}
|
||||||
|
data-module="update-content"
|
||||||
|
{% endif %}
|
||||||
|
data-key="status"
|
||||||
|
data-form=""
|
||||||
|
>
|
||||||
|
{% endif %}
|
||||||
{{ partials['status']|safe }}
|
{{ partials['status']|safe }}
|
||||||
|
{% if not job.finished_processing %}
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
{% if not finished %}
|
{% if not finished %}
|
||||||
<div
|
<div
|
||||||
data-socket-update="counts"
|
|
||||||
data-job-id="{{ job.id }}"
|
|
||||||
data-resource="{{ updates_url }}"
|
data-resource="{{ updates_url }}"
|
||||||
|
{% if FEATURE_SOCKET_ENABLED %}
|
||||||
|
data-socket-update="counts"
|
||||||
|
{% else %}
|
||||||
|
data-module="update-content"
|
||||||
|
{% endif %}
|
||||||
data-key="counts"
|
data-key="counts"
|
||||||
|
data-form=""
|
||||||
>
|
>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{ partials['counts']|safe }}
|
{{ partials['counts']|safe }}
|
||||||
@@ -37,9 +50,12 @@
|
|||||||
</p>
|
</p>
|
||||||
{% if not job.processing_finished %}
|
{% if not job.processing_finished %}
|
||||||
<div
|
<div
|
||||||
data-socket-update="notifications"
|
|
||||||
data-job-id="{{ job.id }}"
|
|
||||||
data-resource="{{ updates_url }}"
|
data-resource="{{ updates_url }}"
|
||||||
|
{% if FEATURE_SOCKET_ENABLED %}
|
||||||
|
data-socket-update="notifications"
|
||||||
|
{% else %}
|
||||||
|
data-module="update-content"
|
||||||
|
{% endif %}
|
||||||
data-key="notifications"
|
data-key="notifications"
|
||||||
data-form=""
|
data-form=""
|
||||||
>
|
>
|
||||||
@@ -48,7 +64,6 @@
|
|||||||
{% if not job.processing_finished %}
|
{% if not job.processing_finished %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
</div>
|
||||||
<div> </div>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -85,7 +85,6 @@ const javascripts = () => {
|
|||||||
paths.src + 'javascripts/sidenav.js',
|
paths.src + 'javascripts/sidenav.js',
|
||||||
paths.src + 'javascripts/validation.js',
|
paths.src + 'javascripts/validation.js',
|
||||||
paths.src + 'javascripts/socketio.js',
|
paths.src + 'javascripts/socketio.js',
|
||||||
|
|
||||||
])
|
])
|
||||||
.pipe(plugins.prettyerror())
|
.pipe(plugins.prettyerror())
|
||||||
.pipe(
|
.pipe(
|
||||||
|
|||||||
Reference in New Issue
Block a user