@fc3/mmcadi 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +673 -0
- package/README.md +5 -0
- package/bin/compile +63 -0
- package/bin/copy-static-files +13 -0
- package/bin/install +5 -0
- package/bin/precompile +55 -0
- package/bin/prepublish +7 -0
- package/bin/remap-paths +113 -0
- package/bin/test +9 -0
- package/config/tsconfig.json +37 -0
- package/package.json +33 -0
- package/src/bootstrap/start.ts +12 -0
- package/src/client/bootstrap.ts +5 -0
- package/src/client/client.ts +54 -0
- package/src/client/enum/key-code.ts +34 -0
- package/src/client/enum/page-type.ts +19 -0
- package/src/client/factory/page.ts +61 -0
- package/src/client/page/confirm-delete-block.ts +30 -0
- package/src/client/page/create-block.ts +6 -0
- package/src/client/page/day.ts +8 -0
- package/src/client/page/edit-block.ts +43 -0
- package/src/client/page/edit-custom.ts +16 -0
- package/src/client/page/home.ts +8 -0
- package/src/client/page/login.ts +8 -0
- package/src/client/page/logout.ts +8 -0
- package/src/client/page/month.ts +8 -0
- package/src/client/page/move-block.ts +8 -0
- package/src/client/page/select-block-type.ts +56 -0
- package/src/client/page/settings.ts +8 -0
- package/src/client/page/view-custom.ts +665 -0
- package/src/client/page/week.ts +8 -0
- package/src/client/page/year.ts +8 -0
- package/src/client/page.ts +128 -0
- package/src/client/shim/execute.ts +5 -0
- package/src/client/shim/logger.ts +44 -0
- package/src/client/utility/get-meta-value.ts +23 -0
- package/src/common/builder/block/background.ts +25 -0
- package/src/common/builder/block/folder.ts +43 -0
- package/src/common/builder/block/header.ts +15 -0
- package/src/common/builder/block/link.ts +32 -0
- package/src/common/builder/block/multicolumn.ts +16 -0
- package/src/common/builder/block/note.ts +13 -0
- package/src/common/builder/block/whitespace.ts +13 -0
- package/src/common/utility/get-parent-path.ts +29 -0
- package/src/constant/month-names.ts +16 -0
- package/src/enum/action-type.ts +11 -0
- package/src/enum/block-type.ts +18 -0
- package/src/enum/calendar-view-mode.ts +9 -0
- package/src/enum/color.ts +15 -0
- package/src/enum/default-role.ts +6 -0
- package/src/enum/directory-item-type.ts +6 -0
- package/src/enum/emoji.ts +94 -0
- package/src/enum/field-type.ts +8 -0
- package/src/enum/header-size.ts +7 -0
- package/src/enum/permission-type.ts +8 -0
- package/src/enum/time-place-visibility.ts +8 -0
- package/src/enum/tool-type.ts +14 -0
- package/src/index.ts +8 -0
- package/src/interface/hydration-callback.ts +7 -0
- package/src/interface/provider.ts +8 -0
- package/src/interface/repository.ts +12 -0
- package/src/lib/array/add.ts +10 -0
- package/src/lib/array/assert-is-empty.ts +23 -0
- package/src/lib/array/clone.ts +5 -0
- package/src/lib/array/difference.ts +8 -0
- package/src/lib/array/empty.ts +6 -0
- package/src/lib/array/equal.ts +24 -0
- package/src/lib/array/get-first-value.ts +5 -0
- package/src/lib/array/get-last-value.ts +5 -0
- package/src/lib/array/get-max-value.ts +5 -0
- package/src/lib/array/get-value-after.ts +23 -0
- package/src/lib/array/get-value-before.ts +23 -0
- package/src/lib/array/get-values-between.ts +18 -0
- package/src/lib/array/index.ts +5 -0
- package/src/lib/array/is-empty.ts +6 -0
- package/src/lib/array/remove.ts +19 -0
- package/src/lib/array/sum.ts +11 -0
- package/src/lib/array/unique.ts +13 -0
- package/src/lib/environment/bootstrap.ts +1 -0
- package/src/lib/environment/enum/environment-type.ts +8 -0
- package/src/lib/environment/enum/service-type.ts +5 -0
- package/src/lib/environment/index.ts +7 -0
- package/src/lib/environment/utility/get-environment-type.ts +28 -0
- package/src/lib/environment/utility/is-browser.ts +5 -0
- package/src/lib/environment/utility/is-development.ts +10 -0
- package/src/lib/environment/utility/is-production-or-staging.ts +8 -0
- package/src/lib/environment/utility/is-production.ts +10 -0
- package/src/lib/environment/utility/is-staging.ts +10 -0
- package/src/lib/errors/enum/error-type.ts +13 -0
- package/src/lib/errors/error/base.ts +40 -0
- package/src/lib/errors/error/conflict.ts +16 -0
- package/src/lib/errors/error/generic.ts +23 -0
- package/src/lib/errors/error/invalid.ts +14 -0
- package/src/lib/errors/error/invariant-violation.ts +5 -0
- package/src/lib/errors/error/not-allowed.ts +14 -0
- package/src/lib/errors/error/not-found.ts +16 -0
- package/src/lib/errors/error/not-implemented.ts +20 -0
- package/src/lib/errors/error/omitted.ts +14 -0
- package/src/lib/errors/error/timeout.ts +14 -0
- package/src/lib/errors/error/unauthorized.ts +14 -0
- package/src/lib/errors/index.ts +18 -0
- package/src/lib/errors/sugar/invariant.ts +7 -0
- package/src/lib/errors/type/coded-error.ts +7 -0
- package/src/lib/errors/type/error-data.ts +11 -0
- package/src/lib/errors/utility/create-error-for-error-type.ts +60 -0
- package/src/lib/errors/utility/create-error-from-ambiguous-json-data.ts +26 -0
- package/src/lib/errors/utility/error-matches.ts +28 -0
- package/src/lib/errors/utility/get-error-type-for-posix-error-code.ts +37 -0
- package/src/lib/errors/utility/get-error-type-for-status-code.ts +38 -0
- package/src/lib/errors/utility/get-message-for-error-type.ts +29 -0
- package/src/lib/errors/utility/matches-posix-error-code.ts +11 -0
- package/src/lib/errors/utility/wrap-error.ts +39 -0
- package/src/lib/event-emitter/index.ts +63 -0
- package/src/lib/execution-context/execution-context.ts +90 -0
- package/src/lib/execution-context/index.ts +8 -0
- package/src/lib/execution-context/type/session.ts +7 -0
- package/src/lib/feature/feature.ts +108 -0
- package/src/lib/feature/index.ts +3 -0
- package/src/lib/filesystem/bootstrap.ts +1 -0
- package/src/lib/filesystem/enum/file-extension.ts +19 -0
- package/src/lib/filesystem/index.ts +4 -0
- package/src/lib/filesystem/utility/exists.ts +21 -0
- package/src/lib/filesystem/utility/get-extension-for-filepath.ts +20 -0
- package/src/lib/filesystem/utility/strip-extension.ts +26 -0
- package/src/lib/grammar/index.ts +3 -0
- package/src/lib/grammar/noun-inflector.ts +104 -0
- package/src/lib/grammar/utility/get-words-from-identifier.ts +9 -0
- package/src/lib/grammar/verb-inflector.ts +344 -0
- package/src/lib/http/buffer-stream.ts +76 -0
- package/src/lib/http/enum/content-type.ts +19 -0
- package/src/lib/http/enum/cookie-attribute.ts +11 -0
- package/src/lib/http/enum/header.ts +29 -0
- package/src/lib/http/enum/method.ts +11 -0
- package/src/lib/http/enum/same-site-policy.ts +7 -0
- package/src/lib/http/enum/status-code.ts +9 -0
- package/src/lib/http/factory/body-parser.ts +55 -0
- package/src/lib/http/index.ts +24 -0
- package/src/lib/http/interface/client-request.ts +15 -0
- package/src/lib/http/interface/incoming-message.ts +24 -0
- package/src/lib/http/interface/network-library.ts +9 -0
- package/src/lib/http/interface/request-callback.ts +7 -0
- package/src/lib/http/isomorphic/request.ts +77 -0
- package/src/lib/http/isomorphic/response.ts +77 -0
- package/src/lib/http/isomorphic.ts +20 -0
- package/src/lib/http/parser/accept-header.ts +35 -0
- package/src/lib/http/parser/basic-auth-header.ts +48 -0
- package/src/lib/http/parser/body/json.ts +14 -0
- package/src/lib/http/parser/body/multipart.ts +89 -0
- package/src/lib/http/parser/body/url-encoded.ts +16 -0
- package/src/lib/http/parser/body.ts +44 -0
- package/src/lib/http/parser/cookie.ts +114 -0
- package/src/lib/http/parser/querystring.ts +92 -0
- package/src/lib/http/parser/url.ts +76 -0
- package/src/lib/http/request/incoming.ts +299 -0
- package/src/lib/http/request/outgoing.ts +276 -0
- package/src/lib/http/request.ts +26 -0
- package/src/lib/http/response/incoming.ts +243 -0
- package/src/lib/http/response/outgoing.ts +160 -0
- package/src/lib/http/response.ts +74 -0
- package/src/lib/http/serializer/basic-auth-header.ts +27 -0
- package/src/lib/http/serializer/cookie.ts +90 -0
- package/src/lib/http/serializer/query-data.ts +54 -0
- package/src/lib/http/transaction.ts +320 -0
- package/src/lib/http/type/basic-auth-credentials.ts +6 -0
- package/src/lib/http/type/header-map.ts +5 -0
- package/src/lib/http/type/log-attributes.ts +12 -0
- package/src/lib/http/type/path-parameters.ts +5 -0
- package/src/lib/http/type/query-data.ts +7 -0
- package/src/lib/http/type/query-value.ts +11 -0
- package/src/lib/http/type/request-options.ts +16 -0
- package/src/lib/http/type/transaction-data.ts +4 -0
- package/src/lib/http/utility/get-content-type-for-extension.ts +47 -0
- package/src/lib/http/utility/get-library-for-protocol.ts +25 -0
- package/src/lib/http/utility/get-status-code-for-error-type.ts +37 -0
- package/src/lib/http/utility/get-status-code-for-error.ts +13 -0
- package/src/lib/http/utility/is-client-error-status.ts +15 -0
- package/src/lib/http/utility/is-error-status.ts +9 -0
- package/src/lib/http/utility/is-server-error-status.ts +7 -0
- package/src/lib/http/utility/is-success-status.ts +7 -0
- package/src/lib/http/utility/proxy-request.ts +58 -0
- package/src/lib/http/utility/serialize-request-options.ts +9 -0
- package/src/lib/http/utility/slug-generator.ts +20 -0
- package/src/lib/key-generator/index.ts +3 -0
- package/src/lib/key-generator/key-generator.ts +7 -0
- package/src/lib/logger/enum/ansi-escape-code.ts +14 -0
- package/src/lib/logger/enum/log-level.ts +8 -0
- package/src/lib/logger/formatter.ts +59 -0
- package/src/lib/logger/index.ts +7 -0
- package/src/lib/logger/interface/error-reporter.ts +7 -0
- package/src/lib/logger/interface/logger.ts +13 -0
- package/src/lib/logger/logger.ts +239 -0
- package/src/lib/logger/type/error-parameters.ts +9 -0
- package/src/lib/logger/type/loggable-data.ts +5 -0
- package/src/lib/logger/type/loggable-value.ts +1 -0
- package/src/lib/metrics/dispatcher.ts +264 -0
- package/src/lib/metrics/enum/dispatch-mode.ts +6 -0
- package/src/lib/metrics/index.ts +2 -0
- package/src/lib/metrics/settings-hydrator.ts +51 -0
- package/src/lib/metrics/type/dispatcher-settings.ts +12 -0
- package/src/lib/metrics/type/tag-map.ts +5 -0
- package/src/lib/network/bootstrap.ts +1 -0
- package/src/lib/network/enum/connection-status.ts +14 -0
- package/src/lib/network/enum/http-status-code.ts +75 -0
- package/src/lib/network/enum/network-protocol.ts +10 -0
- package/src/lib/network/event-emitter.ts +63 -0
- package/src/lib/network/index.ts +7 -0
- package/src/lib/network/interface/socket.ts +42 -0
- package/src/lib/network/type/socket-options.ts +6 -0
- package/src/lib/network/utility/get-protocol-from-url.ts +15 -0
- package/src/lib/operation/index.ts +6 -0
- package/src/lib/operation/operation/auto-logging.ts +94 -0
- package/src/lib/operation/operation/silent.ts +17 -0
- package/src/lib/operation/operation.ts +80 -0
- package/src/lib/process/bootstrap.ts +1 -0
- package/src/lib/process/enum/posix-error-code.ts +138 -0
- package/src/lib/process/enum/process-signal.ts +68 -0
- package/src/lib/process/error.ts +6 -0
- package/src/lib/process/execute.ts +77 -0
- package/src/lib/process/index.ts +4 -0
- package/src/lib/process/type/command-options.ts +9 -0
- package/src/lib/process/utility/bind-process-lifespan-to.ts +10 -0
- package/src/lib/promise-wrapper/index.ts +3 -0
- package/src/lib/promise-wrapper/promise-wrapper.ts +51 -0
- package/src/lib/random/chance.ts +5 -0
- package/src/lib/random/element.ts +7 -0
- package/src/lib/random/elements.ts +12 -0
- package/src/lib/random/enum.ts +34 -0
- package/src/lib/random/enums.ts +11 -0
- package/src/lib/random/index.ts +3 -0
- package/src/lib/random/number.ts +8 -0
- package/src/lib/server/base.ts +194 -0
- package/src/lib/server/enum/server-event.ts +5 -0
- package/src/lib/server/enum/server-status.ts +10 -0
- package/src/lib/server/http/endpoint/ping.ts +21 -0
- package/src/lib/server/http/endpoint.ts +345 -0
- package/src/lib/server/http/interface/endpoint-constructor.ts +12 -0
- package/src/lib/server/http/interface/result-serializer.ts +5 -0
- package/src/lib/server/http/middleware.ts +18 -0
- package/src/lib/server/http/result-serializer/html.ts +92 -0
- package/src/lib/server/http/result-serializer/json.ts +23 -0
- package/src/lib/server/http/route.ts +104 -0
- package/src/lib/server/http/router.ts +125 -0
- package/src/lib/server/http/type/session-resolver.ts +8 -0
- package/src/lib/server/http/utility/create-server.ts +34 -0
- package/src/lib/server/http/utility/path-parser.ts +49 -0
- package/src/lib/server/http/utility/standardize-html-indentation.ts +54 -0
- package/src/lib/server/http/websocket-wrapper.ts +83 -0
- package/src/lib/server/http.ts +301 -0
- package/src/lib/server/index.ts +5 -0
- package/src/lib/server/tcp.ts +53 -0
- package/src/lib/server/type/server-options.ts +10 -0
- package/src/lib/string/calculate-length.ts +17 -0
- package/src/lib/string/capitalize.ts +8 -0
- package/src/lib/string/create-slug.ts +14 -0
- package/src/lib/string/enum/ansi-escape-code.ts +14 -0
- package/src/lib/string/enum/string-encoding.ts +9 -0
- package/src/lib/string/hyphenate.ts +5 -0
- package/src/lib/string/index.ts +3 -0
- package/src/lib/string/pad.ts +14 -0
- package/src/lib/string/trim-multiline.ts +21 -0
- package/src/lib/string/trim.ts +8 -0
- package/src/lib/tcp/channel.ts +13 -0
- package/src/lib/tcp/connection/incoming.ts +72 -0
- package/src/lib/tcp/connection/outgoing.ts +219 -0
- package/src/lib/tcp/connection.ts +360 -0
- package/src/lib/tcp/enum/connection-event.ts +12 -0
- package/src/lib/tcp/enum/message-type.ts +9 -0
- package/src/lib/tcp/index.ts +1 -0
- package/src/lib/tcp/type/connection-parameters.ts +6 -0
- package/src/lib/tcp/type/message/channel-close.ts +9 -0
- package/src/lib/tcp/type/message/channel-open.ts +9 -0
- package/src/lib/tcp/type/message.ts +10 -0
- package/src/lib/test/index.ts +2 -0
- package/src/lib/test/utility/build-config.ts +17 -0
- package/src/lib/test/utility/build-execution-context.ts +11 -0
- package/src/lib/time/bootstrap.ts +1 -0
- package/src/lib/time/enum/time-interval.ts +12 -0
- package/src/lib/time/index.ts +4 -0
- package/src/lib/time/utility/format-duration.ts +139 -0
- package/src/lib/time/utility/format-relative-duration.ts +22 -0
- package/src/lib/time/utility/sleep.ts +9 -0
- package/src/operation.ts +18 -0
- package/src/server/endpoint/abstract-page.ts +126 -0
- package/src/server/endpoint/action/create.ts +545 -0
- package/src/server/endpoint/action/get.ts +231 -0
- package/src/server/endpoint/base.ts +51 -0
- package/src/server/endpoint/day.ts +13 -0
- package/src/server/endpoint/generic-page.ts +14 -0
- package/src/server/endpoint/index.ts +11 -0
- package/src/server/endpoint/login.ts +45 -0
- package/src/server/endpoint/logout.ts +38 -0
- package/src/server/endpoint/month.ts +35 -0
- package/src/server/endpoint/robots.ts +18 -0
- package/src/server/endpoint/session/create.ts +62 -0
- package/src/server/endpoint/settings/get.ts +40 -0
- package/src/server/endpoint/settings/update.ts +44 -0
- package/src/server/endpoint/today.ts +15 -0
- package/src/server/endpoint/week.ts +34 -0
- package/src/server/endpoint/year.ts +34 -0
- package/src/server/enum/custom-page-type.ts +10 -0
- package/src/server/factory/block-result-serializer.ts +115 -0
- package/src/server/middleware/base.ts +6 -0
- package/src/server/middleware/error-handler.ts +177 -0
- package/src/server/middleware/static-file.ts +83 -0
- package/src/server/operation/add-block.ts +110 -0
- package/src/server/operation/create-session.ts +43 -0
- package/src/server/operation/delete-block.ts +96 -0
- package/src/server/operation/demote-block.ts +108 -0
- package/src/server/operation/destroy-session.ts +26 -0
- package/src/server/operation/load-account.ts +30 -0
- package/src/server/operation/load-block.ts +48 -0
- package/src/server/operation/load-directory-items.ts +75 -0
- package/src/server/operation/load-page.ts +368 -0
- package/src/server/operation/promote-block.ts +104 -0
- package/src/server/operation/save-page.ts +60 -0
- package/src/server/operation/update-account-settings.ts +52 -0
- package/src/server/operation/update-block.ts +124 -0
- package/src/server/repository/memory.ts +112 -0
- package/src/server/result-serializer/action.ts +939 -0
- package/src/server/result-serializer/base.ts +1267 -0
- package/src/server/result-serializer/block/audio.ts +33 -0
- package/src/server/result-serializer/block/background.ts +20 -0
- package/src/server/result-serializer/block/calendar.ts +148 -0
- package/src/server/result-serializer/block/directory.ts +57 -0
- package/src/server/result-serializer/block/ephemeral.ts +14 -0
- package/src/server/result-serializer/block/folder.ts +106 -0
- package/src/server/result-serializer/block/header.ts +31 -0
- package/src/server/result-serializer/block/image.ts +46 -0
- package/src/server/result-serializer/block/link.ts +40 -0
- package/src/server/result-serializer/block/list.ts +140 -0
- package/src/server/result-serializer/block/multi-column.ts +97 -0
- package/src/server/result-serializer/block/note.ts +44 -0
- package/src/server/result-serializer/block/todo.ts +78 -0
- package/src/server/result-serializer/block/whitespace.ts +15 -0
- package/src/server/result-serializer/block.ts +248 -0
- package/src/server/result-serializer/common/time-place-options.ts +33 -0
- package/src/server/result-serializer/login.ts +58 -0
- package/src/server/result-serializer/month.ts +170 -0
- package/src/server/result-serializer/page.ts +548 -0
- package/src/server/result-serializer/settings.ts +85 -0
- package/src/server/result-serializer/week.ts +195 -0
- package/src/server/result-serializer/year.ts +160 -0
- package/src/server/utility/accepts-content-type.ts +16 -0
- package/src/server/utility/accepts-html.ts +9 -0
- package/src/server/utility/accepts-json.ts +9 -0
- package/src/server/utility/add-days.ts +11 -0
- package/src/server/utility/create-date.ts +23 -0
- package/src/server/utility/create-index-path.ts +5 -0
- package/src/server/utility/create-slug.ts +9 -0
- package/src/server/utility/create-toast-path.ts +19 -0
- package/src/server/utility/date-less-than.ts +5 -0
- package/src/server/utility/date-occurs-before.ts +22 -0
- package/src/server/utility/date-to-key.ts +7 -0
- package/src/server/utility/date-to-label.ts +5 -0
- package/src/server/utility/date-to-path.ts +9 -0
- package/src/server/utility/dates-are-equal.ts +22 -0
- package/src/server/utility/dates-are-in-order.ts +9 -0
- package/src/server/utility/dates-are-on-the-same-day.ts +9 -0
- package/src/server/utility/dates-in-same-month.ts +8 -0
- package/src/server/utility/day-to-date.ts +40 -0
- package/src/server/utility/decrement-date.ts +11 -0
- package/src/server/utility/get-block-at-index-path.ts +32 -0
- package/src/server/utility/get-block-permissions.ts +15 -0
- package/src/server/utility/get-compact-label-for-date.ts +8 -0
- package/src/server/utility/get-custom-page-type-for-path.ts +37 -0
- package/src/server/utility/get-element-id-for-block.ts +15 -0
- package/src/server/utility/get-emoji-for-block-type.ts +39 -0
- package/src/server/utility/get-emoji-for-tool-type.ts +20 -0
- package/src/server/utility/get-end-of-month.ts +13 -0
- package/src/server/utility/get-end-of-week.ts +13 -0
- package/src/server/utility/get-filepath-for-folder-block.ts +23 -0
- package/src/server/utility/get-hex-for-color.ts +31 -0
- package/src/server/utility/get-label-for-time-place-visibility.ts +23 -0
- package/src/server/utility/get-month-name.ts +18 -0
- package/src/server/utility/get-next-day.ts +7 -0
- package/src/server/utility/get-next-month.ts +12 -0
- package/src/server/utility/get-next-week.ts +12 -0
- package/src/server/utility/get-next-year.ts +13 -0
- package/src/server/utility/get-ordinal-label-for-week.ts +11 -0
- package/src/server/utility/get-ordinal-of-week-within-month.ts +15 -0
- package/src/server/utility/get-padded-date.ts +11 -0
- package/src/server/utility/get-parent-index-path.ts +18 -0
- package/src/server/utility/get-path-for-folder-block.ts +25 -0
- package/src/server/utility/get-path-from-url.ts +13 -0
- package/src/server/utility/get-previous-index-path.ts +27 -0
- package/src/server/utility/get-previous-month.ts +12 -0
- package/src/server/utility/get-previous-week.ts +11 -0
- package/src/server/utility/get-previous-year.ts +13 -0
- package/src/server/utility/get-random-emoji-for-date.ts +109 -0
- package/src/server/utility/get-short-label-for-date.ts +11 -0
- package/src/server/utility/get-short-month-name.ts +9 -0
- package/src/server/utility/get-short-ordinal.ts +26 -0
- package/src/server/utility/get-siblings-and-index-for-index-path.ts +67 -0
- package/src/server/utility/get-start-of-month.ts +11 -0
- package/src/server/utility/get-start-of-week.ts +12 -0
- package/src/server/utility/get-start-of-year.ts +12 -0
- package/src/server/utility/get-weekday-name.ts +24 -0
- package/src/server/utility/increment-date.ts +15 -0
- package/src/server/utility/is-index-path.ts +5 -0
- package/src/server/utility/key-to-date.ts +25 -0
- package/src/server/utility/month-has-week-containing-date.ts +13 -0
- package/src/server/utility/month-to-date.ts +28 -0
- package/src/server/utility/month-to-path.ts +10 -0
- package/src/server/utility/months-are-equal.ts +8 -0
- package/src/server/utility/parse-index-path.ts +23 -0
- package/src/server/utility/path-is-date.ts +13 -0
- package/src/server/utility/path-to-date.ts +24 -0
- package/src/server/utility/subtract-days.ts +7 -0
- package/src/server/utility/validate-month.ts +10 -0
- package/src/server/utility/validate-page.ts +46 -0
- package/src/server/utility/validate-path.ts +9 -0
- package/src/server/utility/validate-url.ts +12 -0
- package/src/server/utility/week-greater-than.ts +10 -0
- package/src/server/utility/week-to-date.ts +8 -0
- package/src/server/utility/week-to-path.ts +12 -0
- package/src/server/utility/weeks-are-equal.ts +8 -0
- package/src/server/utility/year-to-date.ts +26 -0
- package/src/server/utility/year-to-path.ts +7 -0
- package/src/server/utility/years-are-equal.ts +8 -0
- package/src/server.ts +140 -0
- package/src/test.ts +195 -0
- package/src/type/account-settings.ts +9 -0
- package/src/type/account.ts +11 -0
- package/src/type/action/add-block.ts +74 -0
- package/src/type/action/complete-block.ts +10 -0
- package/src/type/action/delete-block.ts +11 -0
- package/src/type/action/demote-block.ts +9 -0
- package/src/type/action/edit-block.ts +11 -0
- package/src/type/action/promote-block.ts +9 -0
- package/src/type/action.ts +9 -0
- package/src/type/block/audio.ts +8 -0
- package/src/type/block/background.ts +10 -0
- package/src/type/block/directory.ts +18 -0
- package/src/type/block/ephemeral.ts +9 -0
- package/src/type/block/folder.ts +14 -0
- package/src/type/block/header.ts +11 -0
- package/src/type/block/image.ts +8 -0
- package/src/type/block/link.ts +12 -0
- package/src/type/block/list.ts +24 -0
- package/src/type/block/multi-column.ts +10 -0
- package/src/type/block/note.ts +9 -0
- package/src/type/block/todo.ts +10 -0
- package/src/type/block/whitespace.ts +9 -0
- package/src/type/block-metadata.ts +14 -0
- package/src/type/block.ts +18 -0
- package/src/type/day.ts +5 -0
- package/src/type/field-definition.ts +8 -0
- package/src/type/field-value.ts +5 -0
- package/src/type/file.ts +6 -0
- package/src/type/month.ts +5 -0
- package/src/type/page.ts +8 -0
- package/src/type/price.ts +11 -0
- package/src/type/resource.ts +5 -0
- package/src/type/runtime-config.ts +13 -0
- package/src/type/server-settings.ts +17 -0
- package/src/type/toast.ts +8 -0
- package/src/type/week.ts +5 -0
- package/src/type/year.ts +5 -0
- package/test/unit/index.ts +11 -0
- package/test/unit/server/operation/promote-block.ts +84 -0
|
@@ -0,0 +1,939 @@
|
|
|
1
|
+
import {InvariantViolation} from 'lib/errors';
|
|
2
|
+
import {Session} from 'lib/execution-context';
|
|
3
|
+
|
|
4
|
+
import BaseResultSerializer from 'server/result-serializer/base';
|
|
5
|
+
import Action from 'type/action';
|
|
6
|
+
import CustomPageType from 'server/enum/custom-page-type';
|
|
7
|
+
import ImageBlock from 'type/block/image';
|
|
8
|
+
import LinkBlock from 'type/block/link';
|
|
9
|
+
import PermissionType from 'enum/permission-type';
|
|
10
|
+
import PageType from 'client/enum/page-type';
|
|
11
|
+
import getBlockPermissions from 'server/utility/get-block-permissions';
|
|
12
|
+
import getPathForFolderBlock from 'server/utility/get-path-for-folder-block';
|
|
13
|
+
import validatePath from 'server/utility/validate-path';
|
|
14
|
+
import Block from 'type/block';
|
|
15
|
+
import Color from 'enum/color';
|
|
16
|
+
import getHexForColor from 'server/utility/get-hex-for-color';
|
|
17
|
+
import createDate from 'server/utility/create-date';
|
|
18
|
+
import NoteBlock from 'type/block/note';
|
|
19
|
+
import DefaultRole from 'enum/default-role';
|
|
20
|
+
import AudioBlock from 'type/block/audio';
|
|
21
|
+
import Account from 'type/account';
|
|
22
|
+
import Emoji from 'enum/emoji';
|
|
23
|
+
import HeaderBlock from 'type/block/header';
|
|
24
|
+
import TodoBlock from 'type/block/todo';
|
|
25
|
+
import serializeTimePlaceOptions from 'server/result-serializer/common/time-place-options';
|
|
26
|
+
import getLabelForTimePlaceVisibility from 'server/utility/get-label-for-time-place-visibility';
|
|
27
|
+
import TimePlaceVisibility from 'enum/time-place-visibility';
|
|
28
|
+
import MultiColumnBlock from 'type/block/multi-column';
|
|
29
|
+
import DeleteBlockAction from 'type/action/delete-block';
|
|
30
|
+
import getElementIdForBlock from 'server/utility/get-element-id-for-block';
|
|
31
|
+
import FolderBlock from 'type/block/folder';
|
|
32
|
+
import BlockMetadata from 'type/block-metadata';
|
|
33
|
+
import AddBlockAction from 'type/action/add-block';
|
|
34
|
+
import EditBlockAction from 'type/action/edit-block';
|
|
35
|
+
import getEmojiForBlockType from 'server/utility/get-emoji-for-block-type';
|
|
36
|
+
import BlockType from 'enum/block-type';
|
|
37
|
+
import ActionType from 'enum/action-type';
|
|
38
|
+
import BlockResultSerializerFactory from 'server/factory/block-result-serializer';
|
|
39
|
+
|
|
40
|
+
type ModifyBlockAction = AddBlockAction | EditBlockAction;
|
|
41
|
+
|
|
42
|
+
type BlockAndMetadata = {
|
|
43
|
+
readonly block: Block;
|
|
44
|
+
readonly metadata: BlockMetadata;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
type ActionMetadata = {
|
|
48
|
+
readonly account: Account;
|
|
49
|
+
readonly roles: string[];
|
|
50
|
+
readonly provider_paths: string[];
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
function getBlockIdForAction(action: ModifyBlockAction, action_metadata: ActionMetadata): string {
|
|
54
|
+
const {
|
|
55
|
+
block,
|
|
56
|
+
metadata
|
|
57
|
+
} = buildBlockAndMetadataForAction(action, action_metadata);
|
|
58
|
+
|
|
59
|
+
return getElementIdForBlock(block, metadata);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function getPrivacyEmojiForRole(role: string, roles: string[]): Emoji {
|
|
63
|
+
switch (role) {
|
|
64
|
+
case DefaultRole.PUBLIC:
|
|
65
|
+
return Emoji.GRID_GLOBE;
|
|
66
|
+
case DefaultRole.CREATOR:
|
|
67
|
+
return Emoji.LOCKED;
|
|
68
|
+
default:
|
|
69
|
+
return Emoji.WINDOW;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function serializeColorInputs(attribute: string, selected_color: Color): string {
|
|
74
|
+
const colors = Object.values(Color);
|
|
75
|
+
|
|
76
|
+
const serialized_colors = colors.map((color) => {
|
|
77
|
+
const hex = getHexForColor(color);
|
|
78
|
+
const checked_attribute = color === selected_color ? 'checked' : '';
|
|
79
|
+
|
|
80
|
+
return `
|
|
81
|
+
<input autocomplete="off" class="color-option" type="radio" ${checked_attribute} id="${attribute}-${color}" name="${attribute}" value="${color}" />
|
|
82
|
+
<label class="mb-0" for="${attribute}-${color}" style="background-color:${hex}">
|
|
83
|
+
${color}
|
|
84
|
+
</label>
|
|
85
|
+
`;
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
return serialized_colors.join('\n');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function buildBlockForAction(action: ModifyBlockAction, metadata: ActionMetadata): Block {
|
|
92
|
+
const {action_type} = action;
|
|
93
|
+
|
|
94
|
+
if (action_type === ActionType.EDIT_BLOCK) {
|
|
95
|
+
const {block} = action as EditBlockAction;
|
|
96
|
+
|
|
97
|
+
if (block === undefined) {
|
|
98
|
+
throw new InvariantViolation(`
|
|
99
|
+
Received an EditBlockAction with no block specified
|
|
100
|
+
`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return block;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const {
|
|
107
|
+
block_type,
|
|
108
|
+
create_role,
|
|
109
|
+
read_role,
|
|
110
|
+
update_role,
|
|
111
|
+
delete_role
|
|
112
|
+
} = action as AddBlockAction;
|
|
113
|
+
|
|
114
|
+
const permissions = {
|
|
115
|
+
[PermissionType.CREATE]: create_role,
|
|
116
|
+
[PermissionType.READ]: read_role,
|
|
117
|
+
[PermissionType.UPDATE]: update_role,
|
|
118
|
+
[PermissionType.DELETE]: delete_role
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const {account} = metadata;
|
|
122
|
+
const {settings} = account;
|
|
123
|
+
const {default_time_place_visibility: visibility} = settings;
|
|
124
|
+
const created_at = Date.now();
|
|
125
|
+
|
|
126
|
+
const time = TimePlaceVisibility.TIME;
|
|
127
|
+
const place = TimePlaceVisibility.PLACE;
|
|
128
|
+
const both = TimePlaceVisibility.BOTH;
|
|
129
|
+
|
|
130
|
+
const show_place = visibility === place || visibility === both;
|
|
131
|
+
const show_time = visibility === time || visibility === both;
|
|
132
|
+
|
|
133
|
+
switch (block_type) {
|
|
134
|
+
case BlockType.AUDIO:
|
|
135
|
+
return {
|
|
136
|
+
block_type: BlockType.AUDIO,
|
|
137
|
+
show_place,
|
|
138
|
+
show_time,
|
|
139
|
+
created_at,
|
|
140
|
+
files: [],
|
|
141
|
+
permissions
|
|
142
|
+
} as AudioBlock;
|
|
143
|
+
|
|
144
|
+
case BlockType.IMAGE:
|
|
145
|
+
return {
|
|
146
|
+
block_type: BlockType.IMAGE,
|
|
147
|
+
show_place,
|
|
148
|
+
show_time,
|
|
149
|
+
created_at,
|
|
150
|
+
files: [],
|
|
151
|
+
permissions
|
|
152
|
+
} as ImageBlock;
|
|
153
|
+
|
|
154
|
+
case BlockType.NOTE:
|
|
155
|
+
return {
|
|
156
|
+
block_type: BlockType.NOTE,
|
|
157
|
+
show_place,
|
|
158
|
+
show_time,
|
|
159
|
+
created_at,
|
|
160
|
+
text: '',
|
|
161
|
+
permissions
|
|
162
|
+
} as NoteBlock;
|
|
163
|
+
|
|
164
|
+
case BlockType.TODO:
|
|
165
|
+
return {
|
|
166
|
+
block_type: BlockType.TODO,
|
|
167
|
+
show_place,
|
|
168
|
+
show_time,
|
|
169
|
+
created_at,
|
|
170
|
+
completed_at: null,
|
|
171
|
+
title: '',
|
|
172
|
+
permissions
|
|
173
|
+
} as TodoBlock;
|
|
174
|
+
|
|
175
|
+
case BlockType.HEADER:
|
|
176
|
+
return {
|
|
177
|
+
block_type: BlockType.HEADER,
|
|
178
|
+
show_place,
|
|
179
|
+
show_time,
|
|
180
|
+
created_at,
|
|
181
|
+
title: '',
|
|
182
|
+
permissions
|
|
183
|
+
} as HeaderBlock;
|
|
184
|
+
|
|
185
|
+
case BlockType.FOLDER:
|
|
186
|
+
return {
|
|
187
|
+
block_type: BlockType.FOLDER,
|
|
188
|
+
show_place,
|
|
189
|
+
show_time,
|
|
190
|
+
created_at,
|
|
191
|
+
title: '',
|
|
192
|
+
subtitle: '',
|
|
193
|
+
emoji: Emoji.FOLDER,
|
|
194
|
+
color: Color.GREY,
|
|
195
|
+
permissions
|
|
196
|
+
} as FolderBlock;
|
|
197
|
+
|
|
198
|
+
case BlockType.LINK:
|
|
199
|
+
return {
|
|
200
|
+
block_type: BlockType.LINK,
|
|
201
|
+
show_place,
|
|
202
|
+
show_time,
|
|
203
|
+
created_at,
|
|
204
|
+
href: '',
|
|
205
|
+
label: '',
|
|
206
|
+
color: Color.GREY,
|
|
207
|
+
permissions
|
|
208
|
+
} as LinkBlock;
|
|
209
|
+
|
|
210
|
+
case BlockType.MULTI_COLUMN:
|
|
211
|
+
return {
|
|
212
|
+
block_type: BlockType.MULTI_COLUMN,
|
|
213
|
+
show_place,
|
|
214
|
+
show_time,
|
|
215
|
+
created_at,
|
|
216
|
+
children: [],
|
|
217
|
+
max_columns: 3,
|
|
218
|
+
permissions
|
|
219
|
+
} as MultiColumnBlock;
|
|
220
|
+
|
|
221
|
+
default:
|
|
222
|
+
throw new InvariantViolation(`Unsupported block type: ${block_type}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function buildMetadataForAction(action: ModifyBlockAction, action_metadata: ActionMetadata): BlockMetadata {
|
|
227
|
+
const {path, editing, index_path} = action;
|
|
228
|
+
const {roles, account} = action_metadata;
|
|
229
|
+
const creator_username = '0xfc3';
|
|
230
|
+
|
|
231
|
+
validatePath(path);
|
|
232
|
+
|
|
233
|
+
return {
|
|
234
|
+
page_path: path,
|
|
235
|
+
editing,
|
|
236
|
+
// TODO: Investigate whether there's a way to preserve this
|
|
237
|
+
referrer_url: null,
|
|
238
|
+
index_path,
|
|
239
|
+
target_index_path: null,
|
|
240
|
+
roles,
|
|
241
|
+
account,
|
|
242
|
+
creator_username
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function buildBlockAndMetadataForAction(action: ModifyBlockAction, action_metadata: ActionMetadata): BlockAndMetadata {
|
|
247
|
+
const block = buildBlockForAction(action, action_metadata);
|
|
248
|
+
const metadata = buildMetadataForAction(action, action_metadata);
|
|
249
|
+
|
|
250
|
+
return {
|
|
251
|
+
block,
|
|
252
|
+
metadata
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
class ActionResultSerializer extends BaseResultSerializer<Partial<Action>> {
|
|
259
|
+
private metadata: ActionMetadata;
|
|
260
|
+
|
|
261
|
+
public constructor(
|
|
262
|
+
result: Partial<Action>,
|
|
263
|
+
metadata: ActionMetadata,
|
|
264
|
+
path: string,
|
|
265
|
+
referrer_url: string,
|
|
266
|
+
session: Session
|
|
267
|
+
) {
|
|
268
|
+
super(result, path, referrer_url, session);
|
|
269
|
+
|
|
270
|
+
this.metadata = metadata;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
protected getTitle(): string {
|
|
274
|
+
const {action_type, path} = this.getResult();
|
|
275
|
+
|
|
276
|
+
return `applying action ${action_type} to page ${path}`;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
protected getPageType(): PageType {
|
|
280
|
+
const {action_type} = this.getResult();
|
|
281
|
+
|
|
282
|
+
switch (action_type) {
|
|
283
|
+
case ActionType.ADD_BLOCK:
|
|
284
|
+
return PageType.SELECT_BLOCK_TYPE;
|
|
285
|
+
case ActionType.DELETE_BLOCK:
|
|
286
|
+
return PageType.CONFIRM_DELETE_BLOCK;
|
|
287
|
+
case ActionType.EDIT_BLOCK:
|
|
288
|
+
return PageType.EDIT_BLOCK;
|
|
289
|
+
default:
|
|
290
|
+
throw new InvariantViolation(`
|
|
291
|
+
Unsupported action type when mapping to page type: ${action_type}
|
|
292
|
+
`);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
protected serializeSections(): string {
|
|
297
|
+
const action = this.getResult();
|
|
298
|
+
const {action_type} = action;
|
|
299
|
+
|
|
300
|
+
switch (action_type) {
|
|
301
|
+
case ActionType.ADD_BLOCK:
|
|
302
|
+
return this.serializeAddBlock(action as AddBlockAction);
|
|
303
|
+
|
|
304
|
+
case ActionType.DELETE_BLOCK:
|
|
305
|
+
return this.serializeDeleteBlock(action as DeleteBlockAction);
|
|
306
|
+
|
|
307
|
+
case ActionType.EDIT_BLOCK:
|
|
308
|
+
return this.serializeModifiableBlock(action as EditBlockAction);
|
|
309
|
+
|
|
310
|
+
default:
|
|
311
|
+
throw new InvariantViolation(`
|
|
312
|
+
Invalid action type: ${action_type}
|
|
313
|
+
`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
private serializeAddBlock(action: AddBlockAction): string {
|
|
318
|
+
const {block_type} = action;
|
|
319
|
+
|
|
320
|
+
if (block_type === undefined) {
|
|
321
|
+
return this.serializeUnselectedBlockType(action);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return this.serializeModifiableBlock(action);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
private serializeModifiableBlock(action: ModifyBlockAction): string {
|
|
328
|
+
const metadata = this.getMetadata();
|
|
329
|
+
const {block_type} = buildBlockForAction(action, metadata);
|
|
330
|
+
|
|
331
|
+
switch (block_type) {
|
|
332
|
+
case BlockType.NOTE:
|
|
333
|
+
return this.serializeModifiableNoteBlock(action);
|
|
334
|
+
|
|
335
|
+
case BlockType.TODO:
|
|
336
|
+
return this.serializeModifiableTodoBlock(action);
|
|
337
|
+
|
|
338
|
+
case BlockType.IMAGE:
|
|
339
|
+
return this.serializeModifiableImageBlock(action);
|
|
340
|
+
|
|
341
|
+
case BlockType.AUDIO:
|
|
342
|
+
return this.serializeModifiableAudioBlock(action);
|
|
343
|
+
|
|
344
|
+
case BlockType.HEADER:
|
|
345
|
+
return this.serializeModifiableHeaderBlock(action);
|
|
346
|
+
|
|
347
|
+
case BlockType.FOLDER:
|
|
348
|
+
return this.serializeModifiableFolderBlock(action);
|
|
349
|
+
|
|
350
|
+
case BlockType.MULTI_COLUMN:
|
|
351
|
+
return this.serializeModifiableMultiColumnBlock(action);
|
|
352
|
+
|
|
353
|
+
case BlockType.LINK:
|
|
354
|
+
return this.serializeModifiableLinkBlock(action);
|
|
355
|
+
|
|
356
|
+
default:
|
|
357
|
+
throw new InvariantViolation(`
|
|
358
|
+
Invalid block type: ${block_type}
|
|
359
|
+
`);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
private serializeUnselectedBlockType(action: AddBlockAction): string {
|
|
364
|
+
const {path, editing, index_path} = action;
|
|
365
|
+
|
|
366
|
+
function serializeBlockLink(block_type: BlockType, last = false): string {
|
|
367
|
+
const offset_class = last ? '' : 'mb-8';
|
|
368
|
+
const emoji = getEmojiForBlockType(block_type);
|
|
369
|
+
const block_type_label = block_type.replace(/_/g, '-');
|
|
370
|
+
const first_letter = block_type[0];
|
|
371
|
+
|
|
372
|
+
return `
|
|
373
|
+
<li class="${offset_class}">
|
|
374
|
+
<a id="add-block-${block_type}" href="/actions?action_type=${ActionType.ADD_BLOCK}&editing=${editing}&path=${path}&index_path=${index_path}&block_type=${block_type}" class="biglink yellow align-left">
|
|
375
|
+
${emoji} ${block_type_label} <span class="half-opacity">[${first_letter}]</span>
|
|
376
|
+
</a>
|
|
377
|
+
</li>
|
|
378
|
+
`;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return `
|
|
382
|
+
<section>
|
|
383
|
+
<h2>${Emoji.BOOKS} add block:</h2>
|
|
384
|
+
<ul>
|
|
385
|
+
${serializeBlockLink(BlockType.NOTE)}
|
|
386
|
+
${serializeBlockLink(BlockType.IMAGE)}
|
|
387
|
+
${serializeBlockLink(BlockType.AUDIO)}
|
|
388
|
+
${serializeBlockLink(BlockType.TODO)}
|
|
389
|
+
${serializeBlockLink(BlockType.HEADER)}
|
|
390
|
+
${serializeBlockLink(BlockType.LINK)}
|
|
391
|
+
${serializeBlockLink(BlockType.FOLDER)}
|
|
392
|
+
${serializeBlockLink(BlockType.MULTI_COLUMN)}
|
|
393
|
+
</ul>
|
|
394
|
+
</section>
|
|
395
|
+
|
|
396
|
+
<!--
|
|
397
|
+
<section>
|
|
398
|
+
<h2>create page:</h2>
|
|
399
|
+
<ul>
|
|
400
|
+
<li>
|
|
401
|
+
<a href="/actions?action_type=${ActionType.CREATE_PAGE}&custom_page_type=${CustomPageType.BLANK}" class="biglink align-left">
|
|
402
|
+
${Emoji.DOCUMENT} blank
|
|
403
|
+
</a>
|
|
404
|
+
</li>
|
|
405
|
+
<li class="mt-8">
|
|
406
|
+
<a href="/actions?action_type=${ActionType.CREATE_PAGE}&custom_page_type=${CustomPageType.FORM}" class="biglink align-left">
|
|
407
|
+
${Emoji.RECEIPT} form
|
|
408
|
+
</a>
|
|
409
|
+
<li class="mt-8">
|
|
410
|
+
</li>
|
|
411
|
+
<a href="/actions?action_type=${ActionType.CREATE_PAGE}&custom_page_type=${CustomPageType.PRODUCT}" class="biglink align-left">
|
|
412
|
+
${Emoji.SHOPPING_BAGS} product
|
|
413
|
+
</a>
|
|
414
|
+
</li>
|
|
415
|
+
</ul>
|
|
416
|
+
</section>
|
|
417
|
+
-->
|
|
418
|
+
`;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
private serializeModifiableImageBlock(action: ModifyBlockAction): string {
|
|
422
|
+
const {path} = action;
|
|
423
|
+
|
|
424
|
+
return this.wrapModifyBlockAction(action, `
|
|
425
|
+
<fieldset>
|
|
426
|
+
<legend>${Emoji.CAMERA} adding image(s) to page: [${path}]</legend>
|
|
427
|
+
<div class="file-wrapper">
|
|
428
|
+
<input id="file-input" type="file" name="files" accept="image/*" multiple />
|
|
429
|
+
<label class="biglink" for="files">select images</label>
|
|
430
|
+
</div>
|
|
431
|
+
</fieldset>
|
|
432
|
+
`);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
private serializeModifiableAudioBlock(action: ModifyBlockAction): string {
|
|
436
|
+
const {path} = action;
|
|
437
|
+
|
|
438
|
+
return this.wrapModifyBlockAction(action, `
|
|
439
|
+
<fieldset>
|
|
440
|
+
<legend>${Emoji.MICROPHONE} adding audio to page: [${path}]</legend>
|
|
441
|
+
<div class="file-wrapper">
|
|
442
|
+
<input type="file" name="files" accept="audio/*" capture />
|
|
443
|
+
<label class="biglink" for="files">upload audio</label>
|
|
444
|
+
</div>
|
|
445
|
+
</fieldset>
|
|
446
|
+
`);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
private serializeModifiableTodoBlock(action: ModifyBlockAction): string {
|
|
450
|
+
const {path, action_type} = action;
|
|
451
|
+
const is_adding = action_type === ActionType.ADD_BLOCK;
|
|
452
|
+
const verb = is_adding ? 'adding' : 'updating';
|
|
453
|
+
const metadata = this.getMetadata();
|
|
454
|
+
const block = buildBlockForAction(action, metadata);
|
|
455
|
+
const todo_block = block as TodoBlock;
|
|
456
|
+
const title = todo_block.title || '';
|
|
457
|
+
const placeholder = title || 'enter todo';
|
|
458
|
+
const {completed_at} = todo_block;
|
|
459
|
+
const completed = completed_at !== null;
|
|
460
|
+
const checked_attribute = completed ? 'checked' : '';
|
|
461
|
+
|
|
462
|
+
return this.wrapModifyBlockAction(action, `
|
|
463
|
+
<fieldset>
|
|
464
|
+
<legend>${Emoji.COMPLETED_CHECKMARK} ${verb} todo on page: [${path}]</legend>
|
|
465
|
+
<input id="text-input" name="title" placeholder="${placeholder}" autofocus autocomplete="off" value="${title}" />
|
|
466
|
+
</fieldset>
|
|
467
|
+
|
|
468
|
+
<fieldset>
|
|
469
|
+
<legend>completed?</legend>
|
|
470
|
+
<input type="checkbox" name="completed" ${checked_attribute} />
|
|
471
|
+
<label for="completed">immediately mark this task as complete</label>
|
|
472
|
+
</fieldset>
|
|
473
|
+
`);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
private serializeModifiableNoteBlock(action: ModifyBlockAction): string {
|
|
477
|
+
const {path, action_type} = action;
|
|
478
|
+
const is_adding = action_type === ActionType.ADD_BLOCK;
|
|
479
|
+
const verb = is_adding ? 'adding' : 'updating';
|
|
480
|
+
const metadata = this.getMetadata();
|
|
481
|
+
const block = buildBlockForAction(action, metadata);
|
|
482
|
+
const {text} = block as NoteBlock;
|
|
483
|
+
|
|
484
|
+
return this.wrapModifyBlockAction(action, `
|
|
485
|
+
<fieldset>
|
|
486
|
+
<legend>${Emoji.NOTEPAD} ${verb} text on page: [${path}]</legend>
|
|
487
|
+
<textarea id="text-input" name="text" placeholder="${text}" autofocus autocomplete="off">${text}</textarea>
|
|
488
|
+
</fieldset>
|
|
489
|
+
`);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
private serializeModifiableHeaderBlock(action: ModifyBlockAction): string {
|
|
493
|
+
const {path} = action;
|
|
494
|
+
|
|
495
|
+
return this.wrapModifyBlockAction(action, `
|
|
496
|
+
<fieldset>
|
|
497
|
+
<legend>${Emoji.PLACARD} adding title to page: [${path}]</legend>
|
|
498
|
+
<input name="title" type="text" placeholder="your title here" autofocus autocomplete="off" />
|
|
499
|
+
</fieldset>
|
|
500
|
+
`);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
private serializeModifiableLinkBlock(action: ModifyBlockAction): string {
|
|
504
|
+
const metadata = this.getMetadata();
|
|
505
|
+
const block = buildBlockForAction(action, metadata);
|
|
506
|
+
const link_block = block as LinkBlock;
|
|
507
|
+
const {label, href, color} = link_block;
|
|
508
|
+
|
|
509
|
+
const color_inputs = serializeColorInputs('color', color);
|
|
510
|
+
|
|
511
|
+
return this.wrapModifyBlockAction(action, `
|
|
512
|
+
<fieldset>
|
|
513
|
+
<legend>${Emoji.LINK} link target</legend>
|
|
514
|
+
<p class="text-smaller half-opacity">
|
|
515
|
+
the URL where your link should point
|
|
516
|
+
</p>
|
|
517
|
+
<input id="href-text-input" name="href" type="text" placeholder="${href}" value="${href}" autofocus autocomplete="off" />
|
|
518
|
+
</fieldset>
|
|
519
|
+
|
|
520
|
+
<fieldset>
|
|
521
|
+
<legend>${Emoji.SIGN} link label</legend>
|
|
522
|
+
<p class="text-smaller half-opacity">
|
|
523
|
+
the text label for your link
|
|
524
|
+
</p>
|
|
525
|
+
<input id="label-text-input" name="label" type="text" placeholder="${label}" value="${label}" autocomplete="off" />
|
|
526
|
+
</fieldset>
|
|
527
|
+
|
|
528
|
+
<fieldset>
|
|
529
|
+
<legend>${Emoji.PALETTE} link color</legend>
|
|
530
|
+
<div class="pt-8">
|
|
531
|
+
${color_inputs}
|
|
532
|
+
</div>
|
|
533
|
+
</fieldset>
|
|
534
|
+
`);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
private serializeModifiableMultiColumnBlock(action: ModifyBlockAction): string {
|
|
538
|
+
const {path} = action;
|
|
539
|
+
const metadata = this.getMetadata();
|
|
540
|
+
const {block} = buildBlockAndMetadataForAction(action, metadata);
|
|
541
|
+
const {max_columns} = block as MultiColumnBlock;
|
|
542
|
+
|
|
543
|
+
return this.wrapModifyBlockAction(action, `
|
|
544
|
+
<fieldset>
|
|
545
|
+
<legend>${Emoji.BAR_CHART} adding multi-column block to page: [${path}]</legend>
|
|
546
|
+
|
|
547
|
+
<p>max columns:</p>
|
|
548
|
+
|
|
549
|
+
<div class="p-16">
|
|
550
|
+
<input type="range" min="1" max="8" value="${max_columns}" id="max-columns" name="max_columns" list="column_values" />
|
|
551
|
+
|
|
552
|
+
<datalist id="column_values">
|
|
553
|
+
<option value="1" label="1"></option>
|
|
554
|
+
<option value="2" label="2"></option>
|
|
555
|
+
<option value="3" label="3"></option>
|
|
556
|
+
<option value="4" label="4"></option>
|
|
557
|
+
<option value="5" label="5"></option>
|
|
558
|
+
<option value="6" label="6"></option>
|
|
559
|
+
<option value="7" label="7"></option>
|
|
560
|
+
<option value="8" label="8"></option>
|
|
561
|
+
</datalist>
|
|
562
|
+
</div>
|
|
563
|
+
</fieldset>
|
|
564
|
+
`);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
private serializeModifiableFolderBlock(action: ModifyBlockAction): string {
|
|
568
|
+
const {action_type, path} = action;
|
|
569
|
+
const is_adding = action_type === ActionType.ADD_BLOCK;
|
|
570
|
+
const adjective = is_adding ? 'new' : 'updated';
|
|
571
|
+
const metadata = this.getMetadata();
|
|
572
|
+
const block = buildBlockForAction(action, metadata);
|
|
573
|
+
const folder_block = block as FolderBlock;
|
|
574
|
+
const {title, subtitle, emoji, color} = folder_block;
|
|
575
|
+
const block_id = getBlockIdForAction(action, metadata);
|
|
576
|
+
|
|
577
|
+
const folder_path = getPathForFolderBlock({
|
|
578
|
+
base_path: path,
|
|
579
|
+
block: folder_block
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
const color_inputs = serializeColorInputs('color', color);
|
|
583
|
+
|
|
584
|
+
return this.wrapModifyBlockAction(action, `
|
|
585
|
+
<fieldset>
|
|
586
|
+
<legend>${Emoji.FOLDER} folder title</legend>
|
|
587
|
+
<p class="text-smaller half-opacity">
|
|
588
|
+
your ${adjective} page will live at:
|
|
589
|
+
</p>
|
|
590
|
+
<p class="text-smaller">
|
|
591
|
+
<code class="text-yellow" id="${block_id}-folder-path-target">${folder_path}</code>
|
|
592
|
+
</p>
|
|
593
|
+
<input id="title-text-input" name="title" type="text" placeholder="${title}" value="${title}" autofocus autocomplete="off" />
|
|
594
|
+
</fieldset>
|
|
595
|
+
|
|
596
|
+
<fieldset>
|
|
597
|
+
<legend>${Emoji.SUN_WITH_FACE} preview emoji</legend>
|
|
598
|
+
<p class="text-smaller half-opacity">
|
|
599
|
+
<span class="text-bold">[optional]</span> appears inside the folder button on its parent page
|
|
600
|
+
</p>
|
|
601
|
+
<input id="emoji-text-input" name="emoji" type="text" placeholder="${emoji}" value="${emoji}" autocomplete="off" />
|
|
602
|
+
</fieldset>
|
|
603
|
+
|
|
604
|
+
<fieldset>
|
|
605
|
+
<legend>${Emoji.NOTEPAD} folder subtitle</legend>
|
|
606
|
+
<p class="text-smaller half-opacity">
|
|
607
|
+
<span class="text-bold">[optional]</span> appears below the folder name
|
|
608
|
+
</p>
|
|
609
|
+
<input id="subtitle-text-input" name="subtitle" type="text" placeholder="${subtitle}" value="${subtitle}" autocomplete="off" />
|
|
610
|
+
</fieldset>
|
|
611
|
+
|
|
612
|
+
<fieldset>
|
|
613
|
+
<legend>${Emoji.PALETTE} link color</legend>
|
|
614
|
+
<div class="pt-8">
|
|
615
|
+
${color_inputs}
|
|
616
|
+
</div>
|
|
617
|
+
</fieldset>
|
|
618
|
+
`);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
private wrapModifyBlockAction(action: ModifyBlockAction, block_specific_markup: string): string {
|
|
622
|
+
const {path, editing, action_type, index_path} = action;
|
|
623
|
+
const action_metadata = this.getMetadata();
|
|
624
|
+
|
|
625
|
+
const {
|
|
626
|
+
block,
|
|
627
|
+
metadata
|
|
628
|
+
} = buildBlockAndMetadataForAction(action, action_metadata);
|
|
629
|
+
|
|
630
|
+
const {block_type} = block;
|
|
631
|
+
const session = this.getSession();
|
|
632
|
+
|
|
633
|
+
const updated_metadata = {
|
|
634
|
+
...metadata,
|
|
635
|
+
editing: false
|
|
636
|
+
};
|
|
637
|
+
|
|
638
|
+
const factory = new BlockResultSerializerFactory(block, updated_metadata, session);
|
|
639
|
+
|
|
640
|
+
const serializer = factory.create();
|
|
641
|
+
const block_preview = serializer.serializeContent();
|
|
642
|
+
const selected_color = block.color || Color.GREY;
|
|
643
|
+
const color_inputs = serializeColorInputs('border_color', selected_color);
|
|
644
|
+
const time_place_section = this.renderTimePlaceSection(block);
|
|
645
|
+
const permissions_section = this.renderPermissionsSection(block);
|
|
646
|
+
|
|
647
|
+
return `
|
|
648
|
+
<section class="grey">
|
|
649
|
+
<fieldset>
|
|
650
|
+
<legend>${Emoji.MAGNIFYING_GLASS} preview</legend>
|
|
651
|
+
${block_preview}
|
|
652
|
+
</fieldset>
|
|
653
|
+
|
|
654
|
+
<form class="mt-64" enctype="multipart/form-data" method="post" action="/actions?editing=${editing}">
|
|
655
|
+
<input type="hidden" name="action_type" value="${action_type}" />
|
|
656
|
+
<input type="hidden" name="path" value="${path}" />
|
|
657
|
+
<input type="hidden" name="index_path" value="${index_path}" />
|
|
658
|
+
<input type="hidden" name="block_type" value="${block_type}" />
|
|
659
|
+
|
|
660
|
+
${block_specific_markup}
|
|
661
|
+
|
|
662
|
+
<fieldset class="mt-64">
|
|
663
|
+
<legend>${Emoji.GEAR} additional settings</legend>
|
|
664
|
+
|
|
665
|
+
<details class="mb-8 clearfix">
|
|
666
|
+
<summary>
|
|
667
|
+
<span>border color</span>
|
|
668
|
+
<span class="summary-label">
|
|
669
|
+
<span class="icon" style="background-color: ${selected_color}"></span>
|
|
670
|
+
${selected_color}
|
|
671
|
+
</span>
|
|
672
|
+
</summary>
|
|
673
|
+
|
|
674
|
+
<p class="mb-32 clearfix">
|
|
675
|
+
${color_inputs}
|
|
676
|
+
</p>
|
|
677
|
+
|
|
678
|
+
<aside>
|
|
679
|
+
colors are defined in your <a href="/settings">account settings</a>.
|
|
680
|
+
</aside>
|
|
681
|
+
</details>
|
|
682
|
+
|
|
683
|
+
${permissions_section}
|
|
684
|
+
${time_place_section}
|
|
685
|
+
|
|
686
|
+
</fieldset>
|
|
687
|
+
|
|
688
|
+
<table class="button-row fixed mt-32">
|
|
689
|
+
<tbody>
|
|
690
|
+
<tr>
|
|
691
|
+
<td>
|
|
692
|
+
<a class="biglink grey" href="${path}?editing=true">
|
|
693
|
+
${Emoji.LEFT_ARROW_UNICODE} cancel
|
|
694
|
+
</a>
|
|
695
|
+
</td>
|
|
696
|
+
|
|
697
|
+
<td>
|
|
698
|
+
<button class="biglink green" type="submit">
|
|
699
|
+
submit ${Emoji.RIGHT_ARROW_UNICODE}
|
|
700
|
+
</button>
|
|
701
|
+
</td>
|
|
702
|
+
</tr>
|
|
703
|
+
</tbody>
|
|
704
|
+
</table>
|
|
705
|
+
</form>
|
|
706
|
+
</section>
|
|
707
|
+
`;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
private renderPermissionsSection(block: Block): string {
|
|
711
|
+
const permissions = getBlockPermissions(block);
|
|
712
|
+
const permission_types = Object.keys(permissions) as PermissionType[];
|
|
713
|
+
const {roles} = this.getMetadata();
|
|
714
|
+
|
|
715
|
+
const permission_rows: string[] = [];
|
|
716
|
+
const summary_emojis: string[] = [];
|
|
717
|
+
|
|
718
|
+
function renderPermissionOptions(selected_role: string): string {
|
|
719
|
+
const serialized_options = roles.map((role) => {
|
|
720
|
+
const selected_attribute = selected_role === role ? 'selected' : '';
|
|
721
|
+
|
|
722
|
+
return `
|
|
723
|
+
<option ${selected_attribute} value="${role}">
|
|
724
|
+
${role}
|
|
725
|
+
</option>
|
|
726
|
+
`;
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
return serialized_options.join('\n');
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
Object.entries(permissions).forEach(([permission_type, role]) => {
|
|
733
|
+
const emoji = getPrivacyEmojiForRole(role, roles);
|
|
734
|
+
const options = renderPermissionOptions(role);
|
|
735
|
+
|
|
736
|
+
const row = `
|
|
737
|
+
<tr>
|
|
738
|
+
<td>
|
|
739
|
+
${permission_type}
|
|
740
|
+
</td>
|
|
741
|
+
<td>
|
|
742
|
+
<select name="${permission_type}_role" autocomplete="off">
|
|
743
|
+
${options}
|
|
744
|
+
</select>
|
|
745
|
+
</td>
|
|
746
|
+
</tr>
|
|
747
|
+
`;
|
|
748
|
+
|
|
749
|
+
permission_rows.push(row);
|
|
750
|
+
summary_emojis.push(emoji);
|
|
751
|
+
});
|
|
752
|
+
|
|
753
|
+
const summary_label = (() => {
|
|
754
|
+
let role_index = 0;
|
|
755
|
+
|
|
756
|
+
while (role_index < roles.length) {
|
|
757
|
+
const role = roles[role_index++];
|
|
758
|
+
|
|
759
|
+
let permission_index = 0;
|
|
760
|
+
|
|
761
|
+
while (permission_index < permission_types.length) {
|
|
762
|
+
const permission_type = permission_types[permission_index++];
|
|
763
|
+
const assignment = permissions[permission_type];
|
|
764
|
+
|
|
765
|
+
if (assignment === role) {
|
|
766
|
+
return `${role} ${permission_type}`;
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
throw new InvariantViolation(`
|
|
772
|
+
Unable to determine minimum role permission
|
|
773
|
+
`);
|
|
774
|
+
})();
|
|
775
|
+
|
|
776
|
+
return `
|
|
777
|
+
<details class="mb-8">
|
|
778
|
+
<summary>
|
|
779
|
+
permissions
|
|
780
|
+
<span class="summary-label">
|
|
781
|
+
${summary_emojis.join('')} ${summary_label}
|
|
782
|
+
</span>
|
|
783
|
+
</summary>
|
|
784
|
+
<table>
|
|
785
|
+
<thead>
|
|
786
|
+
<tr>
|
|
787
|
+
<th>
|
|
788
|
+
operation
|
|
789
|
+
</th>
|
|
790
|
+
<th>
|
|
791
|
+
minimum required role
|
|
792
|
+
</th>
|
|
793
|
+
</tr>
|
|
794
|
+
</thead>
|
|
795
|
+
<tbody>
|
|
796
|
+
${permission_rows.join('\n')}
|
|
797
|
+
</tbody>
|
|
798
|
+
</table>
|
|
799
|
+
</details>
|
|
800
|
+
`;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
private renderTimePlaceSection(block: Block): string {
|
|
804
|
+
const current_visibility = (() => {
|
|
805
|
+
if (block.show_time && block.show_place) {
|
|
806
|
+
return TimePlaceVisibility.BOTH;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
if (block.show_time) {
|
|
810
|
+
return TimePlaceVisibility.TIME;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
if (block.show_place) {
|
|
814
|
+
return TimePlaceVisibility.PLACE;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
return TimePlaceVisibility.NONE;
|
|
818
|
+
})();
|
|
819
|
+
|
|
820
|
+
const label = getLabelForTimePlaceVisibility(current_visibility);
|
|
821
|
+
const options = serializeTimePlaceOptions(current_visibility);
|
|
822
|
+
|
|
823
|
+
return `
|
|
824
|
+
<details>
|
|
825
|
+
<summary>time and place
|
|
826
|
+
<span class="summary-label">
|
|
827
|
+
${label}
|
|
828
|
+
</span>
|
|
829
|
+
</summary>
|
|
830
|
+
|
|
831
|
+
${options}
|
|
832
|
+
</details>
|
|
833
|
+
`;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
private serializeDeleteBlock(action: DeleteBlockAction): string {
|
|
837
|
+
const {path, block, editing, index_path} = action;
|
|
838
|
+
const session = this.getSession();
|
|
839
|
+
const roles = this.getRoles();
|
|
840
|
+
const account = this.getAccount();
|
|
841
|
+
const creator_username = '0xfc3';
|
|
842
|
+
|
|
843
|
+
const block_metadata = {
|
|
844
|
+
editing,
|
|
845
|
+
page_path: path,
|
|
846
|
+
// We are just displaying the single block;
|
|
847
|
+
// there's no reason to highlight it.
|
|
848
|
+
target_index: null,
|
|
849
|
+
referrer_url: null,
|
|
850
|
+
roles,
|
|
851
|
+
account,
|
|
852
|
+
index_path,
|
|
853
|
+
target_index_path: null,
|
|
854
|
+
creator_username
|
|
855
|
+
};
|
|
856
|
+
|
|
857
|
+
const factory = new BlockResultSerializerFactory(block, block_metadata, session);
|
|
858
|
+
const serializer = factory.create();
|
|
859
|
+
const serialized_block = serializer.serializeContent();
|
|
860
|
+
const block_type = 'title';
|
|
861
|
+
const created_date = createDate(block.created_at);
|
|
862
|
+
const created_timestamp = created_date.toString();
|
|
863
|
+
|
|
864
|
+
return `
|
|
865
|
+
<section>
|
|
866
|
+
<h2>really delete this block?</h2>
|
|
867
|
+
|
|
868
|
+
${serialized_block}
|
|
869
|
+
|
|
870
|
+
<section class="align-left mt-32">
|
|
871
|
+
<h4 class="mb-8">block metadata</h4>
|
|
872
|
+
<table style="font-size:75%">
|
|
873
|
+
<tbody>
|
|
874
|
+
<tr>
|
|
875
|
+
<th>
|
|
876
|
+
type
|
|
877
|
+
</th>
|
|
878
|
+
<td class="align-left">
|
|
879
|
+
${block_type}
|
|
880
|
+
</td>
|
|
881
|
+
</tr>
|
|
882
|
+
|
|
883
|
+
<tr>
|
|
884
|
+
<th>
|
|
885
|
+
created on
|
|
886
|
+
</th>
|
|
887
|
+
<td class="align-left">
|
|
888
|
+
${created_timestamp}
|
|
889
|
+
</td>
|
|
890
|
+
</tr>
|
|
891
|
+
</tbody>
|
|
892
|
+
</table>
|
|
893
|
+
</section>
|
|
894
|
+
|
|
895
|
+
<form id="deletion-form" method="post" action="/actions?editing=${editing}">
|
|
896
|
+
<input type="hidden" name="action_type" value="${ActionType.DELETE_BLOCK}" />
|
|
897
|
+
<input type="hidden" name="path" value="${path}" />
|
|
898
|
+
<input type="hidden" name="index_path" value="${index_path}" />
|
|
899
|
+
|
|
900
|
+
<table class="fixed mt-32">
|
|
901
|
+
<tbody>
|
|
902
|
+
<tr>
|
|
903
|
+
<td>
|
|
904
|
+
<a class="biglink grey" href="${path}?editing=${editing}">
|
|
905
|
+
${Emoji.LEFT_ARROW_UNICODE} cancel
|
|
906
|
+
</a>
|
|
907
|
+
</td>
|
|
908
|
+
|
|
909
|
+
<td>
|
|
910
|
+
<button class="biglink red" type="submit">
|
|
911
|
+
delete ${Emoji.RIGHT_ARROW_UNICODE}
|
|
912
|
+
</button>
|
|
913
|
+
</td>
|
|
914
|
+
</tr>
|
|
915
|
+
</tbody>
|
|
916
|
+
</table>
|
|
917
|
+
</form>
|
|
918
|
+
</section>
|
|
919
|
+
`;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
private getRoles(): string[] {
|
|
923
|
+
const {roles} = this.getMetadata();
|
|
924
|
+
|
|
925
|
+
return roles;
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
private getAccount(): Account {
|
|
929
|
+
const {account} = this.getMetadata();
|
|
930
|
+
|
|
931
|
+
return account;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
private getMetadata(): ActionMetadata {
|
|
935
|
+
return this.metadata;
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
export default ActionResultSerializer;
|