Solución al Error de Angular: ERR_OSSL_EVP_UNSUPPORTED

Si estás aquí es porque, al intentar lanzar tu proyecto Angular, te has topado con el molesto error «error:0308010C:digital envelope routines::unsupported». No te preocupes, aquí te dejo una solución detallada para que puedas superar este obstáculo y seguir con tu desarrollo sin mayores complicaciones.

Te dejo un ejemplo del error:

PS C:\Users\usr\Documents\Projects\Angular-Master-Workspace> ng s --project=cris9
10% building 3/4 modules 1 active C:\Users\usr\Documents\Projects\Angular-Master-Workspace\node_modules\webpack-dev-server\client\index.js?http://0.0.0.0:0/sockjs-node&sockPath=/sockjs-nodenode:internal/crypto/hash:69
  this[kHandle] = new _Hash(algorithm, xofLen);
                  ^

Error: error:0308010C:digital envelope routines::unsupported
    at new Hash (node:internal/crypto/hash:69:19)
    at Object.createHash (node:crypto:133:10)
    at module.exports (C:\Users\usr\Documents\Projects\Angular-Master-Workspace\node_modules\webpack\lib\util\createHash.js:135:53)
    at NormalModule._initBuildHash (C:\Users\usr\Documents\Projects\Angular-Master-Workspace\node_modules\webpack\lib\NormalModule.js:417:16)
    a t [.....]
    at C:\Users\usr\Documents\Projects\Angular-Master-Workspace\node_modules\webpack\lib\Compilation.js:981:14 {
  opensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error' ],
  library: 'digital envelope routines',
  reason: 'unsupported',
  code: 'ERR_OSSL_EVP_UNSUPPORTED'
}

Descripción del Problema:

Este error tan peculiar viene con la incompatibilidad de las rutinas de sobre digital, lo que puede haber interrumpido tu flujo de trabajo en Angular. Pero tranquilo/a, que aquí tienes la solución.

Solución Paso a Paso:

Paso 1: Actualizar la Configuración de Node.js

Abre tu terminal de PowerShell y ejecuta este comando para ajustar las opciones de Node.js:

$env:NODE_OPTIONS = "--openssl-legacy-provider"

Este paso es fundamental para asegurar la compatibilidad y solucionar el problema.

Paso 2: Reinicia tu Aplicación Angular

Con las opciones de Node.js actualizadas, reinicia tu aplicación Angular con el siguiente comando:

Este reinicio debería permitir que tu aplicación vuelva a la normalidad, superando el error digital que estaba causando el paro.

Nota Importante:

Asegúrate de tener la versión adecuada de Node.js instalada en tu sistema. Se recomienda utilizar la versión estable más reciente para aprovechar las últimas correcciones y mejoras.

Windows 11 y la barra de tareas en la parte superior de la pantalla

Windows 11 ha cambiado muchos aspectos esteticos del sistema operativo de Microsoft. Desde cosas mas o menos tribiales, como por ejemplo el listado de wifis hasta rediseñar completamente el concepto de «Mi PC» (ahora Equipo) o el «Panel de Control».

En mi caso, lo cierto es que la estética no me preocupa demasiado y me adapto bastante rapido a este tipo de cambios, pero con W11 también ha llegado un cambio, probablemente imperceptible para la mayoria de usuarios que, personalmente, me ha provocado un verdadero dolor de cabeza.

Una de las configuraciones (que probablemente no usa prácticamente nadie) que ha desaparecido es el posicionamiento de la barra de tareas.

Desde Windows 98 la posición puedes escogerse, ya sea arrastrando la propia barra hasta el lateral de la pantalla o a la parte superior, pero esta configuración no existe en Windows 11, lo que obliga a tenerla siempre en la parte inferior de la pantalla.

Hasta la fecha, no he averiguado el por qué de eliminar esta configuración, pero después de hartarme de que no añadan esta funcionalidad he estado investigando como volver a poner la barra en la parte superior.

Hasta hace unos meses una manera de ponerla en la parte superior era mediante el registro de windows, modificando la siguiente clave (no entraré en explicar los diferentes valores por que este metodo ya no funciona):

HKEY_CURRENT_USER > Software > Microsoft > Windows > CurrentVersion > Explorer > StuckRects3

Esta opción movia la barra de sitio, pero las miniaturas de las pantallas abiertas que aparecen al poner el raton encima, dejaban de mostrarse. Para mi, esto no es una solución.

Asi que finalmente he dado con un programa que si permite mover la barra a la posicion que quiero y que muestra las miniaturas correctamente.

Explorer Patcher

La solución es simple, instalar el programa Explore Patcher desde la siguiente URL

https://github.com/valinet/ExplorerPatcher/wiki

Este programita permite un montón de personalizaciones, cambiar la ubicación de la barra, recuperar la estética de W10 y muchisimas cosas más.

Para facilitarte el trabajo, he preparado un fichero de configuración para dejar la barra de Windows 11 totalmente operativa con estética de Windows 11 en la parte superior de la pantalla.

Descargar “config de explroer patcher”

ExplorerPatcher_22621.2428.59.1.zip – Descargado 1173 veces – 1,48 KB

Para importar la configuración una vez instalado, solo hay que darle botón derecho a la barra de tareas, darle a propiedades y en el menu seleccionar:

About > Import Settings

En este punto seleccionas el fichero de config .reg y listo, ya tienes la barra en la parte superior de tu pantalla!

*Ojo: es probable que necesites reinicar el explorador para que cargue la nueva configuración

Auto-guardado local, no vuelvas a perder nada

Imagínate esta situación: estás trabajando en un informe importante en un editor en línea y, de repente, ¡la conexión a Internet se cae! ¿El resultado? Podrías perder todo tu trabajo. Para evitar este dolor de cabeza digital, el guardado local se convierte en tu mejor amigo. Así que, en un tono amigable y serio, exploremos esta característica y cómo funciona en un editor de informes en Angular.

El Guardado Local: Tu Compañero de Confianza

En este mundo de interrupciones y problemas técnicos constantes, el guardado local es como un héroe digital. Es una función que te permite guardar una copia de tu trabajo en tu dispositivo, asegurando que no se pierda en las nubes de Internet. El código que te voy a mostrar te enseña cómo implementar el guardado local en una aplicación Angular, especialmente en un editor de informes. ¿Las ventajas? Son muchas y muy valiosas.

