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

[WIP] Update Manager Refactor #1259

Draft
wants to merge 94 commits into
base: develop
Choose a base branch
from

Conversation

jaxwilko
Copy link
Member

@jaxwilko jaxwilko commented Nov 29, 2024

Me and Luke are working on a little refactor of how the UpdateManager works...

It also includes some components from my old composer PR found here: #967

The core idea of this is that there should be consistent interfaces to interact with different things built on top of Winter (i.e. modules, plugins & themes). Each of these elements will now have their class (i.e. Theme, PluginBase, ModuleServiceProvider) will now extend WinterExtension which will allow them to all interact with the update manager and other system functions directly.

In addition PluginManager, ThemeManager & ModuleManager (new) will all implement the ExtensionManager interface, which will allow for a consistant way to interact with all Winter extensions.

I.e. You will be able to call PluginManager::instance()->update($plugin) or ThemeManager::instance()->update($theme).

This also allows us to do some cool stuff like (only support for plugin installing is currently functional)

(new ExtensionSource(
    ExtensionSource::SOURCE_COMPOSER,
    ExtensionSource::TYPE_PLUGIN,
    composerPackage: 'jaxwilko/datamigrator'
))->install();

(new ExtensionSource(
    ExtensionSource::SOURCE_COMPOSER,
    ExtensionSource::TYPE_THEME,
    composerPackage: 'jaxwilko/custom-theme'
))->install();

(new ExtensionSource(
    ExtensionSource::SOURCE_LOCAL,
    ExtensionSource::TYPE_PLUGIN,
    code: 'winter.demo'
))->install();

(new ExtensionSource(
    ExtensionSource::SOURCE_LOCAL,
    ExtensionSource::TYPE_PLUGIN,
    path: 'plugins/winter/demo'
))->install();

By the end of the PR, the UpdateManager as is may no longer exist as is, instead each ExtensionManager will be responsible for it's existing functionality.

Requires storm branch: https://github.com/wintercms/storm/tree/wip/support-uploading-packages-update-manager-changes

@jaxwilko jaxwilko marked this pull request as draft November 29, 2024 18:41
@jaxwilko jaxwilko requested a review from LukeTowers November 29, 2024 18:41
@jaxwilko
Copy link
Member Author

jaxwilko commented Jan 6, 2025

@bennothommo plz need sexy help!
image

<div title="Downloads" class="downloads">
<span class="product-badge"><i class="icon-download"></i></span>
{{product.downloads}}
</div>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably add the license as well

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, it'll have to come from the marketplace tho as the packagist api does not provide it

@LukeTowers
Copy link
Member

For future reference, @jaxwilko's JS for the event stream handling

const response = await fetch(window.location.href, {
                method: 'POST',
                headers: {
                    'Accept': 'text/event-stream',
                    'X-Requested-With': 'XMLHttpRequest',
                    'X-WINTER-REQUEST-HANDLER': 'onInstallPlugin',
                    'X-WINTER-REQUEST-PARTIALS': '',
                    'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
                },
                body: data,
                redirect: 'follow',
                mode: 'same-origin',
            });

            if (response.status !== 200) {
                console.log('BAD');
                this.installing = false;
                return;
            }

            $.popup({
                size: 'installer-popup',
                content: `
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                        <h4 class="modal-title">Installing ${this.product.name}</h4>
                    </div>
                    <div class="modal-body"></div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-default" data-dismiss="modal">Blue Pill</button>
                        <button type="button" class="btn btn-primary" data-dismiss="modal">Red Pill</button>
                    </div>
                `
            });

            const popup = document.querySelector('.size-installer-popup');

            const chunk = async (response) => {
                const reader = response.body.getReader();
                const decoder = new TextDecoder();

                const parse = (str) => str.split("\n").filter((line) => !!line).map((line) => ({
                    type: line.substring(0, line.indexOf(': ')),
                    value: line.substring(line.indexOf(': ') + 2)
                }));

                const prepareMessage = (str) => {
                    ['INFO', 'ERROR'].forEach((status) => {
                        if (str.indexOf(status) === 0) {
                            str = `<span class="message-${status.toLowerCase()}">${status}</span> <pre>${str.substring(status.length + 1)}</pre>`;
                        }
                    });
                    return `<div class="install-message">${str}</div>`;
                };

                let done, value, message;
                while (!done) {
                    ({value, done} = await reader.read());
                    if (done) {
                        return;
                    }

                    message = parse(decoder.decode(value));

                    if (message[0].value === 'message') {
                        popup.querySelector('.modal-body').innerHTML += prepareMessage(message[1].value);
                    }

                    if (message[0].value === 'error') {
                        alert(message[1].value);
                    }
                }
            };

            await chunk(response);
            this.installing = false;

@LukeTowers LukeTowers changed the base branch from wip/support-uploading-packages to develop March 12, 2025 20:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants