Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion lib/schema_web/controllers/page_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ defmodule SchemaWeb.PageController do

@spec category_by_id(Plug.Conn.t(), map()) :: Plug.Conn.t()
def category_by_id(conn, params) do
params = Map.put_new(params, "extensions", "")

case SchemaController.category_classes(params) do
nil ->
send_resp(conn, 404, "Not Found: #{SchemaController.params_to_uid(params)}")
Expand All @@ -49,6 +51,7 @@ defmodule SchemaWeb.PageController do

@spec profiles(Plug.Conn.t(), map) :: Plug.Conn.t()
def profiles(conn, params) do
params = Map.put_new(params, "extensions", "")
profiles = get_profiles(params)
sorted_profiles = sort_by_descoped_key(profiles)

Expand Down Expand Up @@ -81,7 +84,10 @@ defmodule SchemaWeb.PageController do

@spec classes(Plug.Conn.t(), any) :: Plug.Conn.t()
def classes(conn, params) do
data = SchemaController.classes(params) |> sort_by(:uid)
data =
Map.put_new(params, "extensions", "")
|> SchemaController.classes()
|> sort_by(:uid)

render(conn, "classes.html",
extensions: Schema.extensions(),
Expand Down Expand Up @@ -137,6 +143,8 @@ defmodule SchemaWeb.PageController do

@spec objects(Plug.Conn.t(), map()) :: Plug.Conn.t()
def objects(conn, params) do
params = Map.put_new(params, "extensions", "")

data =
SchemaController.parse_options(SchemaController.extensions(params))
|> Schema.objects_filter_extensions()
Expand Down Expand Up @@ -190,6 +198,7 @@ defmodule SchemaWeb.PageController do

@spec dictionary(Plug.Conn.t(), any) :: Plug.Conn.t()
def dictionary(conn, params) do
params = Map.put_new(params, "extensions", "")
schema = Schema.schema()

data =
Expand Down
25 changes: 23 additions & 2 deletions lib/schema_web/templates/layout/app.html.eex
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,26 @@ limitations under the License.
this.href = this.href + params;
});

// Also update main navigation links
// Also update main navigation links (skip dropdown toggles and hash-only links)
$(".top-navbar-nav a.nav-link").each(function() {
if (this.getAttribute('href') === '#' || this.classList.contains('dropdown-toggle')) {
return;
}
this.href = this.href + params;
});

// Update content links (class, object, category, profile links in page body)
$(".main-page a").each(function() {
const href = this.getAttribute('href');
if (!href || href.startsWith('http') || href.startsWith('#') || href.startsWith('javascript:') || href.includes('?')) {
return;
}
// Only update internal schema navigation links
if (href.match(/^\/(classes|objects|categories|profiles|dictionary|data_types)/)) {
this.href = this.href + params;
}
});

// set the profile checkboxes
init_selected_profiles();

Expand Down Expand Up @@ -95,6 +110,9 @@ limitations under the License.
case '/objects':
$('#objects_id a.nav-link').addClass("active");
break;
case '/profiles':
$('#profiles_id a.nav-link').addClass("active");
break;
case '/objects/observable':
$('#observable_id a.nav-link').addClass("active");
break;
Expand Down Expand Up @@ -248,6 +266,9 @@ limitations under the License.
<li id="objects_id" class="nav-item">
<a class="nav-link" href='<%= Routes.static_path(@conn, "/objects") %>'>Objects</a>
</li>
<li id="profiles_id" class="nav-item">
<a class="nav-link" href='<%= Routes.static_path(@conn, "/profiles") %>'>Profiles</a>
</li>
<li id="observable_id" class="nav-item">
<a class="nav-link" href='<%= Routes.static_path(@conn, "/objects/observable") %>'>Observable</a>
</li>
Expand All @@ -261,7 +282,7 @@ limitations under the License.
<div class="navbar-text">|</div>