1. Protección contra la Pérdida de Datos

Nada es más desalentador que perder horas de trabajo debido a problemas de conexión. Con el guardado local, esta pesadilla se desvanece. El código que vamos a ver se encarga de guardar automáticamente el informe en tu dispositivo, garantizando que tus datos estén a salvo, incluso cuando la tormenta digital hace de las suyas.

2. Flexibilidad y Continuidad

El guardado local también te da la libertad que necesitas. ¿Necesitas seguir trabajando en tu informe en un vuelo o en un lugar con una conexión limitada? No hay problema. Con el guardado local, puedes seguir trabajando sin problemas, sin importar dónde estés. Esto te asegura que tu trabajo siga avanzando sin contratiempos.

3. Protección contra Errores Humanos

Quién no ha borrado accidentalmente una sección importante de un informe o ha sobrescrito información crucial. Con el guardado local, los errores humanos son menos aterradores. El sistema te permite restaurar versiones anteriores de tu trabajo, lo que actúa como un salvavidas cuando cometes un error. Así, se reducen las situaciones de estrés y desesperación.

4. Ahorro de Tiempo y Estrés

La amenaza constante de perder datos puede ser estresante y llevar a perder tiempo valioso. El guardado local, en cambio, te ofrece tranquilidad al asegurarte de que tus datos estén respaldados en tu propio dispositivo. Esto ahorra tiempo y esfuerzo, algo realmente valioso en entornos profesionales y personales.

El Código en Acción: Implementación en Angular

Ahora que hemos hablado de los beneficios del guardado local, veamos cómo funciona en una aplicación Angular. En el componente «AutosaveComponent,» el código se encarga de guardar automáticamente el informe en tu dispositivo y de recuperar versiones anteriores en caso de problemas. A continuación, te muestro el código completo y una breve explicación de cómo funciona:

import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import * as moment from 'moment';
import { AuthUserService } from 'projects/cris9/src/app/services/authUser.service';

@Component({
  selector: "app-autosave",
  templateUrl: "./autosave.component.html",
  styleUrls: ["./autosave.component.css"],
})
export class AutosaveComponent implements OnInit {
  @Input()
  set report(value: string) {
    this._report = {report: value, TTL: moment().format("DD/MM/yyyy HH:mm:ss") };
  }

@Input() set report(value: string): Aquí definimos un «setter» para la entrada «report» que nos permite capturar el valor del informe y su marca de tiempo actual. Esto nos ayudará a mantener un registro de los cambios.

@Input() set AN(value: string) { this._AN = value; }

@Input() set AN(value: string): Similar al anterior, este «setter» captura el valor de «AN,» que es parte del contexto del informe.

@Output() restoreTemplate = new EventEmitter<string>();

@Output() restoreTemplate: Esta línea define un evento de salida que nos permitirá restaurar una versión anterior del informe si es necesario.

constructor(private _authUser: AuthUserService) {}

constructor(private _authUser: AuthUserService): Aquí estamos inyectando el servicio «_authUser» para poder utilizarlo en nuestras funciones.

  lastTime;
  lastResult: boolean;
  saving: boolean;
  notSavedYet;
  private _report;
  private _AN;
  private _refreshInterval;

Variables: Estamos declarando varias variables que se usarán en todo el componente para realizar un seguimiento del estado del guardado y la información del informe.

  ngOnInit(): void {
    // Verificar si existe un informe anterior
    if (this.checkExist()) {
      // Iniciar temporizador
      this._refreshInterval = setInterval(() => {
        this.autosave();
      }, 15000);
    }
  }

ngOnInit(): Esta es una función del ciclo de vida de Angular. Aquí comenzamos por verificar si existe un informe anterior (la función checkExist lo hará por nosotros). Si hay un informe anterior, iniciamos un temporizador para el guardado automático con un intervalo de 15 segundos (15000 milisegundos).

  checkExist(): Boolean {
    try {
      if (
        localStorage.getItem(this._authUser.getUser() + "-" + this._AN) !=
          null &&
        localStorage.getItem(
          this._authUser.getUser() + "-" + this._AN + "-" + "lastDate"
        ) != null
      ) {

checkExist(): Esta función verifica si existen datos previamente guardados. Revisamos si hay una entrada en el almacenamiento local para el usuario y para «AN» (parte del contexto del informe), así como la marca de tiempo de la última modificación.

        if (
          (JSON.stringify(JSON.parse(localStorage.getItem(this._authUser.getUser() + "-" + this._AN)).report) != JSON.stringify(this._report.report)) &&
          confirm(
            "Se ha encontrado una versión local del informe con fecha " +
              localStorage.getItem(
                this._authUser.getUser() + "-" + this._AN + "-" + "lastDate"
              ) + " que no ha sido guardada en el servidor." +
              "\n¿Quieres cargarla?\n\n" +
              "** Si no cargas el informe recuperado, se descartará y se sobrescribirá **"
          )
        ) {

Continuación de checkExist(): Aquí, comparamos el informe actual con el informe guardado localmente para ver si ha habido cambios. Si se detectan cambios, mostramos un mensaje de confirmación para cargar la versión local. Si el usuario confirma, recuperamos el informe local y actualizamos el estado.

          this._report = JSON.parse(
            localStorage.getItem(this._authUser.getUser() + "-" + this._AN)
          );
          this.lastTime = localStorage.getItem(
            this._authUser.getUser() + "-" + this._AN + "-" + "lastDate"
          );
          this.lastResult = true;
          this.notSavedYet = false;
          this.restoreTemplate.emit(JSON.stringify(this._report.report));
        }
      } else {
        localStorage.removeItem(this._authUser.getUser() + "-" + this._AN);
        localStorage.removeItem(
          this._authUser.getUser() + "-" + this._AN + "-" + "lastDate"
        );
        this.notSavedYet = true;
      }

Continuación de checkExist(): Si el usuario decide cargar la versión local, aquí actualizamos el estado del informe y marcamos que no se ha guardado aún en el servidor. Si no hay datos locales, eliminamos cualquier información antigua y marcamos que aún no se ha guardado.

      return true;
    } catch (exception) {
      console.log(exception);
      alert("Lo sentimos, se ha producido un error al recuperar el informe :(");
      localStorage.removeItem(this._authUser.getUser() + "-" + this._AN);
      localStorage.removeItem(
        this._authUser.getUser() + "-" + this._AN + "-" + "lastDate"
      );
      this.notSavedYet = true;
      return true;
    }
  }

Continuación de checkExist(): En caso de que ocurra algún error durante la verificación, manejamos la excepción y mostramos un mensaje de alerta. Luego, limpiamos los datos locales y marcamos que no se ha guardado.

autosave() {
    try {
      this.saving = true;
      localStorage.setItem(
        this._authUser.getUser() + "-" + this._AN,
           JSON.stringify(this._report));
      localStorage.setItem(
        this._authUser.getUser() + "-" + this._AN + "-" + "lastDate",
        moment().format("DD/MM/yyyy HH:mm:ss")
      );
      this.lastTime = moment().format("DD/MM/yyyy HH:mm:ss");
      this.lastResult = true;
      this.saving = false;
      this.notSavedYet = false;
    } catch (exception) {
      this.lastTime = moment().format("DD/MM/yyyy HH:mm:ss");
      this.lastResult = false;
      this sving = false;
      this.notSavedYet = false;
    }
  }
}

autosave(): Esta función se encarga de guardar automáticamente el informe en el dispositivo del usuario. Primero, marcamos que estamos en proceso de guardado y luego almacenamos el informe y la marca de tiempo en el almacenamiento local. Si todo va bien, actualizamos el estado y marcamos que no se ha guardado en el servidor. Si ocurre un error, manejamos la excepción y marcamos que no se ha guardado.

Conclusión

En resumen, el guardado local es una función esencial para garantizar la seguridad y la continuidad en la creación de informes en línea. Protege contra la pérdida de datos, ofrece flexibilidad, previene errores humanos y ahorra tiempo. La implementación de esta característica, como se muestra en el código de Angular, es una excelente decisión para crear un editor en línea más amigable y eficiente.

Nuestra intención es ayudarte a que tu experiencia en la creación de informes sea lo más agradable y sin preocupaciones posible. Con el guardado local, puedes estar seguro de que tu trabajo está en buenas manos, incluso cuando las nubes digitales amenazan con tormenta.

Mejorando la Experiencia de Inicio de Sesión: Simulando Actividad con Mensajes Dinámicos

En el mundo de la tecnología, la primera impresión es crucial. En un proceso de inicio de sesión de aplicación web, a menudo se recurre a la típica barra de progreso o al icónico spinner de carga para mantener a los usuarios informados sobre el progreso de la autenticación. Sin embargo, hoy queremos presentar una técnica más interesante y atractiva inspirada en juegos como The Sims: la simulación de actividad con mensajes dinámicos.

El codigo que os muestro es real y esta en producción, concretamente en el login de SWPanel de la empresa SW Hosting (espero que si leen el artículo no se enfaden 😄)

Manteniendo al Usuario Entretenido durante el Inicio de Sesión:

En lugar de hacer que los usuarios observen pasivamente una barra de progreso, ¿por qué no darles la sensación de que la aplicación está ocupada realizando múltiples tareas? Esta técnica simula actividad y proporciona una experiencia más interactiva y atractiva.

El Código en Acción:

A continuación, presentaremos el código JavaScript que permite simular mensajes de carga en un proceso de inicio de sesión. Esto es especialmente útil cuando se trata de aplicaciones que pueden tener una autenticación más larga y compleja. Los usuarios sentirán que algo está sucediendo en segundo plano.

function cambio_estado_login(tipo) {
    var temps = 2e3;

    if (document.getElementById('info_login_status')) {
        if (tipo == '2') {
            texto = login_texto_2fa;
        } else {
            texto = login_texto_1;
        }
        clearInterval(timer_status_login);

        var texto_load = texto.split(',');
        text_info_login_status += 1;

        if (text_info_login_status >= texto_load.length) {
            if (tipo == '2') {
                text_info_login_status = 0;
            } else {
                text_info_login_status = 0;
            }
            document.getElementById('info_login_status').innerHTML =
                texto_load[text_info_login_status];
        } else {
            document.getElementById('info_login_status').innerHTML =
                texto_load[text_info_login_status];
            timer_status_login = setInterval(function () {
                cambio_estado_login(tipo);
            }, temps);
        }
    }
}

var login_texto_1='Validando acceso SWPanel';
	login_texto_1 = login_texto_1 + ',' + 'Generando conexión segura de acceso'
	login_texto_1 = login_texto_1 + ',' + 'Cargando configuración de cuenta de cliente'
	login_texto_1 = login_texto_1 + ',' + 'Cargando datos personalizados de entorno'
	login_texto_1 = login_texto_1 + ',' + 'Personalizando tu SWPanel'
	login_texto_1 = login_texto_1 + ',' + 'Analizando servicios activos y recursos'
	login_texto_1 = login_texto_1 + ',' + 'Analizando uso de recursos de los servicios activos'
	login_texto_1 = login_texto_1 + ',' + 'Analizando servicios de Cloud'
	login_texto_1 = login_texto_1 + ',' + 'Analizando escalabilidad y disponibilidad de Cloud'
	login_texto_1 = login_texto_1 + ',' + 'Estudiando opciones y oportunidades de mejora'
	login_texto_1 = login_texto_1 + ',' + 'Analizando cartera de dominios'
	login_texto_1 = login_texto_1 + ',' + 'Preparando informes de caducidad de dominios'
	login_texto_1 = login_texto_1 + ',' + 'Analizando certificados SSL'
	login_texto_1 = login_texto_1 + ',' + 'Preparando informes de caducidad de SSL'
	login_texto_1 = login_texto_1 + ',' + 'Generando dashboard de SWPanel'
	login_texto_1 = login_texto_1 + ',' + 'Generando dashboards de servicios'
	login_texto_1 = login_texto_1 + ',' + 'Generando datos estadísticos'
	login_texto_1 = login_texto_1 + ',' + 'Generando entorno privado de soporte'
	login_texto_1 = login_texto_1 + ',' + 'Generando entorno privado de soporte'
	login_texto_1 = login_texto_1 + ',' + 'Actualizando cache de SWPanel'
	login_texto_1 = login_texto_1 + ',' + 'Revisando notificaciones pendientes'
	login_texto_1 = login_texto_1 + ',' + 'Revisando mensajes de soporte'
	login_texto_1 = login_texto_1 + ',' + 'Revisando estado de tu cuenta de cliente'
	login_texto_1 = login_texto_1 + ',' + 'Iniciando Interface de usuario de SWPanel'
	login_texto_1 = login_texto_1 + ',' + 'Aplicando perfiles de usuarios'
	login_texto_1 = login_texto_1 + ',' + 'Aplicando permisos de SWPanel'
	login_texto_1 = login_texto_1 + ',' + 'Aplicando seguridad'
	login_texto_1 = login_texto_1 + ',' + 'Analizando restricciones de acceso'
	login_texto_1 = login_texto_1 + ',' + 'Generando estadísticas e históricos de acceso'
	login_texto_1 = login_texto_1 + ',' + 'Generando identificador de sesión único'
	login_texto_1 = login_texto_1 + ',' + 'Iniciando tu SWPanel'
var login_texto_2fa = 'Iniciando verificación de doble factor';
	login_texto_2fa = login_texto_2fa + ',' + 'Validando códigos y tokens de seguridad'
	login_texto_2fa = login_texto_2fa + ',' + 'Comprobando identidad de acceso a SWPanel'
	login_texto_2fa = login_texto_2fa + ',' + 'Últimas validaciones de seguridad'
var text_contrato = 'Debes aceptar los términos del contrato de servicios.';

Cómo Funciona:

  • La función cambio_estado_login toma un argumento tipo, que determina los mensajes a mostrar.
  • Los mensajes se dividen en una matriz para que se puedan mostrar uno tras otro.
  • Se usa un contador para rastrear qué mensaje se mostrará a continuación.
  • Si se llega al final de la matriz de mensajes, el contador se reinicia.
  • Se configura un temporizador para llamar a la función nuevamente, simulando la animación de mensajes cambiantes.

Inspiración en The Sims:

Si alguna vez has jugado a The Sims, recordarás los mensajes extravagantes que aparecían en la parte inferior de la pantalla. Aunque exagerados, mantenían a los jugadores entretenidos mientras se realizaban tareas en el juego. Esta técnica toma inspiración de ese enfoque, adaptándolo de manera elegante y atractiva a un proceso de inicio de sesión en una aplicación.

En resumen, la simulación de mensajes de carga es una forma efectiva de mantener a tus usuarios entretenidos durante el proceso de inicio de sesión, proporcionando una experiencia más atractiva en lugar de una barra de progreso estática. Al tomar inspiración de juegos como The Sims, podemos mejorar la impresión del usuario y mantener su atención mientras la aplicación se autentica.

Cómo Filtrar y Gestionar Datos del Local Storage en JavaScript

En este artículo, exploraremos cómo filtrar y gestionar datos almacenados en el Local Storage de tu navegador web utilizando un script JavaScript. Descubre cómo aplicar expresiones regulares para seleccionar datos específicos y cómo calcular el tamaño del Local Storage. ¡Optimiza tus proyectos web y ofrece a tus usuarios una experiencia más eficiente!

Introducción

Aprenderemos a utilizar un script JavaScript para filtrar datos en el Local Storage y calcular su tamaño. Estos conocimientos son esenciales para el desarrollo de aplicaciones web y pueden marcar la diferencia en la experiencia del usuario. Expliquemos el funcionamiento de este script de manera accesible y amigable.

Filtrando Datos del Local Storage

El primer script que vamos a explorar se utiliza para filtrar datos específicos en el Local Storage. Aquí está el código:

const re = /[a-zA-Z]/g;

Object.keys(localStorage).forEach(function (key) {
  if (key.match(re)) {
    // Realizar alguna acción
  }
});

Vamos a analizarlo paso a paso para comprenderlo a fondo:

  1. const re = /[a-zA-Z]/g;: En esta línea, definimos una expresión regular que busca letras en mayúsculas y minúsculas. Este enfoque es fundamental para seleccionar datos específicos en el Local Storage.
  2. Object.keys(localStorage).forEach(function (key) { ... });: Aquí, obtenemos las claves almacenadas en el Local Storage y las recorremos usando un bucle forEach. Es un paso importante para acceder a los datos que deseamos filtrar.
  3. if (key.match(re)) { ... }: En cada iteración, comprobamos si la clave actual coincide con nuestra expresión regular utilizando el método match(). Si la clave contiene al menos una letra, ejecutamos un código personalizado dentro del bloque if.

Calculando el Tamaño del Local Storage

Añadiremos otro script que calcula el tamaño total del Local Storage y lo muestra en kilobytes (KB) o megabytes (MB). Aquí tienes el código:

var allStrings = '';
for (var key in window.localStorage) {
  if (window.localStorage.hasOwnProperty(key)) {
    allStrings += window.localStorage[key];
  }
}

let size = 3 + (allStrings.length * 16) / (8 * 1024);

if (size > 1024) {
  this.localStorageSize = Math.ceil(size / 1024) + ' MB';
} else {
  this.localStorageSize = allStrings
    ? Math.ceil(3 + (allStrings.length * 16) / (8 * 1024)) + ' KB'
    : '0 KB';
}

Este script recorre todas las claves del Local Storage, recopila sus valores y calcula el tamaño total en KB o MB. Esto es útil para monitorear y gestionar el espacio utilizado por tus datos almacenados en el navegador.

Uso y Personalización

Puedes personalizar estos scripts según tus necesidades. Además de realizar una «acción» en el primer script, ahora también puedes mostrar el tamaño total del Local Storage a tus usuarios. Esto es útil para mantener un control sobre el espacio de almacenamiento y tomar decisiones informadas.

Consejos Útiles de SQL para Usuarios Avanzados y no tan avanzados en Oracle

En este artículo, escribo una serie de consejos útiles de SQL para usuarios avanzados que trabajan con la base de datos Oracle. Estas consultas y técnicas te ayudarán a optimizar tus operaciones y obtener información valiosa de tu base de datos.

No hay una temática concreta sobre los consejos o snippets de codigo que comparto, más bien son un manojo de herramientas que he ido acumulando con el tiempo y que creo que pueden resultarte útil😆

Consejo 1: Formatear una Fecha a Cadena

/* Formatted on 26/10/2023 9:01:36 (QP5 v5.360) */
-- FORMAT DATE TO STR

select TO_DATE('05/06/1987 16:30','DD/MM/YYYY HH24:MI') AS FechayHora from dual;
/* Formatted on 26/10/2023 9:01:36 (QP5 v5.360) */
-- FORMAT DATE TO STR
SELECT to_char(col_name, 'YYYY-MM-DD HH24:MI:SS') from tab_name;
-- CONVERT VARCHAR COL TO DATE
SELECT TO_DATE (col_name, 'YYYY/MM/DD HH24:MI:SS') from tab_name;
-- CONVERT STR TO DATE
SELECT TO_DATE (str, 'YYYY/MM/DD HH24:MI:SS') from DUAL;

Esta consulta te permitirá formatear una fecha como una cadena en el formato deseado.

Consejo 2: Seleccionar Datos de una Columna JSON en Oracle

-- EXAMPLE TABLE STRUCTURE:
CREATE TABLE LDAP_USERS.API_LOG
(
  DATETIME  	DATE,
  JSONCOLUMN    CLOB
)

-- JSON STRUCTURE:
{ keyname1: value1, keyname2: value2, ... }

-- SELECT EXAMPLE
SELECT a.*, j.*
  FROM YOURSCHEMA.yourtable a, 
  JSON_TABLE ( a.JSONCOLUMN,
               '$'  COLUMNS(
                     keyname1 VARCHAR(10) PATH '$.keyname1',
                     keyname2 VARCHAR(10) PATH '$.keyname2'
                     )
            ) as j
            

Esta consulta te permite seleccionar datos específicos de una columna JSON en Oracle.

Consejo 3: Calcular el Hash MD5 en Oracle

/* Formatted on 26/10/2023 9:07:00 (QP5 v5.360) */
SELECT standard_hash ('foo', 'MD5') FROM DUAL;

Con esta consulta, puedes calcular el hash MD5 de una cadena en Oracle.

Consejo 4: Ver el Tamaño de los Usuarios en Oracle

/* Formatted on 26/10/2023 9:07:30 (QP5 v5.360) */
  SELECT owner, SUM (BYTES) / 1024 / 1024
    FROM DBA_EXTENTS MB
GROUP BY owner

Esta consulta te mostrará el tamaño de los usuarios en Oracle.

Consejo 5: Analizar el Uso de la Memoria Cache en Oracle

select sum(pins) Executions, sum(reloads) cache_fails,
  trunc(sum(reloads)/sum(pins)*100,2) AS "Match%"
from v$librarycache
where namespace in ('TABLE/PROCEDURE','SQL AREA','BODY','TRIGGER');

Aprende a analizar el uso de la memoria cache en Oracle y mejorar el rendimiento.

Consejo 6: Monitorear Cursores Abiertos en Oracle

/* Formatted on 26/10/2023 9:09:14 (QP5 v5.360) */
-- Sessions by user 

  SELECT b.sid, a.username, b.VALUE Cursores_Abiertos
    FROM v$session a, v$sesstat b, v$statname c
   WHERE     c.name IN ('opened cursors current')
         AND b.statistic# = c.statistic#
         AND a.sid = b.sid
         AND a.username IS NOT NULL
         AND b.VALUE > 0
ORDER BY 3

Esta consulta te permitirá monitorear y rastrear la cantidad de cursores abiertos en tu base de datos Oracle.

Consejo 7: Analizar el Último SQL Ejecutado en Oracle

/* Formatted on 26/10/2023 9:13:06 (QP5 v5.360) */
  SELECT DISTINCT
         vs.sql_text,
         vs.sharable_mem,
         vs.persistent_mem,
         vs.runtime_mem,
         vs.sorts,
         vs.executions,
         vs.parse_calls,
         vs.module,
         vs.buffer_gets,
         vs.disk_reads,
         vs.version_count,
         vs.users_opening,
         vs.loads,
         TO_CHAR (TO_DATE (vs.first_load_time, 'YYYY-MM-DD/HH24:MI:SS'),
                  'MM/DD  HH24:MI:SS')    first_load_time,
         RAWTOHEX (vs.address)            address,
         vs.hash_value                    hash_value,
         rows_processed,
         vs.command_type,
         vs.parsing_user_id,
         OPTIMIZER_MODE,
         au.USERNAME                      parseuser
    FROM v$sqlarea vs, all_users au
   WHERE     (parsing_user_id != 0)
         AND (au.user_id(+) = vs.parsing_user_id)
         AND (executions >= 1)
ORDER BY buffer_gets / executions DESC

Con esta consulta, podrás obtener detalles sobre la ejecución del último SQL en tu base de datos Oracle, lo que es fundamental para la optimización.

Consejo 8: Identificar Propietarios de Tablespace en Oracle

/* Formatted on 26/10/2023 9:14:02 (QP5 v5.360) */
  SELECT owner,
         DECODE (partition_name,
                 NULL, segment_name,
                 segment_name || ':' || partition_name)    name,
         segment_type,
         tablespace_name,
         bytes,
         initial_extent,
         next_extent,
         PCT_INCREASE,
         extents,
         max_extents
    FROM dba_segments
   WHERE 1 = 1 AND extents > 1
ORDER BY 9 DESC, 3

Utiliza esta consulta para identificar los propietarios de tablespaces en Oracle y comprender la asignación de espacio.

Consejo 9: Visualizar Parámetros de Configuración de Oracle

/* Formatted on 26/10/2023 9:16:36 (QP5 v5.360) */
  SELECT v.name,
         v.VALUE
             VALUE,
         DECODE (ISSYS_MODIFIABLE, 'DEFERRED', 'TRUE', 'FALSE')
             ISSYS_MODIFIABLE,
         DECODE (v.isDefault,  'TRUE', 'YES',  'FALSE', 'NO')
             "DEFAULT",
         DECODE (ISSES_MODIFIABLE,
                 'IMMEDIATE', 'YES',
                 'FALSE', 'NO',
                 'DEFERRED', 'NO',
                 'YES')
             SES_MODIFIABLE,
         DECODE (ISSYS_MODIFIABLE,
                 'IMMEDIATE', 'YES',
                 'FALSE', 'NO',
                 'DEFERRED', 'YES',
                 'YES')
             SYS_MODIFIABLE,
         v.description
    FROM V$PARAMETER v
   WHERE name NOT LIKE 'nls%'
ORDER BY 1

Esta consulta te proporciona información detallada sobre los parámetros de configuración de Oracle.

Consejo 10: Supervisar el Estado de los Tablespace en Oracle

/* Formatted on 26/10/2023 9:17:38 (QP5 v5.360) */
  SELECT t.tablespace_name
             "Tablespace",
         t.status
             "Status",
         ROUND (MAX (d.bytes) / 1024 / 1024, 2)
             "MB Size",
         ROUND (
               (MAX (d.bytes) / 1024 / 1024)
             - (SUM (DECODE (f.bytes, NULL, 0, f.bytes)) / 1024 / 1024),
             2)
             "MB Used",
         ROUND (SUM (DECODE (f.bytes, NULL, 0, f.bytes)) / 1024 / 1024, 2)
             "MB Free",
         t.pct_increase
             "% increase",
         SUBSTR (d.file_name, 1, 80)
             "File"
    FROM DBA_FREE_SPACE f, DBA_DATA_FILES d, DBA_TABLESPACES t
   WHERE     t.tablespace_name = d.tablespace_name
         AND f.tablespace_name(+) = d.tablespace_name
         AND f.file_id(+) = d.file_id
GROUP BY t.tablespace_name,
         d.file_name,
         t.pct_increase,
         t.status
ORDER BY 1, 3 DESC

Utiliza esta consulta para supervisar el estado y el uso de los tablespaces en Oracle.

Consejo 11: Explorar la Estructura de la Base de Datos

select * from dictionary

Una de las primeras tareas al administrar una base de datos es explorar su estructura. Esta consulta te proporciona información sobre los objetos y las vistas disponibles en la base de datos Oracle.

Consejo 12: Monitorear Sesiones de Usuarios en Oracle

/* Formatted on 26/10/2023 9:18:43 (QP5 v5.360) */
-- Sessions by user

  SELECT username Usuario_Oracle, COUNT (username) Numero_Sesiones
    FROM v$session
GROUP BY username
ORDER BY Numero_Sesiones DESC

El monitoreo de sesiones de usuarios es esencial para garantizar un rendimiento óptimo de la base de datos. Utiliza esta consulta para conocer cuántas sesiones de usuarios están activas y quiénes son los principales usuarios.

Consejo 13: Ordenar Sesiones por Aplicación en Oracle

/* Formatted on 26/10/2023 9:19:10 (QP5 v5.360) */
-- Order sessions by app

  SELECT program Aplicacion, COUNT (program) Numero_Sesiones
    FROM v$session
GROUP BY program
ORDER BY Numero_Sesiones DESC

Ordenar las sesiones por aplicación te ayuda a identificar las aplicaciones que generan más actividad en la base de datos. Esta información es crucial para la asignación de recursos y la resolución de problemas.

Consejo 14: Supervisar Parámetros de Configuración en Oracle

select * from v$system_parameter

La configuración de la base de datos es fundamental. Utiliza esta consulta para obtener una lista completa de los parámetros de configuración de Oracle y sus valores actuales.

Consejo 15: Verificar el Nombre de la Base de Datos en Oracle

select value from v$system_parameter where name = 'db_name'

Es importante conocer el nombre de la base de datos que estás administrando. Esta consulta te proporciona el nombre de la base de datos actual.

Consejo 16: Revisar Archivos de Control en Oracle

select value from v$system_parameter where name = 'control_files'

Los archivos de control son esenciales para la integridad de la base de datos. Utiliza esta consulta para verificar la ubicación de los archivos de control en Oracle.

Consejo 17: Consultar la Versión de Oracle en Uso

select value from v$system_parameter where name = 'compatible'

Conocer la versión de Oracle en uso es crucial para la administración y la planificación a largo plazo. Esta consulta te proporciona información sobre la compatibilidad de la base de datos.

Consejo 18: Supervisar Archivos de Registro (Redo Logs) en Oracle

/* Formatted on 26/10/2023 9:21:37 (QP5 v5.360) */
-- Show log files

SELECT * FROM v$logfile;

-- Load file
EXECUTE DBMS_LOGMNR.add_logfile('/path/to/file.log');
-- Start Session
EXECUTE DBMS_LOGMNR.START_LOGMNR(
  -- Add dictionary (if not, you will get sql's like "UNKNOWN"."OBJ# and HEXTORAW('45465f4748'))
  options => dbms_logmnr.dict_from_online_catalog
  /*
    Example Options
    STARTTIME => '19-Sep-2003 10:15:00',
    NDTIME => '19-Sep-2003 10:45:00',
    DBMS_LOGMNR.CONTINUOUS_MINE);
  */
);

-- Check your file 

SELECT * FROM v$logmnr_contents;

-- End session
EXECUTE DBMS_LOGMNR.end_logmnr();

El monitoreo de archivos de registro es esencial para garantizar la recuperación de datos en caso de fallos. Utiliza estas consultas para supervisar y administrar los archivos de registro en Oracle.

Consejo 19: Verificar el Estado de la Base de Datos en Oracle

select status from v$instance

Conocer el estado de la base de datos es fundamental. Utiliza esta consulta para obtener información sobre el estado actual de tu base de datos Oracle.

Hacer compatible Angular 9 con Internet Explorer

En este mini-tutorial vamos a ver que pasos tienes que hacer para que tu proyecto Angular 9 (también es compatible con Angular 8) compilado funcione correctamente en todos los navegado, incluido el odioso Internet Explorar.

Paso 1: Polyfills.ts

En el fichero polyfills.ts, descomenta estas dos líneas:

  import 'classlist.js';
  import 'web-animations-js';

Una vez descomentadas, necesitaremos instalar los paquetes de classlist y web-animations-js. Así abriremos un terminal y navegaremos hasta el directorio de nuestro proyecto. Una vez allí, ejecutamos:

npm install --save classlist.js
npm install --save web-animations-js

En el fichero polyfills.ts, asegurate de tener importado zone.js
Se supone que viene por defecto con angular-cli, pero algunos me han reportado problemas y era debido a esto.

import 'zone.js/dist/zone';  // Included with Angular CLI.

Paso 2: tsconfig

Vamos a crear un acrchivo en la raiz de nuestro entorno de trabajo (junto al tsconfig.json) llamado «tsconfig.es5.json» con el siguiente contenido

{
  "extends": "./tsconfig.app.json",
  "compilerOptions": {
      "target": "es5"
  }
}

Paso 3: angular.json

En el fichero angular.json, vamos a agregar una nueva configuración a nuestro proyecto. En las secciones «build» y «serve», necesitamos agregar una nueva configuración «es5», para especificar el nuevo tsconfig creado, y su uso en el comando serve.

// sección build > configurations > production
            "es5": {
              "tsConfig": "./tsconfig.es5.json"
            }

// Sección serve:
            "es5": {
              "browserTarget": ":build:es5"
            }

Nuestro angular.json quedaría así en las secciones build y serve

"build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist/",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.app.json",
            "aot": false,
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [
              "src/styles.css"
            ],
            "scripts": []
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true,
              "budgets": [
                {
                  "type": "initial",
                  "maximumWarning": "2mb",
                  "maximumError": "5mb"
                }
              ]
            },
            "es5": {
              "tsConfig": "./tsconfig.es5.json"
            }
          }
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": ":build"
          },
          "configurations": {
            "production": {
              "browserTarget": ":build:production"
            },
            "es5": {
              "browserTarget": ":build:es5"
            }
          }
        },

