Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SPIKE Managed archiving of Links in Fluent #285

Open
maxime-rainville opened this issue May 12, 2024 · 2 comments
Open

SPIKE Managed archiving of Links in Fluent #285

maxime-rainville opened this issue May 12, 2024 · 2 comments

Comments

@maxime-rainville
Copy link

maxime-rainville commented May 12, 2024

We've recently identified that managing Archiving Link in Fluent doesn't work ... or at least works in a very clumsy way.

See #273 (comment) for the full context.

Timebox

1 work day

Objectives

  • Identify approaches to link archival that could work with Fluent.
  • Present approaches at our next architecture catch up.
@GuySartorelli GuySartorelli changed the title SPIKE Managed archived Links in Fluent SPIKE Managed archiving of Links in Fluent May 14, 2024
@GuySartorelli GuySartorelli self-assigned this May 19, 2024
@GuySartorelli
Copy link
Member

GuySartorelli commented May 20, 2024

Current behaviour

Localisation behaviour and UX in gridfields

  • If draft in one locale, no versioned flag in other locale
  • If archived, has "ARCHIVED" flag when falling back to other locale
  • Archiving from the other locale gets rid of it entirely

Localisation behaviour and UX in linkfields

  • Shows as "Draft" if exists in the other locale
  • On archive, disappears - on refresh, other-locale link appears as draft
  • Archiving from the other locale gets rid of it entirely

Current badges/flags fluent uses

  • "no source" when not in this locale and no fallback available (seems to be sitetree only)
  • greyed out but no badge when not in this locale but has fallback (seems to be sitetree only)
  • badge with the locale name in edit form itself (not in tree) when viewing content in this locale (all entwine edit forms)
    • Colour change depending on whether it's in this locale or not

Possible solutions

CMS5:

  • Make sure on clicking archive the data is refetched from the server so we don't show link disappearing if there's still a link in another locale
  • Add "Archived" state to getVersionedState() (fluent updates this to correctly indicate if the item is archived for the current locale)
    • Updates versioned flag for visual reference
    • Don't show archive button if link is already archived
  • Maybe implement canArchive() in FluentVersionedExtension to return false if isArchivedInLocale() returns true? Not sure what flow-on that might have as it might result in errors now being thrown where before actions would just result in nothing happening.
  • Provide some way to see which fluent locales the link is in
    • Could be a LiteralField in the edit form
    • Could be a new API for passing flags from PHP through to the react component, replacing the current logic that adds the versioned status flags in the react component directly

