Skip to content

Commit

Permalink
Merge pull request #476 from eyra/external-storages
Browse files Browse the repository at this point in the history
Add Fabric framework and Assignment Connection logic for external panel agencies and storage services
  • Loading branch information
mellelieuwes authored Nov 16, 2023
2 parents c9d08cc + 0d72810 commit 66dd3fc
Show file tree
Hide file tree
Showing 131 changed files with 3,794 additions and 889 deletions.
297 changes: 189 additions & 108 deletions core/assets/css/app.css

Large diffs are not rendered by default.

201 changes: 112 additions & 89 deletions core/assets/js/live_content.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
let liveContentId = "";
let liveContentShowErrors = false;
let liveContentActiveField = "";

const STATIC_CLASS_ATTR = "__eyra_field_static_class";
const HAS_ERRORS_ATTR = "__eyra_field_has_errors";
const ACTIVE_COLOR_ATTR = "__eyra_field_active_color";
Expand All @@ -22,122 +18,149 @@ const HIDDEN = "hidden";

export const LiveContent = {
mounted() {
liveContentId = this.el.id;
liveContentShowErrors = this.el.getAttribute(DATA_SHOW_ERRORS) != null;
console.log("LiveContent mounted", this.el);
this.showErrors = this.el.getAttribute(DATA_SHOW_ERRORS) != null;
this.activeField = undefined;

this.el.addEventListener("click", (event) => {
makeActive(undefined);
this.activeField = undefined;
this.applyActiveField();
});

applyErrors();
makeActive(undefined);
},
this.el.addEventListener("field-activated", (event) => {
event.stopPropagation();
this.activeField = event.target.dataset.fieldId;
this.applyActiveField();
});

this.el.addEventListener("field-deactivated", (event) => {
event.stopPropagation();
if (this.activeField == event.target.id) {
this.activeField = undefined;
this.applyActiveField();
}
});

this.applyErrors();
this.applyActiveField();
},
updated() {
liveContentShowErrors = this.el.getAttribute(DATA_SHOW_ERRORS) != null;
applyErrors();
this.showErrors = this.el.getAttribute(DATA_SHOW_ERRORS) != null;
this.applyErrors();
this.applyActiveField();
},

onBeforeElUpdated(from, to) {
const field_id = from.getAttribute("__eyra_field_id");

if (field_id != null) {
updateFieldItem(to, field_id);
to.classList = from.classList;
}
},
applyErrors() {
const fieldErrors = Array.from(
this.el.querySelectorAll(`.${FIELD_ERROR_TYPE}`)
);

console.log("fieldErrors", fieldErrors);

if (this.showErrors) {
fieldErrors.forEach((fieldError) => fieldError.classList.remove(HIDDEN));
} else {
fieldErrors.forEach((fieldError) => fieldError.classList.add(HIDDEN));
}
},
updateFieldItem(fieldItem, activate) {
const hasErrors = fieldItem.getAttribute(HAS_ERRORS_ATTR) != null;

if (fieldItem.classList.contains(FIELD_LABEL_TYPE)) {
this.updateFieldLabel(fieldItem, activate, hasErrors);
} else if (fieldItem.classList.contains(FIELD_INPUT_TYPE)) {
this.updateFieldInput(fieldItem, activate, hasErrors);
}
},
applyActiveField() {
var fields = Array.from(this.el.querySelectorAll('[id^="field-"]'));
fields.forEach((field) => {
var activate = field.dataset.fieldId === this.activeField;
this.updateField(field, activate);
});
},
updateField(field, activate) {
const label = field.getElementsByClassName(FIELD_LABEL_TYPE)[0];
const input = field.getElementsByClassName(FIELD_INPUT_TYPE)[0];

const hasErrors = field.getElementsByClassName(FIELD_ERROR_TYPE)[0] != null;

if (label) {
this.updateFieldLabel(label, activate, hasErrors);
}

if (input) {
this.updateFieldInput(input, activate, hasErrors);
}
},
updateFieldLabel(label, activate, hasErrors) {
this.updateFieldItemClass(
label,
activate,
hasErrors,
LABEL_IDLE,
LABEL_ERROR
);
},
updateFieldInput(input, activate, hasErrors) {
this.updateFieldItemClass(
input,
activate,
hasErrors,
INPUT_IDLE,
INPUT_ERROR
);
},
updateFieldItemClass(
fieldItem,
activate,
hasErrors,
idle_class,
error_class
) {
var dynamic_class = idle_class;
if (activate) {
dynamic_class = fieldItem.getAttribute(ACTIVE_COLOR_ATTR);
} else if (this.showErrors && hasErrors) {
dynamic_class = error_class;
}
const static_class = fieldItem.getAttribute(STATIC_CLASS_ATTR);
fieldItem.setAttribute("class", static_class + " " + dynamic_class);
},
};

