Compare commits

..

46 commits

Author SHA1 Message Date
4dd445be57 wip: wcag structure
Some checks failed
/ Run tests (push) Successful in 7m57s
/ Run system tests (push) Failing after 4m18s
/ Build, push and deploy image (push) Failing after 59s
2025-05-16 19:02:33 +02:00
4c31dbbed0 Update docker 2025-05-16 18:19:30 +02:00
b756df38a9 Docker config changes for cli editor 2024-11-25 00:06:53 +01:00
297138b0d4 add translation 2024-11-24 22:38:51 +01:00
12ea9ea1fb Add missing routes update
Some checks failed
/ Run tests (push) Successful in 2m2s
/ Run system tests (push) Failing after 2m27s
/ Build, push and deploy image (push) Successful in 3m44s
2024-11-24 22:37:05 +01:00
8b4ffb83ec Added projects
Some checks failed
/ Run tests (push) Failing after 2m3s
/ Run system tests (push) Failing after 2m17s
/ Build, push and deploy image (push) Has been skipped
2024-11-24 22:08:36 +01:00
0964187f22 tidy
Some checks failed
/ Run tests (push) Successful in 2m7s
/ Run system tests (push) Failing after 2m22s
/ Build, push and deploy image (push) Successful in 1m41s
2024-11-24 16:50:10 +01:00
83dd857776 Fix some pdf errors
Some checks failed
/ Run tests (push) Successful in 2m5s
/ Run system tests (push) Failing after 2m34s
/ Build, push and deploy image (push) Successful in 1m45s
2024-11-24 11:03:44 +01:00
650bec3f57 cosmetics
Some checks failed
/ Run tests (push) Successful in 2m3s
/ Run system tests (push) Failing after 2m22s
/ Build, push and deploy image (push) Successful in 1m38s
2024-11-24 03:58:28 +01:00
e1dfb14d4d finish customer report pdf
Some checks failed
/ Run tests (push) Successful in 1m58s
/ Run system tests (push) Failing after 2m23s
/ Build, push and deploy image (push) Successful in 1m36s
2024-11-24 03:40:48 +01:00
2082b20d5a list items
Some checks failed
/ Run tests (push) Successful in 2m2s
/ Run system tests (push) Failing after 2m27s
/ Build, push and deploy image (push) Successful in 1m38s
2024-11-24 03:22:51 +01:00
2de996a194 Fix link inline format true
Some checks failed
/ Run system tests (push) Waiting to run
/ Build, push and deploy image (push) Blocked by required conditions
/ Run tests (push) Has been cancelled
2024-11-24 03:21:52 +01:00
976936d480 Improve pdf
Some checks failed
/ Run tests (push) Successful in 2m4s
/ Run system tests (push) Failing after 2m30s
/ Build, push and deploy image (push) Successful in 1m34s
2024-11-24 03:16:36 +01:00
bf0548ecfe Improve pdf more
Some checks failed
/ Run tests (push) Successful in 2m0s
/ Run system tests (push) Failing after 2m21s
/ Build, push and deploy image (push) Successful in 1m37s
2024-11-24 01:32:24 +01:00
4abae91a5a Improve pdf
Some checks failed
/ Run tests (push) Successful in 2m9s
/ Run system tests (push) Failing after 2m35s
/ Build, push and deploy image (push) Successful in 1m33s
2024-11-24 00:58:36 +01:00
89ef15f41d Fix syntax
Some checks failed
/ Run tests (push) Successful in 2m1s
/ Run system tests (push) Failing after 2m19s
/ Build, push and deploy image (push) Successful in 1m31s
2024-11-23 23:26:21 +01:00
2a8e2835f3 Fix error handling
Some checks failed
/ Run tests (push) Failing after 1m51s
/ Run system tests (push) Failing after 1m46s
/ Build, push and deploy image (push) Has been skipped
2024-11-23 23:19:06 +01:00
bf2001d39c Fix unprocessable files
Some checks failed
/ Run tests (push) Successful in 1m57s
/ Run system tests (push) Has been cancelled
/ Build, push and deploy image (push) Has been cancelled
2024-11-23 23:16:24 +01:00
3f76aeeb3c improve pdf
Some checks failed
/ Run tests (push) Successful in 2m6s
/ Build, push and deploy image (push) Successful in 1m39s
/ Run system tests (push) Has been cancelled
2024-11-23 23:12:06 +01:00
02e13871bb Try fix faulty images
Some checks failed
/ Run tests (push) Successful in 2m3s
/ Run system tests (push) Failing after 2m22s
/ Build, push and deploy image (push) Successful in 1m38s
2024-11-23 22:06:50 +01:00
fd11eaff33 Add screenshot image to pdf export
Some checks failed
/ Run system tests (push) Waiting to run
/ Build, push and deploy image (push) Blocked by required conditions
/ Run tests (push) Has been cancelled
2024-11-23 22:05:01 +01:00
c36230b8ba edit comment and pdf export
Some checks failed
/ Run tests (push) Successful in 2m6s
/ Run system tests (push) Failing after 2m29s
/ Build, push and deploy image (push) Successful in 1m46s
2024-11-23 21:11:01 +01:00
110d75f2b7 fix lightbox
Some checks failed
/ Run tests (push) Successful in 2m4s
/ Run system tests (push) Failing after 2m34s
/ Build, push and deploy image (push) Successful in 4m5s
2024-11-23 19:24:43 +01:00
70500c49a1 Model menus, modal edit and layout improvements
Some checks failed
/ Run tests (push) Successful in 2m44s
/ Run system tests (push) Failing after 2m43s
/ Build, push and deploy image (push) Successful in 4m3s
2024-11-23 19:10:09 +01:00
7b0f05a448 fix external number params
Some checks failed
/ Run tests (push) Successful in 1m44s
/ Run system tests (push) Failing after 2m4s
/ Build, push and deploy image (push) Successful in 1m28s
2024-11-17 19:37:02 +01:00
889ad3275b Fix title
Some checks failed
/ Run tests (push) Successful in 1m42s
/ Run system tests (push) Failing after 2m4s
/ Build, push and deploy image (push) Successful in 1m33s
2024-11-17 19:02:59 +01:00
bf03407bb9 more beautiful button and export
Some checks failed
/ Run tests (push) Successful in 1m41s
/ Build, push and deploy image (push) Has been cancelled
/ Run system tests (push) Has been cancelled
2024-11-17 19:00:52 +01:00
e576aa1e39 Add page to hierarchy
Some checks failed
/ Run tests (push) Successful in 1m48s
/ Build, push and deploy image (push) Has been cancelled
/ Run system tests (push) Has been cancelled
2024-11-17 18:57:44 +01:00
acc5357627 Font color on danger menu item 2024-11-17 18:57:33 +01:00
b400ba7cea show check number and select correct elements
Some checks failed
/ Run tests (push) Successful in 1m42s
/ Run system tests (push) Failing after 2m1s
/ Build, push and deploy image (push) Successful in 1m35s
2024-11-17 17:11:17 +01:00
92c7fd43b1 Fix number in export
Some checks failed
/ Run tests (push) Successful in 1m49s
/ Build, push and deploy image (push) Has been cancelled
/ Run system tests (push) Has been cancelled
2024-11-17 17:07:54 +01:00
096e541969 Fix last fix........
Some checks failed
/ Run tests (push) Successful in 1m43s
/ Run system tests (push) Failing after 2m0s
/ Build, push and deploy image (push) Successful in 1m24s
2024-11-17 13:53:40 +01:00
1082011941 fix attribute name
Some checks failed
/ Run tests (push) Successful in 1m43s
/ Run system tests (push) Failing after 1m59s
/ Build, push and deploy image (push) Failing after 1m23s
2024-11-17 13:48:05 +01:00
fa1d5b8bce Improve exports and GUI
Some checks failed
/ Run tests (push) Successful in 1m47s
/ Run system tests (push) Has been cancelled
/ Build, push and deploy image (push) Has been cancelled
2024-11-17 13:44:51 +01:00
0a48759576 Remove styles from export
Some checks failed
/ Run tests (push) Successful in 1m44s
/ Run system tests (push) Failing after 2m1s
/ Build, push and deploy image (push) Successful in 1m29s
2024-11-17 02:44:04 +01:00
13755bacdb Improve export html for libreoffice writer
Some checks failed
/ Run tests (push) Successful in 1m44s
/ Run system tests (push) Failing after 2m1s
/ Build, push and deploy image (push) Successful in 1m30s
2024-11-17 01:58:47 +01:00
aa1552db81 Fix test
Some checks failed
/ Run tests (push) Successful in 2m13s
/ Run system tests (push) Failing after 2m16s
/ Build, push and deploy image (push) Successful in 2m7s
2024-11-17 00:50:39 +01:00
7f1c634996 Basic report export 2024-11-17 00:46:22 +01:00
65568ac27b Improve editor/dockerfile 2024-11-17 00:46:01 +01:00
c258754069 Ask before deleting report 2024-11-17 00:45:41 +01:00
3e2cef9907 GUI cosmetics 2024-11-17 00:45:23 +01:00
fab4981508 Add lightbox
Some checks failed
/ Run tests (push) Successful in 1m51s
/ Run system tests (push) Failing after 3m5s
/ Build, push and deploy image (push) Successful in 3m30s
2024-11-13 00:26:07 +01:00
934deddec4 Add some toasts 2024-11-12 23:55:00 +01:00
84fc1d2d93 Use blank in save display because file attributes are never nil
Some checks failed
/ Run tests (push) Successful in 1m38s
/ Run system tests (push) Failing after 2m5s
/ Build, push and deploy image (push) Successful in 3m9s
2024-11-12 22:57:47 +01:00
2f1566718e Fix nil pointer
Some checks failed
/ Run tests (push) Failing after 1m37s
/ Run system tests (push) Failing after 1m52s
/ Build, push and deploy image (push) Has been skipped
2024-11-12 22:49:07 +01:00
2293751fe2 Add screenshots to elements
Some checks failed
/ Run tests (push) Failing after 1m43s
/ Run system tests (push) Failing after 2m10s
/ Build, push and deploy image (push) Has been skipped
2024-11-12 22:43:59 +01:00
149 changed files with 2770 additions and 2113 deletions

View file

@ -41,3 +41,5 @@
/.forgejo/ /.forgejo/
/core* /core*
/.devenv

2
.gitignore vendored
View file

@ -74,3 +74,5 @@ public/504.html
public/505.html public/505.html
public/507.html public/507.html
public/510.html public/510.html
/.devenv

View file

@ -1 +1 @@
ruby-3.3.5 ruby-3.4

View file

@ -1,19 +1,19 @@
ARG RUBY_VERSION=3.4
ARG NAME=app ARG NAME=app
ARG UID=1000 ARG UID=1000
ARG GID=1000 ARG GID=1000
ARG APP_PORT=3000 ARG INSTALL_DIR=/home/${NAME}/src
ARG INSTALL_DIR=/${NAME}
ARG RUBY_VERSION=3.2.5 FROM ruby:${RUBY_VERSION} as development
FROM ruby:${RUBY_VERSION} AS development
LABEL maintainer='david@hohl.cloud'
ARG NAME ARG NAME
ARG UID ARG UID
ARG GID ARG GID
ARG APP_PORT
ARG INSTALL_DIR ARG INSTALL_DIR
LABEL maintainer='david@hohl.cloud'
WORKDIR ${INSTALL_DIR} WORKDIR ${INSTALL_DIR}
ENV GEM_HOME=${INSTALL_DIR}/.bundle ENV GEM_HOME=${INSTALL_DIR}/.bundle
@ -39,6 +39,7 @@ RUN \
--disabled-login \ --disabled-login \
--shell /bin/bash \ --shell /bin/bash \
${NAME} && \ ${NAME} && \
chown -R ${NAME}:${NAME} /home/${NAME} && \
apt-get update && \ apt-get update && \
apt-get install -yqq --no-install-recommends \ apt-get install -yqq --no-install-recommends \
gnupg2 \ gnupg2 \
@ -47,9 +48,8 @@ RUN \
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \ echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \
apt-get update -yqq && \ apt-get update -yqq && \
apt-get install -yqq --no-install-recommends \ apt-get install -yqq --no-install-recommends \
sqlite3 nodejs npm sassc yarn libvips fish ranger pandoc libjemalloc2 && \ sqlite3 nodejs npm sassc yarn libvips libjemalloc2 && \
apt-get clean && \ apt-get clean && \
npm install tabby-agent && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \ rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \
truncate -s 0 /var/log/*log && \ truncate -s 0 /var/log/*log && \
gem update --system && \ gem update --system && \
@ -57,135 +57,91 @@ RUN \
ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2
USER ${NAME} COPY bin/dev_entrypoint /usr/local/bin/dev_entrypoint
RUN mkdir -p ~/.config/fish && echo "set fish_greeting" >> ~/.config/fish/config.fish
RUN \
echo >> ~/.config/fish/config.fish &&\
echo "function fish_prompt" >> ~/.config/fish/config.fish &&\
echo " set -l last_status \$status" >> ~/.config/fish/config.fish &&\
echo " set -l stat" >> ~/.config/fish/config.fish &&\
echo " if test \$last_status -ne 0" >> ~/.config/fish/config.fish &&\
echo " set stat (set_color red)\"[\$last_status]\"(set_color normal)" >> ~/.config/fish/config.fish &&\
echo " end" >> ~/.config/fish/config.fish &&\
echo " string join '' -- (set_color green) (prompt_pwd) (set_color normal) \$stat ' 🐳 '" >> ~/.config/fish/config.fish && \
echo "end" >> ~/.config/fish/config.fish
FROM ruby:${RUBY_VERSION}-alpine AS builder
ARG NAME
ARG UID
ARG GID
ARG APP_PORT
ARG INSTALL_DIR
WORKDIR ${INSTALL_DIR}
ENV GEM_HOME=${INSTALL_DIR}/.bundle
ENV \
LANG=C.UTF-8 \
INSTALL_DIR=${INSTALL_DIR} \
RAILS_ENV=development \
TZ=Europe/Zurich \
PATH=${INSTALL_DIR}/bin:$GEM_HOME/bin:$GEM_HOME/gems/bin:$PATH \
EDITOR=vim
RUN apk add --update --no-cache \
binutils-gold \
build-base \
curl \
file \
g++ \
gcc \
git \
less \
libstdc++ \
libffi-dev \
libc-dev \
linux-headers \
libxml2-dev \
libxslt-dev \
libgcrypt-dev \
make \
netcat-openbsd \
nodejs \
openssl \
pkgconfig \
tzdata \
yarn \
sqlite \
vips-dev \
npm \
sassc \
jemalloc \
pandoc-cli \
sqlite-libs \
build-base && \
truncate -s 0 /var/log/*log && \
gem update --system && \
bundle config set app_config ${GEM_HOME}
ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2
USER ${NAME} USER ${NAME}
ENTRYPOINT ["/usr/local/bin/dev_entrypoint"]
CMD ["/bin/sh", "-c", "dev"]
FROM development AS build
USER root USER root
COPY Gemfile Gemfile.lock package.json yarn.lock ./ # Wir wollen die bundles nicht im app directory
ENV GEM_HOME=/usr/local/bundle \
BUNDLE_WITHOUT="development test" \
RAILS_ENV=production \
SECRET_KEY_BASE_DUMMY=1
ENV PATH=${INSTALL_DIR}/bin:$GEM_HOME/bin:$GEM_HOME/gems/bin:$PATH
RUN bundle config without test development && bundle install && yarn install COPY ./Gemfile ./Gemfile.lock ./
FROM builder AS assets
RUN bundle config set app_config ${GEM_HOME} && \
bundle config && \
bundle install && \
rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
bundle exec bootsnap precompile --gemfile
RUN bundle config
COPY . . COPY . .
COPY --from=builder ${INSTALL_DIR}/.bundle ${INSTALL_DIR}/.bundle RUN bundle exec bootsnap precompile app/ lib/ && \
COPY --from=builder ${INSTALL_DIR}/node_modules ${INSTALL_DIR}/node_modules rails assets:precompile && \
rm -rf log/* tmp/* && \
chown -R ${NAME}:${NAME} log tmp
RUN RAILS_ENV=production SECRET_KEY_BASE_DUMMY=1 rails assets:precompile
FROM ruby:${RUBY_VERSION}-alpine AS production FROM ruby:${RUBY_VERSION}-slim AS release
ARG INSTALL_DIR ARG UID
ARG NAME ARG GID
ARG NAME=app
ARG INSTALL_DIR
ARG BUILD_DIR=${INSTALL_DIR}
ARG INSTALL_DIR=/app
ENV GEM_HOME=/usr/local/bundle \
BUNDLE_WITHOUT="development test" \
BUNDLE_SYSTEM=1 \
RAILS_ENV=production \
LANG=C.UTF-8 \
INSTALL_DIR=${INSTALL_DIR} \
TZ=Europe/Zurich
ENV PATH=${INSTALL_DIR}/bin:$GEM_HOME/bin:$GEM_HOME/gems/bin:$PATH
WORKDIR ${INSTALL_DIR} WORKDIR ${INSTALL_DIR}
ENV GEM_HOME=${INSTALL_DIR}/.bundle RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
echo $TZ > /etc/timezone && \
adduser --disabled-password --disabled-login ${NAME} &&\
apt-get update -yqq && \
apt-get install -yqq --no-install-recommends \
sqlite3 libjemalloc2 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \
gem update --system && \
truncate -s 0 /var/log/*log
ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2
ENV \ RUN pwd
RAILS_ENV=production \
PATH=${INSTALL_DIR}/bin:$GEM_HOME/bin:$GEM_HOME/gems/bin:$PATH \
TZ=Europe/Zurich
RUN \ COPY --from=build ${GEM_HOME} ${GEM_HOME}
adduser ${NAME} --disabled-password --shell /bin/ash && \ COPY --from=build ${BUILD_DIR} .
apk add --update --no-cache \
tzdata \ RUN ls -la && chown -R ${NAME}:${NAME} ./tmp ./log ./storage
sqlite \
vips-dev \
jemalloc && \
gem update --system && \
bundle config set app_config ${GEM_HOME} && \
bundle config set without development test && \
apk add patchelf && \
patchelf --add-needed libjemalloc.so.2 /usr/local/bin/ruby && \
apk del patchelf && \
truncate -s 0 /var/log/*log
EXPOSE 3000 EXPOSE 3000
COPY . . ENTRYPOINT ["bin/docker-entrypoint"]
COPY --from=builder ${INSTALL_DIR}/.bundle ${INSTALL_DIR}/.bundle
COPY --from=assets ${INSTALL_DIR}/public/assets ${INSTALL_DIR}/public/assets
RUN chown -R ${NAME}:${NAME} ${INSTALL_DIR}/tmp ${INSTALL_DIR}/log ${INSTALL_DIR}/storage && \
date +"%Y-%m-%d %H:%M:%S %Z" >> .build_version
USER ${NAME} USER ${NAME}
ENTRYPOINT [ "bin/entrypoint" ] CMD ["./bin/rails", "server", "-b", "0"]
CMD [ "rails", "server", "--binding", "0.0.0.0", "--no-daemon", "--port" , "3000" ]

View file

@ -2,8 +2,6 @@
source "https://rubygems.org" source "https://rubygems.org"
ruby "3.2.5"
# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main" # Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
gem "rails", "~> 8.0" gem "rails", "~> 8.0"
@ -50,6 +48,7 @@ gem "bootsnap", require: false
gem "bootstrap_form" gem "bootstrap_form"
gem "caxlsx" gem "caxlsx"
gem "caxlsx_rails" gem "caxlsx_rails"
gem "deepl-rb", require: "deepl"
gem "image_processing", "~> 1.2" gem "image_processing", "~> 1.2"
gem "openxml-docx" gem "openxml-docx"
gem "pagy", "~> 9.0" gem "pagy", "~> 9.0"
@ -58,6 +57,7 @@ gem "prawn-markup"
gem "prawn-rails" gem "prawn-rails"
gem "sablon" gem "sablon"
gem "slim" gem "slim"
gem "solid_queue"
group :development, :test do group :development, :test do
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem

View file

@ -1,29 +1,29 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
actioncable (8.0.0) actioncable (8.0.2)
actionpack (= 8.0.0) actionpack (= 8.0.2)
activesupport (= 8.0.0) activesupport (= 8.0.2)
nio4r (~> 2.0) nio4r (~> 2.0)
websocket-driver (>= 0.6.1) websocket-driver (>= 0.6.1)
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
actionmailbox (8.0.0) actionmailbox (8.0.2)
actionpack (= 8.0.0) actionpack (= 8.0.2)
activejob (= 8.0.0) activejob (= 8.0.2)
activerecord (= 8.0.0) activerecord (= 8.0.2)
activestorage (= 8.0.0) activestorage (= 8.0.2)
activesupport (= 8.0.0) activesupport (= 8.0.2)
mail (>= 2.8.0) mail (>= 2.8.0)
actionmailer (8.0.0) actionmailer (8.0.2)
actionpack (= 8.0.0) actionpack (= 8.0.2)
actionview (= 8.0.0) actionview (= 8.0.2)
activejob (= 8.0.0) activejob (= 8.0.2)
activesupport (= 8.0.0) activesupport (= 8.0.2)
mail (>= 2.8.0) mail (>= 2.8.0)
rails-dom-testing (~> 2.2) rails-dom-testing (~> 2.2)
actionpack (8.0.0) actionpack (8.0.2)
actionview (= 8.0.0) actionview (= 8.0.2)
activesupport (= 8.0.0) activesupport (= 8.0.2)
nokogiri (>= 1.8.5) nokogiri (>= 1.8.5)
rack (>= 2.2.4) rack (>= 2.2.4)
rack-session (>= 1.0.1) rack-session (>= 1.0.1)
@ -31,35 +31,35 @@ GEM
rails-dom-testing (~> 2.2) rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6) rails-html-sanitizer (~> 1.6)
useragent (~> 0.16) useragent (~> 0.16)
actiontext (8.0.0) actiontext (8.0.2)
actionpack (= 8.0.0) actionpack (= 8.0.2)
activerecord (= 8.0.0) activerecord (= 8.0.2)
activestorage (= 8.0.0) activestorage (= 8.0.2)
activesupport (= 8.0.0) activesupport (= 8.0.2)
globalid (>= 0.6.0) globalid (>= 0.6.0)
nokogiri (>= 1.8.5) nokogiri (>= 1.8.5)
actionview (8.0.0) actionview (8.0.2)
activesupport (= 8.0.0) activesupport (= 8.0.2)
builder (~> 3.1) builder (~> 3.1)
erubi (~> 1.11) erubi (~> 1.11)
rails-dom-testing (~> 2.2) rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6) rails-html-sanitizer (~> 1.6)
activejob (8.0.0) activejob (8.0.2)
activesupport (= 8.0.0) activesupport (= 8.0.2)
globalid (>= 0.3.6) globalid (>= 0.3.6)
activemodel (8.0.0) activemodel (8.0.2)
activesupport (= 8.0.0) activesupport (= 8.0.2)
activerecord (8.0.0) activerecord (8.0.2)
activemodel (= 8.0.0) activemodel (= 8.0.2)
activesupport (= 8.0.0) activesupport (= 8.0.2)
timeout (>= 0.4.0) timeout (>= 0.4.0)
activestorage (8.0.0) activestorage (8.0.2)
actionpack (= 8.0.0) actionpack (= 8.0.2)
activejob (= 8.0.0) activejob (= 8.0.2)
activerecord (= 8.0.0) activerecord (= 8.0.2)
activesupport (= 8.0.0) activesupport (= 8.0.2)
marcel (~> 1.0) marcel (~> 1.0)
activesupport (8.0.0) activesupport (8.0.2)
base64 base64
benchmark (>= 0.3) benchmark (>= 0.3)
bigdecimal bigdecimal
@ -74,18 +74,18 @@ GEM
uri (>= 0.13.1) uri (>= 0.13.1)
addressable (2.8.7) addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0) public_suffix (>= 2.0.2, < 7.0)
ast (2.4.2) ast (2.4.3)
base64 (0.2.0) base64 (0.2.0)
bcrypt (3.1.20) bcrypt (3.1.20)
benchmark (0.4.0) benchmark (0.4.0)
bigdecimal (3.1.8) bigdecimal (3.1.9)
bindex (0.8.1) bindex (0.8.1)
bootsnap (1.18.3) bootsnap (1.18.6)
msgpack (~> 1.2) msgpack (~> 1.2)
bootstrap_form (5.4.0) bootstrap_form (5.4.0)
actionpack (>= 6.1) actionpack (>= 6.1)
activemodel (>= 6.1) activemodel (>= 6.1)
brakeman (6.1.2) brakeman (7.0.2)
racc racc
builder (3.3.0) builder (3.3.0)
capybara (3.40.0) capybara (3.40.0)
@ -97,7 +97,7 @@ GEM
rack-test (>= 0.6.3) rack-test (>= 0.6.3)
regexp_parser (>= 1.5, < 3.0) regexp_parser (>= 1.5, < 3.0)
xpath (~> 3.2) xpath (~> 3.2)
caxlsx (4.1.0) caxlsx (4.2.0)
htmlentities (~> 4.3, >= 4.3.4) htmlentities (~> 4.3, >= 4.3.4)
marcel (~> 1.0) marcel (~> 1.0)
nokogiri (~> 1.10, >= 1.10.4) nokogiri (~> 1.10, >= 1.10.4)
@ -105,47 +105,57 @@ GEM
caxlsx_rails (0.6.4) caxlsx_rails (0.6.4)
actionpack (>= 3.1) actionpack (>= 3.1)
caxlsx (>= 3.0) caxlsx (>= 3.0)
concurrent-ruby (1.3.3) concurrent-ruby (1.3.5)
connection_pool (2.4.1) connection_pool (2.5.3)
crass (1.0.6) crass (1.0.6)
cssbundling-rails (1.4.0) cssbundling-rails (1.4.3)
railties (>= 6.0.0) railties (>= 6.0.0)
date (3.4.0) date (3.4.1)
debug (1.9.2) debug (1.10.0)
irb (~> 1.10) irb (~> 1.10)
reline (>= 0.3.8) reline (>= 0.3.8)
deepl-rb (3.2.0)
drb (2.2.1) drb (2.2.1)
erubi (1.13.0) erubi (1.13.1)
ffi (1.17.0-aarch64-linux-gnu) et-orbi (1.2.11)
ffi (1.17.0-arm-linux-gnu) tzinfo
ffi (1.17.0-arm64-darwin) ffi (1.17.2-aarch64-linux-gnu)
ffi (1.17.0-x86-linux-gnu) ffi (1.17.2-aarch64-linux-musl)
ffi (1.17.0-x86_64-darwin) ffi (1.17.2-arm-linux-gnu)
ffi (1.17.0-x86_64-linux-gnu) ffi (1.17.2-arm-linux-musl)
ffi (1.17.2-arm64-darwin)
ffi (1.17.2-x86_64-darwin)
ffi (1.17.2-x86_64-linux-gnu)
ffi (1.17.2-x86_64-linux-musl)
fugit (1.11.1)
et-orbi (~> 1, >= 1.2.11)
raabro (~> 1.4)
globalid (1.2.1) globalid (1.2.1)
activesupport (>= 6.1) activesupport (>= 6.1)
hpricot (0.8.6) hpricot (0.8.6)
html2slim (0.2.0) html2slim (0.2.0)
hpricot hpricot
htmlentities (4.3.4) htmlentities (4.3.4)
i18n (1.14.5) i18n (1.14.7)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
image_processing (1.12.2) image_processing (1.14.0)
mini_magick (>= 4.9.5, < 5) mini_magick (>= 4.9.5, < 6)
ruby-vips (>= 2.0.17, < 3) ruby-vips (>= 2.0.17, < 3)
io-console (0.7.2) io-console (0.8.0)
irb (1.14.0) irb (1.15.2)
pp (>= 0.6.0)
rdoc (>= 4.0.0) rdoc (>= 4.0.0)
reline (>= 0.4.2) reline (>= 0.4.2)
jbuilder (2.12.0) jbuilder (2.13.0)
actionview (>= 5.0.0) actionview (>= 5.0.0)
activesupport (>= 5.0.0) activesupport (>= 5.0.0)
jsbundling-rails (1.3.0) jsbundling-rails (1.3.1)
railties (>= 6.0.0) railties (>= 6.0.0)
json (2.7.2) json (2.12.0)
language_server-protocol (3.17.0.3) language_server-protocol (3.17.0.5)
logger (1.6.1) lint_roller (1.1.0)
loofah (2.22.0) logger (1.7.0)
loofah (2.24.1)
crass (~> 1.0.2) crass (~> 1.0.2)
nokogiri (>= 1.12.0) nokogiri (>= 1.12.0)
mail (2.8.1) mail (2.8.1)
@ -155,31 +165,37 @@ GEM
net-smtp net-smtp
marcel (1.0.4) marcel (1.0.4)
matrix (0.4.2) matrix (0.4.2)
mini_magick (4.13.2) mini_magick (5.2.0)
benchmark
logger
mini_mime (1.1.5) mini_mime (1.1.5)
minitest (5.24.1) minitest (5.25.5)
msgpack (1.7.2) msgpack (1.8.0)
net-imap (0.5.0) net-imap (0.5.8)
date date
net-protocol net-protocol
net-pop (0.1.2) net-pop (0.1.2)
net-protocol net-protocol
net-protocol (0.2.2) net-protocol (0.2.2)
timeout timeout
net-smtp (0.5.0) net-smtp (0.5.1)
net-protocol net-protocol
nio4r (2.7.3) nio4r (2.7.4)
nokogiri (1.16.6-aarch64-linux) nokogiri (1.18.8-aarch64-linux-gnu)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.16.6-arm-linux) nokogiri (1.18.8-aarch64-linux-musl)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.16.6-arm64-darwin) nokogiri (1.18.8-arm-linux-gnu)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.16.6-x86-linux) nokogiri (1.18.8-arm-linux-musl)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.16.6-x86_64-darwin) nokogiri (1.18.8-arm64-darwin)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.16.6-x86_64-linux) nokogiri (1.18.8-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.18.8-x86_64-linux-gnu)
racc (~> 1.4)
nokogiri (1.18.8-x86_64-linux-musl)
racc (~> 1.4) racc (~> 1.4)
openxml-docx (0.11.5) openxml-docx (0.11.5)
nokogiri nokogiri
@ -189,76 +205,83 @@ GEM
openxml-drawingml (0.3.1) openxml-drawingml (0.3.1)
nokogiri nokogiri
openxml-package (~> 0.3.2) openxml-package (~> 0.3.2)
openxml-package (0.3.4) openxml-package (0.3.5)
nokogiri nokogiri
ox ox
rubyzip rubyzip (~> 2.3)
ox (2.14.18) ox (2.14.22)
pagy (9.0.2) bigdecimal (>= 3.0)
pagy (9.3.4)
pandoc-ruby (2.1.10) pandoc-ruby (2.1.10)
parallel (1.25.1) parallel (1.27.0)
parser (3.3.4.0) parser (3.3.8.0)
ast (~> 2.4.1) ast (~> 2.4.1)
racc racc
pdf-core (0.10.0) pdf-core (0.10.0)
pp (0.6.2)
prettyprint
prawn (2.5.0) prawn (2.5.0)
matrix (~> 0.4) matrix (~> 0.4)
pdf-core (~> 0.10.0) pdf-core (~> 0.10.0)
ttfunk (~> 1.8) ttfunk (~> 1.8)
prawn-markup (1.0.0) prawn-markup (1.1.0)
nokogiri nokogiri
prawn prawn
prawn-table prawn-table
prawn-rails (1.4.2) prawn-rails (1.6.0)
actionview (>= 3.1.0) actionview (>= 3.1.0)
activesupport (>= 3.1.0)
prawn prawn
prawn-table prawn-table
prawn-table (0.2.2) prawn-table (0.2.2)
prawn (>= 1.3.0, < 3.0.0) prawn (>= 1.3.0, < 3.0.0)
prism (1.2.0) prettyprint (0.2.0)
prism (1.4.0)
propshaft (1.1.0) propshaft (1.1.0)
actionpack (>= 7.0.0) actionpack (>= 7.0.0)
activesupport (>= 7.0.0) activesupport (>= 7.0.0)
rack rack
railties (>= 7.0.0) railties (>= 7.0.0)
psych (5.1.2) psych (5.2.6)
date
stringio stringio
public_suffix (6.0.0) public_suffix (6.0.2)
puma (6.4.2) puma (6.6.0)
nio4r (~> 2.0) nio4r (~> 2.0)
racc (1.8.0) raabro (1.4.0)
rack (3.1.7) racc (1.8.1)
rack-session (2.0.0) rack (3.1.14)
rack-session (2.1.1)
base64 (>= 0.1.0)
rack (>= 3.0.0) rack (>= 3.0.0)
rack-test (2.1.0) rack-test (2.2.0)
rack (>= 1.3) rack (>= 1.3)
rackup (2.1.0) rackup (2.2.1)
rack (>= 3) rack (>= 3)
webrick (~> 1.8) rails (8.0.2)
rails (8.0.0) actioncable (= 8.0.2)
actioncable (= 8.0.0) actionmailbox (= 8.0.2)
actionmailbox (= 8.0.0) actionmailer (= 8.0.2)
actionmailer (= 8.0.0) actionpack (= 8.0.2)
actionpack (= 8.0.0) actiontext (= 8.0.2)
actiontext (= 8.0.0) actionview (= 8.0.2)
actionview (= 8.0.0) activejob (= 8.0.2)
activejob (= 8.0.0) activemodel (= 8.0.2)
activemodel (= 8.0.0) activerecord (= 8.0.2)
activerecord (= 8.0.0) activestorage (= 8.0.2)
activestorage (= 8.0.0) activesupport (= 8.0.2)
activesupport (= 8.0.0)
bundler (>= 1.15.0) bundler (>= 1.15.0)
railties (= 8.0.0) railties (= 8.0.2)
rails-dom-testing (2.2.0) rails-dom-testing (2.2.0)
activesupport (>= 5.0.0) activesupport (>= 5.0.0)
minitest minitest
nokogiri (>= 1.6) nokogiri (>= 1.6)
rails-html-sanitizer (1.6.0) rails-html-sanitizer (1.6.2)
loofah (~> 2.21) loofah (~> 2.21)
nokogiri (~> 1.14) nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
railties (8.0.0) railties (8.0.2)
actionpack (= 8.0.0) actionpack (= 8.0.2)
activesupport (= 8.0.0) activesupport (= 8.0.2)
irb (~> 1.13) irb (~> 1.13)
rackup (>= 1.0.0) rackup (>= 1.0.0)
rake (>= 12.2) rake (>= 12.2)
@ -266,62 +289,62 @@ GEM
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
rainbow (3.1.1) rainbow (3.1.1)
rake (13.2.1) rake (13.2.1)
rbs (3.6.1) rbs (3.9.4)
logger logger
rdoc (6.7.0) rdoc (6.13.1)
psych (>= 4.0.0) psych (>= 4.0.0)
regexp_parser (2.9.2) regexp_parser (2.10.0)
reline (0.5.9) reline (0.6.1)
io-console (~> 0.5) io-console (~> 0.5)
rexml (3.3.2) rexml (3.4.1)
strscan rubocop (1.75.6)
rubocop (1.65.0)
json (~> 2.3) json (~> 2.3)
language_server-protocol (>= 3.17.0) language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0)
parallel (~> 1.10) parallel (~> 1.10)
parser (>= 3.3.0.2) parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0) rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 2.4, < 3.0) regexp_parser (>= 2.9.3, < 3.0)
rexml (>= 3.2.5, < 4.0) rubocop-ast (>= 1.44.0, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0)
ruby-progressbar (~> 1.7) ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0) unicode-display_width (>= 2.4.0, < 4.0)
rubocop-ast (1.31.3) rubocop-ast (1.44.1)
parser (>= 3.3.1.0) parser (>= 3.3.7.2)
rubocop-capybara (2.21.0) prism (~> 1.4)
rubocop (~> 1.41) rubocop-capybara (2.22.1)
rubocop-minitest (0.35.1) lint_roller (~> 1.1)
rubocop (>= 1.61, < 2.0) rubocop (~> 1.72, >= 1.72.1)
rubocop-ast (>= 1.31.1, < 2.0) rubocop-performance (1.25.0)
rubocop-performance (1.21.1) lint_roller (~> 1.1)
rubocop (>= 1.48.1, < 2.0) rubocop (>= 1.75.0, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0) rubocop-ast (>= 1.38.0, < 2.0)
rubocop-rails (2.25.1) rubocop-rails (2.31.0)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
lint_roller (~> 1.1)
rack (>= 1.1) rack (>= 1.1)
rubocop (>= 1.33.0, < 2.0) rubocop (>= 1.75.0, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0) rubocop-ast (>= 1.38.0, < 2.0)
rubocop-rails-omakase (1.0.0) rubocop-rails-omakase (1.1.0)
rubocop rubocop (>= 1.72)
rubocop-minitest rubocop-performance (>= 1.24)
rubocop-performance rubocop-rails (>= 2.30)
rubocop-rails ruby-lsp (0.23.20)
ruby-lsp (0.20.1)
language_server-protocol (~> 3.17.0) language_server-protocol (~> 3.17.0)
prism (>= 1.2, < 2.0) prism (>= 1.2, < 2.0)
rbs (>= 3, < 4) rbs (>= 3, < 4)
sorbet-runtime (>= 0.5.10782) sorbet-runtime (>= 0.5.10782)
ruby-lsp-rails (0.3.21) ruby-lsp-rails (0.4.3)
ruby-lsp (>= 0.20.0, < 0.21.0) ruby-lsp (>= 0.23.18, < 0.24.0)
ruby-progressbar (1.13.0) ruby-progressbar (1.13.0)
ruby-vips (2.2.1) ruby-vips (2.2.3)
ffi (~> 1.12) ffi (~> 1.12)
rubyzip (2.3.2) logger
rubyzip (2.4.1)
sablon (0.4.1) sablon (0.4.1)
nokogiri (>= 1.8.5) nokogiri (>= 1.8.5)
rubyzip (>= 1.3.0) rubyzip (>= 1.3.0)
securerandom (0.3.1) securerandom (0.4.1)
selenium-webdriver (4.23.0) selenium-webdriver (4.32.0)
base64 (~> 0.2) base64 (~> 0.2)
logger (~> 1.4) logger (~> 1.4)
rexml (~> 3.2, >= 3.2.5) rexml (~> 3.2, >= 3.2.5)
@ -330,53 +353,64 @@ GEM
slim (5.2.1) slim (5.2.1)
temple (~> 0.10.0) temple (~> 0.10.0)
tilt (>= 2.1.0) tilt (>= 2.1.0)
sorbet-runtime (0.5.11625) solid_queue (1.1.5)
sqlite3 (2.2.0-aarch64-linux-gnu) activejob (>= 7.1)
sqlite3 (2.2.0-arm-linux-gnu) activerecord (>= 7.1)
sqlite3 (2.2.0-arm64-darwin) concurrent-ruby (>= 1.3.1)
sqlite3 (2.2.0-x86-linux-gnu) fugit (~> 1.11.0)
sqlite3 (2.2.0-x86_64-darwin) railties (>= 7.1)
sqlite3 (2.2.0-x86_64-linux-gnu) thor (~> 1.3.1)
stimulus-rails (1.3.3) sorbet-runtime (0.5.12109)
sqlite3 (2.6.0-aarch64-linux-gnu)
sqlite3 (2.6.0-aarch64-linux-musl)
sqlite3 (2.6.0-arm-linux-gnu)
sqlite3 (2.6.0-arm-linux-musl)
sqlite3 (2.6.0-arm64-darwin)
sqlite3 (2.6.0-x86_64-darwin)
sqlite3 (2.6.0-x86_64-linux-gnu)
sqlite3 (2.6.0-x86_64-linux-musl)
stimulus-rails (1.3.4)
railties (>= 6.0.0) railties (>= 6.0.0)
stringio (3.1.1) stringio (3.1.7)
strscan (3.1.0)
temple (0.10.3) temple (0.10.3)
thor (1.3.1) thor (1.3.2)
tilt (2.4.0) tilt (2.6.0)
timeout (0.4.1) timeout (0.4.3)
ttfunk (1.8.0) ttfunk (1.8.0)
bigdecimal (~> 3.1) bigdecimal (~> 3.1)
turbo-rails (2.0.5) turbo-rails (2.0.13)
actionpack (>= 6.0.0) actionpack (>= 7.1.0)
activejob (>= 6.0.0) railties (>= 7.1.0)
railties (>= 6.0.0)
tzinfo (2.0.6) tzinfo (2.0.6)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
unicode-display_width (2.5.0) unicode-display_width (3.1.4)
uri (1.0.1) unicode-emoji (~> 4.0, >= 4.0.4)
useragent (0.16.10) unicode-emoji (4.0.4)
uri (1.0.3)
useragent (0.16.11)
web-console (4.2.1) web-console (4.2.1)
actionview (>= 6.0.0) actionview (>= 6.0.0)
activemodel (>= 6.0.0) activemodel (>= 6.0.0)
bindex (>= 0.4.0) bindex (>= 0.4.0)
railties (>= 6.0.0) railties (>= 6.0.0)
webrick (1.8.1)
websocket (1.2.11) websocket (1.2.11)
websocket-driver (0.7.6) websocket-driver (0.7.7)
base64
websocket-extensions (>= 0.1.0) websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5) websocket-extensions (0.1.5)
xpath (3.2.0) xpath (3.2.0)
nokogiri (~> 1.8) nokogiri (~> 1.8)
zeitwerk (2.6.16) zeitwerk (2.7.2)
PLATFORMS PLATFORMS
aarch64-linux aarch64-linux-gnu
arm-linux aarch64-linux-musl
arm-linux-gnu
arm-linux-musl
arm64-darwin arm64-darwin
x86-linux
x86_64-darwin x86_64-darwin
x86_64-linux x86_64-linux-gnu
x86_64-linux-musl
DEPENDENCIES DEPENDENCIES
bcrypt (~> 3.1.7) bcrypt (~> 3.1.7)
@ -388,6 +422,7 @@ DEPENDENCIES
caxlsx_rails caxlsx_rails
cssbundling-rails cssbundling-rails
debug debug
deepl-rb
html2slim html2slim
image_processing (~> 1.2) image_processing (~> 1.2)
jbuilder jbuilder
@ -409,14 +444,12 @@ DEPENDENCIES
sablon sablon
selenium-webdriver selenium-webdriver
slim slim
solid_queue
sqlite3 (>= 2.1) sqlite3 (>= 2.1)
stimulus-rails stimulus-rails
turbo-rails turbo-rails
tzinfo-data tzinfo-data
web-console web-console
RUBY VERSION
ruby 3.2.5p208
BUNDLED WITH BUNDLED WITH
2.5.15 2.6.2

View file

@ -1,3 +1,3 @@
web: env RUBY_DEBUG_OPEN=true bin/rails server -b 0 web: RUBY_DEBUG_OPEN=true bin/rails server -b 0
js: yarn build --watch js: yarn build --watch=forever
css: yarn watch:css css: yarn watch:css

View file

@ -2,3 +2,7 @@
`rails new -n a11yist -d sqlite3 --skip-action-mailbox --css bootstrap --js esbuild .` `rails new -n a11yist -d sqlite3 --skip-action-mailbox --css bootstrap --js esbuild .`
## Installation
To [install](readme)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -28,13 +28,8 @@ $enable-rounded: false;
@import 'bootstrap/scss/bootstrap'; @import 'bootstrap/scss/bootstrap';
@font-face { $lg-path-images: "";
font-display: block; $bootstrap-icons-font-dir: "";
font-family: "bootstrap-icons";
src: url("./bootstrap-icons.woff2") format("woff2"),
url("./bootstrap-icons.woff") format("woff");
}
@import 'bootstrap-icons/font/bootstrap-icons'; @import 'bootstrap-icons/font/bootstrap-icons';
@ -52,6 +47,10 @@ $enable-rounded: false;
@import "trix/dist/trix"; @import "trix/dist/trix";
$lg-path-fonts: "";
@import "lightgallery/scss/lightgallery";
/* /*
* Provides a drop-in pointer for the default Trix stylesheet that will format the toolbar and * Provides a drop-in pointer for the default Trix stylesheet that will format the toolbar and
* the trix-editor content (whether displayed or under editing). Feel free to incorporate this * the trix-editor content (whether displayed or under editing). Feel free to incorporate this
@ -164,4 +163,5 @@ trix-toolbar .trix-dialog--link {
overflow-y: auto; overflow-y: auto;
} */ } */
@import "./layout"; @import "./layout";
@import "./dropdown";

View file

@ -0,0 +1,67 @@
.details-dropdown {
display: inline-block;
position: relative;
}
/* Hide The disclosure widget: */
.details-dropdown summary {
list-style: none;
cursor: pointer;
}
.details-dropdown[open] summary {
list-style: none;
cursor: pointer;
i {
color: var(--bs-body-color)
}
/* border-left: solid 1px $secondary; */
/* border-top: solid 1px $secondary; */
/* border-right: solid 1px $secondary; */
}
.details-dropdown[open] {
background-color: $secondary;
}
/* Detache details content */
.details-dropdown .details-dropdown-content {
border: solid 1px $secondary;
position: absolute;
min-inline-size: max-content;
z-index: 2000;
/* In case the details-dropdown should open to the left: */
right: 0;
}
/* Closing the details-dropdown on clicking anywhere else */
.details-dropdown[open] summary::before {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
content: "";
cursor: default;
}
/* Visual styles for your details-dropdown: */
.details-dropdown .details-dropdown-trigger {
/* your look and feel here */
}
.details-dropdown .details-dropdown-content {
/* your look and feel here */
}
form.no-padding {
button {
padding: 0;
}
}
li.list-group-item-danger:hover {
button {
color: var(--bs-body-color) !important;
}
}

View file

@ -20,37 +20,6 @@ $tertiary-dark-active-open: $gray-600;
} }
} }
// // Fix trix dark mode
// .trix-button-row {
// .trix-button-group {
// border: var(--bs-border-width) solid var(--bs-border-color);
// .trix-button {
// border: 0;
// }
// }
// }
// [data-bs-theme=dark] {
// .trix-button-row {
// .trix-button-group {
// .trix-button {
// background-color: transparent;
// filter: invert(100%);
// }
// }
// }
// }
// // end fix trix dark mode
// .trix-content pre {
// background-color: var(--bs-secondary-bg);
// color: var(--bs-secondary-color);
// border: var(--bs-border-width) solid var(--bs-border-color);
// border-radius: var(--bs-border-radius);
// padding: var(--bs-padding);
// }
.hover-row:hover { .hover-row:hover {
background-color: var(--bs-tertiary-bg); background-color: var(--bs-tertiary-bg);
} }
@ -91,7 +60,10 @@ $tertiary-dark-active-open: $gray-600;
.page_nav nav ul { .page_nav nav ul {
padding-left: 0; padding-left: 0;
list-style-type: none; list-style-type: none;
line-height: 2rem;
li {
margin-bottom: 0.5rem;
}
a { a {
color: var(--bs-text); color: var(--bs-text);
@ -223,7 +195,15 @@ details.tree[open]>summary::before {
padding-bottom: 0; padding-bottom: 0;
} }
details.success_criterion:last-child {
border-bottom: solid 1px $tertiary;
}
details.success_criterion { details.success_criterion {
border-left: solid 1px $tertiary;
border-right: solid 0px $tertiary;
border-top: solid 0px $tertiary;
summary:hover { summary:hover {
background-color: $tertiary-hover; background-color: $tertiary-hover;
@ -239,6 +219,7 @@ details.success_criterion {
>.content { >.content {
padding-left: 1rem; padding-left: 1rem;
padding-right: 1rem; padding-right: 1rem;
padding-bottom: 1rem;
} }
} }
@ -253,26 +234,36 @@ details.success_criterion {
details.success_criterion[open] { details.success_criterion[open] {
border: solid 1px $tertiary; /* border: solid 1px $tertiary; */
summary { >summary {
background-color: $tertiary; background-color: $tertiary;
} }
summary:hover { >summary:hover {
background-color: $tertiary-active-hover; background-color: $tertiary-active-hover;
} }
} }
@include color-mode(dark) { @include color-mode(dark) {
details.success_criterion[open] { details.success_criterion {
border: solid 1px $tertiary-dark; border-left: solid 1px $tertiary-dark;
border-right: solid 1px $tertiary-dark;
border-top: solid 1px $tertiary-dark;
}
summary { details.success_criterion:last-child {
border-bottom: solid 1px $tertiary-dark;
}
details.success_criterion[open] {
/* border: solid 1px $tertiary-dark; */
>summary {
background-color: $tertiary-dark; background-color: $tertiary-dark;
} }
summary:hover { >summary:hover {
background-color: $tertiary-dark-active-open; background-color: $tertiary-dark-active-open;
} }
} }
@ -326,4 +317,65 @@ details[open] {
.sortable-ghost { .sortable-ghost {
border: solid 3px $primary !important; border: solid 3px $primary !important;
}
$dialog-animation-time: 0.5s;
$dialog-animation-start-state: scaleX(1);
$dialog-animation-end-state: scaleX(1);
/* dialog::backdrop { */
/* background-color: white; */
/* opacity: 0.75; */
/* } */
/* Open state of the dialog */
dialog[open] {
opacity: 1;
transform: $dialog-animation-end-state;
}
/* Closed state of the dialog */
dialog {
opacity: 0;
transform: $dialog-animation-start-state;
transition:
opacity $dialog-animation-time ease-out,
transform $dialog-animation-time ease-out,
overlay $dialog-animation-time ease-out allow-discrete,
display $dialog-animation-time ease-out allow-discrete;
/* Equivalent to
transition: all $dialog-animation-time allow-discrete; */
}
/* Before-open state */
/* Needs to be after the previous dialog[open] rule to take effect,
as the specificity is the same */
@starting-style {
dialog[open] {
opacity: 0;
transform: $dialog-animation-start-state;
}
}
/* Transition the :backdrop when the dialog modal is promoted to the top layer */
dialog::backdrop {
background-color: rgb(0 0 0 / 75%);
transition:
display $dialog-animation-time allow-discrete,
overlay $dialog-animation-time allow-discrete,
background-color $dialog-animation-time;
/* Equivalent to
transition: all $dialog-animation-time allow-discrete; */
}
dialog[open]::backdrop {
background-color: rgb(0 0 0 / 75%);
}
/* This starting-style rule cannot be nested inside the above selector
because the nesting selector cannot represent pseudo-elements. */
@starting-style {
dialog[open]::backdrop {
background-color: rgb(0 0 0 / 0%);
}
} }

View file

@ -22,9 +22,9 @@ class ApplicationController < ActionController::Base
path: :root path: :root
}, },
{ {
label: Report.model_name.human(count: 2), label: Project.model_name.human(count: 2),
icon: :'journal-text', icon: :'folder',
path: :reports }, path: :projects },
{ {
label: I18n.t("backoffice"), label: I18n.t("backoffice"),
icon: :gear, icon: :gear,
@ -32,7 +32,8 @@ class ApplicationController < ActionController::Base
active: %w[backoffice checklists checks links link_categories].include?(controller_name) }, active: %w[backoffice checklists checks links link_categories].include?(controller_name) },
{ {
label: "Konto", label: "Konto",
path: profile_path path: profile_path,
icon: "person-circle"
} }
] ]
else else
@ -50,4 +51,8 @@ class ApplicationController < ActionController::Base
def initialize_sidebar_items def initialize_sidebar_items
[] []
end end
def render_modal(action: action_name)
render action, layout: "modal" if turbo_frame_request_id == "modal"
end
end end

View file

@ -81,7 +81,7 @@ class ChecksController < ApplicationController
# Only allow a list of trusted parameters through. # Only allow a list of trusted parameters through.
def check_params def check_params
params.require(:check).permit(:principle_id, params.require(:check).permit(:guideline_id,
:number, :number,
:name_de, :name_de,
:name_en, :name_en,
@ -95,7 +95,9 @@ class ChecksController < ApplicationController
:applicable_to_analogue, :applicable_to_analogue,
:applicable_to_document, :applicable_to_document,
:applicable_to_non_web, :applicable_to_non_web,
:external_number, :external_number_1,
:external_number_2,
:external_number_3,
:external_url, :external_url,
:conformity_level, :conformity_level,
:conformity_notice_de, :conformity_notice_de,

View file

@ -21,7 +21,6 @@ module Authentication
resume_session || request_authentication resume_session || request_authentication
end end
def resume_session def resume_session
Current.session ||= find_session_by_cookie Current.session ||= find_session_by_cookie
end end
@ -30,7 +29,6 @@ module Authentication
Session.find_by(id: cookies.signed[:session_id]) Session.find_by(id: cookies.signed[:session_id])
end end
def request_authentication def request_authentication
session[:return_to_after_authenticating] = request.url session[:return_to_after_authenticating] = request.url
redirect_to new_session_path redirect_to new_session_path
@ -40,7 +38,6 @@ module Authentication
session.delete(:return_to_after_authenticating) || root_url session.delete(:return_to_after_authenticating) || root_url
end end
def start_new_session_for(user) def start_new_session_for(user)
user.sessions.create!(user_agent: request.user_agent, ip_address: request.remote_ip).tap do |session| user.sessions.create!(user_agent: request.user_agent, ip_address: request.remote_ip).tap do |session|
Current.session = session Current.session = session

View file

@ -5,6 +5,7 @@ module BackofficeMenu
[ [
{ label: "Einstellungen", icon: :sliders, path: :backoffice }, { label: "Einstellungen", icon: :sliders, path: :backoffice },
{ label: Checklist.model_name.human(count: 2), icon: :'list-check', path: :checklists }, { label: Checklist.model_name.human(count: 2), icon: :'list-check', path: :checklists },
{ label: Guideline.model_name.human(count: 2), icon: :'rulers', path: :guidelines },
{ label: Check.model_name.human(count: 2), icon: :check2, path: :checks }, { label: Check.model_name.human(count: 2), icon: :check2, path: :checks },
{ label: Link.model_name.human(count: 2), icon: :link, path: :links }, { label: Link.model_name.human(count: 2), icon: :link, path: :links },
{ label: LinkCategory.model_name.human(count: 2), icon: :folder, path: :link_categories } ] { label: LinkCategory.model_name.human(count: 2), icon: :folder, path: :link_categories } ]

View file

@ -19,7 +19,9 @@ class ElementsController < ApplicationController
end end
# GET /elements/1/edit # GET /elements/1/edit
def edit; end def edit
render_modal
end
# POST /elements # POST /elements
def create def create
@ -87,6 +89,6 @@ class ElementsController < ApplicationController
# Only allow a list of trusted parameters through. # Only allow a list of trusted parameters through.
def element_params def element_params
params.require(:element).permit(:page_id, :title, :description, :position) params.require(:element).permit(:page_id, :title, :description, :position, :screenshot)
end end
end end

View file

@ -0,0 +1,58 @@
class GuidelinesController < BackofficeController
before_action :set_guideline, only: %i[ show edit update destroy ]
# GET /guidelines
def index
@guidelines = Guideline.all
end
# GET /guidelines/1
def show
end
# GET /guidelines/new
def new
@guideline = Guideline.new
end
# GET /guidelines/1/edit
def edit
end
# POST /guidelines
def create
@guideline = Guideline.new(guideline_params)
if @guideline.save
redirect_to @guideline, notice: "Guideline was successfully created."
else
render :new, status: :unprocessable_entity
end
end
# PATCH/PUT /guidelines/1
def update
if @guideline.update(guideline_params)
redirect_to @guideline, notice: "Guideline was successfully updated.", status: :see_other
else
render :edit, status: :unprocessable_entity
end
end
# DELETE /guidelines/1
def destroy
@guideline.destroy!
redirect_to guidelines_url, notice: "Guideline was successfully destroyed.", status: :see_other
end
private
# Use callbacks to share common setup or constraints between actions.
def set_guideline
@guideline = Guideline.find(params[:id])
end
# Only allow a list of trusted parameters through.
def guideline_params
params.require(:guideline).permit(:principle_id, :number, :name_de, :name_en, :description_de, :description_en)
end
end

View file

@ -20,11 +20,6 @@ class HomeController < ApplicationController
path: profile_path, path: profile_path,
active: action_name == "profile" active: action_name == "profile"
}, },
# {
# label: "Passwort ändern",
# path: new_password_path,
# icon: :lock
# },
{ {
label: "Logout", label: "Logout",
icon: :"box-arrow-right", icon: :"box-arrow-right",

View file

@ -19,6 +19,7 @@ class PagesController < ApplicationController
# GET /pages/1/edit # GET /pages/1/edit
def edit def edit
render_modal
end end
# POST /pages # POST /pages

View file

@ -0,0 +1,62 @@
class ProjectsController < ApplicationController
before_action :set_project, only: %i[ show edit update destroy ]
# GET /projects
def index
@projects = Project.all
end
# GET /projects/1
def show
end
# GET /projects/new
def new
@project = Project.new
end
# GET /projects/1/edit
def edit
end
# POST /projects
def create
@project = if params[:copy_from_id]
Project.find(params[:copy_from_id]).dup
else
Project.new(project_params)
end
if @project.save
redirect_to @project, notice: "Project was successfully created."
else
render :new, status: :unprocessable_entity
end
end
# PATCH/PUT /projects/1
def update
if @project.update(project_params)
redirect_to @project, notice: "Project was successfully updated.", status: :see_other
else
render :edit, status: :unprocessable_entity
end
end
# DELETE /projects/1
def destroy
@project.destroy!
redirect_to projects_url, notice: "Project was successfully destroyed.", status: :see_other
end
private
# Use callbacks to share common setup or constraints between actions.
def set_project
@project = Project.find(params[:id])
end
# Only allow a list of trusted parameters through.
def project_params
params.require(:project).permit(:name, :details)
end
end

View file

@ -1,11 +1,12 @@
# frozen_string_literal: true # frozen_string_literal: true
class ReportsController < ApplicationController class ReportsController < ApplicationController
before_action :set_project, only: %i[index new create]
before_action :set_report, only: %i[show edit update destroy work] before_action :set_report, only: %i[show edit update destroy work]
# GET /reports # GET /reports
def index def index
@reports = Report.all @reports = @project.reports
end end
# GET /reports/1 # GET /reports/1
@ -85,7 +86,7 @@ class ReportsController < ApplicationController
# GET /reports/new # GET /reports/new
def new def new
@report = Report.new @report = Report.new(project_id: @project.id)
end end
# GET /reports/1/edit # GET /reports/1/edit
@ -93,10 +94,45 @@ class ReportsController < ApplicationController
# POST /reports # POST /reports
def create def create
@report = Report.new(report_params) success = if params[:copy_from_id]
original = Report.find(params[:copy_from_id])
@report = original.dup
@report.pages = original.pages.map do |page|
page.dup.tap do |p|
p.elements = page.elements.map do |element|
element.dup.tap do |e|
e.success_criteria = element.success_criteria.map do |sc|
csc = sc.dup
SuccessCriterion.rich_text_association_names
.map { _1.to_s.sub(/^rich_text_/, "") }
.each do |a|
csc.send("#{a}=", sc.send(a).dup)
end
csc
end
e.screenshot = element.screenshot&.dup
Element.rich_text_association_names
.map { _1.to_s.sub(/^rich_text_/, "") }
.each do |a|
e.send("#{a}=", element.send(a).dup)
end
end
end
Page.rich_text_association_names
.map { _1.to_s.sub(/^rich_text_/, "") }
.each do |a|
p.send("#{a}=", page.send(a).dup)
end
end
end
@report.save
else
@report = Report.new(report_params.merge(project_id: @project.id))
@report.save
end
if @report.save if success
redirect_to @report, notice: "Report was successfully created." redirect_to @report.reload, notice: "Report was successfully created."
else else
render :new, status: :unprocessable_entity render :new, status: :unprocessable_entity
end end
@ -114,7 +150,7 @@ class ReportsController < ApplicationController
# DELETE /reports/1 # DELETE /reports/1
def destroy def destroy
@report.destroy! @report.destroy!
redirect_to reports_url, notice: "Report was successfully destroyed.", status: :see_other redirect_to project_url(@report.project), notice: "Report was successfully destroyed.", status: :see_other
end end
def work def work
@ -130,7 +166,7 @@ class ReportsController < ApplicationController
# Only allow a list of trusted parameters through. # Only allow a list of trusted parameters through.
def report_params def report_params
params.require(:report).permit(:name, :comment, :url) params.require(:report).permit(:name, :comment, :url, :project_id)
end end
def filename(report, extension: "html") def filename(report, extension: "html")
@ -140,4 +176,8 @@ class ReportsController < ApplicationController
def page_param def page_param
params[:page_id] params[:page_id]
end end
def set_project
@project = Project.find(params[:project_id])
end
end end

View file

@ -2,7 +2,7 @@
class SuccessCriteriaController < ApplicationController class SuccessCriteriaController < ApplicationController
before_action :set_element, only: %i[new create index new_from_checklist create_from_checklist] before_action :set_element, only: %i[new create index new_from_checklist create_from_checklist]
before_action :set_success_criterion, only: %i[show edit update destroy] before_action :set_success_criterion, only: %i[show edit update destroy edit_comment]
# GET /success_criteria # GET /success_criteria
def index def index
@ -18,7 +18,9 @@ class SuccessCriteriaController < ApplicationController
end end
# GET /success_criteria/1/edit # GET /success_criteria/1/edit
def edit; end def edit
render_modal()
end
# POST /success_criteria # POST /success_criteria
def create def create
@ -106,6 +108,10 @@ class SuccessCriteriaController < ApplicationController
end end
end end
def edit_comment
render_modal()
end
private private
# Use callbacks to share common setup or constraints between actions. # Use callbacks to share common setup or constraints between actions.

View file

@ -20,7 +20,7 @@ module ApplicationHelper
end end
def safe_display(value, &block) def safe_display(value, &block)
return unless value return if value.blank?
yield(value) yield(value)
end end
@ -28,4 +28,41 @@ module ApplicationHelper
def current_page_displayed(page) def current_page_displayed(page)
@current_page&.id == page.id ? "open" : nil @current_page&.id == page.id ? "open" : nil
end end
def turbo_stream_toast(content, alert)
turbo_stream.append("toasts", partial: "layouts/toast", locals: { content:, alert: })
end
def dropdown_menu(items, klass: "")
tag.details(class: "details-dropdown #{klass}", data: { controller: "dropdown-menu" }) do
tag.summary do
tag.div(class: "details-dropdown-trigger") do
tag.div(tag.i(class: "bi bi-three-dots"), class: "btn btn-outline-body")
end
end +
tag.div(class: "details-dropdown-content bg-secondary") do
tag.div(class: "list-group") do
safe_join(items.map do |item|
c = "list-group-item list-group-item-action #{ item[:color] ? " list-group-item-#{item[:color]}" : "list-group-item-secondary"}"
text = item[:icon] ? tag.i(class: "bi bi-#{item[:icon]} me-2") + " #{item[:text]}".html_safe : item[:text]
case item[:method]
when nil, :get
link_to(text, item[:href], class: "#{c}", data: { turbo_frame: item[:turbo_frame], action: item[:action] })
else
button_to(text,
item[:href],
method: item[:method],
class: "#{c}",
data: { turbo_confirm: item[:confirm] })
end
end)
end
end
end
end
def modal?
turbo_frame_request_id == "modal"
end
end end

View file

@ -1,4 +1,19 @@
# frozen_string_literal: true # frozen_string_literal: true
module ElementsHelper module ElementsHelper
def element_menu(element)
dropdown_menu([
{ text: "Bearbeiten",
icon: "pencil",
href: edit_element_path(element),
turbo_frame: "modal",
color: "body" },
{ text: "Löschen",
icon: "trash",
href: element_path(element),
color: :danger,
method: :delete,
confirm: "Bist du sicher?" } ],
klass: "ms-auto")
end
end end

View file

@ -1,2 +1,27 @@
module PagesHelper module PagesHelper
def page_menu(page)
dropdown_menu([
{
text: "Alle zu [s]",
href: "#",
action: "click->details-list#closeAll"
},
{
text: "Alle auf [a]",
href: "#",
action: "click->details-list#openAll"
},
{ text: "Bearbeiten",
icon: "pencil",
href: edit_page_path(page),
turbo_frame: "modal",
color: "body" },
{ text: "Löschen",
icon: "trash",
href: page_path(page),
color: :danger,
method: :delete,
confirm: "Bist du sicher?" } ],
klass: "ms-auto")
end
end end

View file

@ -0,0 +1,2 @@
module ProjectsHelper
end

View file

@ -25,8 +25,23 @@ module SuccessCriteriaHelper
end end
end end
def success_criterion_menu(success_criterion, show_mode = true)
dropdown_menu([
{ text: "Bearbeiten",
icon: "pencil",
href: edit_success_criterion_path(success_criterion),
turbo_frame: "modal",
color: "body" },
{ text: "Löschen",
icon: "trash",
href: success_criterion_path(success_criterion),
color: :danger,
method: :delete,
confirm: "Bist du sicher?" } ],
klass: "mt-3 ms-auto")
end
def success_criterion_edit_button(success_criterion, edit_mode) def success_criterion_edit_button(success_criterion, edit_mode)
path = if success_criterion.persisted? path = if success_criterion.persisted?
if edit_mode if edit_mode
success_criterion success_criterion
@ -37,9 +52,9 @@ module SuccessCriteriaHelper
else else
success_criterion.element success_criterion.element
end end
link_to tag.i(class: "bi bi-pencil"), link_to tag.i(class: "bi bi-pencil") + " Bearbeiten".html_safe,
path, path,
class: "btn btn-#{edit_mode ? 'link text-warning' : 'link text-body'}" class: "text-decoration-none xbtn xbtn-#{edit_mode ? 'link text-warning' : 'link text-body'}"
end end
def success_criterion_badge(content, extra_classes: "") def success_criterion_badge(content, extra_classes: "")

View file

@ -1,7 +1,6 @@
// Entry point for the build script in your package.json // Entry point for the build script in your package.json
import "@hotwired/turbo-rails" import "@hotwired/turbo-rails"
import "./controllers" import "./controllers"
import * as bootstrap from "bootstrap"
import "trix" import "trix"
import "@rails/actiontext" import "@rails/actiontext"

View file

@ -10,7 +10,7 @@ export default class extends Controller {
e.preventDefault(); e.preventDefault();
const id = this.element.dataset["targetId"] const id = this.element.dataset["targetId"]
const el = document.getElementById(id) const el = document.getElementById(id)
el.querySelectorAll("details").forEach(el => { el.querySelectorAll("details.success_criterion").forEach(el => {
el.setAttribute("open", "") el.setAttribute("open", "")
}) })
} }
@ -19,7 +19,7 @@ export default class extends Controller {
e.preventDefault(); e.preventDefault();
const id = this.element.dataset["targetId"] const id = this.element.dataset["targetId"]
const el = document.getElementById(id) const el = document.getElementById(id)
el.querySelectorAll("details").forEach(el => { el.querySelectorAll("details.success_criterion").forEach(el => {
el.removeAttribute("open") el.removeAttribute("open")
}) })
} }

View file

@ -0,0 +1,53 @@
// app/javascript/controllers/dialog_controller.js
import { Controller } from "@hotwired/stimulus"
// Connects to data-controller="dialog"
export default class extends Controller {
connect() {
this.open()
console.log("connect dialog", this.element)
this.element.addEventListener("turbo:submit-end", e => {
this.submitEnd(e)
})
this.element.addEventListener("click", e => this.clickOutside(e))
}
disconnect() {
}
// hide modal on successful form submission
// data-action="turbo:submit-end->turbo-modal#submitEnd"
submitEnd(e) {
if (e.detail.success) {
this.close()
}
}
open() {
console.log("open dialog")
this.element.showModal()
document.body.classList.add('overflow-hidden')
this.element.addEventListener("close", this.enableBodyScroll.bind(this))
}
close() {
this.element.removeEventListener("close", this.enableBodyScroll.bind(this))
this.element.close()
// clean up modal content
const frame = document.getElementById('modal')
frame.removeAttribute("src")
frame.innerHTML = ""
}
enableBodyScroll() {
document.body.classList.remove('overflow-hidden')
}
clickOutside(event) {
console.log("clickOutside", event.target, this)
if (event.target === this.element) {
this.close()
}
}
}

View file

@ -0,0 +1,16 @@
import { Controller } from "@hotwired/stimulus"
// Connects to data-controller="dropdown-menu"
export default class extends Controller {
connect() {
const x = this.element
this.element.addEventListener("turbo:click", e => {
console.log("turbo visit dropdown", e, this.element)
this.element.removeAttribute("open");
})
this.element.addEventListener("turbo:submit-start", e => {
console.log("turbo submit dropdown", e, this.element)
this.element.removeAttribute("open");
})
}
}

View file

@ -4,6 +4,9 @@
import { application } from "./application" import { application } from "./application"
import Lightbox from '@stimulus-components/lightbox'
application.register('lightbox', Lightbox)
import AutosubmitController from "./autosubmit_controller" import AutosubmitController from "./autosubmit_controller"
application.register("autosubmit", AutosubmitController) application.register("autosubmit", AutosubmitController)
@ -19,9 +22,15 @@ application.register("collapse-chevron-toggler", CollapseChevronTogglerControlle
import DetailsListController from "./details_list_controller" import DetailsListController from "./details_list_controller"
application.register("details-list", DetailsListController) application.register("details-list", DetailsListController)
import DialogController from "./dialog_controller"
application.register("dialog", DialogController)
import DragController from "./drag_controller" import DragController from "./drag_controller"
application.register("drag", DragController) application.register("drag", DragController)
import DropdownMenuController from "./dropdown_menu_controller"
application.register("dropdown-menu", DropdownMenuController)
import HelloController from "./hello_controller" import HelloController from "./hello_controller"
application.register("hello", HelloController) application.register("hello", HelloController)
@ -43,5 +52,8 @@ application.register("sortable", SortableController)
import ThemeSwitcherController from "./theme_switcher_controller" import ThemeSwitcherController from "./theme_switcher_controller"
application.register("theme-switcher", ThemeSwitcherController) application.register("theme-switcher", ThemeSwitcherController)
import ToastController from "./toast_controller"
application.register("toast", ToastController)
import UnsavedChangesController from "./unsaved_changes_controller" import UnsavedChangesController from "./unsaved_changes_controller"
application.register("unsaved-changes", UnsavedChangesController) application.register("unsaved-changes", UnsavedChangesController)

View file

@ -0,0 +1,14 @@
import { Controller } from "@hotwired/stimulus"
import * as bootstrap from "bootstrap"
// Connects to data-controller="toast"
export default class extends Controller {
connect() {
const shownKey = `toastsShown[${this.element.getAttribute("data-ts")}]`
if(!window.sessionStorage.getItem(shownKey)) {
window.sessionStorage.setItem(shownKey, Date.now());
const toastBootstrap = bootstrap.Toast.getOrCreateInstance(this.element)
toastBootstrap.show()
}
}
}

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class Check < ApplicationRecord class Check < ApplicationRecord
belongs_to :principle belongs_to :guideline
has_and_belongs_to_many :links has_and_belongs_to_many :links
has_and_belongs_to_many :standards has_and_belongs_to_many :standards
@ -51,9 +51,9 @@ class Check < ApplicationRecord
:standard_text, :standard_text,
:powerpoint_text :powerpoint_text
validates :number, uniqueness: true, presence: true validates :number, uniqueness: { scope: :guideline_id }, presence: true
before_validation { self.number = self.class.maximum(:id).to_i + 1 unless self.number.present? } # before_validation { self.number = self.class.maximum(:id).to_i + 1 unless self.number.present? }
scope(:search, lambda { |terms| scope(:search, lambda { |terms|
# TODO: Search only fields for current locale. # TODO: Search only fields for current locale.
@ -129,4 +129,20 @@ class Check < ApplicationRecord
def external_number def external_number
[ external_number_1, external_number_2, external_number_3 ].compact_blank.join(".") [ external_number_1, external_number_2, external_number_3 ].compact_blank.join(".")
end end
def external_number
[
guideline.principle.id,
guideline.number,
number
].compact.join(".")
end
def full_number
external_number
end
def to_s
display_label
end
end end

View file

@ -11,6 +11,12 @@ class Element < ApplicationRecord
before_validation :set_position before_validation :set_position
before_update :update_positions, if: :position_changed? before_update :update_positions, if: :position_changed?
has_one_attached :screenshot do |attachable|
attachable.variant :thumbnail, resize_to_limit: [ 200, 200 ]
end
scope :failed, -> { where(SuccessCriterion.where(result: SuccessCriterion.results[:failed]).arel.exists) }
# Calculate actual conformity level: # Calculate actual conformity level:
# - if a success_criterion has result :failed -> the confirmity_level # - if a success_criterion has result :failed -> the confirmity_level
# of that success_criterion is not reached. # of that success_criterion is not reached.

18
app/models/guideline.rb Normal file
View file

@ -0,0 +1,18 @@
class Guideline < ApplicationRecord
belongs_to :principle
has_many :checks
has_rich_text :description_de
has_rich_text :description_en
translates_attributes :name, :description
def to_s
"#{full_number} #{t_name}"
end
def full_number
[ principle.id, number ].join(".")
end
end

View file

@ -2,7 +2,7 @@
module PdfDocuments module PdfDocuments
class Base class Base
attr_reader :params attr_reader :params, :font
def initialize(prawn_document, **params) def initialize(prawn_document, **params)
@prawn_document = prawn_document @prawn_document = prawn_document
@ -13,7 +13,8 @@ module PdfDocuments
# exta_bold: 'vendor/assets/fonts/Lexend-ExtraBold.ttf', # exta_bold: 'vendor/assets/fonts/Lexend-ExtraBold.ttf',
# italic: 'vendor/assets/fonts/Lexend-Regular.ttf' # italic: 'vendor/assets/fonts/Lexend-Regular.ttf'
# }) # })
@prawn_document.font "Helvetica", size: 12 @font = "Helvetica"
@prawn_document.font @font, size: 12
@params = OpenStruct.new(params) @params = OpenStruct.new(params)
end end
@ -40,8 +41,12 @@ module PdfDocuments
@prawn_document.markup "<h3>#{text}</h3>" @prawn_document.markup "<h3>#{text}</h3>"
end end
def text(text) def heading4(text)
@prawn_document.text text, markup_options[:text] @prawn_document.markup "<h4>#{text}</h4>"
end
def text(text, **args)
@prawn_document.text text, markup_options[:text].merge(args)
end end
def rich_text(text) def rich_text(text)
@ -55,28 +60,28 @@ module PdfDocuments
def markup_options def markup_options
{ {
text: { size: 12, margin_bottom: 5 }, text: { size: 12, margin_bottom: 5 },
heading1: { style: :bold, size: 26, margin_bottom: 10, margin_top: 0 }, heading1: { style: :bold, size: 26, margin_bottom: 5, margin_top: 0 },
heading2: { style: :bold, size: 17, margin_bottom: 10, margin_top: 5 }, heading2: { style: :bold, size: 17, margin_bottom: 5, margin_top: 5 },
heading3: { style: :bold, size: 13, margin_bottom: 10, margin_top: 5 }, heading3: { style: :bold, size: 13, margin_bottom: 5, margin_top: 5 },
heading4: { style: :bold, size: 12, margin_bottom: 10, margin_top: 5 }, heading4: { style: :bold, size: 12, margin_bottom: 5, margin_top: 5 },
heading5: { style: :bold, size: 12, margin_bottom: 10, margin_top: 5 }, heading5: { style: :bold, size: 12, margin_bottom: 5, margin_top: 5 },
heading6: { style: :thin, size: 12, margin_bottom: 10, margin_top: 5 } heading6: { style: :thin, size: 12, margin_bottom: 5, margin_top: 5 }
} }
end end
def logo def logo(width: 24, xs: true)
@prawn_document.image "app/assets/images/logo-apfelschule.png", width: 150 @prawn_document.image "app/assets/images/logo-apfelschule#{ xs ? "_xs" : "" }.png", width:
@prawn_document.move_down 30
end end
def prepare_rich_text(rich_text) def prepare_rich_text(rich_text)
{ h1: "h4" }.each do |tag, replacement| { h1: "h5" }.each do |tag, replacement|
rich_text = rich_text.to_s.gsub("<#{tag}", "<#{replacement}") rich_text = rich_text.to_s.gsub("<#{tag}", "<#{replacement}")
rich_text = rich_text.to_s.gsub("</#{tag}>", "</#{replacement}>") rich_text = rich_text.to_s.gsub("</#{tag}>", "</#{replacement}>")
end end
rich_text rich_text.sub(/(<br>)+$/, "")
end end
# @prawn_document.draw_text("Dokument erstellt am #{Time.current.strftime('%d %B %Y')} um #{Time.current.strftime('%H:%M:%S')}", at: [ 0, -15 ])
def font(...) def font(...)
@prawn_document.font(...) @prawn_document.font(...)
@ -89,5 +94,58 @@ module PdfDocuments
def move_down(...) def move_down(...)
@prawn_document.move_down(...) @prawn_document.move_down(...)
end end
def safe_display(value, &block)
return if value.blank?
begin
yield(value)
rescue StandardError
nil
end
end
def bold(text)
@prawn_document.font(@font, style: :bold) do
@prawn_document.text text
end
end
def image(attachable, **args)
begin
@prawn_document.image(ActiveStorage::Blob.service.path_for(attachable.key), **args) && raise("david")
rescue StandardError
false
end
end
def without_page_break(&block)
return yield
return @prawn_document.bounding_box([ 0, @prawn_document.cursor ], width: 300) do
yield
# @prawn_document.stroke_bounds if Rails.env.development?
# print_coordinates
end
@prawn_document.span(520) do
yield
# @prawn_document.stroke_bounds
end
end
def print_coordinates
@prawn_document.text("top: #{@prawn_document.bounds.top}")
@prawn_document.text("bottom: #{@prawn_document.bounds.bottom}")
@prawn_document.text("left: #{@prawn_document.bounds.left}")
@prawn_document.text("right: #{@prawn_document.bounds.right}")
@prawn_document.move_down(10)
@prawn_document.text("absolute top: #{Float(@prawn_document.bounds.absolute_top).round(2)}")
@prawn_document.text("absolute bottom: #{Float(@prawn_document.bounds.absolute_bottom).round(2)}")
@prawn_document.text("absolute left: #{Float(@prawn_document.bounds.absolute_left).round(2)}")
@prawn_document.text("absolute right: #{Float(@prawn_document.bounds.absolute_right).round(2)}")
end
def new_page(required_space: 0)
@prawn_document.start_new_page if @prawn_document.cursor <= required_space + 10
end
end end
end end

View file

@ -5,26 +5,163 @@ module PdfDocuments
private private
def generate def generate
logo move_down 130
@prawn_document.formatted_text_box [ { logo(width: 250, xs: false)
text: "Dieses Dokument wurd am #{Time.current.strftime('%d %B %Y')} um #{Time.current.strftime('%H:%M:%S')} erstellt.", size: 8, align: :right move_down 40
} ], align: :right
heading1 params.report.name heading1 params.report.name
rich_text params.report.comment
params.report.elements.each.with_index(1) do |element, element_index| move_down 20
heading2 "#{element_index} #{element.title}" @prawn_document.text "#{I18n.l params.report.updated_at.to_date, format: :long}"
formatted_text [ { text: element.path, styles: %i[bold italic underline] } ] move_down 40
move_down(5) safe_display(params.report.comment) do
rich_text element.description_html rich_text _1
move_down 30
end
element.success_criteria.each.with_index(1) do |success_criterion, sc_index| @prawn_document.font_size(8) do
heading3 "#{element_index}.#{sc_index} #{success_criterion.title}" @prawn_document.draw_text("Dokument erstellt am #{Time.current.strftime('%d %B %Y')} um #{Time.current.strftime('%H:%M:%S')}", at: [ 0, 0 ])
rich_text success_criterion.description_html end
rich_text success_criterion.comment @prawn_document.start_new_page
@pages = {}
params.report.export[:elements].each.with_index(1) do |(element, success_criteria), element_index|
new_page(required_space: 200) if element_index > 1
without_page_break do
heading2 "#{element_index} #{element.title}"
@prawn_document.text("<b>Pfad:</b> #{element.page.path}", inline_format: true)
safe_display(element.screenshot) do
image(_1.variant(:thumbnail), height: 160)
move_down(15)
end
end
rich_text element.description
move_down(10)
success_criteria.each.with_index(1) do |success_criterion, sc_index|
@pages[success_criterion] = @prawn_document.page_number
success_criterion_row(success_criterion, [ element_index, sc_index ])
end
end
@prawn_document.start_new_page
heading1("Anhang: Richtlinien")
params.report.export[:success_criteria].group_by(&:check).sort_by { |c, _scs| c.external_number }.each do |check, criteria|
heading2(check.display_label)
@pages[check] = @prawn_document.page_number
{
external_number: { label: "WCAG Nummer" },
external_url: { label: "WCAG Link" },
conformity_level: { label: "Konformität" },
conformity_notice_de: { label: "Anmerkung Konformität", rich: true },
priority: { label: "Priorität" },
criterion_de: { label: "Kriterium/Grundlage", rich: true },
exemption_details_de: { label: "Ausnahmen", rich: true },
criterion_details_de: { label: "Verstehen", rich: true },
example_de: { label: "Beispiel", rich: true },
annotation_de: { label: "Anmerkung", rich: true }
}.each do |attribute, options|
v = check.send(attribute)
safe_display(v) do
text("<b>#{options[:label]}</b>", inline_format: true)
if options[:rich]
rich_text(_1)
else
text(_1)
end
end
end
if check.links.any?
move_down 5
text("<b>Links</b>", inline_format: true)
move_down 5
check.links.group_by(&:link_category).each do |cat, links|
rich_text(%Q(
<span>#{cat.name}</span>
<ul>
#{links.map { "<li><a href='#{_1.url}'>#{_1.text}</a></li>" }.join() }
</ul>
))
end
end
text("<b>Erfolgskriterien</b>", inline_format: true)
text criteria.map(&:number).sort.join(", ")
end
string = "Seite <page> / <total>"
# Green page numbers 1 to 7
options = {
at: [ @prawn_document.bounds.right - 150, 776 ],
width: 150,
align: :right,
start_count_at: 2,
page_filter: ->(x) { x > 1 }
}
@prawn_document.number_pages string, options
@prawn_document.repeat(2..) do
@prawn_document.text_box "<b>#{params.report.name}</b>", at: [ 50, 777 ], inline_format: true, width: 300
@prawn_document.bounding_box([ 0, 766 ], width: 532) do
hr
end
@prawn_document.bounding_box([ 0, 796 ], width: 200, height: 200) do
logo
end
end
x = params
p = @pages
@prawn_document.outline.define do
x.report.export[:elements].each.with_index(1) do |(element, success_criteria), element_index|
section("#{element_index} #{element.title}") do
success_criteria.each.with_index(1) do |sc, sc_index|
page(title: "#{element_index}.#{sc_index} #{sc.title}", destination: p[sc])
end
end
end
section("Anhang: Richtlinien") do
x.report.export[:success_criteria].group_by(&:check).sort_by { |c, _scs| c.external_number }.each do |check, _criteria|
page(title: check.display_label, destination: p[check])
end
end end
end end
end end
private
def success_criterion_row(success_criterion, index)
heading3 "#{index.join(".")} #{success_criterion.title}"
safe_display(success_criterion.test_comment) do
without_page_break do
heading4 "Kommentar"
rich_text success_criterion.test_comment
end
end
safe_display(success_criterion.quick_criterion) do
without_page_break do
heading4 "Kriterium"
rich_text success_criterion.quick_criterion
end
end
safe_display(success_criterion.quick_fail) do
without_page_break do
heading4 "Fail"
rich_text success_criterion.quick_fail
end
end
safe_display(success_criterion.quick_fix) do
without_page_break do
heading4 "Fix"
rich_text success_criterion.quick_fix
end
end
heading4("Protokollnummer")
text(success_criterion.number)
safe_display(success_criterion.check.external_url) do
heading4("WCAG")
text("<link href='#{_1}'>#{success_criterion.check.external_number || _1}</link>", inline_format: true)
end
move_down(10)
end
end end
end end

7
app/models/project.rb Normal file
View file

@ -0,0 +1,7 @@
class Project < ApplicationRecord
has_many :reports, dependent: :restrict_with_error
has_rich_text :details
scope :current, -> { where("updated_at > ?", 1.month.ago) }
end

View file

@ -1,9 +1,28 @@
# frozen_string_literal: true # frozen_string_literal: true
class Report < ApplicationRecord class Report < ApplicationRecord
belongs_to :project, touch: true
has_many :pages, -> { order(:position) }, dependent: :destroy has_many :pages, -> { order(:position) }, dependent: :destroy
has_many :elements, through: :pages, dependent: :destroy has_many :elements, through: :pages, dependent: :destroy
has_many :success_criteria, through: :elements, dependent: :destroy
has_rich_text :comment has_rich_text :comment
validates :name, presence: true validates :name, presence: true
def export
export_success_criteria = success_criteria.failed
export_elements = export_success_criteria.group_by(&:element)
export_pages = export_elements.group_by { |k, v| k }
{
pages: export_pages,
elements: export_elements,
success_criteria: export_success_criteria
}
end
def test
139
end
end end

View file

@ -17,6 +17,10 @@ class SuccessCriterion < ApplicationRecord
before_save :set_position before_save :set_position
before_update :update_positions, if: :position_changed? before_update :update_positions, if: :position_changed?
validates :result, inclusion: { in: self.results.keys + [ nil ] }
scope :failed, -> { where(result: :failed) }
def level_value def level_value
return nil unless level return nil unless level

View file

@ -7,6 +7,12 @@
<%= link_to Checklist.model_name.human(count: Checklist.count), :checklists %> <%= link_to Checklist.model_name.human(count: Checklist.count), :checklists %>
</p> </p>
<p>
<i class="bi bi-rulers"></i>
<%= Guideline.count %>
<%= link_to Guideline.model_name.human(count: Guideline.count), :guidelines %>
</p>
<p> <p>
<i class="bi bi-check2"></i> <i class="bi bi-check2"></i>
<%= Check.count %> <%= Check.count %>
@ -27,4 +33,4 @@
<li> <li>
<%= link_to "ZIP Backup herunterladen", admin_backup_url(format: :zip), class: " ", data: { turbo_prefetch: false, frame: "_top", turbo: false } %> <%= link_to "ZIP Backup herunterladen", admin_backup_url(format: :zip), class: " ", data: { turbo_prefetch: false, frame: "_top", turbo: false } %>
</li> </li>
</ul> </ul>

View file

@ -1 +1,2 @@
<%= turbo_stream.remove dom_id(@checklist_entry) %> <%= turbo_stream.remove dom_id(@checklist_entry) %>
<%= turbo_stream_toast("Check wurde aus Checkliste entfernt", true) %>

View file

@ -11,8 +11,8 @@ div id=dom_id(check)
th = Check.human_attribute_name(:number) th = Check.human_attribute_name(:number)
td = check.number td = check.number
tr tr
th = Principle.model_name.human th = Guideline.model_name.human
td = check.principle&.t_name td = check.guideline&.name_en
tr tr
th = Standard.model_name.human(count: check.standard_ids.size) th = Standard.model_name.human(count: check.standard_ids.size)
td = check.standards.map(&:t_name).sort_by(&:downcase).join(", ") td = check.standards.map(&:t_name).sort_by(&:downcase).join(", ")
@ -80,4 +80,4 @@ div id=dom_id(check)
ul ul
- check.links.select{ _1.link_category == category }.map { |link| link_to link.text, link.url, target: :_blank }.each do |link| - check.links.select{ _1.link_category == category }.map { |link| link_to link.text, link.url, target: :_blank }.each do |link|
li = link li = link

View file

@ -1,9 +1,9 @@
= bootstrap_form_with(model: check, remote: true, data: { controller: "unsaved-changes" }) do |form| = bootstrap_form_with(model: check, remote: true, data: { controller: "unsaved-changes" }) do |form|
h2 Details h2 Details
= multilang_form_field(form, :name) = multilang_form_field(form, :name)
= form.text_field :number, required: false
.row .row
= form.collection_radio_buttons(:principle_id, Principle.all.sort_by(&:t_name), :id, :t_name) { |b| b.label(class: "col-md-2") { b.radio_button + b.text } } = form.collection_radio_buttons(:guideline_id, Guideline.all.sort_by(&:full_number), :id, :to_s) { |b| b.label(class: "col-md-2") { b.radio_button + b.text } }
= form.text_field :number, required: false
= form.collection_check_boxes :standard_ids, Standard.all.sort_by{ _1.t_name.downcase }, :id, :t_name, include_blank: true = form.collection_check_boxes :standard_ids, Standard.all.sort_by{ _1.t_name.downcase }, :id, :t_name, include_blank: true
h2 Einschränkung/Zugänglichkeit h2 Einschränkung/Zugänglichkeit

View file

@ -1,6 +1,6 @@
<div id="<%= dom_id element %>" class="mb-5"> <div id="<%= dom_id element %>" class="mb-5">
<%= turbo_frame_tag dom_id(element, :frame) do %> <%= turbo_frame_tag dom_id(element, :frame) do %>
<div class="d-flex"> <div class="d-flex border-bottom mb-3">
<h3 class="h4"> <h3 class="h4">
<i class="bi bi-boxes"> <i class="bi bi-boxes">
</i> </i>
@ -9,22 +9,23 @@
<%= element.title %> <%= element.title %>
</span> </span>
</h3> </h3>
<%= link_to [:edit, element], class: "btn btn-link text-secondary" do %> <%= element_menu(element) %>
<i class="bi bi-pencil"> </div>
</i>
<div class="d-flex flex-column flex-sm-row">
<% if element.description %>
<div class="mb-3 flex-fill">
<%= element.description %>
</div>
<% end %> <% end %>
<%= button_to(element_path(element), method: :delete, class: "btn btn-link text-danger", data: { turbo_confirm: "Bist du sicher?"}) do %> <% safe_display(element.screenshot) do |s| %>
<i class="bi bi-trash"></i> <div class="mb-3" data-controller="lightbox">
<%= link_to(s) do %>
<%= image_tag(s.variant(:thumbnail), class: "img-fluid", alt: "Screenshot des getesteten Elements") %>
<% end rescue nil %>
</div>
<% end %> <% end %>
</div> </div>
<% if element.description %>
<div class="mb-3">
<%= element.description %>
</div>
<% end %>
<p class="actions">
</p>
<% end %> <% end %>
<div id="<%= dom_id(element, :success_criteria_list) %>" class="mb-3" data-controller="sortable" data-form-name="success_criterion" data-position-attribute= "position" data-draggable-selector=".draggable"> <div id="<%= dom_id(element, :success_criteria_list) %>" class="mb-3" data-controller="sortable" data-form-name="success_criterion" data-position-attribute= "position" data-draggable-selector=".draggable">

View file

@ -7,6 +7,9 @@
</div> </div>
<%= element.description_html %> <%= element.description_html %>
<%= image_tag(element.screenshot.preview(:thumbnail)) %>
<%= image_tag(element.screenshot) %>
<% element.success_criteria.each do |sc| %> <% element.success_criteria.each do |sc| %>
<%= render sc %> <%= render sc %>
<% end %> <% end %>

View file

@ -1,7 +0,0 @@
<%= bootstrap_form_with(model: element.persisted? ? element : [:page, element], class: "mb-3") do |form| %>
<%= form.hidden_field :page_id %>
<%= form.text_field :title %>
<%= form.rich_text_area :description %>
<%= form.submit class: "btn btn-primary" %>
<%= link_to("Abbrechen", element.persisted? ? element : element.report, class: "btn btn-outline-secondary") %>
<% end %>

View file

@ -0,0 +1,10 @@
= bootstrap_form_with(model: element.persisted? ? element : [:page, element], class: "mb-3") do |form|
= form.hidden_field :page_id
= form.text_field :title
= form.rich_text_area :description
= form.file_field :screenshot
- if element.persisted?
= safe_display(element.screenshot) { tag.div(link_to(_1.filename.to_s, _1), class: "mb-3") }
= form.submit class: "btn btn-primary"
- unless modal?
= link_to("Abbrechen", element.persisted? ? element : element.report, class: "btn btn-outline-secondary")

View file

@ -1,13 +1,7 @@
li id=dom_id(element, :page_nav_row) data={ "sortable-url": element_path(element), "form-name": "element", "position-attribute": "position" } li.d-flex id=dom_id(element, :page_nav_row) data={ "sortable-url": element_path(element), "form-name": "element", "position-attribute": "position" }
- if current_page - url = current_page ? "##{dom_id(element)}" : report_path(element.report, page_id: element.page.id, anchor: dom_id(element))
=< link_to("##{dom_id(element)}", data: { "turbo": false }) do i.bi.bi-boxes.me-2
i.bi.bi-boxes.me-2 =< link_to(url, data: { "turbo": false }, class: "me-auto") do
span id=dom_id(element, :page_nav_title) span id=dom_id(element, :page_nav_title)
= "#{element.number} #{element.title}" = "#{element.number} #{element.title}"
i.bi.bi-grip-vertical.float-end.handle i.bi.bi-grip-vertical.handle
- else
=< link_to(report_path(element.report, page_id: element.page.id, anchor: dom_id(element)), data: { "turbo": false }) do
i.bi.bi-boxes.me-2
span id=dom_id(element, :page_nav_title)
=< "#{element.number} #{element.title}"
i.bi.bi-grip-vertical.float-end.handle

View file

@ -1,3 +1,6 @@
= turbo_stream.update "new_element_frame", partial: "pages/new_element_button", locals: { page: @element.page } = turbo_stream.update "new_element_frame", partial: "pages/new_element_button", locals: { page: @element.page }
= turbo_stream.append "element_list", @element = turbo_stream.append "element_list", @element
= turbo_stream.append dom_id(@element.page, :page_nav_elements), partial: "elements/page_nav_row", locals: { element: @element, current_page: true } = turbo_stream.append dom_id(@element.page, :page_nav_elements), partial: "elements/page_nav_row", locals: { element: @element, current_page: true }
= turbo_stream_toast("Element hinzugefügt", false)

View file

@ -2,4 +2,7 @@
= turbo_stream.remove dom_id(@element, :page_nav_row) = turbo_stream.remove dom_id(@element, :page_nav_row)
- @element.page.elements.reject { _1 == @element }.each do |e| - @element.page.elements.reject { _1 == @element }.each do |e|
= turbo_stream.update dom_id(e, :title), "#{e.page.position}.#{e.position} #{e.title}" = turbo_stream.update dom_id(e, :title), "#{e.page.position}.#{e.position} #{e.title}"
= turbo_stream.replace dom_id(e, :page_nav_row), partial: "elements/page_nav_row", locals: { element: e, current_page: true } = turbo_stream.replace dom_id(e, :page_nav_row), partial: "elements/page_nav_row", locals: { element: e, current_page: true }
= turbo_stream_toast("Element wurde gelöscht", true)

View file

@ -1,19 +1,17 @@
<h1><%= t("scaffold.pagetitle_edit", model: Element.model_name.human) %></h1> <h1><%= t("scaffold.pagetitle_edit", model: Element.model_name.human) %></h1>
<%= turbo_frame_tag dom_id(@element, :frame) do %>
<div> <div>
<div class="d-flex"> <div class="d-flex">
<h2 class="h3"> <h2 class="h3">
<i class="bi bi-boxes"> <i class="bi bi-boxes">
</i> </i>
<%= @element.title %> <%= @element.title %>
<%= link_to(tag.i(class: "bi bi-pencil"), @element, class: "btn btn-link text-warning") %>
</div> </div>
<%= render "form", element: @element %> <%= render "form", element: @element %>
</div> </div>
<% unless modal? %>
<div class="action-row">
<%= link_to t("scaffold.link_show", model: Element.model_name.human), @element %>
<%= link_to t("scaffold.link_index", model: Element.model_name.human(count: 2)), page_elements_path(@element.page) %>
</div>
<% end %> <% end %>
<div class="action-row">
<%= link_to t("scaffold.link_show", model: Element.model_name.human), @element %>
<%= link_to t("scaffold.link_index", model: Element.model_name.human(count: 2)), page_elements_path(@element.page) %>
</div>

View file

@ -4,4 +4,8 @@
/ - element.success_criteria.each do |sc| / - element.success_criteria.each do |sc|
/ = turbo_stream.update dom_id(sc, :title), "#{sc.page.position}.#{sc.element.position}.#{sc.position} #{sc.title}" / = turbo_stream.update dom_id(sc, :title), "#{sc.page.position}.#{sc.element.position}.#{sc.position} #{sc.title}"
- element.success_criteria.each do |sc| - element.success_criteria.each do |sc|
= turbo_stream.update dom_id(sc, :position), "#{sc.page.position}.#{sc.element.position}.#{sc.position}" = turbo_stream.update dom_id(sc, :position), "#{sc.page.position}.#{sc.element.position}.#{sc.position}"
= turbo_stream.replace dom_id(element, :frame), element
= turbo_stream_toast("Element gespeichert", false)

View file

@ -1,55 +1,99 @@
h1 id=dom_id(@report) = @report.name h1.title id=dom_id(@report) = @report.name
h2#toc Inhaltsverzeichnis h2 1 Einschätzung
nav p Gibt es hier Text?
= link_to(@report.name, "##{dom_id(@report)}")
ul
li = link_to("Inhaltsverzeichnis", "#toc")
li
= link_to('Testbericht')
ul
- @report.pages.select { |p| p.elements.any? { |e| e.success_criteria.any?(&:failed?) } }.each do |page|
li
= link_to("#{page.position} #{page.path}", "##{dom_id(page)}")
ul
- page.elements.select { |e| e.success_criteria.any?(&:failed?) }.each do |element|
li
= link_to("#{element.number} #{element.title}")
ul
- element.success_criteria.select(&:failed?).each do |sc|
li = link_to("#{sc.number} #{sc.title}", "##{dom_id(sc)}")
li
= link_to("Anhang")
ul
- @failed_success_criteria.group_by(&:check).each do |check, scs|
li = link_to(check.display_label)
h3 1.1 Zielsetzung und Ausgangslage
p Woher kommt dieser Text?
h2 Testbericht h3 1.2 Wie wurde getestet
p Woher kommt dieser Text?
h3 1.3 Einschätzung
p Woher kommt dieser Text?
h2 2 Protokoll
- current_page_pos = 0
- current_abs_element_pos = 0
- @report.pages.select { |p| p.elements.any? { |e| e.success_criteria.any? { _1.failed? } } }.each do |page| - @report.pages.select { |p| p.elements.any? { |e| e.success_criteria.any? { _1.failed? } } }.each do |page|
h3 = "#{page.position} #{page.path}" - current_page_pos += 1
- page.elements { |e| e.success_criteria.any? { _1.failed? } }.each do |element| - current_element_pos = 0
h4 = "#{element.number} #{element.title}" h3 = "2.#{current_page_pos} #{page.path}"
- element.success_criteria.select{ _1.failed? }.each do |sc| p
h5 = "#{sc.number} #{sc.title}" strong URL
= page.url
- page.elements.select { |e| e.success_criteria.any? { _1.failed? } }.each do |element|
- current_element_pos += 1
- current_abs_element_pos += 1
- current_sc_pos = 0
h4 = "2.#{current_page_pos}.#{current_element_pos} #{element.title}"
/h3 = "2.#{current_abs_element_pos} #{element.title}"
= safe_display(element.screenshot) { image_tag(_1.representation(resize_to_fit: [250, 250]))}
= element.description
- element.success_criteria.select(&:failed?).each do |sc|
- current_sc_pos += 1
/h4
= "2.#{current_abs_element_pos}.#{current_sc_pos} #{sc.title}"
h5 = "2.#{current_page_pos}.#{current_element_pos}.#{current_sc_pos} #{sc.title}"
p
strong Protokoll-Nummer
=< sc.number
- if sc.test_comment? - if sc.test_comment?
p = sc.test_comment p = sc.test_comment
dl - safe_display(sc.quick_criterion) do
dt Kriterium strong Kriterium
dd = sc.quick_criterion .body_text = _1
dt Fail - safe_display(sc.quick_fail) do
dd = sc.quick_fail strong Quick Fail
dt Fix .body_text = _1
dd = sc.quick_fix - safe_display(sc.quick_fix) do
dt WCAG strong Quick Fix
dd = link_to(sc.check.external_number, sc.check.external_url) .body_text = _1
strong WCAG
.body_text = link_to(sc.check.external_number, sc.check.external_url)
h2 Anhang h2 3 Anhang: Liste der zu beachtenden WCAG Regeln
- counter = 0
h3 Liste der zu beachtenden WCAG Regeln - @failed_success_criteria.group_by(&:check).sort_by{ |c, scs| c.number }.each do |check, scs|
- counter += 1
- @failed_success_criteria.group_by(&:check).each do |check, scs| h3 = "3.#{counter}. #{check.name_de}"
h4 = check.display_label - safe_display(check.external_number) do
= check.criterion_de strong WCAG Nummer
strong Erfolgskriterien .body_text = _1
p = scs.map(&:number).join(", ") - safe_display(check.external_url) do
strong WCAG Link
.body_text = _1
- safe_display(check.conformity_level) do
strong Konformität
.body_text = _1
- safe_display(check.conformity_notice_de) do
strong Anmerkung Konformität
.body_text = _1
- safe_display(check.priority) do
strong Priorität
.body_text = _1
- safe_display(check.criterion_de) do
strong Kriterium/Grundlage
.body_text = _1
- safe_display(check.exemption_details_de) do
strong Ausnahmen
.body_text = _1
- safe_display(check.criterion_details_de) do
strong Verstehen
.body_text = _1
- safe_display(check.example_de) do
strong Beispiel
.body_text = _1
- safe_display(check.annotation_de) do
strong Anmerkung
.body_text = _1
- if check.links.any?
strong Links
.body_text
- check.links.group_by(&:link_category).each do |category, links|
strong = category.t_name
ul
- links.each do |l|
li = link_to(l.text, l.url)
strong Erfolgskriterien
.body_text = scs.map(&:number).join(", ")

View file

@ -0,0 +1,7 @@
<%= bootstrap_form_with(model: guideline) do |form| %>
<%= form.collection_select :principle_id, Principle.all.sort_by(&:id), :id, :t_name %>
<%= form.number_field :number %>
<%= form.text_field :name_de %>
<%= form.rich_text_area :description_de %>
<%= form.submit %>
<% end %>

View file

@ -0,0 +1,15 @@
<div id="<%= dom_id guideline %>">
<p>
<strong>Principle:</strong>
<%= guideline.principle.t_name %>
</p>
<%= guideline.description_de %>
<h2 class="mt-4">Richtlinien</h2>
<% guideline.checks.each do |check| %>
<section class="pt-3">
<h3 class="fs-5"><%= link_to check %></h3>
<%= check.t_criterion %>
</section>
<% end %>
</div>

View file

@ -0,0 +1,2 @@
json.extract! guideline, :id, :principle_id, :number, :name_de, :created_at, :updated_at
json.url guideline_url(guideline, format: :json)

View file

@ -0,0 +1,8 @@
<h1><%= t("scaffold.pagetitle_edit", model: Guideline.model_name.human) %></h1>
<%= render "form", guideline: @guideline %>
<div class="action-row">
<%= link_to t("scaffold.link_show", model: Guideline.model_name.human), @guideline %>
<%= link_to t("scaffold.link_index", model: Guideline.model_name.human(count: 2)), guidelines_path %>
</div>

View file

@ -0,0 +1,28 @@
<h1><%= t("scaffold.pagetitle_index", model: Guideline.model_name.human(count: 2)) %></h1>
<table class="table table-striped">
<thead>
<tr>
<th><%= Guideline.human_attribute_name(:name_de) %></th>
<th><%= Guideline.human_attribute_name(:description_de) %></th>
</thead>
<tbody>
<% @guidelines.each do |guideline| %>
<tr>
<td><%= link_to(guideline, url_for(guideline)) %></td>
<td><%= link_to(guideline.description_de, url_for(guideline)) %></td>
</tr>
<% end %>
</tbody>
</table>
<div class="action-row">
<%= link_to t("scaffold.link_new", model: Guideline.model_name.human), new_guideline_path %>
</div>

View file

@ -0,0 +1 @@
json.array! @guidelines, partial: "guidelines/guideline", as: :guideline

View file

@ -0,0 +1,7 @@
<h1><%= t("scaffold.pagetitle_new", model: Guideline.model_name.human) %></h1>
<%= render "form", guideline: @guideline %>
<div class="action-row">
<%= link_to t("scaffold.link_index", model: Guideline.model_name.human(count: 2)), guidelines_path %>
</div>

View file

@ -0,0 +1,9 @@
<h1><%= @guideline %></h1>
<%= render @guideline %>
<div class="action-row">
<%= link_to t("scaffold.link_edit", model: @guideline.model_name.human), edit_guideline_path(@guideline) %>
<%= link_to t("scaffold.link_index", model: @guideline.model_name.human(count: 2)), guidelines_path %>
<%= button_to t("scaffold.link_destroy", model: @guideline.model_name.human), @guideline, method: :delete, class: "btn btn-outline-danger" %>
</div>

View file

@ -0,0 +1 @@
json.partial! "guidelines/guideline", guideline: @guideline

View file

@ -1,30 +1,43 @@
h1 a11ydive h1 Dashboard
h2 Dashboard
- if Report.any? .row
h3 Zuletzt bearbeitete Prüfberichte .col-md-6
ul - if Project.current.any?
- Report.all.order(updated_at: :desc).limit(3).each do |r| h2
li = link_to(r.name, r) i.bi.bi-folder>
'Aktuelle Projekte
ul
- Project.current.order(updated_at: :desc).each do |p|
li = link_to(p.name, p)
p - if Report.any?
i.bi.bi-journal-text h2
=< Report.count i.bi.bi-journal-text>
=< link_to Report.model_name.human(count: Report.count), :reports 'Zuletzt bearbeitete Prüfberichte
ul
- Report.all.order(updated_at: :desc).limit(3).each do |r|
li = link_to(r.name, r)
h3 Hotkeys .col-md-6
p Auf der Bericht-Ausfüllen Seite können folgende Shortcuts verwendet werden: h2 Browser Erweiterungen
dl p = link_to "Language Tools KI Korrektur", "https://languagetool.org/services#browsers"
dt t p = link_to "DeepL Firefox Extension", "https://www.deepl.com/en/firefox-extension"
dd Springe zum Anfang des Contents (Skip-Link, kann auf allen Seiten verwendet werden) p = link_to "DeepL Chrome Extension", "https://www.deepl.com/en/chrome-extension"
dt a p = link_to "DeepL Edge Extension", "https://www.deepl.com/en/edge-extension"
dd Alle auf
dt s h2 Hotkeys
dd Alle zu p Auf der Bericht-Ausfüllen Seite können folgende Shortcuts verwendet werden:
dt b dl
dd Baum dt t
dt n dd Springe zum Anfang des Contents (Skip-Link, kann auf allen Seiten verwendet werden)
dd Notizen dt a
dt e dd Alle auf
dd Springe zu erstem Check dt s
dd Alle zu
dt b
dd Baum
dt n
dd Notizen
dt e
dd Springe zu erstem Check

View file

@ -0,0 +1,8 @@
.toast class="#{alert ? "text-bg-danger" : "text-bg-info"}" role="alert" aria-live="assertive" aria-atomic="true" data={ controller: "toast", ts: Time.now.to_f }
.toast-header
/img src="..." class="rounded me-2" alt="...">
/strong.me-auto = heading
.small.me-auto = l(Time.current.to_time)
button.btn-close type="button" data-bs-dismiss="toast" aria-label="Schliessen"
.toast-body
= content

View file

@ -1,5 +1,5 @@
doctype html doctype html
html data-bs-theme="#{cookies[:"modeTheme"] || "light"}" data-controller="set-theme" html lang=:de data-bs-theme="#{cookies[:"modeTheme"] || "light"}" data-controller="set-theme"
head head
title a11ydive title a11ydive
meta[name="viewport" content="width=device-width,initial-scale=1"] meta[name="viewport" content="width=device-width,initial-scale=1"]
@ -16,5 +16,11 @@ html data-bs-theme="#{cookies[:"modeTheme"] || "light"}" data-controller="set-th
main.col.ps-md-2.pt-2 main.col.ps-md-2.pt-2
#main-content[data-controller="rich-text-link-targets"] #main-content[data-controller="rich-text-link-targets"]
= yield = yield
/footer.container-fluid.mt-auto.border-top
= Rails.configuration.build_version && "Version: #{Rails.configuration.build_version}" .toast-container.position-fixed.top-0.end-0.p-3 id="toasts"
- if flash.alert
= render partial: "layouts/toast", locals: { content: flash.alert, alert: true }
- if flash.notice
= render partial: "layouts/toast", locals: { content: flash.notice, alert: false }
= turbo_frame_tag "modal"

View file

@ -1,12 +1,10 @@
doctype html doctype html
html data-bs-theme="light" data-controller="set-theme" html
head head
title a11ydive Export title a11ydive Export
meta[name="viewport" content="width=device-width,initial-scale=1"] meta[name="viewport" content="width=device-width,initial-scale=1"]
= csrf_meta_tags = csrf_meta_tags
= csp_meta_tag = csp_meta_tag
= stylesheet_link_tag "exports", "data-turbo-track": "reload"
= javascript_include_tag "application", "data-turbo-track": "reload", type: "module"
body body
main#main-content main.container#main-content
= yield = yield

View file

@ -0,0 +1,9 @@
= turbo_frame_tag "modal" do
dialog.bg-body id="modal" data={ controller: :dialog }
.float-end
form method="dialog"
button.btn.btn-outline-danger
i.bi.bi-x-lg
= yield
data-action="turbo:submit-end->turbo-modal#submitEnd"

View file

@ -2,4 +2,5 @@
= form.text_field :path = form.text_field :path
= form.text_field :url = form.text_field :url
= form.submit = form.submit
= link_to("Abbrechen", report_path(@page.report), class: "btn btn-outline-secondary") - unless modal?
= link_to("Abbrechen", report_path(@page.report), class: "btn btn-outline-secondary")

View file

@ -11,5 +11,5 @@
<% end %> <% end %>
</div> </div>
<%= link_to("Sprinte zum ersten Element", "##{dom_id(page.elements.first)}", class: "visually-hidden", data: {controller: :hotkey, hotkey: "e", turbo: false}) if page.elements.first %> <%= link_to("Springe zum ersten Element", "##{dom_id(page.elements.first)}", class: "visually-hidden", data: {controller: :hotkey, hotkey: "e", turbo: false}) if page.elements.first %>
</div> </div>

View file

@ -2,7 +2,9 @@
<%= render "form", page: @page %> <%= render "form", page: @page %>
<% unless modal? %>
<div class="action-row"> <div class="action-row">
<%= link_to t("scaffold.link_show", model: Page.model_name.human), @page %> <%= link_to t("scaffold.link_show", model: Page.model_name.human), @page %>
<%= link_to t("scaffold.link_index", model: Page.model_name.human(count: 2)), report_pages_path(@page.report) %> <%= link_to t("scaffold.link_index", model: Page.model_name.human(count: 2)), report_pages_path(@page.report) %>
</div> </div>
<% end %>

View file

@ -11,7 +11,8 @@ h2
= turbo_frame_tag(dom_id(@page, :notes)) do = turbo_frame_tag(dom_id(@page, :notes)) do
= render partial: "pages/notes", locals: { page: @page } = render partial: "pages/notes", locals: { page: @page }
.action-row - unless modal?
= link_to t("scaffold.link_edit", model: @page.model_name.human), edit_page_path(@page) .action-row
= link_to t("scaffold.link_index", model: @page.model_name.human(count: 2)), report_pages_path(@page.report) = link_to t("scaffold.link_edit", model: @page.model_name.human), edit_page_path(@page)
= button_to t("scaffold.link_destroy", model: @page.model_name.human), @page, method: :delete, class: "btn btn-outline-danger" = link_to t("scaffold.link_index", model: @page.model_name.human(count: 2)), report_pages_path(@page.report)
= button_to t("scaffold.link_destroy", model: @page.model_name.human), @page, method: :delete, class: "btn btn-outline-danger"

View file

@ -4,4 +4,6 @@
= turbo_stream.update dom_id(element, :title), "#{element.page.position}.#{element.position} #{element.title}" = turbo_stream.update dom_id(element, :title), "#{element.page.position}.#{element.position} #{element.title}"
= turbo_stream.replace dom_id(element, :page_nav_row), partial: "elements/page_nav_row", locals: { element: element, current_page: element.page == @page} = turbo_stream.replace dom_id(element, :page_nav_row), partial: "elements/page_nav_row", locals: { element: element, current_page: element.page == @page}
- element.success_criteria.each do |sc| - element.success_criteria.each do |sc|
= turbo_stream.update dom_id(sc, :position), "#{sc.page.position}.#{sc.element.position}.#{sc.position}" = turbo_stream.update dom_id(sc, :position), "#{sc.page.position}.#{sc.element.position}.#{sc.position}"
= turbo_stream_toast("Pfad gespeichert", false)

View file

@ -0,0 +1,5 @@
<%= bootstrap_form_with(model: project) do |form| %>
<%= form.text_field :name %>
<%= form.rich_text_area :details %>
<%= form.submit %>
<% end %>

View file

@ -0,0 +1,20 @@
.project id=dom_id(project)
p
strong Name:
= project.name
p
strong Details:
= project.details
p
strong Berichte:
ul.ps-0
- project.reports.each do
li.d-flex.ps-0
=< "ID #{_1.id}: #{l(_1.created_at,format: :short)} #{_1.name}"
= link_to(_1, class: "btn btn-sm btn-link-secondary") do
i.bi.bi-folder-symlink
= button_to(project_reports_path(project), class: "btn btn-sm btn-link-secondary", params: { copy_from_id: _1.id }) do
i.bi.bi-copy
p
= link_to(new_project_report_path(project), class: "btn btn-secondary") do
i.bi.bi-plus-lg

View file

@ -0,0 +1,2 @@
json.extract! project, :id, :name, :created_at, :updated_at
json.url project_url(project, format: :json)

View file

@ -0,0 +1,8 @@
<h1><%= t("scaffold.pagetitle_edit", model: Project.model_name.human) %></h1>
<%= render "form", project: @project %>
<div class="action-row">
<%= link_to t("scaffold.link_show", model: Project.model_name.human), @project %>
<%= link_to t("scaffold.link_index", model: Project.model_name.human(count: 2)), projects_path %>
</div>

View file

@ -0,0 +1,25 @@
<h1><%= t("scaffold.pagetitle_index", model: Project.model_name.human(count: 2)) %></h1>
<table class="table table-striped">
<thead>
<tr>
<th><%= Project.human_attribute_name(:id) %></th>
<th><%= Project.human_attribute_name(:name) %></th>
</thead>
<tbody>
<% @projects.each do |project| %>
<tr>
<td><%= link_to(project.id, url_for(project)) %></td>
<td><%= link_to(project.name, url_for(project)) %></td>
</tr>
<% end %>
</tbody>
</table>
<div class="action-row">
<%= link_to t("scaffold.link_new", model: Project.model_name.human), new_project_path %>
</div>

View file

@ -0,0 +1 @@
json.array! @projects, partial: "projects/project", as: :project

View file

@ -0,0 +1,7 @@
<h1><%= t("scaffold.pagetitle_new", model: Project.model_name.human) %></h1>
<%= render "form", project: @project %>
<div class="action-row">
<%= link_to t("scaffold.link_index", model: Project.model_name.human(count: 2)), projects_path %>
</div>

View file

@ -0,0 +1,9 @@
<h1><%= t("scaffold.pagetitle_show", model: @project.class.model_name.human) %></h1>
<%= render @project %>
<div class="action-row">
<%= link_to t("scaffold.link_edit", model: @project.model_name.human), edit_project_path(@project) %>
<%= link_to t("scaffold.link_index", model: @project.model_name.human(count: 2)), projects_path %>
<%= button_to t("scaffold.link_destroy", model: @project.model_name.human), @project, method: :delete, class: "btn btn-outline-danger" if @project.reports.none? %>
</div>

View file

@ -0,0 +1 @@
json.partial! "projects/project", project: @project

View file

@ -1,4 +1,5 @@
<%= bootstrap_form_with(model: report) do |form| %> <%= bootstrap_form_with(model: report.persisted? ? report : [@project, report]) do |form| %>
<%= form.collection_select :project_id, Project.all, :id, :name, include_blank: true %>
<%= form.text_field :name %> <%= form.text_field :name %>
<%= form.text_field :url %> <%= form.text_field :url %>
<%= form.rich_text_area :comment %> <%= form.rich_text_area :comment %>

View file

@ -4,5 +4,5 @@
<div class="action-row"> <div class="action-row">
<%= link_to t("scaffold.link_show", model: Report.model_name.human), @report %> <%= link_to t("scaffold.link_show", model: Report.model_name.human), @report %>
<%= link_to t("scaffold.link_index", model: Report.model_name.human(count: 2)), reports_path %> <%= link_to t("scaffold.link_index", model: Report.model_name.human(count: 2)), project_reports_path(@report.project) %>
</div> </div>

View file

@ -27,5 +27,5 @@
</table> </table>
<div class="action-row"> <div class="action-row">
<%= link_to t("scaffold.link_new", model: Report.model_name.human), new_report_path %> <%= link_to t("scaffold.link_new", model: Report.model_name.human), new_project_report_path(@project) %>
</div> </div>

View file

@ -3,5 +3,5 @@
<%= render "form", report: @report %> <%= render "form", report: @report %>
<div class="action-row"> <div class="action-row">
<%= link_to t("scaffold.link_index", model: Report.model_name.human(count: 2)), reports_path %> <%= link_to t("scaffold.link_index", model: Report.model_name.human(count: 2)), project_reports_path(@project) %>
</div> </div>

View file

@ -1,29 +1,32 @@
.border-bottom.mb-3
h1
i.bi.bi-journal-text.me-2
= @report.name
div div
small.float-end small = "Erstellt am #{l(@report.created_at, format: :short)}, zuletzt bearbeitet am #{l(@report.updated_at, format: :short)}"
| Erstellt am
= l(@report.created_at, format: :short) p
| , zuletzt bearbeitet am i.bi.bi-folder
= l(@report.updated_at, format: :short) strong< = link_to(@report.project.name, @report.project)
h1
i.bi.bi-journal-text.me-2 .smb-4.lead.mb-5
= @report.name = @report.comment || tag.i("leer")
- if @report.comment
.smb-4.lead.mb-3
= @report.comment
- if @current_page - if @current_page
h2 .current_page data-controller="details-list" data-target-id="element_list"
i.bi.bi-file-earmark-check .border-bottom.mb-3.d-flex
=< @current_page.position h2
=< @current_page.path i.bi.bi-file-earmark-check
p =< @current_page.position
'URL: =< @current_page.path
= safe_display(@current_page.full_url) { link_to(_1, _1, target: :_blank) } = page_menu(@current_page)
p.actions p
.d-flex.justify-content-end data-controller="details-list" data-target-id="element_list" 'URL:
.btn-group.me-3 = safe_display(@current_page.full_url) { link_to(_1, _1, target: :_blank) }
= link_to("Alle zu [s]", "#", data: { action: "click->details-list#closeAll", controller: :hotkey, hotkey: "s" }, class: "btn btn-outline-secondary") p.actions
= link_to("Alle auf [a]", "#", data: { action: "click->details-list#openAll", controller: :hotkey, hotkey: "a" }, class: "btn btn-outline-secondary") .d-flex.justify-content-end
= button_to(tag.i(class: "bi bi-trash"), page_path(@current_page), method: :delete, class: "btn btn-outline-danger", form: {data: { turbo_confirm: "Bist du sicher?" }}) .btn-group.me-3.visually-hidden
= link_to("Alle zu [s]", "#", data: { action: "click->details-list#closeAll", controller: :hotkey, hotkey: "s" }, class: "btn btn-outline-secondary")
= link_to("Alle auf [a]", "#", data: { action: "click->details-list#openAll", controller: :hotkey, hotkey: "a" }, class: "btn btn-outline-secondary")
.row .row
.col-lg-3.col-md-4.col-sm-12 .col-lg-3.col-md-4.col-sm-12
.page_nav.sticky-top .page_nav.sticky-top
@ -40,9 +43,9 @@ h1
= link_to(report_export_path(@report), class: "btn btn-secondary", target: :_blank) do = link_to(report_export_path(@report), class: "btn btn-secondary", target: :_blank) do
i.bi.bi-filetype-html i.bi.bi-filetype-html
| Online HTML | Online HTML
/ = link_to report_path(@report, format: :pdf), class: "btn btn-secondary", target: "_blank" do = link_to report_path(@report, format: :pdf), class: "btn btn-secondary", target: "_blank" do
/ i.bi.bi-filetype-pdf i.bi.bi-filetype-pdf
/ | PDF | PDF
/ = link_to report_path(@report, format: :docx), class: "btn btn-secondary", target: "_blank" do / = link_to report_path(@report, format: :docx), class: "btn btn-secondary", target: "_blank" do
/ i.bi.bi-filetype-docx / i.bi.bi-filetype-docx
/ | DOCX / | DOCX
@ -60,5 +63,5 @@ h1
| ODT | ODT
.action-row .action-row
= link_to t("scaffold.link_edit", model: @report.model_name.human), edit_report_path(@report) = link_to t("scaffold.link_edit", model: @report.model_name.human), edit_report_path(@report)
= link_to t("scaffold.link_index", model: @report.model_name.human(count: 2)), reports_path = link_to t("scaffold.link_index", model: @report.model_name.human(count: 2)), project_reports_path(@report.project)
= button_to t("scaffold.link_destroy", model: @report.model_name.human), @report, method: :delete, class: "btn btn-outline-danger" = button_to t("scaffold.link_destroy", model: @report.model_name.human), @report, method: :delete, class: "btn btn-outline-danger", data: { turbo_confirm: "Bist du sicher?"}

View file

@ -1,19 +1,21 @@
.content id="#{dom_id(success_criterion, :body)}" .content id="#{dom_id(success_criterion, :body)}"
= turbo_frame_tag(dom_id(success_criterion, :frame)) do = turbo_frame_tag(dom_id(success_criterion, :frame)) do
.row .d-flex
.col .my-3.btn-group[role="group" aria-label="Resultat"]
.my-3.btn-group[role="group" aria-label="Resultat"] = bootstrap_form_with(model: success_criterion, data: { controller: "autosubmit" }) do |form|
= bootstrap_form_with(model: success_criterion, data: { controller: "autosubmit" }) do |form| = form.radio_button_without_bootstrap :result, :passed, class: "btn-check", autocomplete: "off", id: dom_id(success_criterion, :result_passed)
= form.radio_button_without_bootstrap :result, :passed, class: "btn-check", autocomplete: "off", id: dom_id(success_criterion, :result_passed) label.btn.btn-outline-success for=dom_id(success_criterion, :result_passed) Bestanden
label.btn.btn-outline-success for=dom_id(success_criterion, :result_passed) Bestanden = form.radio_button_without_bootstrap :result, :failed, class: "btn-check", autocomplete: "off", id: dom_id(success_criterion, :result_failed)
= form.radio_button_without_bootstrap :result, :failed, class: "btn-check", autocomplete: "off", id: dom_id(success_criterion, :result_failed) label.btn.btn-outline-danger for=dom_id(success_criterion, :result_failed) Durchgefallen
label.btn.btn-outline-danger for=dom_id(success_criterion, :result_failed) Durchgefallen = form.radio_button_without_bootstrap :result, :not_applicable, class: "btn-check", autocomplete: "off", id: dom_id(success_criterion, :result_not_applicable)
= form.radio_button_without_bootstrap :result, :not_applicable, class: "btn-check", autocomplete: "off", id: dom_id(success_criterion, :result_not_applicable) label.btn.btn-outline-secondary for=dom_id(success_criterion, :result_not_applicable) Nicht anwendbar
label.btn.btn-outline-secondary for=dom_id(success_criterion, :result_not_applicable) Nicht anwendbar /= form.radio_button_without_bootstrap :result, nil, class: "btn-check", autocomplete: "off", id: dom_id(success_criterion, :result_not_applicable)
/= form.radio_button_without_bootstrap :result, nil, class: "btn-check", autocomplete: "off", id: dom_id(success_criterion, :result_not_applicable) /label.btn.btn-outline-secondary for=dom_id(success_criterion, :nil) Reset
/label.btn.btn-outline-secondary for=dom_id(success_criterion, :nil) Reset - unless success_criterion.test_comment.blank?
= button_to(tag.i(class: "bi bi-trash"), success_criterion, method: :delete, class: "btn btn-link text-danger", data: { turbo_confirm: "Bist du sicher?"}) = link_to(edit_comment_success_criterion_path(success_criterion), class: "btn btn-outline-warning my-3 ms-3", data: { turbo_frame: "modal" }) do
= success_criterion_edit_button(success_criterion, false) i.bi.bi-chat>
'Kommentar bearbeiten
= success_criterion_menu(success_criterion)
.row .row
.col .col
- if success_criterion.test_comment? - if success_criterion.test_comment?
@ -45,7 +47,7 @@
.text-end.fw-bold = SuccessCriterion.human_attribute_name(:quick_fix) .text-end.fw-bold = SuccessCriterion.human_attribute_name(:quick_fix)
.col-md-8.col-lg-9 .col-md-8.col-lg-9
= success_criterion.quick_fix = success_criterion.quick_fix
.row.mb-3 .row
.col-md-4.col-lg-3 .col-md-4.col-lg-3
.text-end.fw-bold = SuccessCriterion.human_attribute_name(:test_instructions) .text-end.fw-bold = SuccessCriterion.human_attribute_name(:test_instructions)
.col-md-8.col-lg-9 .col-md-8.col-lg-9

View file

@ -1,11 +0,0 @@
<%= bootstrap_form_with(model: success_criterion.persisted? ? success_criterion : [:element, success_criterion], data: { controller: "unsaved-changes" }) do |form| %>
<%= form.text_field :title %>
<%= form.collection_select :result, SuccessCriterion.results.keys.map { [_1, t("activerecord.attributes.success_criterion.results/#{_1}")] }, :first, :second, include_blank: success_criterion.result ? "(Resultat zurücksetzen)" : "(unbeantwortet)" %>
<%= form.rich_text_area :quick_criterion %>
<%= form.rich_text_area :quick_fail %>
<%= form.rich_text_area :quick_fix %>
<%= form.rich_text_area :test_comment %>
<%= form.submit class: "btn btn-primary" %>
<%= link_to "Abbrechen", success_criterion.persisted? ? success_criterion : success_criterion.element, class: "btn btn-outline-secondary" %>
<% end %>

View file

@ -0,0 +1,11 @@
= bootstrap_form_with(model: success_criterion.persisted? ? success_criterion : [:element, success_criterion], data: { controller: "unsaved-changes" }) do |form|
= form.text_field :title
= form.collection_select :result, SuccessCriterion.results.keys.map { [_1, t("activerecord.attributes.success_criterion.results/#{_1}")] }, :first, :second, include_blank: success_criterion.result ? "(Resultat zurücksetzen)" : "(unbeantwortet)"
= form.rich_text_area :quick_criterion
= form.rich_text_area :quick_fail
= form.rich_text_area :quick_fix
= form.rich_text_area :test_comment
= form.submit class: "btn btn-primary"
- unless modal?
p Not MODAL
=< link_to "Abbrechen", success_criterion.persisted? ? success_criterion : success_criterion.element, class: "btn btn-outline-secondary"

View file

@ -3,7 +3,7 @@ summary.d-flex.align-items-start id=dom_id(success_criterion, :header)
.content.d-flex.align-items-center.w-100 .content.d-flex.align-items-center.w-100
.result-icon.flex-shrink-0 class=[success_criterion_result_color_classes(success_criterion)] .result-icon.flex-shrink-0 class=[success_criterion_result_color_classes(success_criterion)]
span.h1.bi class=[success_criterion_result_icon_classes(success_criterion)] span.h1.bi class=[success_criterion_result_icon_classes(success_criterion)]
.flex-fill .flex-fill.py-1
span id=dom_id(success_criterion, :position) span id=dom_id(success_criterion, :position)
= success_criterion.page.position = success_criterion.page.position
| . | .
@ -19,4 +19,4 @@ summary.d-flex.align-items-start id=dom_id(success_criterion, :header)
= success_criterion_badge(success_criterion.check.external_number, extra_classes: "text-bg-info me-1") = success_criterion_badge(success_criterion.check.external_number, extra_classes: "text-bg-info me-1")
= success_criterion_badge(success_criterion.level, extra_classes: "sc-level-#{success_criterion.level.to_s.downcase} me-1") = success_criterion_badge(success_criterion.level, extra_classes: "sc-level-#{success_criterion.level.to_s.downcase} me-1")
i.bi.bi-grip-vertical.handle i.bi.bi-grip-vertical.handle.me-1

View file

@ -0,0 +1,3 @@
= dropdown_menu(klass: "mt-3 ms-auto b-0") do
= success_criterion_edit_button(@success_criterion, true)
= button_to(tag.i(class: "bi bi-trash") + " Löschen".html_safe, @success_criterion, method: :delete, class: "text-danger", data: { turbo_confirm: "Bist du sicher?"})

View file

@ -1,4 +1,6 @@
= turbo_stream.remove dom_id(@success_criterion) = turbo_stream.remove dom_id(@success_criterion)
- @success_criterion.element.success_criteria.reject { _1 == @success_criterion }.each do |sc| - @success_criterion.element.success_criteria.reject { _1 == @success_criterion }.each do |sc|
- Rails.logger.debug "Send to sc #{sc.id}" - Rails.logger.debug "Send to sc #{sc.id}"
= turbo_stream.update dom_id(sc, :position), "#{sc.page.position}.#{sc.element.position}.#{sc.position}" = turbo_stream.update dom_id(sc, :position), "#{sc.page.position}.#{sc.element.position}.#{sc.position}"
= turbo_stream_toast("Erfolgskriterium wurde gelöscht", true)

View file

@ -1,10 +0,0 @@
<h1><%= t("scaffold.pagetitle_edit", model: SuccessCriterion.model_name.human) %></h1>
<%= turbo_frame_tag(dom_id(@success_criterion, :frame)) do %>
<%= render "form", success_criterion: @success_criterion %>
<% end %>
<div class="action-row">
<%= link_to t("scaffold.link_show", model: SuccessCriterion.model_name.human), @success_criterion %>
<%= link_to t("scaffold.link_index", model: SuccessCriterion.model_name.human(count: 2)), element_success_criteria_path(@success_criterion.element) %>
</div>

View file

@ -0,0 +1,7 @@
h2 Erfolgskriterium bearbeiten
.mb-3
= render "form", success_criterion: @success_criterion
- unless modal?
.action-row
= link_to t("scaffold.link_show", model: SuccessCriterion.model_name.human), @success_criterion
= link_to t("scaffold.link_index", model: SuccessCriterion.model_name.human(count: 2)), element_success_criteria_path(@success_criterion.element)

View file

@ -0,0 +1,6 @@
h2 Kommentar bearbeiten
= bootstrap_form_with(model: @success_criterion.persisted? ? @success_criterion : [:element, @success_criterion], data: { controller: "unsaved-changes" }) do |form|
= form.rich_text_area :test_comment, hide_label: true
= form.submit class: "btn btn-primary"
- unless modal?
=< link_to "Abbrechen", @success_criterion.persisted? ? @success_criterion : @success_criterion.element, class: "btn btn-outline-secondary"

View file

@ -2,4 +2,5 @@
= turbo_stream.replace dom_id(@success_criterion, :body), partial: "success_criteria/body", locals: {success_criterion: @success_criterion } = turbo_stream.replace dom_id(@success_criterion, :body), partial: "success_criteria/body", locals: {success_criterion: @success_criterion }
- @success_criterion.element.success_criteria.each do |sc| - @success_criterion.element.success_criteria.each do |sc|
= turbo_stream.update(dom_id(sc, :position), sc.number) = turbo_stream.update(dom_id(sc, :position), sc.number)
= turbo_stream_toast("Erfolgskriterium gespeichert: #{t("activerecord.attributes.success_criterion.results/#{@success_criterion.result}")}", false)

Some files were not shown because too many files have changed in this diff Show more