Additional, but probably over-the-top options

  • Add an (optional) new admin section for fluent with the same sort of functionality provided by the localisation manager (that gridfield which helps manage locales which we removed for Link since gridfields can't be rendered in react)
  • Pull actions from getCMSActions() into the formschema form
    • Add additional fluent actions such as copy to/from locale, archive from locale, etc
    • Maybe add a ... menu if there are multiple actions, and expose these as available actions when viewing links in a list (similar to the elemental block ... actions menu)

CMS 6

  • Centralised API for flags to be displayed for a record
    • When viewed in a tree/list (hierarchy tree admin, gridfield)
    • When viewed in the edit form for the record itself (e.g. fluent puts a locale flag there but not in tree view)
    • What should be included in a flag?
      • text
      • css class names
      • a tooltip for text on hover
    • Versioned and fluent would use, could also be used for any other purpose people want
  • Re-implement the localisation manager (that gridfield which helps manage locales) in react so it can be rendered in the modal

@mfendeksilverstripe
Copy link
Collaborator

Hey @GuySartorelli thanks for documenting the options we have in tackling this challenge. I really like the idea of focusing on low hanging fruit first before committing too much effort into this.

From all the available options for CMS 5 I like the LiteralField option the best. This is based on the feedback from the client on our project as we actually ended up building something similar for asset admin (similar problem - React UI, no GridFields).

The main reason why this solution was picked is that it gives content authors to overview across all locales. Model deletion was specifically an issue as content authors were reporting that it doesn't work. This is due to the delete / archive button not communicating the information that there is no content to delete in this locale.

We found this solution also to be least invasive as we're mostly just adding new enhancements in instead of replacing existing behaviour.

Here are some details about our solution.

Locale badges widget

Screenshot 2024-06-19 at 12 00 16 PM

class LocalisedBadges extends DataExtension
{
    public function updateCMSFields(FieldList $fields): void
    {
        /** @var SiteTree $owner */
        $owner = $this->getOwner();

        $field = DatalessField::create('LocalisedBadges');
        $field->setTemplate('App\Forms\LocalisedBadges');
        $field->customise(LocalisedBadgesHelper::singleton()->getLocales($owner));
        $fields->unshift($field);
    }
}
class LocalisedBadgesHelper
{

    use Injectable;

    /*
     * Specific logic for deciding how the badges will be displayed on the frontend
     */
    public function getLocales(SiteTree|File $data, string $objectType = 'Page'): array
    {
        $nonExistingLocales = Locale::getLocales()->sort('Sort');
        $existingLocales = Locale::getLocales()->sort('Sort');

        $localeVersions = FluentHelper::getLocaleCodesByObjectInstance($data);

        if (count($localeVersions) > 0) {
            $nonExistingLocales = $nonExistingLocales->exclude('Locale', $localeVersions);
            $existingLocales = $existingLocales->filter('Locale', $localeVersions);
        } else {
            $existingLocales = ArrayList::create();
        }

        $badgeData = [
            'EditLink' => $data->CMSEditLink(),
            'Existing' => $existingLocales,
            'NonExisting' => $nonExistingLocales,
            'ObjectType' => $objectType,
        ];

        return $badgeData;
    }
}
<div class="locale-badges">
  <% if $Current || $Existing %>
    <div class="locale-badge-container">
      <p>Locales</p>
      <div>
        <% loop $Existing %>
          <a href="{$Up.EditLink}/?l={$Locale}"
           aria-label="{$Title}"
           class="badge <% if $CurrentLocale.ID == $ID %>badge-success<% else %>badge-info fluent-badge--localised<% end_if %>"
           data-balloon-pos="down"
           target="_top"
          >
            <% if $LocaleSuffix = 001 %>
              EN
            <% else %>
              $LocaleSuffix
            <% end_if %>
          </a>
        <% end_loop %>
      </div>
    </div>
  <% end_if %>
  <% if $NonExisting %>
    <div class="locale-badge-container">
      <p>{$ObjectType} doesn't exist in</p>
      <div>
        <% loop $NonExisting %>
          <a href="{$Up.EditLink}/?l={$Locale}"
            aria-label="{$Title}"
            class="badge badge-secondary <% if $CurrentLocale.ID == $ID %>badge-success<% end_if %>"
            data-balloon-pos="down"
            target="_top"
            >
            <% if $LocaleSuffix = 001 %>
              EN
            <% else %>
              $LocaleSuffix
            <% end_if %>
          </a>
        <% end_loop %>
      </div>
    </div>
  <% end_if %>
</div>
.locale-badges {
  background-color: #E9F0F4;
  border-bottom: 1px solid #ced5e1;
  display: flex;
  margin: -20px -20px 20px;
  padding: 0 20px;

  [aria-label][data-balloon-pos]:after {
    font-family: inherit;
    text-transform: capitalize;
  }
}

.badge-non-existing-current {
  background-color: #333;

  &:hover {
    background-color: #333;
  }
}

.locale-badge-container {
  padding: 8px 0;

  p {
    margin-bottom: 0;
  }

  &:nth-of-type(n + 2) {
    margin-left: 15px;
    border-left: 1px solid #ced5e1;
    padding-left: 15px;
  }
}

// Asset admin editor locale badges
.editor__details {
  .locale-badges {
    margin-top: 0.5rem;
  }
}

Card fluent flag

Screenshot 2024-06-19 at 12 00 35 PM

public static function resolveInheritStatus(File $object, array $args, array $context, ?ResolveInfo $info): bool
{
    // just for code linting
    /** @var DataObject|Versioned|FluentVersionedExtension $versionedObject */
    $versionedObject = $object;

    return !$versionedObject->isDraftedInLocale();
}

This flag is then injected into the React component.

const inheritBadge = {
  node: "span",
  key: "inherit-status",
  className: `gallery-item--inherit ${styles.flagInheritedLocale}`,
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants