- {!context.loggedIn &&
}
-
- {context.currentConfigurationProfile &&
+ {state.withoutSharedMappings && (
+
+ )}
+
+ {configurationProfile?.withSharedMappings &&
(state.loading ? (
) : (
<>
- {context.currentConfigurationProfile.name} :{' '}
- {i18n.t('ui.view_mapping.subtitle')}
+ {configurationProfile.name} : {i18n.t('ui.view_mapping.subtitle')}
{i18n.t('ui.view_mapping.select_abstract_class')}
- actions.setSelectedDomain(domains.find((domain) => domain.id == id))
- }
+ onTabClick={(id) => updateSelectedDomain(id)}
selectedId={selectedDomain?.id}
values={domains}
/>
@@ -116,6 +141,7 @@ const PropertyMappingList = (props) => {
{
- const selectedDomains = uniq(
- flatMap(term.alignments, (alignment) => alignment.selectedDomains || [])
+export const propertyClassesForSpineTerm = (term) =>
+ intersection(
+ term.compactDomains,
+ flatMap(term.alignments, (a) => a.compactDomains)
);
- const termClasses = term.property.domain || [];
- return intersection(selectedDomains, termClasses);
-};
-export const propertyClassesForAlignmentTerm = (alignment, term) => {
- const selectedDomains = alignment.selectedDomains || [];
- const termClasses = term.property.domain || [];
- return intersection(selectedDomains, termClasses);
-};
+export const propertyClassesForAlignmentTerm = (alignment, term) =>
+ intersection(term.compactDomains, alignment.compactDomains);
export const propertyMappingListStore = (initialData = {}) => ({
...baseModel(initialData),
...easyStateSetters(defaultState, initialData),
// computed
+ selectedConfigurationProfileId: computed((state) => (configurationProfile) => {
+ if (state.configurationProfile) return null;
+ return state.cp ? parseInt(state.cp) : configurationProfile?.id;
+ }),
// actions
setAllOrganizations: action((state, organizations) => {
@@ -67,24 +73,36 @@ export const propertyMappingListStore = (initialData = {}) => ({
state.predicates = predicates;
state.selectedPredicates = predicates;
}),
+ updateSelectedDomain: action((state, selectedDomain) => {
+ state.selectedDomain = selectedDomain;
+ state.abstractClass = null;
+ }),
+ updateSelectedConfigurationProfile: action((state, configurationProfile) => {
+ state.configurationProfile = configurationProfile;
+ if (configurationProfile) {
+ state.cp = null;
+ state.withoutSharedMappings = false;
+ } else {
+ state.withoutSharedMappings = true;
+ }
+ }),
// thunks
// Use the service to get all the available domains
- handleFetchDomains: thunk(async (actions, _params = {}, h) => {
+ handleFetchDomains: thunk(async (actions, params = {}, h) => {
const state = h.getState();
- const response = await fetchDomains();
+ const response = await fetchDomains(params);
if (state.withoutErrors(response)) {
actions.setDomains(response.domains);
- actions.setSelectedDomain(response.domains[0]);
} else {
actions.addError(response.error);
}
return response;
}),
// Use the service to get all the available organizations
- handleFetchOrganizations: thunk(async (actions, _params = {}, h) => {
+ handleFetchOrganizations: thunk(async (actions, params = {}, h) => {
const state = h.getState();
- const response = await fetchOrganizations();
+ const response = await fetchOrganizations(params);
if (state.withoutErrors(response)) {
actions.setAllOrganizations(response.organizations);
} else {
@@ -93,9 +111,9 @@ export const propertyMappingListStore = (initialData = {}) => ({
return response;
}),
// Use the service to get all the available predicates
- handleFetchPredicates: thunk(async (actions, _params = {}, h) => {
+ handleFetchPredicates: thunk(async (actions, params = {}, h) => {
const state = h.getState();
- const response = await fetchPredicates();
+ const response = await fetchPredicates(params);
if (state.withoutErrors(response)) {
actions.setAllPredicates(response.predicates);
} else {
@@ -106,10 +124,14 @@ export const propertyMappingListStore = (initialData = {}) => ({
// Fetch all the necessary data from the API
fetchDataFromAPI: thunk(async (actions, _params = {}, h) => {
actions.setLoading(true);
+ const state = h.getState();
+ const queryParams = {
+ configurationProfileId: state.configurationProfile?.id,
+ };
await Promise.all([
- actions.handleFetchDomains(),
- actions.handleFetchOrganizations(),
- actions.handleFetchPredicates(),
+ actions.handleFetchDomains(queryParams),
+ actions.handleFetchOrganizations(queryParams),
+ actions.handleFetchPredicates(queryParams),
]);
if (!h.getState().hasErrors) actions.setLoading(false);
}),
diff --git a/app/javascript/components/shared/AlertNotice.jsx b/app/javascript/components/shared/AlertNotice.jsx
index 2d252f09..158b3335 100644
--- a/app/javascript/components/shared/AlertNotice.jsx
+++ b/app/javascript/components/shared/AlertNotice.jsx
@@ -15,7 +15,7 @@ const AlertNotice = (props) => {
/**
* Elements from props
*/
- const { cssClass, title, message, onClose, withScroll = false } = props;
+ const { cssClass, title, message, onClose, withScroll = false, withTitle = true } = props;
const myRef = useRef(null);
useEffect(() => {
if (withScroll && !isEmpty(message) && myRef.current) {
@@ -28,14 +28,14 @@ const AlertNotice = (props) => {
const renderError = () => {
if (isArray(message) && message.length > 1) {
return (
-
+
{message.map((msg, i) => (
{msg}
))}
);
} else {
- return {isArray(message) ? message[0] : message}
;
+ return {isArray(message) ? message[0] : message}
;
}
};
@@ -44,9 +44,11 @@ const AlertNotice = (props) => {
ref={myRef}
className={'alert alert-dismissible ' + (cssClass ? cssClass : 'alert-danger')}
>
-
- {title ? title : 'Attention!'}
-
+ {withTitle && (
+
+ {title ? title : 'Attention!'}
+
+ )}
{renderError()}
{onClose && (
diff --git a/app/javascript/components/shared/ConfigurationProfileSelect.jsx b/app/javascript/components/shared/ConfigurationProfileSelect.jsx
index d0b211e1..10d8509b 100644
--- a/app/javascript/components/shared/ConfigurationProfileSelect.jsx
+++ b/app/javascript/components/shared/ConfigurationProfileSelect.jsx
@@ -1,10 +1,21 @@
import { useContext, useEffect, useState } from 'react';
import { AppContext } from '../../contexts/AppContext';
+import AlertNotice from './AlertNotice';
import fetchConfigurationProfiles from '../../services/fetchConfigurationProfiles';
import setConfigurationProfile from '../../services/setConfigurationProfile';
import Loader from '../shared/Loader';
+import { i18n } from 'utils/i18n';
-const ConfigurationProfileSelect = ({ onChange }) => {
+const ConfigurationProfileSelect = ({
+ onChange,
+ onSubmit,
+ requestType,
+ // selected configuration profile id
+ selectedConfigurationProfileId = null,
+ // flag to set or don't set the current configuration profile if no selectedConfigurationProfileId is passed
+ // in use at shared mappings page
+ withoutUserConfigurationProfile = false,
+}) => {
const {
currentConfigurationProfile,
setCurrentConfigurationProfile,
@@ -17,7 +28,9 @@ const ConfigurationProfileSelect = ({ onChange }) => {
const [submitting, setSubmitting] = useState(false);
const [selectedConfigurationProfile, setSelectedConfigurationProfile] = useState(
- currentConfigurationProfile
+ selectedConfigurationProfileId || withoutUserConfigurationProfile
+ ? null
+ : currentConfigurationProfile
);
const handleChange = (e) => {
@@ -30,6 +43,12 @@ const ConfigurationProfileSelect = ({ onChange }) => {
const handleSubmit = async (e) => {
e.preventDefault();
+ // if onSubmit is passed, call it and return, usually it's passed when we don't want to change the current configuration profile
+ // globally but just want to use it for a specific action
+ if (onSubmit) {
+ onSubmit(selectedConfigurationProfile);
+ return;
+ }
setSubmitting(true);
const configurationProfile = configurationProfiles.find(
@@ -55,13 +74,20 @@ const ConfigurationProfileSelect = ({ onChange }) => {
useEffect(() => {
(async () => {
- const { configurationProfiles } = await fetchConfigurationProfiles();
+ const { configurationProfiles } = await fetchConfigurationProfiles(requestType);
setConfigurationProfiles(configurationProfiles);
+ if (configurationProfiles.length && selectedConfigurationProfileId && onSubmit) {
+ const selectedConfigurationProfile = configurationProfiles.find(
+ (p) => p.id === selectedConfigurationProfileId
+ );
+ setSelectedConfigurationProfile(selectedConfigurationProfile);
+ onSubmit(selectedConfigurationProfile);
+ }
setLoading(false);
})();
}, []);
- return (
+ return configurationProfiles.length || loading ? (
Choose Configuration Profile
@@ -89,6 +115,14 @@ const ConfigurationProfileSelect = ({ onChange }) => {
+ ) : (
+
);
};
diff --git a/app/javascript/components/shared/DesmTabs.jsx b/app/javascript/components/shared/DesmTabs.jsx
index 0cc5ac50..358c5fbf 100644
--- a/app/javascript/components/shared/DesmTabs.jsx
+++ b/app/javascript/components/shared/DesmTabs.jsx
@@ -30,7 +30,7 @@ const DesmTabs = ({ values, selectedId, onTabClick }) => {
);
})}
- {selectedValue.definition && (
+ {selectedValue?.definition && (
{selectedValue.definition}
diff --git a/app/javascript/components/specifications-list/SpecsList.jsx b/app/javascript/components/specifications-list/SpecsList.jsx
index c7895b32..11f4b891 100644
--- a/app/javascript/components/specifications-list/SpecsList.jsx
+++ b/app/javascript/components/specifications-list/SpecsList.jsx
@@ -23,6 +23,7 @@ import {
} from '@fortawesome/free-solid-svg-icons';
import { AppContext } from '../../contexts/AppContext';
import { showSuccess } from '../../helpers/Messages';
+import { pageRoutes } from '../../services/pageRoutes';
export default class SpecsList extends Component {
static contextType = AppContext;
@@ -296,7 +297,10 @@ export default class SpecsList extends Component {
)}
diff --git a/app/javascript/helpers/queryString.jsx b/app/javascript/helpers/queryString.jsx
new file mode 100644
index 00000000..340f895b
--- /dev/null
+++ b/app/javascript/helpers/queryString.jsx
@@ -0,0 +1,59 @@
+import queryString from 'query-string';
+import { isEqual } from 'lodash';
+import { camelizeKeys } from 'humps';
+
+export const parseLocationSearch = ({ location }) => queryString.parse(location.search);
+// React Router v6 compatibile
+export const parseSearchParams = (search) => {
+ return Object.fromEntries([...search]);
+};
+// React Router v6 compatibile
+export const camelizeLocationSearch = (props, params = {}) =>
+ camelizeKeys(params.v6 ? Object.fromEntries([...props]) : parseLocationSearch(props));
+
+// React Router v6 compatibile
+export const parseWithRouter = (
+ params,
+ effects,
+ parsingParams = { withCamelizedKeys: false, v6: false }
+) => {
+ let parsed = {};
+
+ if (parsingParams.v6) {
+ parsed = parseSearchParams(params);
+ } else {
+ const { location } = params;
+ parsed = queryString.parse(location.search);
+ }
+
+ if (parsingParams.withCamelizedKeys) parsed = camelizeKeys(parsed);
+
+ if (effects) {
+ for (const param of Object.keys(effects)) {
+ const [effect, defaultValue] = effects[param];
+ const value = parsed[param];
+ if (value) {
+ effect(value);
+ } else {
+ effect(defaultValue);
+ }
+ }
+ }
+ return parsed;
+};
+
+// React Router v6 compatibile
+export const updateWithRouter = ({ history, location, v6 = false }) => (search) => {
+ const oldSearch = v6 ? parseSearchParams(location) : queryString.parse(location.search);
+ const newSearch = { ...oldSearch, ...search };
+ for (const k of Object.keys(newSearch)) {
+ if (!newSearch[k]) {
+ delete newSearch[k];
+ }
+ }
+ // don't need to push history if search is the same
+ if (isEqual(oldSearch, newSearch)) return;
+ const newQuery = new URLSearchParams(newSearch).toString();
+ const params = { pathname: '', search: `?${newQuery}` };
+ v6 ? history(params) : history.push(params);
+};
diff --git a/app/javascript/services/fetchAlignmentsForSpine.jsx b/app/javascript/services/fetchAlignmentsForSpine.jsx
index c19f7272..94ee947b 100644
--- a/app/javascript/services/fetchAlignmentsForSpine.jsx
+++ b/app/javascript/services/fetchAlignmentsForSpine.jsx
@@ -1,15 +1,14 @@
-import { camelizeKeys } from 'humps';
import apiRequest from './api/apiRequest';
-const fetchAlignmentsForSpine = async (spineId) => {
- let response = await apiRequest({
- url: `/api/v1/alignments?spine_id=${spineId}`,
+const fetchAlignmentsForSpine = async (queryParams = {}) => {
+ return await apiRequest({
+ url: '/api/v1/alignments',
method: 'get',
successResponse: 'alignments',
defaultResponse: [],
+ camelizeKeys: true,
+ queryParams,
});
-
- return camelizeKeys(response);
};
export default fetchAlignmentsForSpine;
diff --git a/app/javascript/services/fetchConfigurationProfiles.jsx b/app/javascript/services/fetchConfigurationProfiles.jsx
index c2ea8e3b..e1a2f792 100644
--- a/app/javascript/services/fetchConfigurationProfiles.jsx
+++ b/app/javascript/services/fetchConfigurationProfiles.jsx
@@ -1,15 +1,20 @@
-import { camelizeKeys } from 'humps';
import apiRequest from './api/apiRequest';
-const fetchConfigurationProfiles = async () => {
- let response = await apiRequest({
- url: '/api/v1/configuration_profiles',
+const REQUEST_TYPES = {
+ index: 'configuration_profiles',
+ indexForUser: 'configuration_profiles/index_for_user',
+ indexWithSharedMappings: 'configuration_profiles/index_shared_mappings',
+};
+
+const fetchConfigurationProfiles = async (requestType = 'index', queryParams = {}) => {
+ return await apiRequest({
+ url: `/api/v1/${REQUEST_TYPES[requestType]}`,
method: 'get',
defaultResponse: [],
successResponse: 'configurationProfiles',
+ camelizeKeys: true,
+ queryParams: queryParams,
});
-
- return camelizeKeys(response);
};
export default fetchConfigurationProfiles;
diff --git a/app/javascript/services/fetchDomains.jsx b/app/javascript/services/fetchDomains.jsx
index 34ffe945..3647185d 100644
--- a/app/javascript/services/fetchDomains.jsx
+++ b/app/javascript/services/fetchDomains.jsx
@@ -1,10 +1,11 @@
import apiRequest from './api/apiRequest';
-const fetchDomains = async () => {
+const fetchDomains = async (queryParams = {}) => {
const response = await apiRequest({
url: '/api/v1/domains',
method: 'get',
successResponse: 'domains',
+ queryParams,
});
if (!response.error) {
diff --git a/app/javascript/services/fetchOrganizations.jsx b/app/javascript/services/fetchOrganizations.jsx
index b140f21d..4bee300c 100644
--- a/app/javascript/services/fetchOrganizations.jsx
+++ b/app/javascript/services/fetchOrganizations.jsx
@@ -1,11 +1,12 @@
import apiRequest from './api/apiRequest';
-const fetchOrganizations = async () => {
+const fetchOrganizations = async (queryParams = {}) => {
return await apiRequest({
url: '/api/v1/organizations',
method: 'get',
defaultResponse: [],
successResponse: 'organizations',
+ queryParams,
});
};
diff --git a/app/javascript/services/fetchPredicates.jsx b/app/javascript/services/fetchPredicates.jsx
index 58a4536c..69d43aa2 100644
--- a/app/javascript/services/fetchPredicates.jsx
+++ b/app/javascript/services/fetchPredicates.jsx
@@ -1,11 +1,12 @@
import apiRequest from './api/apiRequest';
-const fetchPredicates = async () => {
+const fetchPredicates = async (queryParams = {}) => {
return await apiRequest({
url: '/api/v1/predicates',
method: 'get',
defaultResponse: [],
successResponse: 'predicates',
+ queryParams,
});
};
diff --git a/app/javascript/services/fetchSpineTerms.jsx b/app/javascript/services/fetchSpineTerms.jsx
index 4ae4f2ff..d15928d4 100644
--- a/app/javascript/services/fetchSpineTerms.jsx
+++ b/app/javascript/services/fetchSpineTerms.jsx
@@ -1,16 +1,15 @@
-import { camelizeKeys } from 'humps';
import apiRequest from './api/apiRequest';
const fetchSpineTerms = async (specId, queryParams = {}) => {
- const response = await apiRequest({
+ return await apiRequest({
// spine_terms#index
url: '/api/v1/spines/' + specId + '/terms',
defaultResponse: [],
successResponse: 'terms',
method: 'get',
+ camelizeKeys: true,
queryParams,
});
- return camelizeKeys(response);
};
export default fetchSpineTerms;
diff --git a/app/javascript/services/pageRoutes.js b/app/javascript/services/pageRoutes.js
index eaf4a8e0..f585ee1b 100644
--- a/app/javascript/services/pageRoutes.js
+++ b/app/javascript/services/pageRoutes.js
@@ -7,4 +7,9 @@ export const pageRoutes = {
organizations: () => '/dashboard/organizations',
configurationProfiles: () => '/dashboard/configuration-profiles',
configurationProfile: (id) => `/dashboard/configuration-profiles/${id}`,
+ // mappings
+ mappingsList: (cp, abstractClass = null) =>
+ `/mappings-list${cp ? `?cp=${cp}` : ''}${
+ abstractClass ? `${cp ? '&' : '?'}abstractClass=${abstractClass}` : ''
+ }`,
};
diff --git a/app/lib/utils.rb b/app/lib/utils.rb
new file mode 100644
index 00000000..a08b0758
--- /dev/null
+++ b/app/lib/utils.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+class Utils
+ ##
+ # Compacts a full URI.
+ #
+ # @param uri [String]
+ # @param context [Hash]
+ # @return [String|nil]
+ # If the `uri` is a compact URI, returns it as is.
+ # If the `uri` is a DESM URI, returns the value from which it was generated.
+ # If the `uri` belongs to a namespace from the `context`, returns its compact version.
+ # Otherwise, returns `nil`.
+ def self.compact_uri(uri, context: Desm::CONTEXT)
+ return uri unless uri.start_with?("http")
+ return URI(uri).path.split("/").last if uri.start_with?(Desm::DESM_NAMESPACE.to_s)
+
+ context.each do |prefix, namespace|
+ next unless namespace.is_a?(String)
+ return uri.sub(namespace, "#{prefix}:") if uri.start_with?(namespace)
+ end
+
+ nil
+ end
+end
diff --git a/app/models/alignment.rb b/app/models/alignment.rb
index 4f37941e..238bf8d7 100644
--- a/app/models/alignment.rb
+++ b/app/models/alignment.rb
@@ -63,6 +63,8 @@ class Alignment < ApplicationRecord
###
has_and_belongs_to_many :mapped_terms, join_table: :alignment_mapped_terms, class_name: :Term
+ has_one :specification, through: :mapping
+
has_one :spine, through: :mapping
###
@@ -99,6 +101,10 @@ class Alignment < ApplicationRecord
###
before_destroy :remove_spine_term, if: :synthetic
+ scope :mapped_for_spine, ->(spine_id) { joins(:mapping).where(mappings: { status: :mapped, spine_id: }) }
+
+ delegate :compact_domains, to: :specification
+
###
# METHODS
###
diff --git a/app/models/configuration_profile.rb b/app/models/configuration_profile.rb
index f22ad17f..14bd2b54 100644
--- a/app/models/configuration_profile.rb
+++ b/app/models/configuration_profile.rb
@@ -88,6 +88,7 @@ class ConfigurationProfile < ApplicationRecord
pg_search_scope :search_by_name, against: :name, using: { tsearch: { prefix: true } }
scope :activated, -> { where(state: %i(active deactivated)) }
+ scope :with_shared_mappings, -> { joins(:mappings).where(mappings: { status: Mapping.statuses[:mapped] }).distinct }
COMPLETE_SCHEMA = Rails.root.join("ns", "complete.configurationProfile.schema.json")
VALID_SCHEMA = Rails.root.join("ns", "valid.configurationProfile.schema.json")
@@ -198,6 +199,10 @@ def transition_to!(new_state)
public_send(persisted? ? :update_column : :update_attribute, :state, new_state)
end
+ def with_shared_mappings?
+ active? && mappings.mapped.any?
+ end
+
private
def update_organizations
diff --git a/app/models/property.rb b/app/models/property.rb
index 72a51c8c..2e859ae8 100644
--- a/app/models/property.rb
+++ b/app/models/property.rb
@@ -36,4 +36,11 @@
###
class Property < ApplicationRecord
belongs_to :term
+
+ ###
+ # @description: Returns the property's compact domains
+ ###
+ def compact_domains
+ @compact_domains ||= Array.wrap(domain).map { Utils.compact_uri(_1) }.compact
+ end
end
diff --git a/app/models/specification.rb b/app/models/specification.rb
index fa210d41..6ddde6e0 100644
--- a/app/models/specification.rb
+++ b/app/models/specification.rb
@@ -91,11 +91,17 @@ def to_json_ld
name:,
uri:,
version:,
- use_case:,
domain: domain.uri,
terms: terms.map(&:source_uri).sort
}
end
+ ###
+ # @description: Returns the specification's compact domains
+ ###
+ def compact_domains
+ @compact_domains ||= Array.wrap(selected_domains_from_file).map { Utils.compact_uri(_1) }.compact
+ end
+
scope :for_dso, ->(dso) { joins(:user).where(users: { id: dso.users }) }
end
diff --git a/app/models/term.rb b/app/models/term.rb
index 1af59c9e..5b2cac2c 100644
--- a/app/models/term.rb
+++ b/app/models/term.rb
@@ -68,6 +68,8 @@ class Term < ApplicationRecord
before_destroy :check_if_alignments_exist
+ delegate :compact_domains, to: :property
+
###
# @description: Include additional information about the specification in
# json responses. This overrides the ApplicationRecord as_json method.
diff --git a/app/policies/agent_policy.rb b/app/policies/agent_policy.rb
index 746fc062..a5e5d2fd 100644
--- a/app/policies/agent_policy.rb
+++ b/app/policies/agent_policy.rb
@@ -5,4 +5,11 @@
# agents records.
###
class AgentPolicy < AdminAccessPolicy
+ class Scope < ApplicationPolicy::Scope
+ def resolve
+ return scope.none unless user.user.super_admin?
+
+ User.joins(:roles).where(roles: { name: Desm::MAPPER_ROLE_NAME }).distinct
+ end
+ end
end
diff --git a/app/policies/configuration_profile_policy.rb b/app/policies/configuration_profile_policy.rb
index 37af8cc5..e47d27db 100644
--- a/app/policies/configuration_profile_policy.rb
+++ b/app/policies/configuration_profile_policy.rb
@@ -5,6 +5,26 @@
# configuration profiles records.
###
class ConfigurationProfilePolicy < AdminAccessPolicy
+ def index?
+ signed_in? && admin_role?
+ end
+
+ def index_shared_mappings?
+ signed_in?
+ end
+
+ def index_for_user?
+ signed_in?
+ end
+
+ def show?
+ signed_in?
+ end
+
+ def set_current?
+ signed_in?
+ end
+
class Scope < ApplicationPolicy::Scope
def resolve
return scope.all if user.user.super_admin?
diff --git a/app/serializers/alignment_serializer.rb b/app/serializers/alignment_serializer.rb
index c0522321..43f80ace 100644
--- a/app/serializers/alignment_serializer.rb
+++ b/app/serializers/alignment_serializer.rb
@@ -1,7 +1,8 @@
# frozen_string_literal: true
class AlignmentSerializer < ApplicationSerializer
- attributes :comment, :mapping_id, :origin, :predicate_id, :spine_term_id, :synthetic, :uri, :vocabulary_id
+ attributes :comment, :compact_domains, :mapping_id, :origin, :predicate_id, :spine_term_id, :synthetic, :uri,
+ :vocabulary_id
attributes :mapped_terms, :predicate
attribute :mapping, if: -> { params[:with_schema_name] } do
{ id: object.mapping.id, title: object.mapping.title, description: object.mapping.description,
@@ -12,11 +13,11 @@ class AlignmentSerializer < ApplicationSerializer
object.uri
end
attribute :schema_name, if: -> { params[:with_schema_name] } do
- schema = object.mapping.specification
+ schema = object.specification
"#{schema.name}#{schema.version.present? ? " (#{schema.version})" : ''}"
end
attribute :selected_domains, if: -> { params[:with_schema_name] } do
- object.mapping.specification.selected_domains_from_file
+ object.specification.selected_domains_from_file
end
# pass the params to the serializer
diff --git a/app/serializers/configuration_profile_serializer.rb b/app/serializers/configuration_profile_serializer.rb
index 9e5259ae..b7f754b1 100644
--- a/app/serializers/configuration_profile_serializer.rb
+++ b/app/serializers/configuration_profile_serializer.rb
@@ -4,6 +4,9 @@ class ConfigurationProfileSerializer < ApplicationSerializer
attributes :administrator_id, :description, :domain_set_id, :json_abstract_classes, :json_mapping_predicates,
:predicate_set_id, :predicate_strongest_match, :slug, :state, :structure
attribute :standards_organizations, if: -> { params[:with_organizations] }
+ attribute :with_shared_mappings, if: -> { params[:with_shared_mappings] } do
+ params[:shared_mappings] || object.with_shared_mappings?
+ end
def standards_organizations
ActiveModel::Serializer::CollectionSerializer.new(
diff --git a/app/serializers/configuration_profile_user_serializer.rb b/app/serializers/configuration_profile_user_serializer.rb
new file mode 100644
index 00000000..f5054417
--- /dev/null
+++ b/app/serializers/configuration_profile_user_serializer.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class ConfigurationProfileUserSerializer < ApplicationSerializer
+ attributes :description, :slug, :state, :lead_mapper
+ delegate :id, :name, :created_at, :updated_at, to: :configuration_profile
+ delegate :description, :slug, :state, to: :configuration_profile
+
+ def configuration_profile
+ object.configuration_profile
+ end
+
+ attribute :with_shared_mappings, if: -> { params[:with_shared_mappings] } do
+ configuration_profile.active? && configuration_profile.mappings.mapped.exists?
+ end
+
+ attribute :organization do
+ PreviewSerializer.new(object.organization)
+ end
+end
diff --git a/app/serializers/term_serializer.rb b/app/serializers/term_serializer.rb
index 93cced29..db21d314 100644
--- a/app/serializers/term_serializer.rb
+++ b/app/serializers/term_serializer.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class TermSerializer < ApplicationSerializer
- attributes :raw, :source_uri, :slug, :uri
+ attributes :compact_domains, :raw, :source_uri, :slug, :uri
has_one :property
has_many :vocabularies, serializer: PreviewSerializer
has_one :organization, if: -> { params[:spine] || params[:with_organization] }, serializer: PreviewSerializer
@@ -10,8 +10,8 @@ class TermSerializer < ApplicationSerializer
object.max_mapping_weight
end
- attribute :current_mapping_weight, if: -> { params[:spine] } do
- object.alignments.joins(:predicate).sum("predicates.weight")
+ attribute :current_mapping_weight, if: -> { params[:spine] && params[:spine_id] } do
+ object.alignments.mapped_for_spine(params[:spine_id]).joins(:predicate).sum("predicates.weight")
end
attribute :title do
diff --git a/app/services/converters/base.rb b/app/services/converters/base.rb
index 7f141dd8..ec9fd23f 100644
--- a/app/services/converters/base.rb
+++ b/app/services/converters/base.rb
@@ -12,8 +12,6 @@ class Base
skos: "http://www.w3.org/2004/02/skos/core#"
}.freeze
- DESM_NAMESPACE = URI("http://desmsolutions.org/ns/")
-
attr_reader :concept_scheme_cache, :domain_class_cache, :resources, :spec_id
##
@@ -54,7 +52,7 @@ def build_domain_class(*args)
# @return [String]
def build_desm_uri(value)
normalized_value = value.squish.gsub(/\W+/, "_")
- (DESM_NAMESPACE + "#{spec_id}/#{normalized_value}").to_s
+ (Desm::DESM_NAMESPACE + "#{spec_id}/#{normalized_value}").to_s
end
##
diff --git a/app/services/exporters/configuration_profile.rb b/app/services/exporters/configuration_profile.rb
index 4f37a222..34515eb6 100644
--- a/app/services/exporters/configuration_profile.rb
+++ b/app/services/exporters/configuration_profile.rb
@@ -104,7 +104,7 @@ def export_spines(spines)
def export_specification(specification)
specification
- .slice(*%w(name selected_domains_from_file version use_case))
+ .slice(*%w(name selected_domains_from_file version))
.merge(
"domain" => specification.domain.source_uri,
"terms" => specification.terms.map(&:source_uri)
diff --git a/app/services/exporters/mapping.rb b/app/services/exporters/mapping.rb
index fd0dd155..1b66744e 100644
--- a/app/services/exporters/mapping.rb
+++ b/app/services/exporters/mapping.rb
@@ -9,22 +9,6 @@ class Mapping
# CONSTANTS
###
- ###
- # @description: These are for established specs used in the mapping. This block will be the same for all mapping,
- # the prefixes an URIs are pre-existing constants.
- ###
- CONTEXT = {
- ceds: "http://desmsolutions.org/ns/ceds/",
- credReg: "http://desmsolutions.org/ns/credReg/",
- dct: "http://purl.org/dc/terms/",
- dcterms: "http://purl.org/dc/terms/",
- desm: "http://desmsolutions.org/ns/",
- rdf: "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
- rdfs: "http://www.w3.org/2000/01/rdf-schema#",
- sdo: "http://schema.org/",
- xsd: "http://www.w3.org/2001/XMLSchema#"
- }.freeze
-
###
# @description: Initializes this class with the instance to export.
###
@@ -37,7 +21,7 @@ def initialize(instance)
###
def export
{
- "@context": CONTEXT,
+ "@context": Desm::CONTEXT,
"@graph": @instance.alignments.map do |alignment|
term_nodes(alignment)
end.flatten.unshift(main_node)
diff --git a/app/services/importers/configuration_profile.rb b/app/services/importers/configuration_profile.rb
index de59f38e..493a20bf 100644
--- a/app/services/importers/configuration_profile.rb
+++ b/app/services/importers/configuration_profile.rb
@@ -108,7 +108,7 @@ def import
domain = domain_set.domains.find_by(source_uri: specification_data.fetch("domain"))
specification = profile_user.specifications.create!(
- **specification_data.slice(*%w(name selected_domains_from_file version use_case)),
+ **specification_data.slice(*%w(name selected_domains_from_file version)),
domain:,
terms: profile.terms.where(source_uri: specification_data.fetch("terms"))
)
diff --git a/app/services/processors/specifications.rb b/app/services/processors/specifications.rb
index 0eccbaeb..89ef0931 100644
--- a/app/services/processors/specifications.rb
+++ b/app/services/processors/specifications.rb
@@ -29,7 +29,6 @@ def self.create(data)
configuration_profile_user: data[:configuration_profile_user],
name: data[:name],
version: data[:version],
- use_case: data[:use_case],
domain: Domain.find(data[:domain_id]),
selected_domains_from_file: data[:selected_domains]
)
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index 3bfabcc8..44250e0c 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -17,6 +17,7 @@
data-logged-in="<%= current_user.present? %>"
data-organization="<%= current_organization&.to_json %>"
>
+ <%= render "shared/impersonation_status" %>
<%= yield %>