export const LiveField = {
mounted() {
const fieldId = this.el.dataset.fieldId;
console.log("LiveField mounted");
const input = this.el.getElementsByClassName(FIELD_INPUT_TYPE)[0];

if (input) {
input.addEventListener("click", (event) => {
event.stopPropagation();
makeActive(fieldId);
this.activate();
});

input.addEventListener("focus", (event) => {
event.stopPropagation();
makeActive(fieldId);
this.activate();
});

input.addEventListener("blur", (event) => {
event.stopPropagation();
makeActive(undefined);
this.deactivate();
});
}
},
activate() {
this.el.dispatchEvent(new Event("field-activated", { bubbles: true }));
},
deactivate() {
this.el.dispatchEvent(new Event("field-deactivated", { bubbles: true }));
},
};

function applyErrors() {
const fieldErrors = Array.from(
document.querySelectorAll(`.${FIELD_ERROR_TYPE}`)
);
if (liveContentShowErrors) {
fieldErrors.forEach((fieldError) => fieldError.classList.remove(HIDDEN));
} else {
fieldErrors.forEach((fieldError) => fieldError.classList.add(HIDDEN));
}
}

function makeActive(fieldId) {
liveContentActiveField = fieldId;
var fields = Array.from(document.querySelectorAll('[id^="field-"]'));
fields.forEach((field) => {
var activate = field.dataset.fieldId === fieldId;
updateField(field, activate);
});
}

function updateField(field, activate) {
const label = field.getElementsByClassName(FIELD_LABEL_TYPE)[0];
const input = field.getElementsByClassName(FIELD_INPUT_TYPE)[0];

const hasErrors = field.getElementsByClassName(FIELD_ERROR_TYPE)[0] != null;

if (label) {
updateFieldLabel(label, activate, hasErrors);
}

if (input) {
updateFieldInput(input, activate, hasErrors);
}
}

function updateFieldItem(fieldItem, field) {
const activate = field == liveContentActiveField;
const hasErrors = fieldItem.getAttribute(HAS_ERRORS_ATTR) != null;

if (fieldItem.classList.contains(FIELD_LABEL_TYPE)) {
updateFieldLabel(fieldItem, activate, hasErrors);
} else if (fieldItem.classList.contains(FIELD_INPUT_TYPE)) {
updateFieldInput(fieldItem, activate, hasErrors);
}
}

function updateFieldLabel(label, activate, hasErrors) {
updateFieldItemClass(label, activate, hasErrors, LABEL_IDLE, LABEL_ERROR);
}

function updateFieldInput(input, activate, hasErrors) {
updateFieldItemClass(input, activate, hasErrors, INPUT_IDLE, INPUT_ERROR);
}

function updateFieldItemClass(
fieldItem,
activate,
hasErrors,
idle_class,
error_class
) {
var dynamic_class = idle_class;
if (activate) {
dynamic_class = fieldItem.getAttribute(ACTIVE_COLOR_ATTR);
} else if (liveContentShowErrors && hasErrors) {
dynamic_class = error_class;
}
const static_class = fieldItem.getAttribute(STATIC_CLASS_ATTR);
fieldItem.setAttribute("class", static_class + " " + dynamic_class);
}
8 changes: 8 additions & 0 deletions core/assets/static/images/icons/disconnect_tertiary.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions core/assets/static/images/icons/edit_tertiary.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions core/assets/static/images/wysiwyg/bullet-secondary.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 15 additions & 12 deletions core/assets/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ module.exports = {
"./js/**/*.js",
],
safelist: [
'drop-shadow-2xl',
'text-bold',
'text-pre',
'font-pre',
{pattern: /bg-wysiwyg-./ },
{pattern: /h-wysiwyg-./ },
{pattern: /border-./ },
],
"drop-shadow-2xl",
"text-bold",
"text-pre",
"font-pre",
{ pattern: /bg-wysiwyg-./ },
{ pattern: /h-wysiwyg-./ },
{ pattern: /border-./ },
],
theme: {
boxShadow: {
top4px: "inset 0 4px 0 0 rgba(0, 0, 0, 0.15)",
Expand Down Expand Up @@ -65,12 +65,15 @@ module.exports = {
"wysiwyg-code": "url('/images/wysiwyg/code.svg')",
"wysiwyg-list-bullet": "url('/images/wysiwyg/list_bullet.svg')",
"wysiwyg-list-number": "url('/images/wysiwyg/list_number.svg')",
"wysiwyg-nesting-level-decrease": "url('/images/wysiwyg/nesting_level_decrease.svg')",
"wysiwyg-nesting-level-increase": "url('/images/wysiwyg/nesting_level_increase.svg')",
"wysiwyg-nesting-level-decrease":
"url('/images/wysiwyg/nesting_level_decrease.svg')",
"wysiwyg-nesting-level-increase":
"url('/images/wysiwyg/nesting_level_increase.svg')",
"wysiwyg-attach": "url('/images/wysiwyg/attach.svg')",
"wysiwyg-history-undo": "url('/images/wysiwyg/history_undo.svg')",
"wysiwyg-history-redo": "url('/images/wysiwyg/history_redo.svg')",
"wysiwyg-bullet": "url('/images/wysiwyg/bullet.svg')",
"wysiwyg-bullet-dark": "url('/images/wysiwyg/bullet-secondary.svg')",
},
spacing: {
"1px": "1px",
Expand Down Expand Up @@ -194,7 +197,7 @@ module.exports = {
bold: ["Finador-Bold", "sans-serif"],
quote: ["Finador-Bold", "sans-serif"],
},
fontSize: {
fontSize: {
title0: ["64px", "68px"],
title1: ["50px", "55px"],
title2: ["40px", "44px"],
Expand Down Expand Up @@ -233,7 +236,7 @@ module.exports = {
card: "376px",
form: "400px",
sheet: "760px",
popup: "480px",
popup: "480px",
"popup-sm": "520px",
"popup-md": "730px",
"popup-lg": "1228px",
Expand Down
4 changes: 4 additions & 0 deletions core/config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ config :web_push_encryption, :vapid_details,

config :core, :version, System.get_env("VERSION", "dev")

config :core, :assignment, external_panels: ~w(liss ioresearch generic)

config :core, :storage, services: ~w(azure aws yoda)

config :core, BankingClient,
host: 'localhost',
port: 5555,
Expand Down
9 changes: 5 additions & 4 deletions core/config/dev.exs
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,11 @@ config :core, :s3, bucket: "eylixir"

config :core,
:data_donation_storage_backend,
fake: Systems.DataDonation.FakeStorageBackend,
s3: Systems.DataDonation.S3StorageBackend,
azure: Systems.DataDonation.AzureStorageBackend,
centerdata: Systems.DataDonation.CenterdataStorageBackend
fake: Systems.Storage.FakeBackend,
s3: Systems.Storage.AWS.Backend,
azure: Systems.Storage.Azure.Backend,
centerdata: Systems.Storage.Centerdata.Backend,
yoda: Systems.Storage.YodaBackend

# For Minio (local S3)
config :ex_aws,
Expand Down
7 changes: 4 additions & 3 deletions core/config/runtime.exs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ if config_env() == :prod do

config :core,
:data_donation_storage_backend,
s3: Systems.DataDonation.S3StorageBackend,
azure: Systems.DataDonation.AzureStorageBackend,
centerdata: Systems.DataDonation.CenterdataStorageBackend
s3: Systems.Storage.AWS.Backend,
azure: Systems.Storage.Azure.Backend,
centerdata: Systems.Storage.Centerdata.Backend,
yoda: Systems.Storage.YodaBackend

# MAILGUN

Expand Down
12 changes: 12 additions & 0 deletions core/frameworks/concept/content_model.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
defprotocol Frameworks.Concept.ContentModel do
@spec ready?(t) :: boolean()
def ready?(_t)

@spec form(t) :: atom()
def form(_t)
end

defimpl Frameworks.Concept.ContentModel, for: Ecto.Changeset do
def form(%{data: data}), do: Frameworks.Concept.ContentModel.form(data)
def ready?(changeset), do: changeset.valid?()
end
Loading

0 comments on commit 66dd3fc

Please sign in to comment.