setup workos
This commit was merged in pull request #10.
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Admin Settings{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<main class="shell">
|
||||
<section class="page-heading stacked-heading">
|
||||
<div>
|
||||
<h1>Admin settings</h1>
|
||||
<p>Admin-only operational controls for the Nornsight workspace.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="admin-card">
|
||||
<h2>WorkOS-managed access</h2>
|
||||
<p>
|
||||
Invitations, Google access, and role assignments are managed in the WorkOS dashboard.
|
||||
This page confirms that app-level admin gating is active.
|
||||
</p>
|
||||
<dl class="admin-meta">
|
||||
<div>
|
||||
<dt>Workspace organization</dt>
|
||||
<dd><code>{{ organization_id }}</code></dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>Current administrator</dt>
|
||||
<dd>{{ current_user_email }}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<div class="admin-actions">
|
||||
<a href="/dashboard">Return to dashboard</a>
|
||||
<a href="https://dashboard.workos.com/" rel="noreferrer" target="_blank">Open WorkOS dashboard</a>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
{% endblock %}
|
||||
@@ -15,23 +15,33 @@
|
||||
</a>
|
||||
{% if show_primary_nav|default(true) %}
|
||||
<nav class="primary-nav" aria-label="Primary">
|
||||
<a href="/">Issues</a>
|
||||
{% if is_authenticated|default(false) %}
|
||||
<a href="/dashboard">Dashboard</a>
|
||||
<a href="/legislators">Legislators</a>
|
||||
<a href="/compare">Compare</a>
|
||||
{% if is_admin|default(false) %}
|
||||
<a href="/admin">Admin</a>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<a href="/">Overview</a>
|
||||
{% endif %}
|
||||
</nav>
|
||||
{% endif %}
|
||||
<nav class="account-nav" aria-label="Account">
|
||||
<a href="#" aria-disabled="true">Help</a>
|
||||
{% if is_authenticated|default(true) %}
|
||||
{% if is_authenticated|default(false) %}
|
||||
<details class="account-menu">
|
||||
<summary>My account</summary>
|
||||
<summary>{{ current_user_name or "My account" }}</summary>
|
||||
<div class="account-menu-panel">
|
||||
<span class="account-email">{{ current_user_email }}</span>
|
||||
<a href="#" aria-disabled="true">Account settings</a>
|
||||
<a class="sign-out" href="/logout">Sign out</a>
|
||||
<form action="/logout" method="post">
|
||||
<button class="sign-out" type="submit">Sign out</button>
|
||||
</form>
|
||||
</div>
|
||||
</details>
|
||||
{% else %}
|
||||
<a class="sign-in" href="/login">Sign in</a>
|
||||
<a class="sign-in" href="/login?next=/dashboard">Sign in</a>
|
||||
{% endif %}
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
<p>US legislative accountability · precomputed legislator topic scores{% if latest_score_year %} through {{ latest_score_year }}{% endif %}</p>
|
||||
</div>
|
||||
<div class="heading-actions">
|
||||
<span>{{ current_user_email }}</span>
|
||||
<a href="#" aria-disabled="true">Methodology</a>
|
||||
<a href="#" aria-disabled="true">Data sources</a>
|
||||
<span>Last updated: {{ last_updated.strftime("%b %Y") if last_updated else "Unavailable" }}</span>
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Nornsight | Legislative Accountability{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<main class="shell home-shell">
|
||||
{% if auth_error %}
|
||||
<div class="notice auth-notice">Authentication failed. Try signing in again.</div>
|
||||
{% endif %}
|
||||
|
||||
<section class="hero-panel">
|
||||
<div class="hero-copy">
|
||||
<p class="eyebrow">Invite-only access</p>
|
||||
<h1>Track legislative behavior with role-aware access and shared WorkOS sign-in.</h1>
|
||||
<p class="hero-text">
|
||||
Nornsight turns roll-call data into issue-level accountability views for your invited team.
|
||||
Use the public home page as the front door, then move signed-in users into the dashboard,
|
||||
legislator search, and comparison tools.
|
||||
</p>
|
||||
<div class="hero-actions">
|
||||
{% if is_authenticated %}
|
||||
<a class="hero-primary" href="/dashboard">Open dashboard</a>
|
||||
{% if is_admin %}
|
||||
<a class="hero-secondary" href="/admin">Admin settings</a>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<a class="hero-primary" href="/login?next=/dashboard">Sign in</a>
|
||||
<a class="hero-secondary" href="#access-model">How access works</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<aside class="hero-card">
|
||||
<h2>Launch access model</h2>
|
||||
<ul>
|
||||
<li>Public landing page at <code>/</code></li>
|
||||
<li>Invite-only AuthKit login with Email + Password and Google</li>
|
||||
<li><code>viewer</code> role for dashboard, legislators, and compare</li>
|
||||
<li><code>admin</code> role for settings and account administration</li>
|
||||
</ul>
|
||||
</aside>
|
||||
</section>
|
||||
|
||||
<section id="access-model" class="home-grid">
|
||||
<article class="home-card">
|
||||
<h2>For invited users</h2>
|
||||
<p>View the dashboard, inspect legislator profiles, and compare issue scoring without sharing a local password.</p>
|
||||
</article>
|
||||
<article class="home-card">
|
||||
<h2>For admins</h2>
|
||||
<p>Manage invitations and role assignments in WorkOS while the app enforces role-based route access.</p>
|
||||
</article>
|
||||
<article class="home-card">
|
||||
<h2>For rollout</h2>
|
||||
<p>Authentication is centralized, sessions are sealed, and the old hard-coded admin login is removed.</p>
|
||||
</article>
|
||||
</section>
|
||||
</main>
|
||||
{% endblock %}
|
||||
@@ -2,7 +2,7 @@
|
||||
<header>
|
||||
<h2>Score history{% if selected_issue_label %} — {{ selected_issue_label }}{% endif %}</h2>
|
||||
<a href="{{ build_url(request, compare=[]) }}"
|
||||
hx-get="/partials/dashboard{{ build_url(request, compare=[])|replace('/', '', 1) }}"
|
||||
hx-get="{{ build_dashboard_partial_url(request, compare=[]) }}"
|
||||
hx-target="#dashboard-body"
|
||||
hx-push-url="{{ build_url(request, compare=[]) }}">Clear comparison</a>
|
||||
</header>
|
||||
|
||||
@@ -3,17 +3,17 @@
|
||||
<div class="chamber-card">
|
||||
<a class="segment {{ 'active' if chamber == 'house' else '' }}"
|
||||
href="{{ build_url(request, chamber='house') }}"
|
||||
hx-get="/partials/dashboard{{ build_url(request, chamber='house')|replace('/', '', 1) }}"
|
||||
hx-get="{{ build_dashboard_partial_url(request, chamber='house') }}"
|
||||
hx-target="#dashboard-body"
|
||||
hx-push-url="{{ build_url(request, chamber='house') }}">House</a>
|
||||
<a class="segment {{ 'active' if chamber == 'senate' else '' }}"
|
||||
href="{{ build_url(request, chamber='senate') }}"
|
||||
hx-get="/partials/dashboard{{ build_url(request, chamber='senate')|replace('/', '', 1) }}"
|
||||
hx-get="{{ build_dashboard_partial_url(request, chamber='senate') }}"
|
||||
hx-target="#dashboard-body"
|
||||
hx-push-url="{{ build_url(request, chamber='senate') }}">Senate</a>
|
||||
<a class="segment {{ 'active' if chamber == 'all' else '' }}"
|
||||
href="{{ build_url(request, chamber='all') }}"
|
||||
hx-get="/partials/dashboard{{ build_url(request, chamber='all')|replace('/', '', 1) }}"
|
||||
hx-get="{{ build_dashboard_partial_url(request, chamber='all') }}"
|
||||
hx-target="#dashboard-body"
|
||||
hx-push-url="{{ build_url(request, chamber='all') }}">All</a>
|
||||
</div>
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
<h2>Issue filters</h2>
|
||||
<form class="issue-form"
|
||||
method="get"
|
||||
action="/"
|
||||
hx-get="/"
|
||||
action="/dashboard"
|
||||
hx-get="/partials/dashboard"
|
||||
hx-target="#dashboard-body"
|
||||
hx-push-url="true">
|
||||
hx-push-url="/dashboard">
|
||||
<input type="hidden" name="chamber" value="{{ chamber }}">
|
||||
{% if congress %}
|
||||
<input type="hidden" name="congress" value="{{ congress }}">
|
||||
@@ -17,7 +17,7 @@
|
||||
<span class="chip">
|
||||
{{ issue }}
|
||||
<a href="{{ build_url(request, issues=issues[:loop.index0] + issues[loop.index:]) }}"
|
||||
hx-get="/partials/dashboard{{ build_url(request, issues=issues[:loop.index0] + issues[loop.index:])|replace('/', '', 1) }}"
|
||||
hx-get="{{ build_dashboard_partial_url(request, issues=issues[:loop.index0] + issues[loop.index:]) }}"
|
||||
hx-target="#dashboard-body"
|
||||
hx-push-url="{{ build_url(request, issues=issues[:loop.index0] + issues[loop.index:]) }}"
|
||||
aria-label="Remove {{ issue }}">×</a>
|
||||
@@ -36,7 +36,7 @@
|
||||
{% for suggestion in suggestions %}
|
||||
{% if suggestion not in issues %}
|
||||
<a href="{{ build_url(request, issues=issues + [suggestion]) }}"
|
||||
hx-get="/partials/dashboard{{ build_url(request, issues=issues + [suggestion])|replace('/', '', 1) }}"
|
||||
hx-get="{{ build_dashboard_partial_url(request, issues=issues + [suggestion]) }}"
|
||||
hx-target="#dashboard-body"
|
||||
hx-push-url="{{ build_url(request, issues=issues + [suggestion]) }}">{{ suggestion }}</a>
|
||||
{% endif %}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
{% set next_compare = toggle_compare(compare, row.legislator_id) %}
|
||||
<li class="{{ 'selected' if row.legislator_id in compare else '' }}">
|
||||
<a href="{{ build_url(request, compare=next_compare) }}"
|
||||
hx-get="/partials/dashboard{{ build_url(request, compare=next_compare)|replace('/', '', 1) }}"
|
||||
hx-get="{{ build_dashboard_partial_url(request, compare=next_compare) }}"
|
||||
hx-target="#dashboard-body"
|
||||
hx-push-url="{{ build_url(request, compare=next_compare) }}">
|
||||
<span class="rank">{{ loop.index }}</span>
|
||||
@@ -40,7 +40,7 @@
|
||||
{% set next_compare = toggle_compare(compare, row.legislator_id) %}
|
||||
<li class="{{ 'selected' if row.legislator_id in compare else '' }}">
|
||||
<a href="{{ build_url(request, compare=next_compare) }}"
|
||||
hx-get="/partials/dashboard{{ build_url(request, compare=next_compare)|replace('/', '', 1) }}"
|
||||
hx-get="{{ build_dashboard_partial_url(request, compare=next_compare) }}"
|
||||
hx-target="#dashboard-body"
|
||||
hx-push-url="{{ build_url(request, compare=next_compare) }}">
|
||||
<span class="rank">{{ loop.index }}</span>
|
||||
|
||||
Reference in New Issue
Block a user