<li id="resources_id" class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button">Resources</a>
<a class="nav-link dropdown-toggle" href="javascript:void(0)" role="button">Resources</a>
<div class="dropdown-content">
<a class="dropdown-link" target="_blank" href='<%= Routes.static_path(@conn, "/doc") %>'>API Documentation</a>
<a class="dropdown-link" target="_blank" href="https://github.com/ocsf/ocsf-docs/blob/main/overview/understanding-ocsf.md">Understanding OCSF</a>
Expand Down
10 changes: 10 additions & 0 deletions lib/schema_web/templates/page/class.html.eex
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ limitations under the License.
<div class="text-secondary description-content">
<%= raw description(@data) %>
</div>
<%= if has_deprecated_attributes?(@data) do %>
<% dep_count = deprecated_attributes_count(@data) %>
<div class="deprecated-attr-notice" id="deprecated-attr-notice">
<i class="fas fa-exclamation-triangle"></i>
<span>
This class contains <strong><%= dep_count %></strong> deprecated <%= if dep_count == 1, do: "attribute", else: "attributes" %>.
Check the <strong>Show deprecated items</strong> box in the sidebar to view <%= if dep_count == 1, do: "it", else: "them" %>.
</span>
</div>
<% end %>
<%= if observables != nil and !Enum.empty?(observables) do %>
<div class="text-secondary mt-2">
Class-specific attribute path observables are <a href="#observables">at the bottom of this page</a>.
Expand Down
10 changes: 10 additions & 0 deletions lib/schema_web/templates/page/object.html.eex
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ limitations under the License.
<div class="text-secondary description-content">
<%= raw description(@data) %>
</div>
<%= if has_deprecated_attributes?(@data) do %>
<% dep_count = deprecated_attributes_count(@data) %>
<div class="deprecated-attr-notice" id="deprecated-attr-notice">
<i class="fas fa-exclamation-triangle"></i>
<span>
This object contains <strong><%= dep_count %></strong> deprecated <%= if dep_count == 1, do: "attribute", else: "attributes" %>.
Check the <strong>Show deprecated items</strong> box in the sidebar to view <%= if dep_count == 1, do: "it", else: "them" %>.
</span>
</div>
<% end %>
<%= raw object_references_section(references) %>
</div>
<div class="navbar-nav col-md-auto fixed-right mt-2">
Expand Down
10 changes: 10 additions & 0 deletions lib/schema_web/templates/page/profile.html.eex
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ limitations under the License.
<div class="text-secondary description-content">
<%= raw @data[:description] %>
</div>
<%= if has_deprecated_attributes?(@data) do %>
<% dep_count = deprecated_attributes_count(@data) %>
<div class="deprecated-attr-notice" id="deprecated-attr-notice">
<i class="fas fa-exclamation-triangle"></i>
<span>
This profile contains <strong><%= dep_count %></strong> deprecated <%= if dep_count == 1, do: "attribute", else: "attributes" %>.
Check the <strong>Show deprecated items</strong> box in the sidebar to view <%= if dep_count == 1, do: "it", else: "them" %>.
</span>
</div>
<% end %>
<%= raw object_references_section(@data[:references]) %>
</div>
<div class="navbar-nav col-md-auto fixed-right mt-2">
Expand Down
32 changes: 32 additions & 0 deletions lib/schema_web/views/page_view.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1743,4 +1743,36 @@ defmodule SchemaWeb.PageView do
def show_deprecated_css_classes(item) do
show_deprecated_css_classes(item, "")
end

@doc """
Returns true if the item (class or object) contains at least one deprecated attribute.
"""
@spec has_deprecated_attributes?(map()) :: boolean()
def has_deprecated_attributes?(item) do
deprecated_attributes_count(item) > 0
end

@doc """
Returns the count of deprecated attributes in the item (class or object).
"""
@spec deprecated_attributes_count(map()) :: non_neg_integer()
def deprecated_attributes_count(item) do
case item[:attributes] do
nil ->
0

attributes when is_map(attributes) ->
Enum.count(attributes, fn {_key, attr} ->
attr[:"@deprecated"] != nil
end)

attributes when is_list(attributes) ->
Enum.count(attributes, fn {_key, attr} ->
attr[:"@deprecated"] != nil
end)

_ ->
0
end
end
end
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
defmodule Schema.MixProject do
use Mix.Project

@version "4.0.2"
@version "4.1.0"

def project do
build = System.get_env("GITHUB_RUN_NUMBER") || "SNAPSHOT"
Expand Down
53 changes: 53 additions & 0 deletions priv/static/css/components.css
Original file line number Diff line number Diff line change
Expand Up @@ -764,3 +764,56 @@ button:hover,
background: var(--surface-color);
border-left-color: var(--accent-color);
}

/* Deprecated Attributes Badge - shown on classes/objects that contain deprecated attributes */
.deprecated-attr-badge {
display: inline-flex;
align-items: center;
justify-content: center;
color: var(--warning-color);
font-size: 0.75rem;
cursor: help;
opacity: 0.85;
transition: var(--transition-fast);
}

.deprecated-attr-badge:hover {
opacity: 1;
transform: scale(1.15);
}

[data-theme="dark"] .deprecated-attr-badge {
color: #FBBF24;
}

/* Deprecated Attributes Notice - banner on class/object detail pages */
.deprecated-attr-notice {
display: inline-flex;
align-items: center;
gap: var(--spacing-sm);
background: rgba(217, 119, 6, 0.08);
border: 1px solid rgba(217, 119, 6, 0.3);
border-left: 3px solid var(--warning-color);
border-radius: var(--radius-md);
padding: var(--spacing-sm) var(--spacing-md);
margin-top: var(--spacing-md);
font-size: 0.875rem;
color: var(--text-primary);
width: fit-content;
}

.deprecated-attr-notice i {
color: var(--warning-color);
font-size: 0.875rem;
flex-shrink: 0;
}

[data-theme="dark"] .deprecated-attr-notice {
background: rgba(251, 191, 36, 0.08);
border-color: rgba(251, 191, 36, 0.3);
border-left-color: #FBBF24;
}

[data-theme="dark"] .deprecated-attr-notice i {
color: #FBBF24;
}
8 changes: 4 additions & 4 deletions priv/static/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,17 @@ function select_extensions(selected) {
function build_url_params(extensions, profiles) {
let params = [];

// Add extensions parameter
// Always add extensions parameter (empty string means core-only)
if (extensions) {
const extensionParams = [];
Object.entries(extensions).forEach(function ([name, value]) {
if (value) {
extensionParams.push(name);
}
});
if (extensionParams.length > 0) {
params.push('extensions=' + extensionParams.join(','));
}
params.push('extensions=' + extensionParams.join(','));
} else {
params.push('extensions=');
}

// Add profiles parameter
Expand Down
Loading