En <nombre-de-tu-app> debes poner el nombre de tu aplicación y (como es lógico, en las secciones style y scripts debes tener importado todo aquello que necesites.

Paso 4: browserslist

En el fichero browserslist, quitar el not de la línea not IE 9-11.

# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries

# You can see what browsers were selected by your queries by running:
#   npx browserslist

> 0.5%
last 2 versions
Firefox ESR
not dead
// not IE 9-11 # For IE 9-11 support, remove 'not'.
IE 9-11 # For IE 9-11 support, remove 'not'.

Paso 5: index.html

En el fichero index.html, añadiremos dentro del <head>:


All is done!

Con esto ya tendremos nuestro proyecto compatible. pero hay un par de detalles que debes tener en cuenta:

  • Si lanzas un «ng serve» sin parametros, tu proyecto seguirá siendo compatible sólo con chrome (yo lo uso así para desarrollar)
  • Si quieres lanzar un «ng serve» compatible con IE, debes hacerlo con el parámetro «–configuracion es5» para que cargue la configuración y quedaría así:

ng serve --configuration es5

  • Una vez conpiles con –prod para publicar tu proyecto, se realizarán dos compilaciones, una para es2015 y otra para es5 dando como resultado esta lista de ficheros (este es un ejemplo de un proyecto real donte tb hay agregados primeng y fontawesome)
      assets
38024 3rdpartylicenses.txt
370756 5-es2015.e783c2997b5e11df7397.js
372417 5-es5.e783c2997b5e11df7397.js
10355 color.6441e63a57ccc5105bad.png
132728 fa-brands-400.1437eef49e3db661f92c.ttf
133034 fa-brands-400.3825c40fd00d9bbb76b7.eot
715890 fa-brands-400.55faa7ef298ebafcc322.svg
76548 fa-brands-400.9a01a31d6767f82529dc.woff2
89824 fa-brands-400.e1c1a88e6228f902435e.woff
13600 fa-regular-400.5fab4ed5c3745c12c7e1.woff2
34092 fa-regular-400.814c2c571f030686e71c.ttf
16800 fa-regular-400.acdccc059cdf7b4063e9.woff
34390 fa-regular-400.eb99d5076e8ce45ccfa1.eot
144322 fa-regular-400.fa5f132deb163050a148.svg
76120 fa-solid-900.0f27e9b933cc50abbbba.woff2
193792 fa-solid-900.8618686494a5c8092120.ttf
194078 fa-solid-900.a0b3c6d0d774520787d8.eot
849240 fa-solid-900.a84653d4fe0072d182b6.svg
99004 fa-solid-900.afbdcbccd6861d9cdc38.woff
168641 favicon.ico
  293 hue.f8505bd4d6f3e3aa435b.png
 1938 index.html
13112 line.39c65dcc08f7edb347b6.gif
 9427 loading.9347db5956a89b0bab38.gif
897689 main-es2015.cec9e5f30730177c99be.js
1004458 main-es5.cec9e5f30730177c99be.js
27604 open-sans-v15-latin-300.252a41f69d4c320154a1.ttf
15545 open-sans-v15-latin-300.2aeabc9e8ed0aef227d7.eot
55181 open-sans-v15-latin-300.bb3b405a4608d51ddb13.svg
18280 open-sans-v15-latin-300.df17d4e30091735253a8.woff
14564 open-sans-v15-latin-300.f2ebdee8c2343f558a02.woff2
18476 open-sans-v15-latin-700.2509c35b0cfc629f81e5.woff
14720 open-sans-v15-latin-700.7435e6c2064f36f48626.woff2
15667 open-sans-v15-latin-700.75e0e55bdb3e82dcacf8.eot
55652 open-sans-v15-latin-700.926388f043fc8117b35b.svg
28192 open-sans-v15-latin-700.ec32d6be7329ece0789c.ttf
56266 open-sans-v15-latin-regular.1d0d8b66fa1da76d69b9.svg
26488 open-sans-v15-latin-regular.61747992dd9a412e601e.ttf
17704 open-sans-v15-latin-regular.87a454b233bedae23f8d.woff
15050 open-sans-v15-latin-regular.a356e361ee6765f3d6d4.eot
14048 open-sans-v15-latin-regular.ec806460121999bcfb12.woff2
  118 password-meter.eea288d50533d7995ec1.png
85747 polyfills-es2015.16ceb16b32a8545e7574.js
180943 polyfills-es5.006e024480b437b2c337.js
39572 primeicons.04701ca33ce96d325419.ttf
39648 primeicons.1d79a0559e5f13294dee.woff
39748 primeicons.c2e128a00fca2640240d.eot
163568 primeicons.fa2c83d2f35244bb10dc.svg
 2289 runtime-es2015.2e6109e62d8c1599b4b0.js
 2286 runtime-es5.2e6109e62d8c1599b4b0.js
557012 scripts.d206f7319f6122bd4e1d.js
407942 styles.47345563e6287b4278d5.css

Con esto ya lo tendrías todo! espero que te sea de utilidad !

Google Analytics en Angular

Si trabajas con Angular (o algún sistema similar SPA) y has intentado usar google analytics para monitorizar tu página, te habrás dado cuenta de que GA no es capaz de «seguir» los cambios de URL de las SPA.

para que el seguimiento se realize correctamente, debemos llamar la función de Google Analytics que notifica que una URL ha sido visitada. Existen diferentes maneras de hacerlo, pero te explicaré la que yo uso 😉


El Script de Google Analytics

Voy a dar por supuesto que te has registrado en Google Analytics y tienes ya tu identificador ( del estilo ‘UA-4353454353-6’) Si no es así, ya sabes lo que toca!

Añade este código en tu ‘index.html’

<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-XXXXXXXXX-X', 'auto');
</script>

Este es el código de Google que realizará el seguimiento. (Recuerda cambiar ‘UA-XXXXXXXXX-X’ por tu ID!!)

 

Fíjate que hemos eliminado del script original de GA la línea

ga('send', 'pageview');

Esta es la función que «comunica» la url que estamos visitando. La eliminamos por que la llamaremos desde el constructor de nuestros componentes.

Cargando las funciones GA en los componentes

Ahora, para poder llamar las funciones de Google Analytics desde nuestros componentes, vamos a instalar los @types/google.analytics que contienen las definiciones para Google Analytics. (Puedes consultar el paquete npm para más información)

Para instalarlas ejecutaremos en la carpeta de nuestro proyecto la siguiente instrucción:

npm install --save-dev @types/google.analytics

De esta manera tendremos disponibles las funciones ga() en nuestros componentes.

 

Llamando a desde el constructor del componente

Genial, pues solo nos falta llamar las funciones desde el componente que deseemos (hay que tener en cuenta que deberemos añadir este código a los constructores de cada componente que sea subsceptible de ser llamado por una ruta)
  constructor(
    private router: Router,
  ) {
    this.router.events.subscribe(event => {
    if (event instanceof NavigationEnd) {
        ga('set', 'page', event.urlAfterRedirects);
        ga('send', 'pageview');
    }
    });
  }
Como habrás adivinado, debes importar el Router de angular y el NavigationEnd para poder usarlos:
import { Router } from '@angular/router';
import { NavigationEnd } from '@angular/router';

En ocasiones algunos usuarios han reportado errores del estilo:
Cannot find name 'ga'. webpack: Failed to compile.
Esto es debido a que al compilar, angular no reconoce ga() como una función (aunque en realidad si esta disponible). Podemos solucionarlo fácilmente escribiendo la siguiente línea justo debajo de los imports:
declare var ga: Function;

Y con esto ya lo tienes! Tu página está monitorizada y podrás saber que le gusta a tus visitantes!

¿Qué són los Evergreen Browsers?

El término «evergreen browser» se refiere a los navegadores que se actualizan automáticamente a futuras versiones, en lugar de actualizarse mediante la distribución de nuevas versiones del fabricante, como es el caso de los exploradores incluidos en sistemas operativos como windows XP, Vista o 7.

El nombre «evergreen browser» viene dado por las hojas de compatibilidad de las versiones, en las que se comparan los navegadores con sus listas de compatibilidades, pintando las celdas de color verde si son compatibles y en rojo si no lo son.

Los evergreen son aquellos que siempre tienen su última versión en verde (compatible con las funcionalidades actuales)

Aparentemente este concepto de puede dar problemas a los desarolladores, ya que están forzados a tener en cuenta cada una de las versiones que se publican y dada la alta frecuencia de  actualizaciones, puede llegar a ser un quebradero de cabeza.

Por suerte, si los desarolladores siguen todos los estándares establecidos, las nuevas versiones respetarán el aspecto general (salvando algunas nuevas funcionalidades) y las webs serán compatibles o parcialmente compatibles.

¿Entonces que navegador debo usar?

Vayamos al grano: a día de hoy, prácticamente todos los sistemas operativos modernos traen un navegador que se actualiza regularmente, por lo tanto si usamos MacOS X 10.4 Mojave, Windows 10, iOS o Android en sus últimas versiones, podemos estar seguros de que los navegadores se mantienen actualizados.

Si por el contrario tenemso Windows XP o 7 (por ejemplo) nuestros navegadores seguramente ya estarán obsoletos.

Dicho esto, en términos generales podemos decir que nuestras preferencias de navegadores deberían ser Chrome, Firefox, Opera o Edge .

Personalmente uso Chrome, pero como os podéis imaginar, es cuestión de gustos!

OJO!

En Windows 10 todavía se conserva Internet Explorer como navegador, pero hay que diferenciarlo de Edge, són navegadores diferentes y Internet Explorer actualmente se considera obsoleto!

Comparando cadenas: Eliminar acentos de una cadena con JavaScript

Desde que me dedico a la programación, me he encontrado en multitud de ocasiones con el problema de los acentos, ya se por que no se visualizan bien en las webs, porque el charset no esta bien especificado en la base de datos y nos los «convierte» en «simbolos raros» o porque al comparar cadenas necesitaríamos eliminarlos.

Habitualmente, al hacer buscadores o programar funciones que comparen un texto, nos encontramos con que el usuario es vago o analfabeto y no escribe correctamente. Esto se traduce en errores al comparar las cadenas de texto.

Lo primero que debemos hacer para garantizar que estamos comparando correctamente es pasar todo el texto a mayúsculas (o minúsculas, como prefieras) para lo cual tenemos las funciones toLowerCase() / toUpperCase() y podemos usarlas así:

let str = 'Mi Cadena de prueba';
console.log(str.toLowerCase());
console.log(str.toUpperCase());

Lo que nos produciría la siguiente salida:

mi cadena de prueba
MI CADENA DE PRUEBA

Hasta aquí todo fácil, ¿no? 
Pero … ¿y para eliminar los acentos?
Pues no existe ninguna función que permita eliminarlos, así que lo único que podemos hacer, es definirnos una nosotros mismos.

Si buscas por Internet, podrás ver una gran cantidad de «maneras» de eliminar los acentos, haciendo sustituciones con expresiones regulares o convirtiendo las cadenas de formato.

Pero muchas de ellas son «sucias» y muy rebuscadas. Por eso te propongo esta:

let str = 'Más Cadenas';
console.log(str.normalize('NFD').replace(/[\u00C0-\u00FF]/g, ''));

// Salida: 'Mas Cadenas'

Con esto ya tendríamos nuestra cadena lista para se comparada de manera que si unimos todos los trozos de código, podemos definirnos una función que nos «prepare» nuestro texto para ser comparado. Te pongo un ejemplo:

cleanCadena(value) {
 return return value.normalize('NFD').replace(/[\u00C0-\u00FF]/g, '').toUpperCase();
}

Recuerda que cuando vayas a comprar dos cadenas, deberás pasar ambas por el cleanCadena(), es muy común limpiar únicamente el valor a buscar por despiste!!